Annotation of OpenXM_contrib/gnuplot/docs/doc2info.c, Revision 1.1.1.1
1.1 maekawa 1: /*
2: * $Id: doc2info.c,v 1.7 1998/04/14 00:16:59 drd Exp $
3: *
4: */
5:
6: /* GNUPLOT - doc2info.c */
7:
8: /*[
9: * Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
10: *
11: * Permission to use, copy, and distribute this software and its
12: * documentation for any purpose with or without fee is hereby granted,
13: * provided that the above copyright notice appear in all copies and
14: * that both that copyright notice and this permission notice appear
15: * in supporting documentation.
16: *
17: * Permission to modify the software is granted, but not the right to
18: * distribute the complete modified source code. Modifications are to
19: * be distributed as patches to the released version. Permission to
20: * distribute binaries produced by compiling modified sources is granted,
21: * provided you
22: * 1. distribute the corresponding source modifications from the
23: * released version in the form of a patch file along with the binaries,
24: * 2. add special version identification to distinguish your version
25: * in addition to the base release version number,
26: * 3. provide your name and address as the primary contact for the
27: * support of your modified version, and
28: * 4. retain our contact information in regard to use of the base
29: * software.
30: * Permission to distribute the released version of the source code along
31: * with corresponding source modifications in the form of a patch file is
32: * granted with same provisions 2 through 4 for binary distributions.
33: *
34: * This software is provided "as is" without express or implied warranty
35: * to the extent permitted by applicable law.
36: ]*/
37:
38: /*
39: * doc2info.c -- program to convert Gnuplot .DOC format to
40: * (Emacs -) Info-file format
41: *
42: * Created by Stefan Bodewig from doc2gih by Thomas Williams
43: * and doc2html by Russel Lang
44: * 1/29/1996
45: *
46: * usage: doc2info gnuplot.doc gnuplot.info
47: *
48: */
49:
50: /* note that tables must begin in at least the second column to */
51: /* be formatted correctly and tabs are forbidden */
52:
53: #ifdef HAVE_CONFIG_H
54: # include "config.h"
55: #endif
56:
57: #include "ansichek.h"
58: #include "stdfn.h"
59:
60: #define MAX_LINE_LEN 1023
61:
62: #include "doc2x.h"
63: #include "xref.h"
64:
65: struct BUFFER { /* buffer to reformat paragraphs with xrefs */
66: char *content;
67: struct BUFFER *next;
68: struct BUFFER *prev;
69: };
70:
71: struct XREFLIST { /* a list of xrefs allready mentioned in this node */
72: struct LIST *ref;
73: struct XREFLIST *next;
74: struct XREFLIST *prev;
75: };
76:
77: /* xref.c */
78: extern struct LIST *list;
79: extern struct LIST *head;
80:
81: extern struct LIST *keylist;
82: extern struct LIST *keyhead;
83:
84: extern int maxlevel;
85: extern int listitems;
86:
87: char title[MAX_LINE_LEN+1];
88: char ifile[MAX_LINE_LEN+1];
89: char ofile[MAX_LINE_LEN+1];
90: struct XREFLIST *refhead = NULL;
91:
92: void convert __PROTO((FILE *, FILE *));
93: void process_line __PROTO((char *, FILE *));
94: void node_head __PROTO((char *, char *, char *, char *, FILE *));
95: void name_free __PROTO((char **));
96: char **name_alloc __PROTO(());
97: void clear_buffer __PROTO((struct BUFFER *, FILE *));
98: int inxreflist __PROTO((struct LIST *));
99: void xref_free __PROTO((void));
100:
101: int main(argc, argv)
102: int argc;
103: char **argv;
104: {
105: FILE *infile;
106: FILE *outfile;
107: infile = stdin;
108: outfile = stdout;
109:
110: if (argc > 3) {
111: fprintf(stderr, "Usage: %s [infile [outfile]]\n", argv[0]);
112: exit(EXIT_FAILURE);
113: }
114: if (argc >= 2) {
115: strcpy(ifile, argv[1]);
116: if ((infile = fopen(argv[1], "r")) == (FILE *) NULL) {
117: fprintf(stderr, "%s: Can't open %s for reading\n",
118: argv[0], argv[1]);
119: exit(EXIT_FAILURE);
120: }
121: } else
122: safe_strncpy(ifile, "gnuplot.doc", sizeof(ifile)); /* default value */
123: if (argc == 3) {
124: safe_strncpy(ofile, argv[2], sizeof(ofile));
125: if ((outfile = fopen(argv[2], "w")) == (FILE *) NULL) {
126: fprintf(stderr, "%s: Can't open %s for writing\n",
127: argv[0], argv[2]);
128: exit(EXIT_FAILURE);
129: }
130: } else
131: safe_strncpy(ofile, "gnuplot.info", sizeof(ofile)); /* default value */
132:
133: safe_strncpy(title, ofile, sizeof(title));
134: strtok(title, "."); /* without type */
135: convert(infile, outfile);
136: exit(EXIT_SUCCESS);
137: }
138:
139:
140: void convert(a, b)
141: FILE *a, *b;
142: {
143: static char line[MAX_LINE_LEN+1];
144:
145: parse(a);
146:
147: refhead = (struct XREFLIST *) xmalloc(sizeof(struct XREFLIST));
148: refhead->next = refhead->prev = NULL;
149:
150: /* Info header */
151: fprintf(b, "This file is %s created by doc2info from %s.\n\n", ofile, ifile);
152:
153: /* and Top node */
154: node_head(NULL, NULL, head->next->string, NULL, b);
155:
156: while (get_line(line, sizeof(line), a)) {
157: process_line(line, b);
158: }
159: list_free();
160: free(refhead);
161: }
162:
163: /*
164: * scans the lines for xrefs, creates new nodes and prints or ignores
165: * the rest.
166: *
167: * Info xrefs are visible. Therefore we have to reformat the paragraphs
168: * containing them. All lines of the paragraph are written into a buffer
169: * and printed at the end of the paragraph.
170: */
171: void process_line(line, b)
172: char *line;
173: FILE *b;
174: {
175: static int line_count = 0;
176: struct LIST *node; /* current node */
177: static struct LIST *prev = NULL; /* previous node */
178: int level; /* current level */
179: static char **up = NULL; /* Array with node names */
180: static char **pre = NULL;
181: char topic[MAX_LINE_LEN+1]; /* for xrefs */
182: int i, j, k, l;
183: static int inref = FALSE; /* flags */
184: static int inbold = FALSE;
185: static struct BUFFER *buffer; /* buffer to hold the lines of a paragraph */
186: static struct BUFFER *buf_head = NULL;
187: int inbuf = 0; /* offset into buffer */
188: char line2[3*MAX_LINE_LEN+1]; /* line of text with added xrefs */
189: struct LIST *reflist;
190: static struct XREFLIST *lastref = NULL; /* xrefs that are already mentioned in this node */
191:
192: line2[0] = NUL;
193: if (!prev) /* last node visited */
194: prev = head;
195: if (!lastref)
196: lastref = refhead;
197: if (!up) { /* Names of `Prev:' and `Up:' nodes */
198: up = name_alloc();
199: pre = name_alloc();
200: strcpy(up[0], "(dir)");
201: strcpy(up[1], "Top");
202: strcpy(pre[1], "(dir)");
203: strcpy(pre[2], "Top");
204: }
205: line_count++;
206:
207: if (line[0] == ' ') /* scan line for xrefs */
208: for (i = 0; line[i] != NUL; ++i)
209: if (line[i] == '`') { /* Reference or boldface (ignore the latter) */
210: if (!inref && !inbold) {
211: k = i + 1; /* next character */
212: j = 0; /* index into topic */
213: while (line[k] != '`' && line[k] != NUL)
214: topic[j++] = line[k++];
215: topic[j] = NUL;
216:
217: /* try to find the xref */
218: reflist = lookup(topic);
219: if (reflist) {
220: /* now we have the (key-)list-entry */
221: /* convert it to a list-entry that represents a node */
222: reflist = lkup_by_number(reflist->line);
223: }
224: /* not interested in xrefs pointing to `Top' or same node */
225: /* we want only one reference per topic in node */
226: if (reflist && reflist->level != 0 && reflist != prev && !inxreflist(reflist)) {
227: /* new entry to xreflist */
228: lastref->next = (struct XREFLIST *) xmalloc(sizeof(struct XREFLIST));
229: lastref->next->prev = lastref;
230: lastref = lastref->next;
231: lastref->ref = reflist;
232: lastref->next = NULL;
233: if (!buf_head) { /* No buffer yet */
234: buf_head = (struct BUFFER *) xmalloc(sizeof(struct BUFFER));
235: buffer = buf_head;
236: buffer->prev = NULL;
237: buffer->next = NULL;
238: }
239: /* eliminate leading spaces of topic */
240: for (j = 0; isspace((int) reflist->string[j]); ++j);
241: /* encountered end of line */
242: if (line[k] == NUL) {
243: if (line[k - 1] == '\n') /* throw away new-lines */
244: line[--k] = NUL;
245: /* insert xref into line */
246: sprintf(line2, "%s%s (*note %s:: )", line2, line + inbuf, reflist->string + j);
247: inref = TRUE;
248: /* line is done */
249: break;
250: }
251: /* eliminate spaces before the second ` */
252: if (isspace((int) line[k - 1]))
253: for (l = k - 1; line[l] != NUL; ++l)
254: line[l] = line[l + 1];
255:
256: /* let `plot`s look nicer */
257: if (isalpha((int) line[k + 1]))
258: ++k;
259: sprintf(line2, "%s%.*s (*note %s:: )", line2, k - inbuf + 1, line + inbuf, reflist->string + j);
260: /* line2 contains first inbuf characters of line */
261: i = inbuf = k;
262: } else { /* found no reference */
263: inbold = TRUE;
264: }
265: } else {
266: if (inref) /* inref || inbold */
267: inref = FALSE;
268: else
269: inbold = FALSE;
270: }
271: }
272: /* just copy normal characters of line with xref */
273: else if (inbuf) {
274: strncat(line2, line + i, 1);
275: inbuf++;
276: }
277: switch (line[0]) { /* control character */
278: case '?':{ /* interactive help entry */
279: break; /* ignore */
280: }
281: case '@':{ /* start/end table */
282: break; /* ignore */
283: }
284: case '#':{ /* latex table entry */
285: break; /* ignore */
286: }
287: case '%':{ /* troff table entry */
288: break; /* ignore */
289: }
290: case '^':{ /* html entry */
291: break; /* ignore */
292: }
293: case '\n': /* empty text line */
294: if (buf_head) { /* do we have a buffer? */
295: /* paragraph finished, print it */
296: clear_buffer(buf_head, b);
297: buffer = buf_head = NULL;
298: } else /* just copy the blank line */
299: fputs(line, b);
300: break;
301: case ' ':{ /* normal text line */
302: if (buf_head) { /* must be inserted in buffer ? */
303: buffer->next = (struct BUFFER *) xmalloc(sizeof(struct BUFFER));
304: buffer->next->prev = buffer;
305: buffer = buffer->next;
306: buffer->next = NULL;
307: if (line2[0] == NUL) { /* line doesn't contain xref */
308: buffer->content = (char *) xmalloc(strlen(line) + 1);
309: strcpy(buffer->content, line);
310: } else { /* line contains xref */
311: buffer->content = (char *) xmalloc(strlen(line2) + 1);
312: strcpy(buffer->content, line2);
313: }
314: } else /* no buffer, just copy */
315: fputs(line, b);
316: break;
317: }
318: default:
319: if (isdigit((int) line[0])) { /* start of section */
320: /* clear xref-list */
321: xref_free();
322: lastref = 0;
323: if (buf_head) { /* do we have a buffer */
324: /* paragraphs are not allways separated by a blank line */
325: clear_buffer(buf_head, b);
326: buffer = buf_head = NULL;
327: }
328: level = line[0] - '0';
329:
330: if (level > prev->level) /* going down */
331: /* so write menu of previous node */
332: refs(prev->line, b, "\n* Menu:\n\n", NULL, "* %s::\n");
333: node = prev->next;
334: if (!node->next) { /* last node ? */
335: node_head(node->string, pre[level + 1], NULL, up[level], b);
336: name_free(up);
337: name_free(pre);
338:
339: /* next node will go up, no 'Next:' node */
340: } else if (node->next->level < level)
341: node_head(node->string, pre[level + 1], NULL, up[level], b);
342:
343: else {
344: node_head(node->string, pre[level + 1], node->next->string, up[level], b);
345: strcpy(pre[level + 1], node->string);
346:
347: /* next node will go down */
348: if (level < node->next->level) {
349: strcpy(up[level + 1], node->string);
350: strcpy(pre[node->next->level + 1], node->string);
351: }
352: }
353: prev = node;
354: } else
355: fprintf(stderr, "unknown control code '%c' in column 1, line %d\n",
356: line[0], line_count);
357: break;
358: }
359: }
360:
361: /*
362: * write the header of an Info node, treat Top node specially
363: */
364: void node_head(node, prev, next, up, b)
365: char *node, *prev, *next, *up;
366: FILE *b;
367: {
368: /* eliminate leading spaces */
369: while (node && isspace((int) *node))
370: node++;
371: while (next && isspace((int) *next))
372: next++;
373: while (prev && isspace((int) *prev))
374: prev++;
375: while (up && isspace((int) *up))
376: up++;
377:
378: if (!prev) { /* Top node */
379: int i;
380: fprintf(b, "\nFile: %s, Node: Top, Prev: (dir), Next: %s, Up: (dir)\n\n", ofile, next);
381: fprintf(b, "%s\n", title);
382: for (i = 0; i < strlen(title); ++i)
383: fprintf(b, "*");
384: fprintf(b, "\n\n");
385: return;
386: }
387: fprintf(b, "\n\nFile: %s, ", ofile);
388: fprintf(b, "Node: %s, Prev: %s, Up: %s", node, prev, up);
389:
390: if (next)
391: fprintf(b, ", Next: %s\n\n", next);
392: else
393: fputs("\n\n", b);
394: }
395:
396: /*
397: * allocate memory for the node titles (up and prev)
398: * need at most maxlevel+Top+(dir) entries
399: */
400: char **name_alloc __PROTO((void))
401: {
402: char **a;
403: int i;
404:
405: a = (char **) xmalloc((maxlevel + 2) * sizeof(char *));
406: for (i = 0; i <= maxlevel + 1; i++)
407: a[i] = (char *) xmalloc(MAX_LINE_LEN+1);
408: return a;
409: }
410:
411: /*
412: * free node names
413: */
414: void name_free(names)
415: char **names;
416: {
417: int i;
418:
419: for (i = 0; i <= maxlevel + 1; i++)
420: free(names[i]);
421: free(names);
422: }
423:
424: /*
425: * reformat the buffered lines
426: */
427: void clear_buffer(buf_head, b)
428: struct BUFFER *buf_head;
429: FILE *b;
430: {
431: struct BUFFER *run;
432: int in_line = 0; /* offset into current line */
433: int in_buf = 0; /* offset into buffer */
434: int i, todo;
435: char c;
436:
437: /* for all buffer entries */
438: for (run = buf_head; run->next; run = run->next) {
439:
440: /* unprinted characters */
441: todo = strlen(run->next->content);
442:
443: /* eliminate new-lines */
444: if (run->next->content[todo - 1] == '\n')
445: run->next->content[--todo] = NUL;
446:
447: while (todo)
448: if (79 - in_line > todo) { /* buffer fits into line */
449: fprintf(b, "%s", run->next->content + in_buf);
450: in_line += todo;
451: todo = in_buf = 0;
452:
453: } else { /* buffer must be split over lines */
454:
455: /* search for whitespace to split at */
456: for (i = 79 - in_line; i > 2; --i)
457: if (isspace((int) (run->next->content[in_buf + i]))) {
458: char *beginnote, *linestart;
459: c = run->next->content[in_buf + i - 1];
460: if (c == '.') /* don't split at end of sentence */
461: continue;
462: if (c == ' ') /* ditto */
463: continue;
464:
465: /* dont break xref */
466: /* search for xref in current line */
467: linestart = run->next->content + in_buf;
468: beginnote = strstr(linestart, "(*note");
469: while (beginnote && beginnote < linestart + i) {
470: /* don't split if it didn't fit into the line as a whole */
471: if (strchr(beginnote, ')') > linestart + i)
472: break;
473: /* xref is complete, maybe there's another one? */
474: beginnote = strstr(beginnote + 1, "(*note");
475: }
476:
477: /* unbalanced xref ? */
478: if (beginnote && beginnote < linestart + i)
479: continue;
480:
481: break;
482: }
483: if (i > 2) { /* found a point to split buffer */
484: fprintf(b, "%.*s\n", i, run->next->content + in_buf);
485: todo -= i;
486: in_buf += i;
487: in_line = 0;
488: } else { /* try with a new line */
489: fputs("\n", b);
490: in_line = 0;
491: }
492: }
493: }
494: if (in_line) /* paragraph ended incomplete line */
495: fputs("\n", b);
496: fputs("\n", b);
497:
498: /* free the buffer */
499: for (run = run->prev; run->prev; run = run->prev) {
500: free(run->next->content);
501: free(run->next);
502: run->next = NULL;
503: }
504: if (buf_head->next) {
505: free(buf_head->next->content);
506: free(buf_head->next);
507: buf_head->next = NULL;
508: }
509: free(buf_head);
510: }
511:
512: /*
513: * test whether topic is allready referenced in node
514: */
515: int inxreflist(reflist)
516: struct LIST *reflist;
517: {
518: struct XREFLIST *run;
519:
520: for (run = refhead; run->next; run = run->next)
521: if (run->next->ref == reflist)
522: return TRUE;
523: return FALSE;
524: }
525:
526: /*
527: * free the list of xrefs
528: */
529: void xref_free __PROTO((void))
530: {
531: struct XREFLIST *lastref;
532:
533: for (lastref = refhead; lastref->next; lastref = lastref->next);
534: if (lastref != refhead)
535: for (lastref = lastref->prev; lastref->prev; lastref = lastref->prev)
536: free(lastref->next);
537: if (refhead->next)
538: free(refhead->next);
539: refhead->next = NULL;
540: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>