Blame cgi-bin/help-index.c

Packit 2fc92b
/*
Packit 2fc92b
 * Online help index routines for CUPS.
Packit 2fc92b
 *
Packit 2fc92b
 * Copyright 2007-2015 by Apple Inc.
Packit 2fc92b
 * Copyright 1997-2007 by Easy Software Products.
Packit 2fc92b
 *
Packit 2fc92b
 * These coded instructions, statements, and computer programs are the
Packit 2fc92b
 * property of Apple Inc. and are protected by Federal copyright
Packit 2fc92b
 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
Packit 2fc92b
 * which should have been included with this file.  If this file is
Packit 2fc92b
 * missing or damaged, see the license at "http://www.cups.org/".
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Include necessary headers...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
#include "cgi-private.h"
Packit 2fc92b
#include <cups/dir.h>
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * List of common English words that should not be indexed...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static char		help_common_words[][6] =
Packit 2fc92b
			{
Packit 2fc92b
			  "about",
Packit 2fc92b
			  "all",
Packit 2fc92b
			  "an",
Packit 2fc92b
			  "and",
Packit 2fc92b
			  "are",
Packit 2fc92b
			  "as",
Packit 2fc92b
			  "at",
Packit 2fc92b
			  "be",
Packit 2fc92b
			  "been",
Packit 2fc92b
			  "but",
Packit 2fc92b
			  "by",
Packit 2fc92b
			  "call",
Packit 2fc92b
			  "can",
Packit 2fc92b
			  "come",
Packit 2fc92b
			  "could",
Packit 2fc92b
			  "day",
Packit 2fc92b
			  "did",
Packit 2fc92b
			  "do",
Packit 2fc92b
			  "down",
Packit 2fc92b
			  "each",
Packit 2fc92b
			  "find",
Packit 2fc92b
			  "first",
Packit 2fc92b
			  "for",
Packit 2fc92b
			  "from",
Packit 2fc92b
			  "go",
Packit 2fc92b
			  "had",
Packit 2fc92b
			  "has",
Packit 2fc92b
			  "have",
Packit 2fc92b
			  "he",
Packit 2fc92b
			  "her",
Packit 2fc92b
			  "him",
Packit 2fc92b
			  "his",
Packit 2fc92b
			  "hot",
Packit 2fc92b
			  "how",
Packit 2fc92b
			  "if",
Packit 2fc92b
			  "in",
Packit 2fc92b
			  "is",
Packit 2fc92b
			  "it",
Packit 2fc92b
			  "know",
Packit 2fc92b
			  "like",
Packit 2fc92b
			  "long",
Packit 2fc92b
			  "look",
Packit 2fc92b
			  "make",
Packit 2fc92b
			  "many",
Packit 2fc92b
			  "may",
Packit 2fc92b
			  "more",
Packit 2fc92b
			  "most",
Packit 2fc92b
			  "my",
Packit 2fc92b
			  "no",
Packit 2fc92b
			  "now",
Packit 2fc92b
			  "of",
Packit 2fc92b
			  "on",
Packit 2fc92b
			  "one",
Packit 2fc92b
			  "or",
Packit 2fc92b
			  "other",
Packit 2fc92b
			  "out",
Packit 2fc92b
			  "over",
Packit 2fc92b
			  "said",
Packit 2fc92b
			  "see",
Packit 2fc92b
			  "she",
Packit 2fc92b
			  "side",
Packit 2fc92b
			  "so",
Packit 2fc92b
			  "some",
Packit 2fc92b
			  "sound",
Packit 2fc92b
			  "than",
Packit 2fc92b
			  "that",
Packit 2fc92b
			  "the",
Packit 2fc92b
			  "their",
Packit 2fc92b
			  "them",
Packit 2fc92b
			  "then",
Packit 2fc92b
			  "there",
Packit 2fc92b
			  "these",
Packit 2fc92b
			  "they",
Packit 2fc92b
			  "thing",
Packit 2fc92b
			  "this",
Packit 2fc92b
			  "time",
Packit 2fc92b
			  "to",
Packit 2fc92b
			  "two",
Packit 2fc92b
			  "up",
Packit 2fc92b
			  "use",
Packit 2fc92b
			  "was",
Packit 2fc92b
			  "water",
Packit 2fc92b
			  "way",
Packit 2fc92b
			  "we",
Packit 2fc92b
			  "were",
Packit 2fc92b
			  "what",
Packit 2fc92b
			  "when",
Packit 2fc92b
			  "which",
Packit 2fc92b
			  "who",
Packit 2fc92b
			  "will",
Packit 2fc92b
			  "with",
Packit 2fc92b
			  "word",
Packit 2fc92b
			  "would",
Packit 2fc92b
			  "write",
Packit 2fc92b
			  "you",
Packit 2fc92b
			  "your"
Packit 2fc92b
			};
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * Local functions...
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static help_word_t	*help_add_word(help_node_t *n, const char *text);
Packit 2fc92b
static void		help_delete_node(help_node_t *n);
Packit 2fc92b
static void		help_delete_word(help_word_t *w);
Packit 2fc92b
static int		help_load_directory(help_index_t *hi,
Packit 2fc92b
			                    const char *directory,
Packit 2fc92b
					    const char *relative);
Packit 2fc92b
static int		help_load_file(help_index_t *hi,
Packit 2fc92b
			               const char *filename,
Packit 2fc92b
				       const char *relative,
Packit 2fc92b
				       time_t     mtime);
Packit 2fc92b
static help_node_t	*help_new_node(const char *filename, const char *anchor,
Packit 2fc92b
			               const char *section, const char *text,
Packit 2fc92b
				       time_t mtime, off_t offset,
Packit 2fc92b
				       size_t length)
Packit 2fc92b
				       __attribute__((nonnull(1,3,4)));
Packit 2fc92b
static int		help_sort_by_name(help_node_t *p1, help_node_t *p2);
Packit 2fc92b
static int		help_sort_by_score(help_node_t *p1, help_node_t *p2);
Packit 2fc92b
static int		help_sort_words(help_word_t *w1, help_word_t *w2);
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'helpDeleteIndex()' - Delete an index, freeing all memory used.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
void
Packit 2fc92b
helpDeleteIndex(help_index_t *hi)	/* I - Help index */
Packit 2fc92b
{
Packit 2fc92b
  help_node_t	*node;			/* Current node */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("helpDeleteIndex(hi=%p)", hi));
