(calculate-c-indent): When testing for function-start line,
[bpt/emacs.git] / lib-src / make-docfile.c
CommitLineData
f2cc4248 1/* Generate doc-string file for GNU Emacs from source files.
e065a56e 2 Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc.
f2cc4248
RS
3
4This file is part of GNU Emacs.
5
93320c23
JA
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
e065a56e 8the Free Software Foundation; either version 2, or (at your option)
93320c23
JA
9any later version.
10
f2cc4248 11GNU Emacs is distributed in the hope that it will be useful,
93320c23
JA
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
f2cc4248 15
93320c23
JA
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
f2cc4248
RS
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
36FILE *outfile;
37
38main (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
a8a7afbe 67/* Read file FILENAME and output its doc strings to outfile. */
f2cc4248
RS
68/* Return 1 if file is not found, 0 if it is found. */
69
70scan_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\f
82char buf[128];
83
84/* Skip a C string from INFILE,
85 and return the character that follows the closing ".
a8a7afbe 86 If printflag is positive, output string contents to outfile.
f2cc4248
RS
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
91read_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\f
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
141write_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
772e2009 150 fprintf (out, "arguments: ");
f2cc4248
RS
151
152 while (*p)
153 {
154 c = *p++;
155 if (c == ',')
156 {
157 minargs--;
158 maxargs--;
159 if (!space)
160 putc (' ', out);
161 if (minargs == 0 && maxargs > 0)
162 fprintf (out, "&optional ");
163 space = 1;
164 continue;
165 }
166 else if (c == ' ' && space)
167 continue;
168 space = (c == ' ');
e065a56e
JB
169
170 /* Print the C arguments as they would appear in Elisp;
171 print underscores as hyphens. */
172 if (c == '_')
f76475ad 173 putc ('-', out);
e065a56e
JB
174 else
175 putc (c, out);
f2cc4248
RS
176 }
177 putc ('\n', out);
178}
179\f
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
185scan_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);
772e2009
JB
309 c = read_c_string (infile, 1);
310
311 /* If this is a defun, find the arguments and print them. If
312 this function takes MANY or UNEVALLED args, then the C source
313 won't give the names of the arguments, so we shouldn't bother
314 trying to find them. */
315 if (defunflag && maxargs != -1)
f2cc4248
RS
316 {
317 char argbuf[1024], *p = argbuf;
318 while (c != ')')
319 {
320 if (c < 0)
321 goto eof;
322 c = getc (infile);
323 }
324 /* Skip into arguments. */
325 while (c != '(')
326 {
327 if (c < 0)
328 goto eof;
329 c = getc (infile);
330 }
331 /* Copy arguments into ARGBUF. */
332 *p++ = c;
333 do
334 *p++ = c = getc (infile);
335 while (c != ')');
336 *p = '\0';
337 /* Output them. */
338 fprintf (outfile, "\n\n");
339 write_c_args (outfile, argbuf, minargs, maxargs);
340 }
341 }
342 }
343 eof:
344 fclose (infile);
345 return 0;
346}
347\f
348/* Read a file of Lisp code, compiled or interpreted.
349 Looks for
350 (defun NAME ARGS DOCSTRING ...)
23d6b5a6
JB
351 (defmacro NAME ARGS DOCSTRING ...)
352 (autoload (quote NAME) FILE DOCSTRING ...)
f2cc4248
RS
353 (defvar NAME VALUE DOCSTRING)
354 (defconst NAME VALUE DOCSTRING)
23d6b5a6
JB
355 (fset (quote NAME) (make-byte-code ... DOCSTRING ...))
356 (fset (quote NAME) #[... DOCSTRING ...])
f2cc4248 357 starting in column zero.
23d6b5a6
JB
358 (quote NAME) may appear as 'NAME as well.
359 For defun, defmacro, and autoload, we know how to skip over the arglist.
360 For defvar, defconst, and fset we skip to the docstring with a klugey
361 formatting convention: all docstrings must appear on the same line as the
362 initial open-paren (the one in column zero) and must contain a backslash
363 and a double-quote immediately after the initial double-quote. No newlines
364 must appear between the beginning of the form and the first double-quote.
365 The only source file that must follow this convention is loaddefs.el; aside
366 from that, it is always the .elc file that we look at, and they are no
367 problem because byte-compiler output follows this convention.
f2cc4248
RS
368 The NAME and DOCSTRING are output.
369 NAME is preceded by `F' for a function or `V' for a variable.
370 An entry is output only if DOCSTRING has \ newline just after the opening "
371 */
372
23d6b5a6
JB
373void
374skip_white (infile)
375 FILE *infile;
376{
377 char c = ' ';
378 while (c == ' ' || c == '\t' || c == '\n')
379 c = getc (infile);
380 ungetc (c, infile);
381}
382
383void
384read_lisp_symbol (infile, buffer)
385 FILE *infile;
386 char *buffer;
387{
388 char c;
389 char *fillp = buffer;
390
391 skip_white (infile);
392 while (1)
393 {
394 c = getc (infile);
395 if (c == '\\')
396 *(++fillp) = getc (infile);
397 else if (c == ' ' || c == '\t' || c == '\n' || c == '(' || c == ')')
398 {
399 ungetc (c, infile);
400 *fillp = 0;
401 break;
402 }
403 else
404 *fillp++ = c;
405 }
406
407 if (! buffer[0])
408 fprintf (stderr, "## expected a symbol, got '%c'\n", c);
409
410 skip_white (infile);
411}
412
413
f2cc4248
RS
414scan_lisp_file (filename)
415 char *filename;
416{
417 FILE *infile;
418 register int c;
f2cc4248
RS
419
420 infile = fopen (filename, "r");
421 if (infile == NULL)
422 {
423 perror (filename);
424 return 0; /* No error */
425 }
426
427 c = '\n';
428 while (!feof (infile))
429 {
23d6b5a6
JB
430 char buffer [BUFSIZ];
431 char *fillp = buffer;
432 char type;
433
f2cc4248
RS
434 if (c != '\n')
435 {
436 c = getc (infile);
437 continue;
438 }
439 c = getc (infile);
440 if (c != '(')
441 continue;
a8a7afbe 442
23d6b5a6
JB
443 read_lisp_symbol (infile, buffer);
444
445 if (! strcmp (buffer, "defun") ||
446 ! strcmp (buffer, "defmacro"))
f2cc4248 447 {
23d6b5a6
JB
448 type = 'F';
449 read_lisp_symbol (infile, buffer);
f2cc4248 450
23d6b5a6 451 /* Skip the arguments: either "nil" or a list in parens */
f2cc4248 452
23d6b5a6
JB
453 c = getc (infile);
454 if (c == 'n') /* nil */
f2cc4248 455 {
23d6b5a6
JB
456 if ((c = getc (infile)) != 'i' ||
457 (c = getc (infile)) != 'l')
458 {
459 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
460 buffer, filename);
461 continue;
462 }
f2cc4248 463 }
23d6b5a6 464 else if (c != '(')
f2cc4248 465 {
23d6b5a6
JB
466 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
467 buffer, filename);
468 continue;
f2cc4248 469 }
23d6b5a6
JB
470 else
471 while (c != ')')
f2cc4248 472 c = getc (infile);
23d6b5a6
JB
473 skip_white (infile);
474
475 /* If the next three characters aren't `dquote bslash newline'
476 then we're not reading a docstring.
477 */
478 if ((c = getc (infile)) != '"' ||
479 (c = getc (infile)) != '\\' ||
480 (c = getc (infile)) != '\n')
f2cc4248 481 {
23d6b5a6
JB
482#ifdef DEBUG
483 fprintf (stderr, "## non-docstring in %s (%s)\n",
484 buffer, filename);
485#endif
486 continue;
f2cc4248 487 }
f2cc4248 488 }
a8a7afbe 489
23d6b5a6
JB
490 else if (! strcmp (buffer, "defvar") ||
491 ! strcmp (buffer, "defconst"))
f2cc4248 492 {
23d6b5a6
JB
493 char c1 = 0, c2 = 0;
494 type = 'V';
495 read_lisp_symbol (infile, buffer);
a8a7afbe 496
23d6b5a6
JB
497 /* Skip until the first newline; remember the two previous chars. */
498 while (c != '\n' && c >= 0)
f2cc4248 499 {
23d6b5a6
JB
500 c2 = c1;
501 c1 = c;
f2cc4248 502 c = getc (infile);
f2cc4248 503 }
23d6b5a6
JB
504
505 /* If two previous characters were " and \,
506 this is a doc string. Otherwise, there is none. */
507 if (c2 != '"' || c1 != '\\')
f2cc4248 508 {
23d6b5a6
JB
509#ifdef DEBUG
510 fprintf (stderr, "## non-docstring in %s (%s)\n",
511 buffer, filename);
512#endif
513 continue;
f2cc4248 514 }
23d6b5a6
JB
515 }
516
517 else if (! strcmp (buffer, "fset"))
518 {
519 char c1 = 0, c2 = 0;
520 type = 'F';
a8a7afbe 521
23d6b5a6
JB
522 c = getc (infile);
523 if (c == '\'')
524 read_lisp_symbol (infile, buffer);
525 else
f2cc4248 526 {
23d6b5a6
JB
527 if (c != '(')
528 {
529 fprintf (stderr, "## unparsable name in fset in %s\n",
530 filename);
531 continue;
532 }
533 read_lisp_symbol (infile, buffer);
534 if (strcmp (buffer, "quote"))
535 {
536 fprintf (stderr, "## unparsable name in fset in %s\n",
537 filename);
538 continue;
539 }
540 read_lisp_symbol (infile, buffer);
f2cc4248 541 c = getc (infile);
23d6b5a6
JB
542 if (c != ')')
543 {
544 fprintf (stderr,
545 "## unparsable quoted name in fset in %s\n",
546 filename);
547 continue;
548 }
f2cc4248 549 }
f2cc4248 550
23d6b5a6
JB
551 /* Skip until the first newline; remember the two previous chars. */
552 while (c != '\n' && c >= 0)
f2cc4248 553 {
23d6b5a6
JB
554 c2 = c1;
555 c1 = c;
f2cc4248
RS
556 c = getc (infile);
557 }
23d6b5a6
JB
558
559 /* If two previous characters were " and \,
560 this is a doc string. Otherwise, there is none. */
561 if (c2 != '"' || c1 != '\\')
562 {
563#ifdef DEBUG
564 fprintf (stderr, "## non-docstring in %s (%s)\n",
565 buffer, filename);
566#endif
567 continue;
568 }
569 }
f2cc4248 570
23d6b5a6
JB
571 else if (! strcmp (buffer, "autoload"))
572 {
573 type = 'F';
574 c = getc (infile);
575 if (c == '\'')
576 read_lisp_symbol (infile, buffer);
577 else
f2cc4248 578 {
23d6b5a6 579 if (c != '(')
f2cc4248 580 {
23d6b5a6
JB
581 fprintf (stderr, "## unparsable name in autoload in %s\n",
582 filename);
583 continue;
f2cc4248 584 }
23d6b5a6
JB
585 read_lisp_symbol (infile, buffer);
586 if (strcmp (buffer, "quote"))
f2cc4248 587 {
23d6b5a6
JB
588 fprintf (stderr, "## unparsable name in autoload in %s\n",
589 filename);
590 continue;
f2cc4248 591 }
23d6b5a6 592 read_lisp_symbol (infile, buffer);
f2cc4248 593 c = getc (infile);
23d6b5a6 594 if (c != ')')
f2cc4248 595 {
23d6b5a6
JB
596 fprintf (stderr,
597 "## unparsable quoted name in autoload in %s\n",
598 filename);
599 continue;
f2cc4248 600 }
23d6b5a6
JB
601 }
602 skip_white (infile);
603 if ((c = getc (infile)) != '\"')
604 {
605 fprintf (stderr, "## autoload of %s unparsable (%s)\n",
606 buffer, filename);
f2cc4248
RS
607 continue;
608 }
23d6b5a6
JB
609 read_c_string (infile, 0);
610 skip_white (infile);
611
612 /* If the next three characters aren't `dquote bslash newline'
613 then we're not reading a docstring.
614 */
615 if ((c = getc (infile)) != '"' ||
616 (c = getc (infile)) != '\\' ||
617 (c = getc (infile)) != '\n')
a8a7afbe 618 {
23d6b5a6
JB
619#ifdef DEBUG
620 fprintf (stderr, "## non-docstring in %s (%s)\n",
621 buffer, filename);
622#endif
623 continue;
a8a7afbe 624 }
a8a7afbe 625 }
f2cc4248 626
23d6b5a6
JB
627#ifdef DEBUG
628 else if (! strcmp (buffer, "if") ||
629 ! strcmp (buffer, "byte-code"))
630 ;
631#endif
f2cc4248 632
23d6b5a6
JB
633 else
634 {
635#ifdef DEBUG
636 fprintf (stderr, "## unrecognised top-level form, %s (%s)\n",
637 buffer, filename);
638#endif
639 continue;
640 }
f2cc4248 641
23d6b5a6
JB
642 /* At this point, there is a docstring that we should gobble.
643 The opening quote (and leading backslash-newline) have already
644 been read.
645 */
646 putc ('\n', outfile);
f2cc4248 647 putc (037, outfile);
23d6b5a6
JB
648 putc (type, outfile);
649 fprintf (outfile, "%s\n", buffer);
f2cc4248
RS
650 read_c_string (infile, 1);
651 }
652 fclose (infile);
653 return 0;
654}