|
|
1.1 root 1: /* Generate doc-string file for GNU Emacs from source files.
2: Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3:
4: This file is part of GNU Emacs.
5:
6: GNU Emacs is distributed in the hope that it will be useful,
7: but without any warranty. No author or distributor
8: accepts responsibility to anyone for the consequences of using it
9: or for whether it serves any particular purpose or works at all,
10: unless he says so in writing.
11:
12: Everyone is granted permission to copy, modify and redistribute
13: GNU Emacs, but only under the conditions described in the
14: document "GNU Emacs copying permission notice". An exact copy
15: of the document is supposed to have been given to you along with
16: GNU Emacs so that you can know how you may redistribute it all.
17: It should be in a file named COPYING. Among other things, the
18: copyright notice and this notice must be preserved on all copies. */
19:
20: /* The arguments given to this program are all the C and Lisp source files
21: of GNU Emacs. .elc and .el and .c files are allowed.
22: A .o file can also be specified; the .c file it was made from is used.
23: This helps the makefile pass the correct list of files.
24:
25: The results, which go to standard output or to a file
26: specified with -a or -o (-a to append, -o to start from nothing),
27: are entries containing function or variable names and their documentation.
28: Each entry starts with a ^_ character.
29: Then comes F for a function or V for a variable.
30: Then comes the function or variable name, terminated with a newline.
31: Then comes the documentation for that function or variable.
32: */
33:
34: #include <stdio.h>
35:
36: FILE *outfile;
37:
38: main (argc, argv)
39: int argc;
40: char **argv;
41: {
42: int i;
43: int err_count = 0;
44:
45: outfile = stdout;
46:
47: /* If first two args are -o FILE, output to FILE. */
48: i = 1;
49: if (argc > i + 1 && !strcmp (argv[i], "-o"))
50: {
51: outfile = fopen (argv[i + 1], "w");
52: i += 2;
53: }
54: if (argc > i + 1 && !strcmp (argv[i], "-a"))
55: {
56: outfile = fopen (argv[i + 1], "a");
57: i += 2;
58: }
59:
60: for (; i < argc; i++)
61: err_count += scan_file (argv[i]); /* err_count seems to be {mis,un}used */
62: #ifndef VMS
63: exit (err_count); /* see below - shane */
64: #endif VMS
65: }
66:
67: /* Read file FILENAME and output its doc strings to stdout. */
68: /* Return 1 if file is not found, 0 if it is found. */
69:
70: scan_file (filename)
71: char *filename;
72: {
73: int len = strlen (filename);
74: if (!strcmp (filename + len - 4, ".elc"))
75: return scan_lisp_file (filename);
76: else if (!strcmp (filename + len - 3, ".el"))
77: return scan_lisp_file (filename);
78: else
79: return scan_c_file (filename);
80: }
81:
82: char buf[128];
83:
84: /* Skip a C string from INFILE,
85: and return the character that follows the closing ".
86: If printflag is positive, output string contents to stdout.
87: If it is negative, store contents in buf.
88: Convert escape sequences \n and \t to newline and tab;
89: discard \ followed by newline. */
90:
91: read_c_string (infile, printflag)
92: FILE *infile;
93: int printflag;
94: {
95: register int c;
96: char *p = buf;
97:
98: c = getc (infile);
99: while (c != EOF)
100: {
101: while (c != '"' && c != EOF)
102: {
103: if (c == '\\')
104: {
105: c = getc (infile);
106: if (c == '\n')
107: {
108: c = getc (infile);
109: continue;
110: }
111: if (c == 'n')
112: c = '\n';
113: if (c == 't')
114: c = '\t';
115: }
116: if (printflag > 0)
117: putc (c, outfile);
118: else if (printflag < 0)
119: *p++ = c;
120: c = getc (infile);
121: }
122: c = getc (infile);
123: if (c != '"')
124: break;
125: if (printflag > 0)
126: putc (c, outfile);
127: else if (printflag < 0)
128: *p++ = c;
129: c = getc (infile);
130: }
131:
132: if (printflag < 0)
133: *p = 0;
134:
135: return c;
136: }
137:
138: /* Read through a c file. If a .o file is named,
139: the corresponding .c file is read instead.
140: Looks for DEFUN constructs such as are defined in ../src/lisp.h.
141: Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */
142:
143: scan_c_file (filename)
144: char *filename;
145: {
146: FILE *infile;
147: register int c;
148: register int commas;
149: register int defunflag;
150: register int defvarflag;
151:
152: if (filename[strlen (filename) - 1] == 'o')
153: filename[strlen (filename) - 1] = 'c';
154:
155: infile = fopen (filename, "r");
156:
157: /* No error if non-ex input file */
158: if (infile == NULL)
159: {
160: perror (filename);
161: return 0;
162: }
163:
164: c = '\n';
165: while (!feof (infile))
166: {
167: if (c != '\n')
168: {
169: c = getc (infile);
170: continue;
171: }
172: c = getc (infile);
173: if (c == ' ')
174: {
175: while (c == ' ')
176: c = getc (infile);
177: if (c != 'D')
178: continue;
179: c = getc (infile);
180: if (c != 'E')
181: continue;
182: c = getc (infile);
183: if (c != 'F')
184: continue;
185: c = getc (infile);
186: if (c != 'V')
187: continue;
188: defvarflag = 1;
189: defunflag = 0;
190: c = getc (infile);
191: }
192: else if (c == 'D')
193: {
194: c = getc (infile);
195: if (c != 'E')
196: continue;
197: c = getc (infile);
198: if (c != 'F')
199: continue;
200: c = getc (infile);
201: defunflag = c == 'U';
202: defvarflag = 0;
203: }
204: else continue;
205:
206: while (c != '(')
207: {
208: if (c < 0)
209: return 0;
210: c = getc (infile);
211: }
212:
213: c = getc (infile);
214: if (c != '"')
215: continue;
216: c = read_c_string (infile, -1);
217:
218: if (defunflag)
219: commas = 5;
220: else if (defvarflag)
221: commas = 1;
222: else /* For DEFSIMPLE and DEFPRED */
223: commas = 2;
224:
225: while (commas)
226: {
227: if (c == ',') commas --;
228: if (c < 0)
229: return 0;
230: c = getc (infile);
231: }
232: while (c == ' ' || c == '\n' || c == '\t')
233: c = getc (infile);
234: if (c == '"')
235: c = read_c_string (infile, 0);
236: while (c != ',')
237: c = getc (infile);
238: c = getc (infile);
239: while (c == ' ' || c == '\n' || c == '\t')
240: c = getc (infile);
241:
242: if (c == '"')
243: {
244: putc (037, outfile);
245: putc (defvarflag ? 'V' : 'F', outfile);
246: fprintf (outfile, "%s\n", buf);
247: read_c_string (infile, 1);
248: }
249: }
250: fclose (infile);
251: return 0;
252: }
253:
254: /* Read a file of Lisp code, compiled or interpreted.
255: Looks for
256: (defun NAME ARGS DOCSTRING ...)
257: (autoload 'NAME FILE DOCSTRING ...)
258: (defvar NAME VALUE DOCSTRING)
259: (defconst NAME VALUE DOCSTRING)
260: starting in column zero.
261: ARGS, FILE or VALUE is ignored. We do not know how to parse Lisp code
262: so we use a kludge to skip them:
263: In a function definition, the form of ARGS of FILE is known, and we
264: can skip it.
265: In a variable definition, we use a formatting convention:
266: the DOCSTRING, if present, must be followed by a closeparen and a newline,
267: and no newline must appear between the defvar or defconst and the docstring,
268: The only source file that must follow this convention is loaddefs.el;
269: aside from that, it is always the .elc file that we look at, and
270: they are no problem because byte-compiler output follows this convention.
271: The NAME and DOCSTRING are output.
272: NAME is preceded by `F' for a function or `V' for a variable.
273: An entry is output only if DOCSTRING has \ newline just after the opening "
274: */
275:
276: scan_lisp_file (filename)
277: char *filename;
278: {
279: FILE *infile;
280: register int c;
281: register int commas;
282: register char *p;
283: int defvarflag;
284:
285: infile = fopen (filename, "r");
286: if (infile == NULL)
287: {
288: perror (filename);
289: return 0; /* No error */
290: }
291:
292: c = '\n';
293: while (!feof (infile))
294: {
295: if (c != '\n')
296: {
297: c = getc (infile);
298: continue;
299: }
300: c = getc (infile);
301: if (c != '(')
302: continue;
303: c = getc (infile);
304: if (c == 'a')
305: {
306: c = getc (infile);
307: if (c != 'u')
308: continue;
309: c = getc (infile);
310: if (c != 't')
311: continue;
312: c = getc (infile);
313: if (c != 'o')
314: continue;
315: c = getc (infile);
316: if (c != 'l')
317: continue;
318: c = getc (infile);
319: if (c != 'o')
320: continue;
321: c = getc (infile);
322: if (c != 'a')
323: continue;
324: c = getc (infile);
325: if (c != 'd')
326: continue;
327:
328: c = getc (infile);
329: while (c == ' ')
330: c = getc (infile);
331:
332: if (c == '\'')
333: {
334: c = getc (infile);
335: }
336: else
337: {
338: if (c != '(')
339: continue;
340: c = getc (infile);
341: if (c != 'q')
342: continue;
343: c = getc (infile);
344: if (c != 'u')
345: continue;
346: c = getc (infile);
347: if (c != 'o')
348: continue;
349: c = getc (infile);
350: if (c != 't')
351: continue;
352: c = getc (infile);
353: if (c != 'e')
354: continue;
355: c = getc (infile);
356: if (c != ' ')
357: continue;
358: while (c == ' ')
359: c = getc (infile);
360: }
361:
362: p = buf;
363: while (c != ' ' && c != ')')
364: {
365: if (c == EOF)
366: return 1;
367: if (c == '\\')
368: c = getc (infile);
369: *p++ = c;
370: c = getc (infile);
371: }
372: *p = 0;
373:
374: while (c != '"')
375: {
376: if (c == EOF)
377: return 1;
378: c = getc (infile);
379: }
380: c = read_c_string (infile, 0);
381: }
382: else if (c == 'd')
383: {
384: c = getc (infile);
385: if (c != 'e')
386: continue;
387: c = getc (infile);
388: if (c != 'f')
389: continue;
390: c = getc (infile);
391: if (c == 'u')
392: {
393: c = getc (infile);
394: if (c != 'n')
395: continue;
396: defvarflag = 0;
397: }
398: else if (c == 'v')
399: {
400: c = getc (infile);
401: if (c != 'a')
402: continue;
403: c = getc (infile);
404: if (c != 'r')
405: continue;
406: defvarflag = 1;
407: }
408: else if (c == 'c')
409: {
410: c = getc (infile);
411: if (c != 'o')
412: continue;
413: c = getc (infile);
414: if (c != 'n')
415: continue;
416: c = getc (infile);
417: if (c != 's')
418: continue;
419: c = getc (infile);
420: if (c != 't')
421: continue;
422: defvarflag = 1;
423: }
424: else
425: continue;
426:
427: /* Now we have seen "defun" or "defvar" or "defconst". */
428:
429: while (c != ' ' && c != '\n' && c != '\t')
430: c = getc (infile);
431:
432: while (c == ' ' || c == '\n' || c == '\t')
433: c = getc (infile);
434:
435: /* Read and store name of function or variable being defined
436: Discard backslashes that are for quoting. */
437: p = buf;
438: while (c != ' ' && c != '\n' && c != '\t')
439: {
440: if (c == '\\')
441: c = getc (infile);
442: *p++ = c;
443: c = getc (infile);
444: }
445: *p = 0;
446:
447: while (c == ' ' || c == '\n' || c == '\t')
448: c = getc (infile);
449:
450: if (! defvarflag)
451: {
452: /* A function: */
453: /* Skip the arguments: either "nil" or a list in parens */
454: if (c == 'n')
455: {
456: while (c != ' ' && c != '\n' && c != '\t')
457: c = getc (infile);
458: }
459: else
460: {
461: while (c != '(')
462: c = getc (infile);
463: while (c != ')')
464: c = getc (infile);
465: }
466: c = getc (infile);
467: }
468: else
469: {
470: /* A variable: */
471:
472: /* Skip until the first newline; remember
473: the two previous characters. */
474: char c1 = 0, c2 = 0;
475:
476: while (c != '\n' && c >= 0)
477: {
478: c2 = c1;
479: c1 = c;
480: c = getc (infile);
481: }
482:
483: /* If two previous characters were " and \,
484: this is a doc string. Otherwise, there is none. */
485: if (c2 == '"' && c1 == '\\')
486: {
487: putc (037, outfile);
488: putc ('V', outfile);
489: fprintf (outfile, "%s\n", buf);
490: read_c_string (infile, 1);
491: }
492: continue;
493: }
494: }
495: else
496: continue;
497:
498: /* Here for a function definition.
499: We have skipped the file name or arguments
500: and arrived at where the doc string is,
501: if there is a doc string. */
502:
503: /* Skip whitespace */
504:
505: while (c == ' ' || c == '\n' || c == '\t')
506: c = getc (infile);
507:
508: /* " followed by \ and newline means a doc string we should gobble */
509: if (c != '"')
510: continue;
511: c = getc (infile);
512: if (c != '\\')
513: continue;
514: c = getc (infile);
515: if (c != '\n')
516: continue;
517:
518: putc (037, outfile);
519: putc ('F', outfile);
520: fprintf (outfile, "%s\n", buf);
521: read_c_string (infile, 1);
522: }
523: fclose (infile);
524: return 0;
525: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.