Blame cgi-bin/help-index.c

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