Packit 2fc92b
Packit 2fc92b
  if (!hi)
Packit 2fc92b
    return;
Packit 2fc92b
Packit 2fc92b
  for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
Packit 2fc92b
       node;
Packit 2fc92b
       node = (help_node_t *)cupsArrayNext(hi->nodes))
Packit 2fc92b
  {
Packit 2fc92b
    if (!hi->search)
Packit 2fc92b
      help_delete_node(node);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  cupsArrayDelete(hi->nodes);
Packit 2fc92b
  cupsArrayDelete(hi->sorted);
Packit 2fc92b
Packit 2fc92b
  free(hi);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'helpFindNode()' - Find a node in an index.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
help_node_t *				/* O - Node pointer or NULL */
Packit 2fc92b
helpFindNode(help_index_t *hi,		/* I - Index */
Packit 2fc92b
             const char   *filename,	/* I - Filename */
Packit 2fc92b
             const char   *anchor)	/* I - Anchor */
Packit 2fc92b
{
Packit 2fc92b
  help_node_t	key;			/* Search key */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("helpFindNode(hi=%p, filename=\"%s\", anchor=\"%s\")",
Packit 2fc92b
                hi, filename, anchor));
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Range check input...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (!hi || !filename)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Initialize the search key...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  key.filename = (char *)filename;
Packit 2fc92b
  key.anchor   = (char *)anchor;
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Return any match...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  return ((help_node_t *)cupsArrayFind(hi->nodes, &key));
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'helpLoadIndex()' - Load a help index from disk.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
help_index_t *				/* O - Index pointer or NULL */
Packit 2fc92b
helpLoadIndex(const char *hifile,	/* I - Index filename */
Packit 2fc92b
              const char *directory)	/* I - Directory that is indexed */
Packit 2fc92b
{
Packit 2fc92b
  help_index_t	*hi;			/* Help index */
Packit 2fc92b
  cups_file_t	*fp;			/* Current file */
Packit 2fc92b
  char		line[2048],		/* Line from file */
Packit 2fc92b
		*ptr,			/* Pointer into line */
Packit 2fc92b
		*filename,		/* Filename in line */
Packit 2fc92b
		*anchor,		/* Anchor in line */
Packit 2fc92b
		*sectptr,		/* Section pointer in line */
Packit 2fc92b
		section[1024],		/* Section name */
Packit 2fc92b
		*text;			/* Text in line */
Packit 2fc92b
  time_t	mtime;			/* Modification time */
Packit 2fc92b
  off_t		offset;			/* Offset into file */
Packit 2fc92b
  size_t	length;			/* Length in bytes */
Packit 2fc92b
  int		update;			/* Update? */
Packit 2fc92b
  help_node_t	*node;			/* Current node */
Packit 2fc92b
  help_word_t	*word;			/* Current word */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("helpLoadIndex(hifile=\"%s\", directory=\"%s\")",
Packit 2fc92b
                hifile, directory));
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Create a new, empty index.
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if ((hi = (help_index_t *)calloc(1, sizeof(help_index_t))) == NULL)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  hi->nodes  = cupsArrayNew((cups_array_func_t)help_sort_by_name, NULL);
Packit 2fc92b
  hi->sorted = cupsArrayNew((cups_array_func_t)help_sort_by_score, NULL);
Packit 2fc92b
Packit 2fc92b
  if (!hi->nodes || !hi->sorted)
Packit 2fc92b
  {
Packit 2fc92b
    cupsArrayDelete(hi->nodes);
Packit 2fc92b
    cupsArrayDelete(hi->sorted);
Packit 2fc92b
    free(hi);
Packit 2fc92b
    return (NULL);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Try loading the existing index file...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if ((fp = cupsFileOpen(hifile, "r")) != NULL)
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Lock the file and then read the first line...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    cupsFileLock(fp, 1);
Packit 2fc92b
Packit 2fc92b
    if (cupsFileGets(fp, line, sizeof(line)) && !strcmp(line, "HELPV2"))
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Got a valid header line, now read the data lines...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      node = NULL;
Packit 2fc92b
Packit 2fc92b
      while (cupsFileGets(fp, line, sizeof(line)))
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
	* Each line looks like one of the following:
Packit 2fc92b
	*
Packit 2fc92b
	*     filename mtime offset length "section" "text"
Packit 2fc92b
	*     filename#anchor offset length "text"
Packit 2fc92b
	*     SP count word
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
        if (line[0] == ' ')
Packit 2fc92b
	{
Packit 2fc92b
	 /*
Packit 2fc92b
	  * Read a word in the current node...
Packit 2fc92b
	  */
Packit 2fc92b
Packit 2fc92b
          if (!node || (ptr = strrchr(line, ' ')) == NULL)
Packit 2fc92b
	    continue;
Packit 2fc92b
Packit 2fc92b
          if ((word = help_add_word(node, ptr + 1)) != NULL)
Packit 2fc92b
	    word->count = atoi(line + 1);
Packit 2fc92b
        }
Packit 2fc92b
	else
Packit 2fc92b
	{
Packit 2fc92b
	 /*
Packit 2fc92b
	  * Add a node...
Packit 2fc92b
	  */
Packit 2fc92b
Packit 2fc92b
	  filename = line;
Packit 2fc92b
Packit 2fc92b
	  if ((ptr = strchr(line, ' ')) == NULL)
Packit 2fc92b
            break;
Packit 2fc92b
Packit 2fc92b
	  while (isspace(*ptr & 255))
Packit 2fc92b
            *ptr++ = '\0';
Packit 2fc92b
Packit 2fc92b
	  if ((anchor = strrchr(filename, '#')) != NULL)
Packit 2fc92b
	  {
Packit 2fc92b
            *anchor++ = '\0';
Packit 2fc92b
	    mtime = 0;
Packit 2fc92b
	  }
Packit 2fc92b
	  else
Packit 2fc92b
	    mtime = strtol(ptr, &ptr, 10);
Packit 2fc92b
Packit 2fc92b
	  offset = strtoll(ptr, &ptr, 10);
Packit 2fc92b
	  length = (size_t)strtoll(ptr, &ptr, 10);
Packit 2fc92b
Packit 2fc92b
	  while (isspace(*ptr & 255))
Packit 2fc92b
            ptr ++;
Packit 2fc92b
Packit 2fc92b
          if (!anchor)
Packit 2fc92b
	  {
Packit 2fc92b
	   /*
Packit 2fc92b
	    * Get section...
Packit 2fc92b
	    */
Packit 2fc92b
Packit 2fc92b
            if (*ptr != '\"')
Packit 2fc92b
	      break;
Packit 2fc92b
Packit 2fc92b
            ptr ++;
Packit 2fc92b
	    sectptr = ptr;
Packit 2fc92b
Packit 2fc92b
            while (*ptr && *ptr != '\"')
Packit 2fc92b
	      ptr ++;
Packit 2fc92b
Packit 2fc92b
            if (*ptr != '\"')
Packit 2fc92b
	      break;
Packit 2fc92b
Packit 2fc92b
            *ptr++ = '\0';
Packit 2fc92b
Packit 2fc92b
            strlcpy(section, sectptr, sizeof(section));
Packit 2fc92b
Packit 2fc92b
	    while (isspace(*ptr & 255))
Packit 2fc92b
              ptr ++;
Packit 2fc92b
          }
Packit 2fc92b
Packit 2fc92b
          if (*ptr != '\"')
Packit 2fc92b
	    break;
Packit 2fc92b
Packit 2fc92b
          ptr ++;
Packit 2fc92b
	  text = ptr;
Packit 2fc92b
Packit 2fc92b
          while (*ptr && *ptr != '\"')
Packit 2fc92b
	    ptr ++;
Packit 2fc92b
Packit 2fc92b
          if (*ptr != '\"')
Packit 2fc92b
	    break;
Packit 2fc92b
Packit 2fc92b
          *ptr++ = '\0';
Packit 2fc92b
Packit 2fc92b
	  if ((node = help_new_node(filename, anchor, section, text,
Packit 2fc92b
				    mtime, offset, length)) == NULL)
Packit 2fc92b
            break;
Packit 2fc92b
Packit 2fc92b
	  node->score = -1;
Packit 2fc92b
Packit 2fc92b
	  cupsArrayAdd(hi->nodes, node);
Packit 2fc92b
        }
Packit 2fc92b
      }
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    cupsFileClose(fp);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Scan for new/updated files...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  update = help_load_directory(hi, directory, NULL);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Remove any files that are no longer installed...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
Packit 2fc92b
       node;
Packit 2fc92b
       node = (help_node_t *)cupsArrayNext(hi->nodes))
