]>
git.ipfire.org Git - thirdparty/cups.git/blob - cgi-bin/help-index.c
2 * "$Id: help-index.c 7717 2008-07-04 02:35:33Z mike $"
4 * Online help index routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * helpDeleteIndex() - Delete an index, freeing all memory used.
18 * helpFindNode() - Find a node in an index.
19 * helpLoadIndex() - Load a help index from disk.
20 * helpSaveIndex() - Save a help index to disk.
21 * helpSearchIndex() - Search an index.
22 * help_add_word() - Add a word to a node.
23 * help_compile_search() - Convert a search string into a regular expression.
24 * help_delete_node() - Free all memory used by a node.
25 * help_delete_word() - Free all memory used by a word.
26 * help_load_directory() - Load a directory of files into an index.
27 * help_load_file() - Load a HTML files into an index.
28 * help_new_node() - Create a new node and add it to an index.
29 * help_sort_nodes_by_name() - Sort nodes by section, filename, and anchor.
30 * help_sort_nodes_by_score() - Sort nodes by score and text.
31 * help_sort_words() - Sort words alphabetically.
35 * Include necessary headers...
38 #include "cgi-private.h"
43 * List of common English words that should not be indexed...
46 static char help_common_words
[][6] =
151 static help_word_t
*help_add_word(help_node_t
*n
, const char *text
);
152 static void help_delete_node(help_node_t
*n
);
153 static void help_delete_word(help_word_t
*w
);
154 static int help_load_directory(help_index_t
*hi
,
155 const char *directory
,
156 const char *relative
);
157 static int help_load_file(help_index_t
*hi
,
158 const char *filename
,
159 const char *relative
,
161 static help_node_t
*help_new_node(const char *filename
, const char *anchor
,
162 const char *section
, const char *text
,
163 time_t mtime
, off_t offset
,
165 static int help_sort_by_name(help_node_t
*p1
, help_node_t
*p2
);
166 static int help_sort_by_score(help_node_t
*p1
, help_node_t
*p2
);
167 static int help_sort_words(help_word_t
*w1
, help_word_t
*w2
);
171 * 'helpDeleteIndex()' - Delete an index, freeing all memory used.
175 helpDeleteIndex(help_index_t
*hi
) /* I - Help index */
177 help_node_t
*node
; /* Current node */
180 DEBUG_printf(("helpDeleteIndex(hi=%p)\n", hi
));
185 for (node
= (help_node_t
*)cupsArrayFirst(hi
->nodes
);
187 node
= (help_node_t
*)cupsArrayNext(hi
->nodes
))
190 help_delete_node(node
);
193 cupsArrayDelete(hi
->nodes
);
194 cupsArrayDelete(hi
->sorted
);
201 * 'helpFindNode()' - Find a node in an index.
204 help_node_t
* /* O - Node pointer or NULL */
205 helpFindNode(help_index_t
*hi
, /* I - Index */
206 const char *filename
, /* I - Filename */
207 const char *anchor
) /* I - Anchor */
209 help_node_t key
; /* Search key */
212 DEBUG_printf(("helpFindNode(hi=%p, filename=\"%s\", anchor=\"%s\")\n",
213 hi
, filename
? filename
: "(nil)", anchor
? anchor
: "(nil)"));
216 * Range check input...
219 if (!hi
|| !filename
)
223 * Initialize the search key...
226 key
.filename
= (char *)filename
;
227 key
.anchor
= (char *)anchor
;
230 * Return any match...
233 return ((help_node_t
*)cupsArrayFind(hi
->nodes
, &key
));
238 * 'helpLoadIndex()' - Load a help index from disk.
241 help_index_t
* /* O - Index pointer or NULL */
242 helpLoadIndex(const char *hifile
, /* I - Index filename */
243 const char *directory
) /* I - Directory that is indexed */
245 help_index_t
*hi
; /* Help index */
246 cups_file_t
*fp
; /* Current file */
247 char line
[2048], /* Line from file */
248 *ptr
, /* Pointer into line */
249 *filename
, /* Filename in line */
250 *anchor
, /* Anchor in line */
251 *sectptr
, /* Section pointer in line */
252 section
[1024], /* Section name */
253 *text
; /* Text in line */
254 time_t mtime
; /* Modification time */
255 off_t offset
; /* Offset into file */
256 size_t length
; /* Length in bytes */
257 int update
; /* Update? */
258 help_node_t
*node
; /* Current node */
259 help_word_t
*word
; /* Current word */
262 DEBUG_printf(("helpLoadIndex(hifile=\"%s\", directory=\"%s\")\n",
266 * Create a new, empty index.
269 if ((hi
= (help_index_t
*)calloc(1, sizeof(help_index_t
))) == NULL
)
272 hi
->nodes
= cupsArrayNew((cups_array_func_t
)help_sort_by_name
, NULL
);
273 hi
->sorted
= cupsArrayNew((cups_array_func_t
)help_sort_by_score
, NULL
);
275 if (!hi
->nodes
|| !hi
->sorted
)
277 cupsArrayDelete(hi
->nodes
);
278 cupsArrayDelete(hi
->sorted
);
284 * Try loading the existing index file...
287 if ((fp
= cupsFileOpen(hifile
, "r")) != NULL
)
290 * Lock the file and then read the first line...
295 if (cupsFileGets(fp
, line
, sizeof(line
)) && !strcmp(line
, "HELPV2"))
298 * Got a valid header line, now read the data lines...
303 while (cupsFileGets(fp
, line
, sizeof(line
)))
306 * Each line looks like one of the following:
308 * filename mtime offset length "section" "text"
309 * filename#anchor offset length "text"
316 * Read a word in the current node...
319 if (!node
|| (ptr
= strrchr(line
, ' ')) == NULL
)
322 if ((word
= help_add_word(node
, ptr
+ 1)) != NULL
)
323 word
->count
= atoi(line
+ 1);
333 if ((ptr
= strchr(line
, ' ')) == NULL
)
336 while (isspace(*ptr
& 255))
339 if ((anchor
= strrchr(filename
, '#')) != NULL
)
345 mtime
= strtol(ptr
, &ptr
, 10);
347 offset
= strtoll(ptr
, &ptr
, 10);
348 length
= strtoll(ptr
, &ptr
, 10);
350 while (isspace(*ptr
& 255))
365 while (*ptr
&& *ptr
!= '\"')
373 strlcpy(section
, sectptr
, sizeof(section
));
375 while (isspace(*ptr
& 255))
385 while (*ptr
&& *ptr
!= '\"')
393 if ((node
= help_new_node(filename
, anchor
, section
, text
,
394 mtime
, offset
, length
)) == NULL
)
399 cupsArrayAdd(hi
->nodes
, node
);
408 * Scan for new/updated files...
411 update
= help_load_directory(hi
, directory
, NULL
);
414 * Remove any files that are no longer installed...
417 for (node
= (help_node_t
*)cupsArrayFirst(hi
->nodes
);
419 node
= (help_node_t
*)cupsArrayNext(hi
->nodes
))
423 * Delete this node...
426 cupsArrayRemove(hi
->nodes
, node
);
427 help_delete_node(node
);
431 * Add nodes to the sorted array...
434 for (node
= (help_node_t
*)cupsArrayFirst(hi
->nodes
);
436 node
= (help_node_t
*)cupsArrayNext(hi
->nodes
))
437 cupsArrayAdd(hi
->sorted
, node
);
440 * Save the index if we updated it...
444 helpSaveIndex(hi
, hifile
);
447 * Return the index...
455 * 'helpSaveIndex()' - Save a help index to disk.
458 int /* O - 0 on success, -1 on error */
459 helpSaveIndex(help_index_t
*hi
, /* I - Index */
460 const char *hifile
) /* I - Index filename */
462 cups_file_t
*fp
; /* Index file */
463 help_node_t
*node
; /* Current node */
464 help_word_t
*word
; /* Current word */
467 DEBUG_printf(("helpSaveIndex(hi=%p, hifile=\"%s\")\n", hi
, hifile
));
470 * Try creating a new index file...
473 if ((fp
= cupsFileOpen(hifile
, "w9")) == NULL
)
477 * Lock the file while we write it...
482 cupsFilePuts(fp
, "HELPV2\n");
484 for (node
= (help_node_t
*)cupsArrayFirst(hi
->nodes
);
486 node
= (help_node_t
*)cupsArrayNext(hi
->nodes
))
489 * Write the current node with/without the anchor...
494 if (cupsFilePrintf(fp
, "%s#%s " CUPS_LLFMT
" " CUPS_LLFMT
" \"%s\"\n",
495 node
->filename
, node
->anchor
,
496 CUPS_LLCAST node
->offset
, CUPS_LLCAST node
->length
,
502 if (cupsFilePrintf(fp
, "%s %d " CUPS_LLFMT
" " CUPS_LLFMT
" \"%s\" \"%s\"\n",
503 node
->filename
, (int)node
->mtime
,
504 CUPS_LLCAST node
->offset
, CUPS_LLCAST node
->length
,
505 node
->section
? node
->section
: "", node
->text
) < 0)
510 * Then write the words associated with the node...
513 for (word
= (help_word_t
*)cupsArrayFirst(node
->words
);
515 word
= (help_word_t
*)cupsArrayNext(node
->words
))
516 if (cupsFilePrintf(fp
, " %d %s\n", word
->count
, word
->text
) < 0)
522 if (cupsFileClose(fp
) < 0)
532 * 'helpSearchIndex()' - Search an index.
535 help_index_t
* /* O - Search index */
536 helpSearchIndex(help_index_t
*hi
, /* I - Index */
537 const char *query
, /* I - Query string */
538 const char *section
, /* I - Limit search to this section */
539 const char *filename
) /* I - Limit search to this file */
541 help_index_t
*search
; /* Search index */
542 help_node_t
*node
; /* Current node */
543 help_word_t
*word
; /* Current word */
544 void *sc
; /* Search context */
545 int matches
; /* Number of matches */
548 DEBUG_printf(("helpSearchIndex(hi=%p, query=\"%s\", filename=\"%s\")\n",
549 hi
, query
? query
: "(nil)",
550 filename
? filename
: "(nil)"));
560 * Reset the scores of all nodes to 0...
563 for (node
= (help_node_t
*)cupsArrayFirst(hi
->nodes
);
565 node
= (help_node_t
*)cupsArrayNext(hi
->nodes
))
569 * Find the first node to search in...
574 node
= helpFindNode(hi
, filename
, NULL
);
579 node
= (help_node_t
*)cupsArrayFirst(hi
->nodes
);
582 * Convert the query into a regular expression...
585 sc
= cgiCompileSearch(query
);
590 * Allocate a search index...
593 search
= calloc(1, sizeof(help_index_t
));
600 search
->nodes
= cupsArrayNew((cups_array_func_t
)help_sort_by_name
, NULL
);
601 search
->sorted
= cupsArrayNew((cups_array_func_t
)help_sort_by_score
, NULL
);
603 if (!search
->nodes
|| !search
->sorted
)
605 cupsArrayDelete(search
->nodes
);
606 cupsArrayDelete(search
->sorted
);
615 * Check each node in the index, adding matching nodes to the
619 for (; node
; node
= (help_node_t
*)cupsArrayNext(hi
->nodes
))
620 if (section
&& strcmp(node
->section
, section
))
622 else if (filename
&& strcmp(node
->filename
, filename
))
626 matches
= cgiDoSearch(sc
, node
->text
);
628 for (word
= (help_word_t
*)cupsArrayFirst(node
->words
);
630 word
= (help_word_t
*)cupsArrayNext(node
->words
))
631 if (cgiDoSearch(sc
, word
->text
) > 0)
632 matches
+= word
->count
;
637 * Found a match, add the node to the search index...
640 node
->score
= matches
;
642 cupsArrayAdd(search
->nodes
, node
);
643 cupsArrayAdd(search
->sorted
, node
);
648 * Free the search context...
654 * Return the results...
662 * 'help_add_word()' - Add a word to a node.
665 static help_word_t
* /* O - New word */
666 help_add_word(help_node_t
*n
, /* I - Node */
667 const char *text
) /* I - Word text */
669 help_word_t
*w
, /* New word */
670 key
; /* Search key */
673 DEBUG_printf(("help_add_word(n=%p, text=\"%s\")\n", n
, text
));
676 * Create the words array as needed...
680 n
->words
= cupsArrayNew((cups_array_func_t
)help_sort_words
, NULL
);
683 * See if the word is already added...
686 key
.text
= (char *)text
;
688 if ((w
= (help_word_t
*)cupsArrayFind(n
->words
, &key
)) == NULL
)
691 * Create a new word...
694 if ((w
= calloc(1, sizeof(help_word_t
))) == NULL
)
697 if ((w
->text
= strdup(text
)) == NULL
)
703 cupsArrayAdd(n
->words
, w
);
707 * Bump the counter for this word and return it...
717 * 'help_delete_node()' - Free all memory used by a node.
721 help_delete_node(help_node_t
*n
) /* I - Node */
723 help_word_t
*w
; /* Current word */
726 DEBUG_printf(("help_delete_node(n=%p)\n", n
));
743 for (w
= (help_word_t
*)cupsArrayFirst(n
->words
);
745 w
= (help_word_t
*)cupsArrayNext(n
->words
))
748 cupsArrayDelete(n
->words
);
755 * 'help_delete_word()' - Free all memory used by a word.
759 help_delete_word(help_word_t
*w
) /* I - Word */
761 DEBUG_printf(("help_delete_word(w=%p)\n", w
));
774 * 'help_load_directory()' - Load a directory of files into an index.
777 static int /* O - 0 = success, -1 = error, 1 = updated */
779 help_index_t
*hi
, /* I - Index */
780 const char *directory
, /* I - Directory */
781 const char *relative
) /* I - Relative path */
783 cups_dir_t
*dir
; /* Directory file */
784 cups_dentry_t
*dent
; /* Directory entry */
785 char *ext
, /* Pointer to extension */
786 filename
[1024], /* Full filename */
787 relname
[1024]; /* Relative filename */
788 int update
; /* Updated? */
789 help_node_t
*node
; /* Current node */
792 DEBUG_printf(("help_load_directory(hi=%p, directory=\"%s\", relative=\"%s\")\n",
793 hi
, directory
? directory
: "(nil)", relative
? relative
: "(nil)"));
796 * Open the directory and scan it...
799 if ((dir
= cupsDirOpen(directory
)) == NULL
)
804 while ((dent
= cupsDirRead(dir
)) != NULL
)
810 if (dent
->filename
[0] == '.')
814 * Get absolute and relative filenames...
817 snprintf(filename
, sizeof(filename
), "%s/%s", directory
, dent
->filename
);
819 snprintf(relname
, sizeof(relname
), "%s/%s", relative
, dent
->filename
);
821 strlcpy(relname
, dent
->filename
, sizeof(relname
));
824 * Check if we have a HTML file...
827 if ((ext
= strstr(dent
->filename
, ".html")) != NULL
&&
828 (!ext
[5] || !strcmp(ext
+ 5, ".gz")))
831 * HTML file, see if we have already indexed the file...
834 if ((node
= helpFindNode(hi
, relname
, NULL
)) != NULL
)
837 * File already indexed - check dates to confirm that the
838 * index is up-to-date...
841 if (node
->mtime
== dent
->fileinfo
.st_mtime
)
844 * Same modification time, so mark all of the nodes
845 * for this file as up-to-date...
848 for (; node
; node
= (help_node_t
*)cupsArrayNext(hi
->nodes
))
849 if (!strcmp(node
->filename
, relname
))
860 help_load_file(hi
, filename
, relname
, dent
->fileinfo
.st_mtime
);
862 else if (S_ISDIR(dent
->fileinfo
.st_mode
))
865 * Process sub-directory...
868 if (help_load_directory(hi
, filename
, relname
) == 1)
880 * 'help_load_file()' - Load a HTML files into an index.
883 static int /* O - 0 = success, -1 = error */
885 help_index_t
*hi
, /* I - Index */
886 const char *filename
, /* I - Filename */
887 const char *relative
, /* I - Relative path */
888 time_t mtime
) /* I - Modification time */
890 cups_file_t
*fp
; /* HTML file */
891 help_node_t
*node
; /* Current node */
892 char line
[1024], /* Line from file */
893 temp
[1024], /* Temporary word */
894 section
[1024], /* Section */
895 *ptr
, /* Pointer into line */
896 *anchor
, /* Anchor name */
897 *text
; /* Text for anchor */
898 off_t offset
; /* File offset */
899 char quote
; /* Quote character */
900 help_word_t
*word
; /* Current word */
901 int wordlen
; /* Length of word */
904 DEBUG_printf(("help_load_file(hi=%p, filename=\"%s\", relative=\"%s\", mtime=%ld)\n",
905 hi
, filename
? filename
: "(nil)",
906 relative
? relative
: "(nil)", mtime
));
908 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
914 strcpy(section
, "Other");
916 while (cupsFileGets(fp
, line
, sizeof(line
)))
919 * Look for "<TITLE>", "<A NAME", or "<!-- SECTION:" prefix...
922 if (!strncasecmp(line
, "<!-- SECTION:", 13))
925 * Got section line, copy it!
928 for (ptr
= line
+ 13; isspace(*ptr
& 255); ptr
++);
930 strlcpy(section
, ptr
, sizeof(section
));
931 if ((ptr
= strstr(section
, "-->")) != NULL
)
934 * Strip comment stuff from end of line...
937 for (*ptr
-- = '\0'; ptr
> line
&& isspace(*ptr
& 255); *ptr
-- = '\0');
939 if (isspace(*ptr
& 255))
945 for (ptr
= line
; (ptr
= strchr(ptr
, '<')) != NULL
;)
949 if (!strncasecmp(ptr
, "TITLE>", 6))
958 else if (!strncasecmp(ptr
, "A NAME=", 7))
966 if (*ptr
== '\"' || *ptr
== '\'')
969 * Get quoted anchor...
974 if ((ptr
= strchr(anchor
, quote
)) != NULL
)
982 * Get unquoted anchor...
987 for (ptr
= anchor
; *ptr
&& *ptr
!= '>' && !isspace(*ptr
& 255); ptr
++);
996 * Got the anchor, now lets find the end...
999 while (*ptr
&& *ptr
!= '>')
1011 * Now collect text for the link...
1015 while ((ptr
= strchr(text
, '<')) == NULL
)
1017 ptr
= text
+ strlen(text
);
1018 if (ptr
>= (line
+ sizeof(line
) - 2))
1023 if (!cupsFileGets(fp
, ptr
, sizeof(line
) - (ptr
- line
) - 1))
1030 node
->length
= offset
- node
->offset
;
1038 if ((node
= helpFindNode(hi
, relative
, anchor
)) != NULL
)
1041 * Node already in the index, so replace the text and other
1045 cupsArrayRemove(hi
->nodes
, node
);
1048 free(node
->section
);
1055 for (word
= (help_word_t
*)cupsArrayFirst(node
->words
);
1057 word
= (help_word_t
*)cupsArrayNext(node
->words
))
1058 help_delete_word(word
);
1060 cupsArrayDelete(node
->words
);
1064 node
->section
= section
[0] ? strdup(section
) : NULL
;
1065 node
->text
= strdup(text
);
1066 node
->mtime
= mtime
;
1067 node
->offset
= offset
;
1076 node
= help_new_node(relative
, anchor
, section
, text
, mtime
, offset
, 0);
1080 * Go through the text value and replace tabs and newlines with
1081 * whitespace and eliminate extra whitespace...
1084 for (ptr
= node
->text
, text
= node
->text
; *ptr
;)
1085 if (isspace(*ptr
& 255))
1087 while (isspace(*ptr
& 255))
1092 else if (text
!= ptr
)
1103 * (Re)add the node to the array...
1106 cupsArrayAdd(hi
->nodes
, node
);
1116 * Scan this line for words...
1119 for (ptr
= line
; *ptr
; ptr
++)
1122 * Skip HTML stuff...
1127 if (!strncmp(ptr
, "<!--", 4))
1130 * Skip HTML comment...
1133 if ((text
= strstr(ptr
+ 4, "-->")) == NULL
)
1134 ptr
+= strlen(ptr
) - 1;
1141 * Skip HTML element...
1144 for (ptr
++; *ptr
&& *ptr
!= '>'; ptr
++)
1146 if (*ptr
== '\"' || *ptr
== '\'')
1148 for (quote
= *ptr
++; *ptr
&& *ptr
!= quote
; ptr
++);
1161 else if (*ptr
== '&')
1164 * Skip HTML entity...
1167 for (ptr
++; *ptr
&& *ptr
!= ';'; ptr
++);
1174 else if (!isalnum(*ptr
& 255))
1178 * Found the start of a word, search until we find the end...
1181 for (text
= ptr
, ptr
++; *ptr
&& isalnum(*ptr
& 255); ptr
++);
1183 wordlen
= ptr
- text
;
1185 memcpy(temp
, text
, wordlen
);
1186 temp
[wordlen
] = '\0';
1190 if (wordlen
> 1 && !bsearch(temp
, help_common_words
,
1191 (sizeof(help_common_words
) /
1192 sizeof(help_common_words
[0])),
1193 sizeof(help_common_words
[0]),
1194 (int (*)(const void *, const void *))
1196 help_add_word(node
, temp
);
1201 * Get the offset of the next line...
1204 offset
= cupsFileTell(fp
);
1210 node
->length
= offset
- node
->offset
;
1217 * 'help_new_node()' - Create a new node and add it to an index.
1220 static help_node_t
* /* O - Node pointer or NULL on error */
1221 help_new_node(const char *filename
, /* I - Filename */
1222 const char *anchor
, /* I - Anchor */
1223 const char *section
, /* I - Section */
1224 const char *text
, /* I - Text */
1225 time_t mtime
, /* I - Modification time */
1226 off_t offset
, /* I - Offset in file */
1227 size_t length
) /* I - Length in bytes */
1229 help_node_t
*n
; /* Node */
1232 DEBUG_printf(("help_new_node(filename=\"%s\", anchor=\"%s\", text=\"%s\", "
1233 "mtime=%ld, offset=%ld, length=%ld)\n",
1234 filename
? filename
: "(nil)", anchor
? anchor
: "(nil)",
1235 text
? text
: "(nil)", (long)mtime
, (long)offset
,
1238 n
= (help_node_t
*)calloc(1, sizeof(help_node_t
));
1242 n
->filename
= strdup(filename
);
1243 n
->anchor
= anchor
? strdup(anchor
) : NULL
;
1244 n
->section
= (section
&& *section
) ? strdup(section
) : NULL
;
1245 n
->text
= strdup(text
);
1255 * 'help_sort_nodes_by_name()' - Sort nodes by section, filename, and anchor.
1258 static int /* O - Difference */
1259 help_sort_by_name(help_node_t
*n1
, /* I - First node */
1260 help_node_t
*n2
) /* I - Second node */
1262 int diff
; /* Difference */
1265 DEBUG_printf(("help_sort_by_name(n1=%p(%s#%s), n2=%p(%s#%s)\n",
1266 n1
, n1
->filename
, n1
->anchor
? n1
->anchor
: "",
1267 n2
, n2
->filename
, n2
->anchor
? n2
->anchor
: ""));
1269 if ((diff
= strcmp(n1
->filename
, n2
->filename
)) != 0)
1272 if (!n1
->anchor
&& !n2
->anchor
)
1274 else if (!n1
->anchor
)
1276 else if (!n2
->anchor
)
1279 return (strcmp(n1
->anchor
, n2
->anchor
));
1284 * 'help_sort_nodes_by_score()' - Sort nodes by score and text.
1287 static int /* O - Difference */
1288 help_sort_by_score(help_node_t
*n1
, /* I - First node */
1289 help_node_t
*n2
) /* I - Second node */
1291 int diff
; /* Difference */
1294 DEBUG_printf(("help_sort_by_score(n1=%p(%d \"%s\" \"%s\"), "
1295 "n2=%p(%d \"%s\" \"%s\")\n",
1296 n1
, n1
->score
, n1
->section
? n1
->section
: "", n1
->text
,
1297 n2
, n2
->score
, n2
->section
? n2
->section
: "", n2
->text
));
1299 if (n1
->score
!= n2
->score
)
1300 return (n2
->score
- n1
->score
);
1302 if (n1
->section
&& !n2
->section
)
1304 else if (!n1
->section
&& n2
->section
)
1306 else if (n1
->section
&& n2
->section
&&
1307 (diff
= strcmp(n1
->section
, n2
->section
)) != 0)
1310 return (strcasecmp(n1
->text
, n2
->text
));
1315 * 'help_sort_words()' - Sort words alphabetically.
1318 static int /* O - Difference */
1319 help_sort_words(help_word_t
*w1
, /* I - Second word */
1320 help_word_t
*w2
) /* I - Second word */
1322 DEBUG_printf(("help_sort_words(w1=%p(\"%s\"), w2=%p(\"%s\"))\n",
1323 w1
, w1
->text
, w2
, w2
->text
));
1325 return (strcasecmp(w1
->text
, w2
->text
));
1330 * End of "$Id: help-index.c 7717 2008-07-04 02:35:33Z mike $".