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 free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
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
main(argc,argv)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
scan_file(filename)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
read_c_string(infile,printflag)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 /* Write to file OUT the argument names of the function whose text is in BUF.
139 MINARGS and MAXARGS are the minimum and maximum number of arguments. */
140
write_c_args(out,buf,minargs,maxargs)141 write_c_args (out, buf, minargs, maxargs)
142 FILE *out;
143 char *buf;
144 int minargs, maxargs;
145 {
146 register int c;
147 register char *p = buf;
148 int space = 0;
149
150 fprintf (out, "arguments:");
151
152 while (*p)
153 {
154 c = *p++;
155 if (c == '(' && minargs == 0 && maxargs > 0)
156 {
157 fprintf (out, "(&optional ");
158 space = 1;
159 continue;
160 }
161 else if (c == ',')
162 {
163 minargs--;
164 maxargs--;
165 if (!space)
166 putc (' ', out);
167 if (minargs == 0 && maxargs > 0)
168 fprintf (out, "&optional ");
169 space = 1;
170 continue;
171 }
172 else if (c == ' ' && space)
173 continue;
174 space = (c == ' ');
175 putc (c, out);
176 }
177 putc ('\n', out);
178 }
179
180 /* Read through a c file. If a .o file is named,
181 the corresponding .c file is read instead.
182 Looks for DEFUN constructs such as are defined in ../src/lisp.h.
183 Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */
184
scan_c_file(filename)185 scan_c_file (filename)
186 char *filename;
187 {
188 FILE *infile;
189 register int c;
190 register int commas;
191 register int defunflag;
192 register int defvarflag;
193 int minargs, maxargs;
194
195 if (filename[strlen (filename) - 1] == 'o')
196 filename[strlen (filename) - 1] = 'c';
197
198 infile = fopen (filename, "r");
199
200 /* No error if non-ex input file */
201 if (infile == NULL)
202 {
203 perror (filename);
204 return 0;
205 }
206
207 c = '\n';
208 while (!feof (infile))
209 {
210 if (c != '\n')
211 {
212 c = getc (infile);
213 continue;
214 }
215 c = getc (infile);
216 if (c == ' ')
217 {
218 while (c == ' ')
219 c = getc (infile);
220 if (c != 'D')
221 continue;
222 c = getc (infile);
223 if (c != 'E')
224 continue;
225 c = getc (infile);
226 if (c != 'F')
227 continue;
228 c = getc (infile);
229 if (c != 'V')
230 continue;
231 defvarflag = 1;
232 defunflag = 0;
233 c = getc (infile);
234 }
235 else if (c == 'D')
236 {
237 c = getc (infile);
238 if (c != 'E')
239 continue;
240 c = getc (infile);
241 if (c != 'F')
242 continue;
243 c = getc (infile);
244 defunflag = c == 'U';
245 defvarflag = 0;
246 }
247 else continue;
248
249 while (c != '(')
250 {
251 if (c < 0)
252 goto eof;
253 c = getc (infile);
254 }
255
256 c = getc (infile);
257 if (c != '"')
258 continue;
259 c = read_c_string (infile, -1);
260
261 if (defunflag)
262 commas = 5;
263 else if (defvarflag)
264 commas = 1;
265 else /* For DEFSIMPLE and DEFPRED */
266 commas = 2;
267
268 while (commas)
269 {
270 if (c == ',')
271 {
272 commas--;
273 if (defunflag && (commas == 1 || commas == 2))
274 {
275 do
276 c = getc (infile);
277 while (c == ' ' || c == '\n' || c == '\t');
278 if (c < 0)
279 goto eof;
280 ungetc (c, infile);
281 if (commas == 2) /* pick up minargs */
282 fscanf (infile, "%d", &minargs);
283 else /* pick up maxargs */
284 if (c == 'M' || c == 'U') /* MANY || UNEVALLED */
285 maxargs = -1;
286 else
287 fscanf (infile, "%d", &maxargs);
288 }
289 }
290 if (c < 0)
291 goto eof;
292 c = getc (infile);
293 }
294 while (c == ' ' || c == '\n' || c == '\t')
295 c = getc (infile);
296 if (c == '"')
297 c = read_c_string (infile, 0);
298 while (c != ',')
299 c = getc (infile);
300 c = getc (infile);
301 while (c == ' ' || c == '\n' || c == '\t')
302 c = getc (infile);
303
304 if (c == '"')
305 {
306 putc (037, outfile);
307 putc (defvarflag ? 'V' : 'F', outfile);
308 fprintf (outfile, "%s\n", buf);
309 c = read_c_string (infile, 1);
310 if (defunflag)
311 {
312 char argbuf[1024], *p = argbuf;
313 while (c != ')')
314 {
315 if (c < 0)
316 goto eof;
317 c = getc (infile);
318 }
319 /* Skip into arguments. */
320 while (c != '(')
321 {
322 if (c < 0)
323 goto eof;
324 c = getc (infile);
325 }
326 /* Copy arguments into ARGBUF. */
327 *p++ = c;
328 do
329 *p++ = c = getc (infile);
330 while (c != ')');
331 *p = '\0';
332 /* Output them. */
333 fprintf (outfile, "\n\n");
334 write_c_args (outfile, argbuf, minargs, maxargs);
335 }
336 }
337 }
338 eof:
339 fclose (infile);
340 return 0;
341 }
342
343 /* Read a file of Lisp code, compiled or interpreted.
344 Looks for
345 (defun NAME ARGS DOCSTRING ...)
346 (defmacro NAME ARGS DOCSTRING ...)
347 (autoload (quote NAME) FILE DOCSTRING ...)
348 (defvar NAME VALUE DOCSTRING)
349 (defconst NAME VALUE DOCSTRING)
350 (fset (quote NAME) (make-byte-code ... DOCSTRING ...))
351 (fset (quote NAME) #[... DOCSTRING ...])
352 starting in column zero.
353 (quote NAME) may appear as 'NAME as well.
354 For defun, defmacro, and autoload, we know how to skip over the arglist.
355 For defvar, defconst, and fset we skip to the docstring with a klugey
356 formatting convention: all docstrings must appear on the same line as the
357 initial open-paren (the one in column zero) and must contain a backslash
358 and a double-quote immediately after the initial double-quote. No newlines
359 must appear between the beginning of the form and the first double-quote.
360 The only source file that must follow this convention is loaddefs.el; aside
361 from that, it is always the .elc file that we look at, and they are no
362 problem because byte-compiler output follows this convention.
363 The NAME and DOCSTRING are output.
364 NAME is preceded by `F' for a function or `V' for a variable.
365 An entry is output only if DOCSTRING has \ newline just after the opening "
366 */
367
368 void
skip_white(infile)369 skip_white (infile)
370 FILE *infile;
371 {
372 char c = ' ';
373 while (c == ' ' || c == '\t' || c == '\n')
374 c = getc (infile);
375 ungetc (c, infile);
376 }
377
378 void
read_lisp_symbol(infile,buffer)379 read_lisp_symbol (infile, buffer)
380 FILE *infile;
381 char *buffer;
382 {
383 char c;
384 char *fillp = buffer;
385
386 skip_white (infile);
387 while (1)
388 {
389 c = getc (infile);
390 if (c == '\\')
391 *(++fillp) = getc (infile);
392 else if (c == ' ' || c == '\t' || c == '\n' || c == '(' || c == ')')
393 {
394 ungetc (c, infile);
395 *fillp = 0;
396 break;
397 }
398 else
399 *fillp++ = c;
400 }
401
402 if (! buffer[0])
403 fprintf (stderr, "## expected a symbol, got '%c'\n", c);
404
405 skip_white (infile);
406 }
407
408
scan_lisp_file(filename)409 scan_lisp_file (filename)
410 char *filename;
411 {
412 FILE *infile;
413 register int c;
414
415 infile = fopen (filename, "r");
416 if (infile == NULL)
417 {
418 perror (filename);
419 return 0; /* No error */
420 }
421
422 c = '\n';
423 while (!feof (infile))
424 {
425 char buffer [BUFSIZ];
426 char *fillp = buffer;
427 char type;
428
429 if (c != '\n')
430 {
431 c = getc (infile);
432 continue;
433 }
434 c = getc (infile);
435 if (c != '(')
436 continue;
437
438 read_lisp_symbol (infile, buffer);
439
440 if (! strcmp (buffer, "defun") ||
441 ! strcmp (buffer, "defmacro"))
442 {
443 type = 'F';
444 read_lisp_symbol (infile, buffer);
445
446 /* Skip the arguments: either "nil" or a list in parens */
447
448 c = getc (infile);
449 if (c == 'n') /* nil */
450 {
451 if ((c = getc (infile)) != 'i' ||
452 (c = getc (infile)) != 'l')
453 {
454 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
455 buffer, filename);
456 continue;
457 }
458 }
459 else if (c != '(')
460 {
461 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
462 buffer, filename);
463 continue;
464 }
465 else
466 while (c != ')')
467 c = getc (infile);
468 skip_white (infile);
469
470 /* If the next three characters aren't `dquote bslash newline'
471 then we're not reading a docstring.
472 */
473 if ((c = getc (infile)) != '"' ||
474 (c = getc (infile)) != '\\' ||
475 (c = getc (infile)) != '\n')
476 {
477 #ifdef DEBUG
478 fprintf (stderr, "## non-docstring in %s (%s)\n",
479 buffer, filename);
480 #endif
481 continue;
482 }
483 }
484
485 else if (! strcmp (buffer, "defvar") ||
486 ! strcmp (buffer, "defconst"))
487 {
488 char c1 = 0, c2 = 0;
489 type = 'V';
490 read_lisp_symbol (infile, buffer);
491
492 /* Skip until the first newline; remember the two previous chars. */
493 while (c != '\n' && c >= 0)
494 {
495 c2 = c1;
496 c1 = c;
497 c = getc (infile);
498 }
499
500 /* If two previous characters were " and \,
501 this is a doc string. Otherwise, there is none. */
502 if (c2 != '"' || c1 != '\\')
503 {
504 #ifdef DEBUG
505 fprintf (stderr, "## non-docstring in %s (%s)\n",
506 buffer, filename);
507 #endif
508 continue;
509 }
510 }
511
512 else if (! strcmp (buffer, "fset"))
513 {
514 char c1 = 0, c2 = 0;
515 type = 'F';
516
517 c = getc (infile);
518 if (c == '\'')
519 read_lisp_symbol (infile, buffer);
520 else
521 {
522 if (c != '(')
523 {
524 fprintf (stderr, "## unparsable name in fset in %s\n",
525 filename);
526 continue;
527 }
528 read_lisp_symbol (infile, buffer);
529 if (strcmp (buffer, "quote"))
530 {
531 fprintf (stderr, "## unparsable name in fset in %s\n",
532 filename);
533 continue;
534 }
535 read_lisp_symbol (infile, buffer);
536 c = getc (infile);
537 if (c != ')')
538 {
539 fprintf (stderr,
540 "## unparsable quoted name in fset in %s\n",
541 filename);
542 continue;
543 }
544 }
545
546 /* Skip until the first newline; remember the two previous chars. */
547 while (c != '\n' && c >= 0)
548 {
549 c2 = c1;
550 c1 = c;
551 c = getc (infile);
552 }
553
554 /* If two previous characters were " and \,
555 this is a doc string. Otherwise, there is none. */
556 if (c2 != '"' || c1 != '\\')
557 {
558 #ifdef DEBUG
559 fprintf (stderr, "## non-docstring in %s (%s)\n",
560 buffer, filename);
561 #endif
562 continue;
563 }
564 }
565
566 else if (! strcmp (buffer, "autoload"))
567 {
568 type = 'F';
569 c = getc (infile);
570 if (c == '\'')
571 read_lisp_symbol (infile, buffer);
572 else
573 {
574 if (c != '(')
575 {
576 fprintf (stderr, "## unparsable name in autoload in %s\n",
577 filename);
578 continue;
579 }
580 read_lisp_symbol (infile, buffer);
581 if (strcmp (buffer, "quote"))
582 {
583 fprintf (stderr, "## unparsable name in autoload in %s\n",
584 filename);
585 continue;
586 }
587 read_lisp_symbol (infile, buffer);
588 c = getc (infile);
589 if (c != ')')
590 {
591 fprintf (stderr,
592 "## unparsable quoted name in autoload in %s\n",
593 filename);
594 continue;
595 }
596 }
597 skip_white (infile);
598 if ((c = getc (infile)) != '\"')
599 {
600 fprintf (stderr, "## autoload of %s unparsable (%s)\n",
601 buffer, filename);
602 continue;
603 }
604 read_c_string (infile, 0);
605 skip_white (infile);
606
607 /* If the next three characters aren't `dquote bslash newline'
608 then we're not reading a docstring.
609 */
610 if ((c = getc (infile)) != '"' ||
611 (c = getc (infile)) != '\\' ||
612 (c = getc (infile)) != '\n')
613 {
614 #ifdef DEBUG
615 fprintf (stderr, "## non-docstring in %s (%s)\n",
616 buffer, filename);
617 #endif
618 continue;
619 }
620 }
621
622 #ifdef DEBUG
623 else if (! strcmp (buffer, "if") ||
624 ! strcmp (buffer, "byte-code"))
625 ;
626 #endif
627
628 else
629 {
630 #ifdef DEBUG
631 fprintf (stderr, "## unrecognised top-level form, %s (%s)\n",
632 buffer, filename);
633 #endif
634 continue;
635 }
636
637 /* At this point, there is a docstring that we should gobble.
638 The opening quote (and leading backslash-newline) have already
639 been read.
640 */
641 putc ('\n', outfile);
642 putc (037, outfile);
643 putc (type, outfile);
644 fprintf (outfile, "%s\n", buffer);
645 read_c_string (infile, 1);
646 }
647 fclose (infile);
648 return 0;
649 }
650