Packit 2fc92b
    if (node->score < 0)
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Delete this node...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      cupsArrayRemove(hi->nodes, node);
Packit 2fc92b
      help_delete_node(node);
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Add nodes to the sorted array...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
Packit 2fc92b
       node;
Packit 2fc92b
       node = (help_node_t *)cupsArrayNext(hi->nodes))
Packit 2fc92b
    cupsArrayAdd(hi->sorted, node);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Save the index if we updated it...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (update)
Packit 2fc92b
    helpSaveIndex(hi, hifile);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Return the index...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  return (hi);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'helpSaveIndex()' - Save a help index to disk.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
int					/* O - 0 on success, -1 on error */
Packit 2fc92b
helpSaveIndex(help_index_t *hi,		/* I - Index */
Packit 2fc92b
              const char   *hifile)	/* I - Index filename */
Packit 2fc92b
{
Packit 2fc92b
  cups_file_t	*fp;			/* Index file */
Packit 2fc92b
  help_node_t	*node;			/* Current node */
Packit 2fc92b
  help_word_t	*word;			/* Current word */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("helpSaveIndex(hi=%p, hifile=\"%s\")", hi, hifile));
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Try creating a new index file...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if ((fp = cupsFileOpen(hifile, "w9")) == NULL)
Packit 2fc92b
    return (-1);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Lock the file while we write it...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  cupsFileLock(fp, 1);
Packit 2fc92b
Packit 2fc92b
  cupsFilePuts(fp, "HELPV2\n");
Packit 2fc92b
Packit 2fc92b
  for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
Packit 2fc92b
       node;
Packit 2fc92b
       node = (help_node_t *)cupsArrayNext(hi->nodes))
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Write the current node with/without the anchor...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    if (node->anchor)
Packit 2fc92b
    {
Packit 2fc92b
      if (cupsFilePrintf(fp, "%s#%s " CUPS_LLFMT " " CUPS_LLFMT " \"%s\"\n",
Packit 2fc92b
                         node->filename, node->anchor,
Packit 2fc92b
                         CUPS_LLCAST node->offset, CUPS_LLCAST node->length,
Packit 2fc92b
			 node->text) < 0)
Packit 2fc92b
        break;
Packit 2fc92b
    }
Packit 2fc92b
    else
