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