]> git.ipfire.org Git - thirdparty/cups.git/blame - cgi-bin/help-index.c
Remove svn:keywords since they cause svn_load_dirs.pl to complain about every file.
[thirdparty/cups.git] / cgi-bin / help-index.c
CommitLineData
ef416fc2 1/*
c07d5b2d 2 * "$Id: help-index.c 181 2006-06-22 20:01:18Z jlovell $"
ef416fc2 3 *
4 * On-line help index routines for the Common UNIX Printing System (CUPS).
5 *
ecdc0628 6 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * helpDeleteIndex() - Delete an index, freeing all memory used.
27 * helpFindNode() - Find a node in an index.
28 * helpLoadIndex() - Load a help index from disk.
29 * helpSaveIndex() - Save a help index to disk.
30 * helpSearchIndex() - Search an index.
31 * help_compile_search() - Convert a search string into a regular expression.
ef416fc2 32 * help_delete_node() - Free all memory used by a node.
ef416fc2 33 * help_load_directory() - Load a directory of files into an index.
34 * help_load_file() - Load a HTML files into an index.
35 * help_new_node() - Create a new node and add it to an index.
36 * help_sort_nodes_by_name() - Sort nodes by section, filename, and anchor.
37 * help_sort_nodes_by_score() - Sort nodes by score and text.
38 */
39
40/*
41 * Include necessary headers...
42 */
43
44#include "cgi-private.h"
45#include <cups/dir.h>
46
47
48/*
49 * Local functions...
50 */
51
ef416fc2 52static void help_delete_node(help_node_t *n);
ef416fc2 53static int help_load_directory(help_index_t *hi,
54 const char *directory,
55 const char *relative);
56static int help_load_file(help_index_t *hi,
57 const char *filename,
58 const char *relative,
59 time_t mtime);
60static help_node_t *help_new_node(const char *filename, const char *anchor,
61 const char *section, const char *text,
62 time_t mtime, off_t offset,
63 size_t length);
ecdc0628 64static int help_sort_by_name(help_node_t *p1, help_node_t *p2);
65static int help_sort_by_score(help_node_t *p1, help_node_t *p2);
ef416fc2 66
67
68/*
69 * 'helpDeleteIndex()' - Delete an index, freeing all memory used.
70 */
71
72void
ecdc0628 73helpDeleteIndex(help_index_t *hi) /* I - Help index */
ef416fc2 74{
ecdc0628 75 help_node_t *node; /* Current node */
ef416fc2 76
77
78 DEBUG_printf(("helpDeleteIndex(hi=%p)\n", hi));
79
80 if (!hi)
81 return;
82
ecdc0628 83 for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
84 node;
85 node = (help_node_t *)cupsArrayNext(hi->nodes))
ef416fc2 86 {
ecdc0628 87 cupsArrayRemove(hi->nodes, node);
88 cupsArrayRemove(hi->sorted, node);
ef416fc2 89
ecdc0628 90 if (!hi->search)
91 help_delete_node(node);
92 }
ef416fc2 93
ecdc0628 94 cupsArrayDelete(hi->nodes);
95 cupsArrayDelete(hi->sorted);
ef416fc2 96
97 free(hi);
98}
99
100
101/*
102 * 'helpFindNode()' - Find a node in an index.
103 */
104
ecdc0628 105help_node_t * /* O - Node pointer or NULL */
ef416fc2 106helpFindNode(help_index_t *hi, /* I - Index */
107 const char *filename, /* I - Filename */
108 const char *anchor) /* I - Anchor */
109{
ecdc0628 110 help_node_t key; /* Search key */
ef416fc2 111
112
113 DEBUG_printf(("helpFindNode(hi=%p, filename=\"%s\", anchor=\"%s\")\n",
114 hi, filename ? filename : "(nil)", anchor ? anchor : "(nil)"));
115
116 /*
117 * Range check input...
118 */
119
120 if (!hi || !filename)
121 return (NULL);
122
123 /*
124 * Initialize the search key...
125 */
126
127 key.filename = (char *)filename;
128 key.anchor = (char *)anchor;
ef416fc2 129
130 /*
131 * Return any match...
132 */
133
ecdc0628 134 return ((help_node_t *)cupsArrayFind(hi->nodes, &key));
ef416fc2 135}
136
137
138/*
139 * 'helpLoadIndex()' - Load a help index from disk.
140 */
141
142help_index_t * /* O - Index pointer or NULL */
143helpLoadIndex(const char *hifile, /* I - Index filename */
144 const char *directory) /* I - Directory that is indexed */
145{
146 help_index_t *hi; /* Help index */
147 cups_file_t *fp; /* Current file */
148 char line[2048], /* Line from file */
149 *ptr, /* Pointer into line */
150 *filename, /* Filename in line */
151 *anchor, /* Anchor in line */
152 *sectptr, /* Section pointer in line */
153 section[1024], /* Section name */
154 *text; /* Text in line */
155 time_t mtime; /* Modification time */
156 off_t offset; /* Offset into file */
157 size_t length; /* Length in bytes */
158 int update; /* Update? */
ef416fc2 159 help_node_t *node; /* Current node */
160
161
162 DEBUG_printf(("helpLoadIndex(hifile=\"%s\", directory=\"%s\")\n",
163 hifile, directory));
164
165 /*
166 * Create a new, empty index.
167 */
168
ecdc0628 169 if ((hi = (help_index_t *)calloc(1, sizeof(help_index_t))) == NULL)
170 return (NULL);
171
172 hi->nodes = cupsArrayNew((cups_array_func_t)help_sort_by_name, NULL);
173 hi->sorted = cupsArrayNew((cups_array_func_t)help_sort_by_score, NULL);
174
175 if (!hi->nodes || !hi->sorted)
176 {
177 cupsArrayDelete(hi->nodes);
178 cupsArrayDelete(hi->sorted);
179 free(hi);
180 return (NULL);
181 }
ef416fc2 182
183 /*
184 * Try loading the existing index file...
185 */
186
187 if ((fp = cupsFileOpen(hifile, "r")) != NULL)
188 {
189 /*
190 * Lock the file and then read the first line...
191 */
192
193 cupsFileLock(fp, 1);
194
195 if (cupsFileGets(fp, line, sizeof(line)) && !strcmp(line, "HELPV1"))
196 {
197 /*
198 * Got a valid header line, now read the data lines...
199 */
200
201 while (cupsFileGets(fp, line, sizeof(line)))
202 {
203 /*
204 * Each line looks like one of the following:
205 *
206 * filename mtime offset length "section" "text"
207 * filename#anchor offset length "text"
208 */
209
210 filename = line;
211
212 if ((ptr = strchr(line, ' ')) == NULL)
213 break;
214
215 while (isspace(*ptr & 255))
216 *ptr++ = '\0';
217
218 if ((anchor = strrchr(filename, '#')) != NULL)
219 {
220 *anchor++ = '\0';
221 mtime = 0;
222 }
223 else
224 mtime = strtol(ptr, &ptr, 10);
225
226 offset = strtoll(ptr, &ptr, 10);
227 length = strtoll(ptr, &ptr, 10);
228
229 while (isspace(*ptr & 255))
230 ptr ++;
231
232 if (!anchor)
233 {
234 /*
235 * Get section...
236 */
237
238 if (*ptr != '\"')
239 break;
240
241 ptr ++;
242 sectptr = ptr;
243
244 while (*ptr && *ptr != '\"')
245 ptr ++;
246
247 if (*ptr != '\"')
248 break;
249
250 *ptr++ = '\0';
251
252 strlcpy(section, sectptr, sizeof(section));
253
254 while (isspace(*ptr & 255))
255 ptr ++;
256 }
257
258 if (*ptr != '\"')
259 break;
260
261 ptr ++;
262 text = ptr;
263
264 while (*ptr && *ptr != '\"')
265 ptr ++;
266
267 if (*ptr != '\"')
268 break;
269
270 *ptr++ = '\0';
271
272 if ((node = help_new_node(filename, anchor, section, text,
273 mtime, offset, length)) == NULL)
274 break;
275
ef416fc2 276 node->score = -1;
ecdc0628 277
278 cupsArrayAdd(hi->nodes, node);
ef416fc2 279 }
280 }
281
282 cupsFileClose(fp);
283 }
284
285 /*
286 * Scan for new/updated files...
287 */
288
289 update = help_load_directory(hi, directory, NULL);
290
291 /*
292 * Remove any files that are no longer installed...
293 */
294
ecdc0628 295 for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
296 node;
297 node = (help_node_t *)cupsArrayNext(hi->nodes))
298 if (node->score < 0)
ef416fc2 299 {
300 /*
301 * Delete this node...
302 */
303
ecdc0628 304 cupsArrayRemove(hi->nodes, node);
305 help_delete_node(node);
ef416fc2 306 }
ef416fc2 307
308 /*
ecdc0628 309 * Add nodes to the sorted array...
ef416fc2 310 */
311
ecdc0628 312 for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
313 node;
314 node = (help_node_t *)cupsArrayNext(hi->nodes))
315 cupsArrayAdd(hi->sorted, node);
ef416fc2 316
317 /*
ecdc0628 318 * Save the index if we updated it...
ef416fc2 319 */
320
ecdc0628 321 if (update)
322 helpSaveIndex(hi, hifile);
ef416fc2 323
324 /*
325 * Return the index...
326 */
327
328 return (hi);
329}
330
331
332/*
333 * 'helpSaveIndex()' - Save a help index to disk.
334 */
335
336int /* O - 0 on success, -1 on error */
337helpSaveIndex(help_index_t *hi, /* I - Index */
338 const char *hifile) /* I - Index filename */
339{
340 cups_file_t *fp; /* Index file */
ef416fc2 341 help_node_t *node; /* Current node */
342
343
344 DEBUG_printf(("helpSaveIndex(hi=%p, hifile=\"%s\")\n", hi, hifile));
345
346 /*
347 * Try creating a new index file...
348 */
349
350 if ((fp = cupsFileOpen(hifile, "w9")) == NULL)
351 return (-1);
352
353 /*
354 * Lock the file while we write it...
355 */
356
357 cupsFileLock(fp, 1);
358
359 cupsFilePuts(fp, "HELPV1\n");
360
ecdc0628 361 for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
362 node;
363 node = (help_node_t *)cupsArrayNext(hi->nodes))
ef416fc2 364 {
365 /*
366 * Write the current node with/without the anchor...
367 */
368
ef416fc2 369 if (node->anchor)
370 {
371 if (cupsFilePrintf(fp, "%s#%s " CUPS_LLFMT " " CUPS_LLFMT " \"%s\"\n",
372 node->filename, node->anchor,
373 CUPS_LLCAST node->offset, CUPS_LLCAST node->length,
374 node->text) < 0)
375 break;
376 }
377 else
378 {
379 if (cupsFilePrintf(fp, "%s %d " CUPS_LLFMT " " CUPS_LLFMT " \"%s\" \"%s\"\n",
380 node->filename, node->mtime,
381 CUPS_LLCAST node->offset, CUPS_LLCAST node->length,
382 node->section ? node->section : "", node->text) < 0)
383 break;
384 }
385 }
386
ecdc0628 387 cupsFileFlush(fp);
388
ef416fc2 389 if (cupsFileClose(fp) < 0)
390 return (-1);
ecdc0628 391 else if (node)
ef416fc2 392 return (-1);
393 else
394 return (0);
395}
396
397
398/*
399 * 'helpSearchIndex()' - Search an index.
400 */
401
402help_index_t * /* O - Search index */
403helpSearchIndex(help_index_t *hi, /* I - Index */
404 const char *query, /* I - Query string */
405 const char *section, /* I - Limit search to this section */
406 const char *filename) /* I - Limit search to this file */
407{
ef416fc2 408 help_index_t *search; /* Search index */
ecdc0628 409 help_node_t *node; /* Current node */
ef416fc2 410 void *sc; /* Search context */
411 int matches; /* Number of matches */
412
413
414 DEBUG_printf(("helpSearchIndex(hi=%p, query=\"%s\", filename=\"%s\")\n",
415 hi, query ? query : "(nil)",
416 filename ? filename : "(nil)"));
417
418 /*
419 * Range check...
420 */
421
422 if (!hi || !query)
423 return (NULL);
424
ecdc0628 425 /*
426 * Reset the scores of all nodes to 0...
427 */
428
429 for (node = (help_node_t *)cupsArrayFirst(hi->nodes);
430 node;
431 node = (help_node_t *)cupsArrayNext(hi->nodes))
432 node->score = 0;
433
434 /*
435 * Find the first node to search in...
436 */
ef416fc2 437
438 if (filename)
439 {
ecdc0628 440 node = helpFindNode(hi, filename, NULL);
441 if (!node)
ef416fc2 442 return (NULL);
443 }
444 else
ecdc0628 445 node = (help_node_t *)cupsArrayFirst(hi->nodes);
ef416fc2 446
447 /*
448 * Convert the query into a regular expression...
449 */
450
451 sc = cgiCompileSearch(query);
452 if (!sc)
453 return (NULL);
454
455 /*
456 * Allocate a search index...
457 */
458
459 search = calloc(1, sizeof(help_index_t));
460 if (!search)
461 {
462 cgiFreeSearch(sc);
463 return (NULL);
464 }
465
ecdc0628 466 search->nodes = cupsArrayNew((cups_array_func_t)help_sort_by_name, NULL);
467 search->sorted = cupsArrayNew((cups_array_func_t)help_sort_by_score, NULL);
468
469 if (!search->nodes || !search->sorted)
470 {
471 cupsArrayDelete(search->nodes);
472 cupsArrayDelete(search->sorted);
473 free(search);
474 cgiFreeSearch(sc);
475 return (NULL);
476 }
477
ef416fc2 478 search->search = 1;
479
480 /*
481 * Check each node in the index, adding matching nodes to the
482 * search index...
483 */
484
ecdc0628 485 for (; node; node = (help_node_t *)cupsArrayNext(hi->nodes))
486 if (section && strcmp(node->section, section))
ef416fc2 487 continue;
ecdc0628 488 else if (filename && strcmp(node->filename, filename))
ef416fc2 489 continue;
ecdc0628 490 else if ((matches = cgiDoSearch(sc, node->text)) > 0)
ef416fc2 491 {
492 /*
493 * Found a match, add the node to the search index...
494 */
495
ecdc0628 496 node->score = matches;
ef416fc2 497
ecdc0628 498 cupsArrayAdd(search->nodes, node);
499 cupsArrayAdd(search->sorted, node);
ef416fc2 500 }
501
502 /*
503 * Free the search context...
504 */
505
506 cgiFreeSearch(sc);
507
ef416fc2 508 /*
509 * Return the results...
510 */
511
512 return (search);
513}
514
515
ef416fc2 516/*
517 * 'help_delete_node()' - Free all memory used by a node.
518 */
519
520static void
521help_delete_node(help_node_t *n) /* I - Node */
522{
523 DEBUG_printf(("help_delete_node(n=%p)\n", n));
524
525 if (!n)
526 return;
527
528 if (n->filename)
529 free(n->filename);
530
531 if (n->anchor)
532 free(n->anchor);
533
534 if (n->section)
535 free(n->section);
536
537 if (n->text)
538 free(n->text);
539
540 free(n);
541}
542
543
ef416fc2 544/*
545 * 'help_load_directory()' - Load a directory of files into an index.
546 */
547
548static int /* O - 0 = success, -1 = error, 1 = updated */
549help_load_directory(
550 help_index_t *hi, /* I - Index */
551 const char *directory, /* I - Directory */
552 const char *relative) /* I - Relative path */
553{
ef416fc2 554 cups_dir_t *dir; /* Directory file */
555 cups_dentry_t *dent; /* Directory entry */
556 char *ext, /* Pointer to extension */
557 filename[1024], /* Full filename */
558 relname[1024]; /* Relative filename */
559 int update; /* Updated? */
ecdc0628 560 help_node_t *node; /* Current node */
ef416fc2 561
562
563 DEBUG_printf(("help_load_directory(hi=%p, directory=\"%s\", relative=\"%s\")\n",
564 hi, directory ? directory : "(nil)", relative ? relative : "(nil)"));
565
566 /*
567 * Open the directory and scan it...
568 */
569
570 if ((dir = cupsDirOpen(directory)) == NULL)
571 return (0);
572
573 update = 0;
574
575 while ((dent = cupsDirRead(dir)) != NULL)
576 {
ecdc0628 577 /*
578 * Skip "." files...
579 */
580
581 if (dent->filename[0] == '.')
582 continue;
583
ef416fc2 584 /*
585 * Get absolute and relative filenames...
586 */
587
588 snprintf(filename, sizeof(filename), "%s/%s", directory, dent->filename);
589 if (relative)
590 snprintf(relname, sizeof(relname), "%s/%s", relative, dent->filename);
591 else
592 strlcpy(relname, dent->filename, sizeof(relname));
593
594 /*
595 * Check if we have a HTML file...
596 */
597
598 if ((ext = strstr(dent->filename, ".html")) != NULL &&
599 (!ext[5] || !strcmp(ext + 5, ".gz")))
600 {
601 /*
602 * HTML file, see if we have already indexed the file...
603 */
604
605 if ((node = helpFindNode(hi, relname, NULL)) != NULL)
606 {
607 /*
608 * File already indexed - check dates to confirm that the
609 * index is up-to-date...
610 */
611
ecdc0628 612 if (node->mtime == dent->fileinfo.st_mtime)
ef416fc2 613 {
614 /*
615 * Same modification time, so mark all of the nodes
616 * for this file as up-to-date...
617 */
618
ecdc0628 619 for (; node; node = (help_node_t *)cupsArrayNext(hi->nodes))
620 if (!strcmp(node->filename, relname))
621 node->score = 0;
ef416fc2 622 else
623 break;
624
625 continue;
626 }
627 }
628
629 update = 1;
630
631 help_load_file(hi, filename, relname, dent->fileinfo.st_mtime);
632 }
633 else if (S_ISDIR(dent->fileinfo.st_mode))
634 {
635 /*
636 * Process sub-directory...
637 */
638
639 if (help_load_directory(hi, filename, relname) == 1)
640 update = 1;
641 }
642 }
643
644 cupsDirClose(dir);
645
646 return (update);
647}
648
649
650/*
651 * 'help_load_file()' - Load a HTML files into an index.
652 */
653
654static int /* O - 0 = success, -1 = error */
655help_load_file(
656 help_index_t *hi, /* I - Index */
657 const char *filename, /* I - Filename */
658 const char *relative, /* I - Relative path */
659 time_t mtime) /* I - Modification time */
660{
661 cups_file_t *fp; /* HTML file */
ecdc0628 662 help_node_t *node; /* Current node */
ef416fc2 663 char line[1024], /* Line from file */
664 section[1024], /* Section */
665 *ptr, /* Pointer into line */
666 *anchor, /* Anchor name */
667 *text; /* Text for anchor */
668 off_t offset; /* File offset */
669 char quote; /* Quote character */
670
671
672 DEBUG_printf(("help_load_file(hi=%p, filename=\"%s\", relative=\"%s\", mtime=%ld)\n",
673 hi, filename ? filename : "(nil)",
674 relative ? relative : "(nil)", mtime));
675
676 if ((fp = cupsFileOpen(filename, "r")) == NULL)
677 return (-1);
678
679 node = NULL;
680 offset = 0;
681
682 strcpy(section, "Other");
683
684 while (cupsFileGets(fp, line, sizeof(line)))
685 {
686 /*
687 * Look for "<TITLE>", "<A NAME", or "<!-- SECTION:" prefix...
688 */
689
690 if (!strncasecmp(line, "<!-- SECTION:", 13))
691 {
692 /*
693 * Got section line, copy it!
694 */
695
696 for (ptr = line + 13; isspace(*ptr & 255); ptr ++);
697
698 strlcpy(section, ptr, sizeof(section));
699 if ((ptr = strstr(section, "-->")) != NULL)
700 {
701 /*
702 * Strip comment stuff from end of line...
703 */
704
705 for (*ptr-- = '\0'; ptr > line && isspace(*ptr & 255); *ptr-- = '\0');
706
707 if (isspace(*ptr & 255))
708 *ptr = '\0';
709 }
710 continue;
711 }
712
713 for (ptr = line; (ptr = strchr(ptr, '<')) != NULL;)
714 {
715 ptr ++;
716
717 if (!strncasecmp(ptr, "TITLE>", 6))
718 {
719 /*
720 * Found the title...
721 */
722
723 anchor = NULL;
724 ptr += 6;
725 }
726 else if (!strncasecmp(ptr, "A NAME=", 7))
727 {
728 /*
729 * Found an anchor...
730 */
731
732 ptr += 7;
733
734 if (*ptr == '\"' || *ptr == '\'')
735 {
736 /*
737 * Get quoted anchor...
738 */
739
740 quote = *ptr;
741 anchor = ptr + 1;
742 if ((ptr = strchr(anchor, quote)) != NULL)
743 *ptr++ = '\0';
744 else
745 break;
746 }
747 else
748 {
749 /*
750 * Get unquoted anchor...
751 */
752
753 anchor = ptr + 1;
754
755 for (ptr = anchor; *ptr && *ptr != '>' && !isspace(*ptr & 255); ptr ++);
756
757 if (*ptr)
758 *ptr++ = '\0';
759 else
760 break;
761 }
762
763 /*
764 * Got the anchor, now lets find the end...
765 */
766
767 while (*ptr && *ptr != '>')
768 ptr ++;
769
770 if (*ptr != '>')
771 break;
772
773 ptr ++;
774 }
775 else
776 continue;
777
778 /*
779 * Now collect text for the link...
780 */
781
782 text = ptr;
783 while ((ptr = strchr(text, '<')) == NULL)
784 {
785 ptr = text + strlen(text);
786 if (ptr >= (line + sizeof(line) - 2))
787 break;
788
789 *ptr++ = ' ';
790
791 if (!cupsFileGets(fp, ptr, sizeof(line) - (ptr - line) - 1))
792 break;
793 }
794
795 *ptr = '\0';
796
797 if (node)
798 node->length = offset - node->offset;
799
800 if (!*text)
801 {
802 node = NULL;
803 break;
804 }
805
ecdc0628 806 if ((node = helpFindNode(hi, relative, anchor)) != NULL)
ef416fc2 807 {
808 /*
809 * Node already in the index, so replace the text and other
810 * data...
811 */
812
ecdc0628 813 cupsArrayRemove(hi->nodes, node);
ef416fc2 814
815 if (node->section)
816 free(node->section);
817
818 if (node->text)
819 free(node->text);
820
821 node->section = section[0] ? strdup(section) : NULL;
822 node->text = strdup(text);
823 node->mtime = mtime;
824 node->offset = offset;
825 node->score = 0;
826 }
827 else
828 {
829 /*
830 * New node...
831 */
832
833 node = help_new_node(relative, anchor, section, text, mtime, offset, 0);
ef416fc2 834 }
835
836 /*
837 * Go through the text value and replace tabs and newlines with
838 * whitespace and eliminate extra whitespace...
839 */
840
841 for (ptr = node->text, text = node->text; *ptr;)
842 if (isspace(*ptr & 255))
843 {
844 while (isspace(*ptr & 255))
ed486911 845 ptr ++;
ef416fc2 846
847 *text++ = ' ';
848 }
849 else if (text != ptr)
850 *text++ = *ptr++;
851 else
852 {
853 text ++;
854 ptr ++;
855 }
856
857 *text = '\0';
858
ecdc0628 859 /*
860 * (Re)add the node to the array...
861 */
862
863 cupsArrayAdd(hi->nodes, node);
ef416fc2 864 break;
865 }
866
867 /*
868 * Get the offset of the next line...
869 */
870
871 offset = cupsFileTell(fp);
872 }
873
874 cupsFileClose(fp);
875
876 if (node)
877 node->length = offset - node->offset;
878
879 return (0);
880}
881
882
883/*
884 * 'help_new_node()' - Create a new node and add it to an index.
885 */
886
887static help_node_t * /* O - Node pointer or NULL on error */
888help_new_node(const char *filename, /* I - Filename */
889 const char *anchor, /* I - Anchor */
890 const char *section, /* I - Section */
891 const char *text, /* I - Text */
892 time_t mtime, /* I - Modification time */
893 off_t offset, /* I - Offset in file */
894 size_t length) /* I - Length in bytes */
895{
896 help_node_t *n; /* Node */
897
898
ecdc0628 899 DEBUG_printf(("help_new_node(filename=\"%s\", anchor=\"%s\", text=\"%s\", "
900 "mtime=%ld, offset=%ld, length=%ld)\n",
ef416fc2 901 filename ? filename : "(nil)", anchor ? anchor : "(nil)",
ecdc0628 902 text ? text : "(nil)", (long)mtime, (long)offset,
903 (long)length));
ef416fc2 904
905 n = (help_node_t *)calloc(1, sizeof(help_node_t));
906 if (!n)
907 return (NULL);
908
909 n->filename = strdup(filename);
910 n->anchor = anchor ? strdup(anchor) : NULL;
911 n->section = (section && *section) ? strdup(section) : NULL;
912 n->text = strdup(text);
913 n->mtime = mtime;
914 n->offset = offset;
915 n->length = length;
916
917 return (n);
918}
919
920
921/*
922 * 'help_sort_nodes_by_name()' - Sort nodes by section, filename, and anchor.
923 */
924
925static int /* O - Difference */
ecdc0628 926help_sort_by_name(help_node_t *n1, /* I - First node */
927 help_node_t *n2) /* I - Second node */
ef416fc2 928{
ef416fc2 929 int diff; /* Difference */
930
931
ecdc0628 932 DEBUG_printf(("help_sort_by_name(n1=%p(%s#%s), n2=%p(%s#%s)\n",
933 n1, n1->filename, n1->anchor ? n1->anchor : "",
934 n2, n2->filename, n2->anchor ? n2->anchor : ""));
ef416fc2 935
ecdc0628 936 if ((diff = strcmp(n1->filename, n2->filename)) != 0)
ef416fc2 937 return (diff);
938
ecdc0628 939 if (!n1->anchor && !n2->anchor)
ef416fc2 940 return (0);
ecdc0628 941 else if (!n1->anchor)
ef416fc2 942 return (-1);
ecdc0628 943 else if (!n2->anchor)
ef416fc2 944 return (1);
945 else
ecdc0628 946 return (strcmp(n1->anchor, n2->anchor));
ef416fc2 947}
948
949
950/*
951 * 'help_sort_nodes_by_score()' - Sort nodes by score and text.
952 */
953
954static int /* O - Difference */
ecdc0628 955help_sort_by_score(help_node_t *n1, /* I - First node */
956 help_node_t *n2) /* I - Second node */
ef416fc2 957{
ef416fc2 958 int diff; /* Difference */
959
960
ecdc0628 961 DEBUG_printf(("help_sort_by_score(n1=%p(%d \"%s\" \"%s\"), "
962 "n2=%p(%d \"%s\" \"%s\")\n",
963 n1, n1->score, n1->section ? n1->section : "", n1->text,
964 n2, n2->score, n2->section ? n2->section : "", n2->text));
ef416fc2 965
ecdc0628 966 if (n1->score != n2->score)
967 return (n1->score - n2->score);
ef416fc2 968
ecdc0628 969 if (n1->section && !n2->section)
ef416fc2 970 return (1);
ecdc0628 971 else if (!n1->section && n2->section)
ef416fc2 972 return (-1);
ecdc0628 973 else if (n1->section && n2->section &&
974 (diff = strcmp(n1->section, n2->section)) != 0)
ef416fc2 975 return (diff);
976
ecdc0628 977 return (strcasecmp(n1->text, n2->text));
ef416fc2 978}
979
980
981/*
c07d5b2d 982 * End of "$Id: help-index.c 181 2006-06-22 20:01:18Z jlovell $".
ef416fc2 983 */