Packit 2fc92b
    {
Packit 2fc92b
      if (cupsFilePrintf(fp, "%s %d " CUPS_LLFMT " " CUPS_LLFMT " \"%s\" \"%s\"\n",
Packit 2fc92b
                         node->filename, (int)node->mtime,
Packit 2fc92b
                         CUPS_LLCAST node->offset, CUPS_LLCAST node->length,
Packit 2fc92b
			 node->section ? node->section : "", node->text) < 0)
Packit 2fc92b
        break;
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
   /*
Packit 2fc92b
    * Then write the words associated with the node...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    for (word = (help_word_t *)cupsArrayFirst(node->words);
Packit 2fc92b
         word;
Packit 2fc92b
	 word = (help_word_t *)cupsArrayNext(node->words))
Packit 2fc92b
      if (cupsFilePrintf(fp, " %d %s\n", word->count, word->text) < 0)
Packit 2fc92b
        break;
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  cupsFileFlush(fp);
Packit 2fc92b
Packit 2fc92b
  if (cupsFileClose(fp) < 0)
Packit 2fc92b
    return (-1);
Packit 2fc92b
  else if (node)
Packit 2fc92b
    return (-1);
Packit 2fc92b
  else
Packit 2fc92b
    return (0);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'helpSearchIndex()' - Search an index.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
help_index_t *				/* O - Search index */
Packit 2fc92b
helpSearchIndex(help_index_t *hi,	/* I - Index */
Packit 2fc92b
                const char   *query,	/* I - Query string */
Packit 2fc92b
		const char   *section,	/* I - Limit search to this section */
Packit 2fc92b
		const char   *filename)	/* I - Limit search to this file */
Packit 2fc92b
{
Packit 2fc92b
  help_index_t	*search;		/* Search index */
Packit 2fc92b
  help_node_t	*node;			/* Current node */
Packit 2fc92b
  help_word_t	*word;			/* Current word */
Packit 2fc92b
  void		*sc;			/* Search context */
Packit 2fc92b
  int		matches;		/* Number of matches */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("helpSearchIndex(hi=%p, query=\"%s\", filename=\"%s\")",
Packit 2fc92b
                hi, query, filename));
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Range check...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (!hi || !query)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Reset the scores of all nodes to 0...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
Packit 2fc92b
       node;
Packit 2fc92b
       node = (help_node_t *)cupsArrayNext(hi->nodes))
Packit 2fc92b
    node->score = 0;
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Find the first node to search in...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (filename)
Packit 2fc92b
  {
Packit 2fc92b
    node = helpFindNode(hi, filename, NULL);
Packit 2fc92b
    if (!node)
Packit 2fc92b
      return (NULL);
Packit 2fc92b
  }
Packit 2fc92b
  else
Packit 2fc92b
    node = (help_node_t *)cupsArrayFirst(hi->nodes);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Convert the query into a regular expression...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  sc = cgiCompileSearch(query);
Packit 2fc92b
  if (!sc)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Allocate a search index...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  search = calloc(1, sizeof(help_index_t));
Packit 2fc92b
  if (!search)
