e056ce1c4828c1a0e3b062a3d3535f54209ea039
[gnuplot] / docs / xref.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: xref.c,v 1.11 2005/04/22 21:40:37 broeker Exp $"); }
3 #endif
4
5 /* GNUPLOT - xref.c */
6
7 /*[
8  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /*
38  * this file is used by doc2ipf, doc2html, doc2rtf and doc2info
39  *
40  * MUST be included after termdoc.c (since termdoc.c redefines fgets() )
41  *
42  * it contains functions needed to handle xrefs, most of them from
43  *     doc2rtf (most likely) by Maurice Castro
44  *  or doc2ipf by Roger Fearick
45  *  or doc2html by Russel Lang
46  *
47  * I have modified the functions a little to make them more flexible
48  * (lookup returns list instead of list->line) or let them work with all
49  * four programs (adding three parameters to refs).
50  *
51  * I switched the search order of lookup. Makes more sense to me
52  *
53  * Stefan Bodewig 1/29/1996
54  */
55
56 #ifdef HAVE_CONFIG_H
57 # include "config.h"
58 #endif
59
60 #define DOCS_XREF_MAIN
61
62 #include "syscfg.h"
63 #include "stdfn.h"
64 #include "doc2x.h"
65 #include "xref.h"
66
67 struct LIST *list = NULL;
68 struct LIST *head = NULL;
69
70 struct LIST *keylist = NULL;
71 struct LIST *keyhead = NULL;
72
73 void dump_list __PROTO((void));
74
75 int maxlevel = 0;               /* how deep are the topics nested? */
76 int listitems = 0;              /* number of topics */
77
78 /* for debugging (invoke from gdb !) */
79 void
80 dump_list()
81 {
82     struct LIST *element = head;
83     while (element) {
84         fprintf(stderr, "%p level %d, line %d, \"%s\"\n", element,
85                 element->level, element->line, element->string);
86         element = element->next;
87     }
88 }
89
90
91 generic *
92 xmalloc(size_t size)
93 {
94     generic *p = malloc(size);
95
96     if (!p) {
97         fprintf(stderr, "Malloc failed\n");
98         exit(EXIT_FAILURE);
99     }
100     return p;
101 }
102
103 /* scan the file and build a list of line numbers where particular levels are */
104 void
105 parse(FILE *a)
106 {
107     static char line[MAX_LINE_LEN+1];
108     char *c;
109     int lineno = 0;
110     int lastline = 0;
111
112     /* insert a special level 0 listitem
113      * this one is the starting point for the table of contents in the html
114      * version and the Top-Node of the info version.
115      *
116      * Added this to support multiple level 1 items.     --SB
117      */
118     listitems = 1;
119     head = (list = (struct LIST *) xmalloc(sizeof(struct LIST)));
120     list->prev = NULL;
121     list->line = 0;
122     list->level = 0;
123     /* I would prefer list->string = NULL, but don't know if free(NULL) is OK
124      * with all supported plattforms. */
125     list->string = (char *) xmalloc(1);
126     list->next = NULL;
127
128     while (get_line(line, sizeof(line), a)) {
129         lineno++;
130         if (isdigit((int)line[0])) {    /* start of new section */
131             listitems++;
132
133             if (list == NULL) { /* impossible with the new level 0 item */
134                 head = (list = (struct LIST *) xmalloc(sizeof(struct LIST)));
135                 list->prev = NULL;
136             } else {
137                 list->next = (struct LIST *) xmalloc(sizeof(struct LIST));
138                 list->next->prev = list;
139                 list = list->next;
140                 list->next = NULL;
141             }
142
143             list->line = lastline = lineno;
144             list->level = line[0] - '0';
145             list->string = (char *) xmalloc(strlen(line) + 1);
146             c = strtok(&(line[1]), "\n");
147             strcpy(list->string, c);
148             list->next = NULL;
149             if (list->level > maxlevel)
150                 maxlevel = list->level;
151         }
152         if (line[0] == '?') {   /* keywords */
153             if (keylist == NULL) {
154                 keyhead = (keylist = (struct LIST *) xmalloc(sizeof(struct LIST)));
155                 keylist->prev = NULL;
156             } else {
157                 keylist->next = (struct LIST *) xmalloc(sizeof(struct LIST));
158                 keylist->next->prev = keylist;
159                 keylist = keylist->next;
160             }
161
162             keylist->line = lastline;
163             keylist->level = list->level;
164             c = strtok(&(line[1]), "\n");
165             if (c == NULL || *c == '\0')
166                 c = list->string;
167             keylist->string = (char *) malloc(strlen(c) + 1);
168             strcpy(keylist->string, c);
169             keylist->next = NULL;
170         }
171     }
172     rewind(a);
173 }
174
175 /* look up a topic in text reference */
176 /*
177  * Original version from doc2rtf (|| ipf || html) scanned keylist before list.
178  * This way we get a reference to `plot` for the topic `splot` instead
179  * of one to `splot`. Switched the search order -SB.
180  */
181 struct LIST *
182 lookup(char *s)
183 {
184     char *c;
185     char tokstr[MAX_LINE_LEN+1];
186     char *match;
187     int l;
188
189     strcpy(tokstr, s);
190
191     /* first try titles */
192     match = strtok(tokstr, " \n\t");
193     if (match == NULL) {
194         fprintf(stderr, "Error in lookup(\"%s\")\n", s);
195
196         /* there should a line number, but it is local to parse()  */
197         fprintf(stderr,
198                 "Possible missing link character (`) near above line number\n");
199         exit(3);
200     }
201     l = 0;                      /* level */
202
203     list = head;
204     while (list != NULL) {
205         c = list->string;
206         while (isspace((int)(*c)))
207             c++;
208         if (!strcmp(match, c)) {
209             l = list->level;
210             match = strtok(NULL, "\n\t ");
211             if (match == NULL) {
212                 return (list);
213             }
214         }
215         if (l > list->level)
216             break;
217         list = list->next;
218     }
219
220     /* then try the ? keyword entries */
221     keylist = keyhead;
222     while (keylist != NULL) {
223         c = keylist->string;
224         while (isspace((int)(*c)))
225             c++;
226         if (!strcmp(s, c))
227             return (keylist);
228         keylist = keylist->next;
229     }
230
231     return (NULL);
232 }
233
234 /*
235  * find title-entry for keyword-entry
236  */
237 struct LIST *
238 lkup_by_number(int line)
239 {
240     struct LIST *run = head;
241
242     while (run->next && run->next->line <= line)
243         run = run->next;
244
245     if (run->next)
246         return run;
247     else
248         return NULL;
249 }
250
251 /*
252  * free the whole list (I never trust the OS -SB)
253  */
254 void
255 list_free()
256 {
257     struct LIST *run;
258
259     for (run = head; run->next; run = run->next)
260         ; /* do nothing */
261
262     for (run = run->prev; run; run = run->prev) {
263         free(run->next->string);
264         free(run->next);
265     }
266     free(head->string);
267     free(head);
268
269     for (run = keyhead; run->next; run = run->next)
270         ; /* do nothing */
271     for (run = run->prev; run; run = run->prev) {
272         free(run->next->string);
273         free(run->next);
274     }
275     free(keyhead->string);
276     free(keyhead);
277 }
278
279
280 /* search through the list to find any references */
281 /*
282  * writes a menu of all subtopics of the topic located at l
283  * format must contain %s for the title of the subtopic and may contain
284  * a %d for the line number of the subtopic (used by doc2html and doc2rtf
285  * The whole menu is preceeded by start and gets the trailer end
286  */
287 void
288 refs( int l, FILE *f, char *start, char *end, char *format)
289 {
290     int curlevel, i;
291     char *c;
292     int inlist = FALSE;
293
294     /* find current line */
295     list = head;
296     while (list->line != l)
297         list = list->next;
298     curlevel = list->level;
299     list = list->next;          /* look at next element before going on */
300
301     if (start != NULL && list != NULL) {
302         /* don't write start if there's no menue at all */
303         inlist = TRUE;
304         fprintf(f, "%s", start);
305     }
306     while (list != NULL) {
307         /* we are onto the next topic so stop */
308         if (list->level == curlevel)
309             break;
310         /* these are the next topics down the list */
311         if (list->level == curlevel + 1) {
312             c = list->string;
313             while (isspace((int)(*c)))
314                 c++;            /* strip leading whitespace */
315
316             if (format != NULL) {
317                 for (i = 0; format[i] != '%' && format[i] != '\0'; i++);
318                 if (format[i] != '\0') {
319                     if (format[i + 1] == 'd') {
320                         /* line number has to be printed first */
321                         fprintf(f, format, list->line, c);
322                     }
323                     else {
324                         ++i;
325                         for (; format[i] != '%' && format[i] != '\0'; i++);
326                         if (format[i] != '\0')  /* line number is second */
327                             fprintf(f, format, c, list->line);
328                         else    /* no line number at all */
329                             fprintf(f, format, c);
330                     }
331                 }
332             }
333         }
334         list = list->next;
335     }
336     if (inlist && end)          /* trailer */
337         fprintf(f, "%s", end);
338 }