Packit 2fc92b
  {
Packit 2fc92b
    cgiFreeSearch(sc);
Packit 2fc92b
    return (NULL);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  search->nodes  = cupsArrayNew((cups_array_func_t)help_sort_by_name, NULL);
Packit 2fc92b
  search->sorted = cupsArrayNew((cups_array_func_t)help_sort_by_score, NULL);
Packit 2fc92b
Packit 2fc92b
  if (!search->nodes || !search->sorted)
Packit 2fc92b
  {
Packit 2fc92b
    cupsArrayDelete(search->nodes);
Packit 2fc92b
    cupsArrayDelete(search->sorted);
Packit 2fc92b
    free(search);
Packit 2fc92b
    cgiFreeSearch(sc);
Packit 2fc92b
    return (NULL);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  search->search = 1;
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Check each node in the index, adding matching nodes to the
Packit 2fc92b
  * search index...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  for (; node; node = (help_node_t *)cupsArrayNext(hi->nodes))
Packit 2fc92b
    if (section && strcmp(node->section, section))
Packit 2fc92b
      continue;
Packit 2fc92b
    else if (filename && strcmp(node->filename, filename))
Packit 2fc92b
      continue;
Packit 2fc92b
    else
Packit 2fc92b
    {
Packit 2fc92b
      matches = cgiDoSearch(sc, node->text);
Packit 2fc92b
Packit 2fc92b
      for (word = (help_word_t *)cupsArrayFirst(node->words);
Packit 2fc92b
           word;
Packit 2fc92b
	   word = (help_word_t *)cupsArrayNext(node->words))
Packit 2fc92b
        if (cgiDoSearch(sc, word->text) > 0)
Packit 2fc92b
          matches += word->count;
Packit 2fc92b
Packit 2fc92b
      if (matches > 0)
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
	* Found a match, add the node to the search index...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
	node->score = matches;
Packit 2fc92b
Packit 2fc92b
	cupsArrayAdd(search->nodes, node);
Packit 2fc92b
	cupsArrayAdd(search->sorted, node);
Packit 2fc92b
      }
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Free the search context...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  cgiFreeSearch(sc);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Return the results...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  return (search);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'help_add_word()' - Add a word to a node.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static help_word_t *			/* O - New word */
Packit 2fc92b
help_add_word(help_node_t *n,		/* I - Node */
Packit 2fc92b
              const char  *text)	/* I - Word text */
Packit 2fc92b
{
Packit 2fc92b
  help_word_t	*w,			/* New word */
Packit 2fc92b
		key;			/* Search key */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("2help_add_word(n=%p, text=\"%s\")", n, text));
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Create the words array as needed...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if (!n->words)
Packit 2fc92b
    n->words = cupsArrayNew((cups_array_func_t)help_sort_words, NULL);
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * See if the word is already added...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  key.text = (char *)text;
Packit 2fc92b
Packit 2fc92b
  if ((w = (help_word_t *)cupsArrayFind(n->words, &key)) == NULL)
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Create a new word...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    if ((w = calloc(1, sizeof(help_word_t))) == NULL)
Packit 2fc92b
      return (NULL);
Packit 2fc92b
Packit 2fc92b
    if ((w->text = strdup(text)) == NULL)
Packit 2fc92b
    {
Packit 2fc92b
      free(w);
Packit 2fc92b
      return (NULL);
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    cupsArrayAdd(n->words, w);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Bump the counter for this word and return it...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  w->count ++;
Packit 2fc92b
Packit 2fc92b
  return (w);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'help_delete_node()' - Free all memory used by a node.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void
Packit 2fc92b
help_delete_node(help_node_t *n)	/* I - Node */
Packit 2fc92b
{
Packit 2fc92b
  help_word_t	*w;			/* Current word */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("2help_delete_node(n=%p)", n));
Packit 2fc92b
Packit 2fc92b
  if (!n)
Packit 2fc92b
    return;
Packit 2fc92b
Packit 2fc92b
  if (n->filename)
Packit 2fc92b
    free(n->filename);
Packit 2fc92b
Packit 2fc92b
  if (n->anchor)
Packit 2fc92b
    free(n->anchor);
Packit 2fc92b
Packit 2fc92b
  if (n->section)
Packit 2fc92b
    free(n->section);
Packit 2fc92b
Packit 2fc92b
  if (n->text)
Packit 2fc92b
    free(n->text);
Packit 2fc92b
Packit 2fc92b
  for (w = (help_word_t *)cupsArrayFirst(n->words);
Packit 2fc92b
       w;
Packit 2fc92b
       w = (help_word_t *)cupsArrayNext(n->words))
Packit 2fc92b
    help_delete_word(w);
Packit 2fc92b
Packit 2fc92b
  cupsArrayDelete(n->words);
Packit 2fc92b
Packit 2fc92b
  free(n);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'help_delete_word()' - Free all memory used by a word.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static void
Packit 2fc92b
help_delete_word(help_word_t *w)	/* I - Word */
Packit 2fc92b
{
Packit 2fc92b
  DEBUG_printf(("2help_delete_word(w=%p)", w));
Packit 2fc92b
Packit 2fc92b
  if (!w)
Packit 2fc92b
    return;
Packit 2fc92b
Packit 2fc92b
  if (w->text)
Packit 2fc92b
    free(w->text);
Packit 2fc92b
Packit 2fc92b
  free(w);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'help_load_directory()' - Load a directory of files into an index.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static int				/* O - 0 = success, -1 = error, 1 = updated */
Packit 2fc92b
help_load_directory(
Packit 2fc92b
    help_index_t *hi,			/* I - Index */
Packit 2fc92b
    const char   *directory,		/* I - Directory */
Packit 2fc92b
    const char   *relative)		/* I - Relative path */
Packit 2fc92b
{
Packit 2fc92b
  cups_dir_t	*dir;			/* Directory file */
Packit 2fc92b
  cups_dentry_t	*dent;			/* Directory entry */
Packit 2fc92b
  char		*ext,			/* Pointer to extension */
Packit 2fc92b
		filename[1024],		/* Full filename */
Packit 2fc92b
		relname[1024];		/* Relative filename */
Packit 2fc92b
  int		update;			/* Updated? */
Packit 2fc92b
  help_node_t	*node;			/* Current node */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("2help_load_directory(hi=%p, directory=\"%s\", relative=\"%s\")",
Packit 2fc92b
                hi, directory, relative));
Packit 2fc92b
Packit 2fc92b
 /*
Packit 2fc92b
  * Open the directory and scan it...
Packit 2fc92b
  */
Packit 2fc92b
Packit 2fc92b
  if ((dir = cupsDirOpen(directory)) == NULL)
Packit 2fc92b
    return (0);
Packit 2fc92b
Packit 2fc92b
  update = 0;
Packit 2fc92b
Packit 2fc92b
  while ((dent = cupsDirRead(dir)) != NULL)
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Skip "." files...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    if (dent->filename[0] == '.')
Packit 2fc92b
      continue;
Packit 2fc92b
Packit 2fc92b
   /*
Packit 2fc92b
    * Get absolute and relative filenames...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    snprintf(filename, sizeof(filename), "%s/%s", directory, dent->filename);
Packit 2fc92b
    if (relative)
Packit 2fc92b
      snprintf(relname, sizeof(relname), "%s/%s", relative, dent->filename);
Packit 2fc92b
    else
Packit 2fc92b
      strlcpy(relname, dent->filename, sizeof(relname));
Packit 2fc92b
Packit 2fc92b
   /*
Packit 2fc92b
    * Check if we have a HTML file...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    if ((ext = strstr(dent->filename, ".html")) != NULL &&
Packit 2fc92b
        (!ext[5] || !strcmp(ext + 5, ".gz")))
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * HTML file, see if we have already indexed the file...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      if ((node = helpFindNode(hi, relname, NULL)) != NULL)
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
        * File already indexed - check dates to confirm that the
Packit 2fc92b
	* index is up-to-date...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
        if (node->mtime == dent->fileinfo.st_mtime)
Packit 2fc92b
	{
Packit 2fc92b
	 /*
Packit 2fc92b
	  * Same modification time, so mark all of the nodes
Packit 2fc92b
	  * for this file as up-to-date...
Packit 2fc92b
	  */
Packit 2fc92b
Packit 2fc92b
          for (; node; node = (help_node_t *)cupsArrayNext(hi->nodes))
Packit 2fc92b
	    if (!strcmp(node->filename, relname))
Packit 2fc92b
	      node->score = 0;
Packit 2fc92b
	    else
Packit 2fc92b
	      break;
Packit 2fc92b
Packit 2fc92b
          continue;
Packit 2fc92b
	}
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
      update = 1;
Packit 2fc92b
Packit 2fc92b
      help_load_file(hi, filename, relname, dent->fileinfo.st_mtime);
Packit 2fc92b
    }
Packit 2fc92b
    else if (S_ISDIR(dent->fileinfo.st_mode))
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Process sub-directory...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      if (help_load_directory(hi, filename, relname) == 1)
Packit 2fc92b
        update = 1;
Packit 2fc92b
    }
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  cupsDirClose(dir);
Packit 2fc92b
Packit 2fc92b
  return (update);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'help_load_file()' - Load a HTML files into an index.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static int				/* O - 0 = success, -1 = error */
Packit 2fc92b
help_load_file(
Packit 2fc92b
    help_index_t *hi,			/* I - Index */
Packit 2fc92b
    const char   *filename,		/* I - Filename */
Packit 2fc92b
    const char   *relative,		/* I - Relative path */
Packit 2fc92b
    time_t       mtime)			/* I - Modification time */
Packit 2fc92b
{
Packit 2fc92b
  cups_file_t	*fp;			/* HTML file */
Packit 2fc92b
  help_node_t	*node;			/* Current node */
Packit 2fc92b
  char		line[1024],		/* Line from file */
Packit 2fc92b
		temp[1024],		/* Temporary word */
Packit 2fc92b
                section[1024],		/* Section */
Packit 2fc92b
		*ptr,			/* Pointer into line */
Packit 2fc92b
		*anchor,		/* Anchor name */
Packit 2fc92b
		*text;			/* Text for anchor */
Packit 2fc92b
  off_t		offset;			/* File offset */
Packit 2fc92b
  char		quote;			/* Quote character */
Packit 2fc92b
  help_word_t	*word;			/* Current word */
Packit 2fc92b
  int		wordlen;		/* Length of word */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("2help_load_file(hi=%p, filename=\"%s\", relative=\"%s\", "
Packit 2fc92b
                "mtime=%ld)", hi, filename, relative, (long)mtime));
Packit 2fc92b
Packit 2fc92b
  if ((fp = cupsFileOpen(filename, "r")) == NULL)
Packit 2fc92b
    return (-1);
Packit 2fc92b
Packit 2fc92b
  node   = NULL;
Packit 2fc92b
  offset = 0;
Packit 2fc92b
Packit 2fc92b
  strlcpy(section, "Other", sizeof(section));
Packit 2fc92b
Packit 2fc92b
  while (cupsFileGets(fp, line, sizeof(line)))
Packit 2fc92b
  {
Packit 2fc92b
   /*
Packit 2fc92b
    * Look for "<TITLE>", "
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    if (!_cups_strncasecmp(line, "
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Got section line, copy it!
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      for (ptr = line + 13; isspace(*ptr & 255); ptr ++);
Packit 2fc92b
Packit 2fc92b
      strlcpy(section, ptr, sizeof(section));
Packit 2fc92b
      if ((ptr = strstr(section, "-->")) != NULL)
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
        * Strip comment stuff from end of line...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
        for (*ptr-- = '\0'; ptr > line && isspace(*ptr & 255); *ptr-- = '\0');
Packit 2fc92b
Packit 2fc92b
	if (isspace(*ptr & 255))
Packit 2fc92b
	  *ptr = '\0';
Packit 2fc92b
      }
Packit 2fc92b
      continue;
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    for (ptr = line; (ptr = strchr(ptr, '<')) != NULL;)
Packit 2fc92b
    {
Packit 2fc92b
      ptr ++;
Packit 2fc92b
Packit 2fc92b
      if (!_cups_strncasecmp(ptr, "TITLE>", 6))
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
        * Found the title...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
	anchor = NULL;
Packit 2fc92b
	ptr += 6;
Packit 2fc92b
      }
Packit 2fc92b
      else if (!_cups_strncasecmp(ptr, "A NAME=", 7))
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
        * Found an anchor...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
        ptr += 7;
Packit 2fc92b
Packit 2fc92b
	if (*ptr == '\"' || *ptr == '\'')
Packit 2fc92b
	{
Packit 2fc92b
	 /*
Packit 2fc92b
	  * Get quoted anchor...
Packit 2fc92b
	  */
Packit 2fc92b
Packit 2fc92b
	  quote  = *ptr;
Packit 2fc92b
          anchor = ptr + 1;
Packit 2fc92b
	  if ((ptr = strchr(anchor, quote)) != NULL)
Packit 2fc92b
	    *ptr++ = '\0';
Packit 2fc92b
	  else
Packit 2fc92b
	    break;
Packit 2fc92b
	}
Packit 2fc92b
	else
Packit 2fc92b
	{
Packit 2fc92b
	 /*
Packit 2fc92b
	  * Get unquoted anchor...
Packit 2fc92b
	  */
Packit 2fc92b
Packit 2fc92b
          anchor = ptr + 1;
Packit 2fc92b
Packit 2fc92b
	  for (ptr = anchor; *ptr && *ptr != '>' && !isspace(*ptr & 255); ptr ++);
Packit 2fc92b
Packit 2fc92b
	  if (*ptr)
Packit 2fc92b
	    *ptr++ = '\0';
Packit 2fc92b
	  else
Packit 2fc92b
	    break;
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
       /*
Packit 2fc92b
        * Got the anchor, now lets find the end...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
        while (*ptr && *ptr != '>')
Packit 2fc92b
	  ptr ++;
Packit 2fc92b
Packit 2fc92b
        if (*ptr != '>')
Packit 2fc92b
	  break;
Packit 2fc92b
Packit 2fc92b
        ptr ++;
Packit 2fc92b
      }
Packit 2fc92b
      else
Packit 2fc92b
        continue;
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * Now collect text for the link...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      text = ptr;
Packit 2fc92b
      while ((ptr = strchr(text, '<')) == NULL)
Packit 2fc92b
      {
Packit 2fc92b
	ptr = text + strlen(text);
Packit 2fc92b
	if (ptr >= (line + sizeof(line) - 2))
Packit 2fc92b
	  break;
Packit 2fc92b
Packit 2fc92b
        *ptr++ = ' ';
Packit 2fc92b
Packit 2fc92b
        if (!cupsFileGets(fp, ptr, sizeof(line) - (size_t)(ptr - line) - 1))
Packit 2fc92b
	  break;
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
      *ptr = '\0';
Packit 2fc92b
Packit 2fc92b
      if (node)
Packit 2fc92b
	node->length = (size_t)(offset - node->offset);
Packit 2fc92b
Packit 2fc92b
      if (!*text)
Packit 2fc92b
      {
Packit 2fc92b
        node = NULL;
Packit 2fc92b
        break;
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
      if ((node = helpFindNode(hi, relative, anchor)) != NULL)
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
	* Node already in the index, so replace the text and other
Packit 2fc92b
	* data...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
        cupsArrayRemove(hi->nodes, node);
Packit 2fc92b
Packit 2fc92b
        if (node->section)
Packit 2fc92b
	  free(node->section);
Packit 2fc92b
Packit 2fc92b
	if (node->text)
Packit 2fc92b
	  free(node->text);
Packit 2fc92b
Packit 2fc92b
        if (node->words)
Packit 2fc92b
	{
Packit 2fc92b
	  for (word = (help_word_t *)cupsArrayFirst(node->words);
Packit 2fc92b
	       word;
Packit 2fc92b
	       word = (help_word_t *)cupsArrayNext(node->words))
Packit 2fc92b
	    help_delete_word(word);
Packit 2fc92b
Packit 2fc92b
	  cupsArrayDelete(node->words);
Packit 2fc92b
	  node->words = NULL;
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
	node->section = section[0] ? strdup(section) : NULL;
Packit 2fc92b
	node->text    = strdup(text);
Packit 2fc92b
	node->mtime   = mtime;
Packit 2fc92b
	node->offset  = offset;
Packit 2fc92b
	node->score   = 0;
Packit 2fc92b
      }
Packit 2fc92b
      else
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
	* New node...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
        node = help_new_node(relative, anchor, section, text, mtime, offset, 0);
Packit 2fc92b
      }
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * Go through the text value and replace tabs and newlines with
Packit 2fc92b
      * whitespace and eliminate extra whitespace...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      for (ptr = node->text, text = node->text; *ptr;)
Packit 2fc92b
	if (isspace(*ptr & 255))
Packit 2fc92b
	{
Packit 2fc92b
	  while (isspace(*ptr & 255))
Packit 2fc92b
	    ptr ++;
Packit 2fc92b
Packit 2fc92b
	  *text++ = ' ';
Packit 2fc92b
        }
Packit 2fc92b
	else if (text != ptr)
Packit 2fc92b
	  *text++ = *ptr++;
Packit 2fc92b
	else
Packit 2fc92b
	{
Packit 2fc92b
	  text ++;
Packit 2fc92b
	  ptr ++;
Packit 2fc92b
	}
Packit 2fc92b
Packit 2fc92b
      *text = '\0';
Packit 2fc92b
Packit 2fc92b
     /*
Packit 2fc92b
      * (Re)add the node to the array...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      cupsArrayAdd(hi->nodes, node);
Packit 2fc92b
Packit 2fc92b
      if (!anchor)
Packit 2fc92b
        node = NULL;
Packit 2fc92b
      break;
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
    if (node)
Packit 2fc92b
    {
Packit 2fc92b
     /*
Packit 2fc92b
      * Scan this line for words...
Packit 2fc92b
      */
Packit 2fc92b
Packit 2fc92b
      for (ptr = line; *ptr; ptr ++)
Packit 2fc92b
      {
Packit 2fc92b
       /*
Packit 2fc92b
	* Skip HTML stuff...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
	if (*ptr == '<')
Packit 2fc92b
	{
Packit 2fc92b
          if (!strncmp(ptr, "
Packit 2fc92b
	  {
Packit 2fc92b
	   /*
Packit 2fc92b
	    * Skip HTML comment...
Packit 2fc92b
	    */
Packit 2fc92b
Packit 2fc92b
            if ((text = strstr(ptr + 4, "-->")) == NULL)
Packit 2fc92b
	      ptr += strlen(ptr) - 1;
Packit 2fc92b
	    else
Packit 2fc92b
	      ptr = text + 2;
Packit 2fc92b
	  }
Packit 2fc92b
	  else
Packit 2fc92b
	  {
Packit 2fc92b
	   /*
Packit 2fc92b
            * Skip HTML element...
Packit 2fc92b
	    */
Packit 2fc92b
Packit 2fc92b
            for (ptr ++; *ptr && *ptr != '>'; ptr ++)
Packit 2fc92b
	    {
Packit 2fc92b
	      if (*ptr == '\"' || *ptr == '\'')
Packit 2fc92b
	      {
Packit 2fc92b
		for (quote = *ptr++; *ptr && *ptr != quote; ptr ++);
Packit 2fc92b
Packit 2fc92b
		if (!*ptr)
Packit 2fc92b
		  ptr --;
Packit 2fc92b
	      }
Packit 2fc92b
	    }
Packit 2fc92b
Packit 2fc92b
	    if (!*ptr)
Packit 2fc92b
	      ptr --;
Packit 2fc92b
          }
Packit 2fc92b
Packit 2fc92b
          continue;
Packit 2fc92b
	}
Packit 2fc92b
	else if (*ptr == '&')
Packit 2fc92b
	{
Packit 2fc92b
	 /*
Packit 2fc92b
	  * Skip HTML entity...
Packit 2fc92b
	  */
Packit 2fc92b
Packit 2fc92b
	  for (ptr ++; *ptr && *ptr != ';'; ptr ++);
Packit 2fc92b
Packit 2fc92b
	  if (!*ptr)
Packit 2fc92b
	    ptr --;
Packit 2fc92b
Packit 2fc92b
	  continue;
Packit 2fc92b
	}
Packit 2fc92b
	else if (!isalnum(*ptr & 255))
Packit 2fc92b
          continue;
Packit 2fc92b
Packit 2fc92b
       /*
Packit 2fc92b
	* Found the start of a word, search until we find the end...
Packit 2fc92b
	*/
Packit 2fc92b
Packit 2fc92b
	for (text = ptr, ptr ++; *ptr && isalnum(*ptr & 255); ptr ++);
Packit 2fc92b
Packit 2fc92b
	wordlen = (int)(ptr - text);
Packit 2fc92b
Packit 2fc92b
        memcpy(temp, text, (size_t)wordlen);
Packit 2fc92b
	temp[wordlen] = '\0';
Packit 2fc92b
Packit 2fc92b
        ptr --;
Packit 2fc92b
Packit 2fc92b
	if (wordlen > 1 && !bsearch(temp, help_common_words,
Packit 2fc92b
	                            (sizeof(help_common_words) /
Packit 2fc92b
				     sizeof(help_common_words[0])),
Packit 2fc92b
				    sizeof(help_common_words[0]),
Packit 2fc92b
				    (int (*)(const void *, const void *))
Packit 2fc92b
				        _cups_strcasecmp))
Packit 2fc92b
          help_add_word(node, temp);
Packit 2fc92b
      }
Packit 2fc92b
    }
Packit 2fc92b
Packit 2fc92b
   /*
Packit 2fc92b
    * Get the offset of the next line...
Packit 2fc92b
    */
Packit 2fc92b
Packit 2fc92b
    offset = cupsFileTell(fp);
Packit 2fc92b
  }
Packit 2fc92b
Packit 2fc92b
  cupsFileClose(fp);
Packit 2fc92b
Packit 2fc92b
  if (node)
Packit 2fc92b
    node->length = (size_t)(offset - node->offset);
Packit 2fc92b
Packit 2fc92b
  return (0);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'help_new_node()' - Create a new node and add it to an index.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static help_node_t *			/* O - Node pointer or NULL on error */
Packit 2fc92b
help_new_node(const char   *filename,	/* I - Filename */
Packit 2fc92b
              const char   *anchor,	/* I - Anchor */
Packit 2fc92b
	      const char   *section,	/* I - Section */
Packit 2fc92b
	      const char   *text,	/* I - Text */
Packit 2fc92b
	      time_t       mtime,	/* I - Modification time */
Packit 2fc92b
              off_t        offset,	/* I - Offset in file */
Packit 2fc92b
	      size_t       length)	/* I - Length in bytes */
Packit 2fc92b
{
Packit 2fc92b
  help_node_t	*n;			/* Node */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("2help_new_node(filename=\"%s\", anchor=\"%s\", text=\"%s\", "
Packit 2fc92b
                "mtime=%ld, offset=%ld, length=%ld)", filename, anchor, text,
Packit 2fc92b
                (long)mtime, (long)offset, (long)length));
Packit 2fc92b
Packit 2fc92b
  n = (help_node_t *)calloc(1, sizeof(help_node_t));
Packit 2fc92b
  if (!n)
Packit 2fc92b
    return (NULL);
Packit 2fc92b
Packit 2fc92b
  n->filename = strdup(filename);
Packit 2fc92b
  n->anchor   = anchor ? strdup(anchor) : NULL;
Packit 2fc92b
  n->section  = *section ? strdup(section) : NULL;
Packit 2fc92b
  n->text     = strdup(text);
Packit 2fc92b
  n->mtime    = mtime;
Packit 2fc92b
  n->offset   = offset;
Packit 2fc92b
  n->length   = length;
Packit 2fc92b
Packit 2fc92b
  return (n);
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'help_sort_nodes_by_name()' - Sort nodes by section, filename, and anchor.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static int				/* O - Difference */
Packit 2fc92b
help_sort_by_name(help_node_t *n1,	/* I - First node */
Packit 2fc92b
                  help_node_t *n2)	/* I - Second node */
Packit 2fc92b
{
Packit 2fc92b
  int		diff;			/* Difference */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("2help_sort_by_name(n1=%p(%s#%s), n2=%p(%s#%s)",
Packit 2fc92b
                n1, n1->filename, n1->anchor,
Packit 2fc92b
		n2, n2->filename, n2->anchor));
Packit 2fc92b
Packit 2fc92b
  if ((diff = strcmp(n1->filename, n2->filename)) != 0)
Packit 2fc92b
    return (diff);
Packit 2fc92b
Packit 2fc92b
  if (!n1->anchor && !n2->anchor)
Packit 2fc92b
    return (0);
Packit 2fc92b
  else if (!n1->anchor)
Packit 2fc92b
    return (-1);
Packit 2fc92b
  else if (!n2->anchor)
Packit 2fc92b
    return (1);
Packit 2fc92b
  else
Packit 2fc92b
    return (strcmp(n1->anchor, n2->anchor));
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'help_sort_nodes_by_score()' - Sort nodes by score and text.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static int				/* O - Difference */
Packit 2fc92b
help_sort_by_score(help_node_t *n1,	/* I - First node */
Packit 2fc92b
                   help_node_t *n2)	/* I - Second node */
Packit 2fc92b
{
Packit 2fc92b
  int		diff;			/* Difference */
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
  DEBUG_printf(("2help_sort_by_score(n1=%p(%d \"%s\" \"%s\"), "
Packit 2fc92b
                "n2=%p(%d \"%s\" \"%s\")",
Packit 2fc92b
                n1, n1->score, n1->section, n1->text,
Packit 2fc92b
                n2, n2->score, n2->section, n2->text));
Packit 2fc92b
Packit 2fc92b
  if (n1->score != n2->score)
Packit 2fc92b
    return (n2->score - n1->score);
Packit 2fc92b
Packit 2fc92b
  if (n1->section && !n2->section)
Packit 2fc92b
    return (1);
Packit 2fc92b
  else if (!n1->section && n2->section)
Packit 2fc92b
    return (-1);
Packit 2fc92b
  else if (n1->section && n2->section &&
Packit 2fc92b
           (diff = strcmp(n1->section, n2->section)) != 0)
Packit 2fc92b
    return (diff);
Packit 2fc92b
Packit 2fc92b
  return (_cups_strcasecmp(n1->text, n2->text));
Packit 2fc92b
}
Packit 2fc92b
Packit 2fc92b
Packit 2fc92b
/*
Packit 2fc92b
 * 'help_sort_words()' - Sort words alphabetically.
Packit 2fc92b
 */
Packit 2fc92b
Packit 2fc92b
static int				/* O - Difference */
Packit 2fc92b
help_sort_words(help_word_t *w1,	/* I - Second word */
Packit 2fc92b
                help_word_t *w2)	/* I - Second word */
Packit 2fc92b
{
Packit 2fc92b
  DEBUG_printf(("2help_sort_words(w1=%p(\"%s\"), w2=%p(\"%s\"))",
Packit 2fc92b
                w1, w1->text, w2, w2->text));
Packit 2fc92b
Packit 2fc92b
  return (_cups_strcasecmp(w1->text, w2->text));
Packit 2fc92b
}