Fix typo in last change.
[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 }
d2d92f7a
JB
59 if (argc > i + 1 && !strcmp (argv[i], "-d"))
60 {
61 chdir (argv[i + 1]);
62 i += 2;
63 }
f2cc4248
RS
64
65 for (; i < argc; i++)
66 err_count += scan_file (argv[i]); /* err_count seems to be {mis,un}used */
67#ifndef VMS
68 exit (err_count); /* see below - shane */
69#endif VMS
70}
71
a8a7afbe 72/* Read file FILENAME and output its doc strings to outfile. */
f2cc4248
RS
73/* Return 1 if file is not found, 0 if it is found. */
74
75scan_file (filename)
76 char *filename;
77{
78 int len = strlen (filename);
79 if (!strcmp (filename + len - 4, ".elc"))
80 return scan_lisp_file (filename);
81 else if (!strcmp (filename + len - 3, ".el"))
82 return scan_lisp_file (filename);
83 else
84 return scan_c_file (filename);
85}
86\f
87char buf[128];
88
89/* Skip a C string from INFILE,
90 and return the character that follows the closing ".
a8a7afbe 91 If printflag is positive, output string contents to outfile.
f2cc4248
RS
92 If it is negative, store contents in buf.
93 Convert escape sequences \n and \t to newline and tab;
94 discard \ followed by newline. */
95
96read_c_string (infile, printflag)
97 FILE *infile;
98 int printflag;
99{
100 register int c;
101 char *p = buf;
102
103 c = getc (infile);
104 while (c != EOF)
105 {
106 while (c != '"' && c != EOF)
107 {
108 if (c == '\\')
109 {
110 c = getc (infile);
111 if (c == '\n')
112 {
113 c = getc (infile);
114 continue;
115 }
116 if (c == 'n')
117 c = '\n';
118 if (c == 't')
119 c = '\t';
120 }
121 if (printflag > 0)
122 putc (c, outfile);
123 else if (printflag < 0)
124 *p++ = c;
125 c = getc (infile);
126 }
127 c = getc (infile);
128 if (c != '"')
129 break;
130 if (printflag > 0)
131 putc (c, outfile);
132 else if (printflag < 0)
133 *p++ = c;
134 c = getc (infile);
135 }
136
137 if (printflag < 0)
138 *p = 0;
139
140 return c;
141}
142\f
143/* Write to file OUT the argument names of the function whose text is in BUF.
144 MINARGS and MAXARGS are the minimum and maximum number of arguments. */
145
146write_c_args (out, buf, minargs, maxargs)
147 FILE *out;
148 char *buf;
149 int minargs, maxargs;
150{
f125a9e8 151 register char *p;
30e4c427
JB
152 int in_ident = 0;
153 int just_spaced = 0;
f2cc4248 154
772e2009 155 fprintf (out, "arguments: ");
f2cc4248 156
f125a9e8 157 for (p = buf; *p; p++)
f2cc4248 158 {
30e4c427 159 char c = *p;
3941a179 160 int ident_start = 0;
30e4c427
JB
161
162 /* Notice when we start printing a new identifier. */
163 if ((('A' <= c && c <= 'Z')
164 || ('a' <= c && c <= 'z')
165 || ('0' <= c && c <= '9')
166 || c == '_')
167 != in_ident)
f2cc4248 168 {
30e4c427
JB
169 if (!in_ident)
170 {
171 in_ident = 1;
3941a179 172 ident_start = 1;
f125a9e8 173
30e4c427
JB
174 if (minargs == 0 && maxargs > 0)
175 fprintf (out, "&optional ");
176 just_spaced = 1;
f125a9e8 177
30e4c427
JB
178 minargs--;
179 maxargs--;
180 }
181 else
182 in_ident = 0;
f2cc4248 183 }
30e4c427
JB
184
185 /* Print the C argument list as it would appear in lisp:
186 print underscores as hyphens, and print commas as spaces.
187 Collapse adjacent spaces into one. */
188 if (c == '_') c = '-';
189 if (c == ',') c = ' ';
190
3941a179
JB
191 /* In C code, `default' is a reserved word, so we spell it
192 `defalt'; unmangle that here. */
193 if (ident_start
194 && strncmp (p, "defalt", 6) == 0
195 && ! (('A' <= p[6] && p[6] <= 'Z')
196 || ('a' <= p[6] && p[6] <= 'z')
197 || ('0' <= p[6] && p[6] <= '9')
198 || p[6] == '_'))
199 {
200 fprintf (out, "default");
201 p += 5;
202 in_ident = 0;
203 just_spaced = 0;
204 }
205 else if (c != ' ' || ! just_spaced)
30e4c427
JB
206 putc (c, out);
207
208 just_spaced = (c == ' ');
f2cc4248 209 }
f2cc4248
RS
210}
211\f
212/* Read through a c file. If a .o file is named,
213 the corresponding .c file is read instead.
214 Looks for DEFUN constructs such as are defined in ../src/lisp.h.
215 Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */
216
217scan_c_file (filename)
218 char *filename;
219{
220 FILE *infile;
221 register int c;
222 register int commas;
223 register int defunflag;
84128dee 224 register int defvarperbufferflag;
f2cc4248
RS
225 register int defvarflag;
226 int minargs, maxargs;
227
228 if (filename[strlen (filename) - 1] == 'o')
229 filename[strlen (filename) - 1] = 'c';
230
231 infile = fopen (filename, "r");
232
233 /* No error if non-ex input file */
234 if (infile == NULL)
235 {
236 perror (filename);
237 return 0;
238 }
239
240 c = '\n';
241 while (!feof (infile))
242 {
243 if (c != '\n')
244 {
245 c = getc (infile);
246 continue;
247 }
248 c = getc (infile);
249 if (c == ' ')
250 {
251 while (c == ' ')
252 c = getc (infile);
253 if (c != 'D')
254 continue;
255 c = getc (infile);
256 if (c != 'E')
257 continue;
258 c = getc (infile);
259 if (c != 'F')
260 continue;
261 c = getc (infile);
262 if (c != 'V')
263 continue;
84128dee
JB
264 c = getc (infile);
265 if (c != 'A')
266 continue;
267 c = getc (infile);
268 if (c != 'R')
269 continue;
270 c = getc (infile);
271 if (c != '_')
272 continue;
273
f2cc4248
RS
274 defvarflag = 1;
275 defunflag = 0;
84128dee
JB
276
277 c = getc (infile);
278 defvarperbufferflag = (c == 'P');
279
f2cc4248
RS
280 c = getc (infile);
281 }
282 else if (c == 'D')
283 {
284 c = getc (infile);
285 if (c != 'E')
286 continue;
287 c = getc (infile);
288 if (c != 'F')
289 continue;
290 c = getc (infile);
291 defunflag = c == 'U';
292 defvarflag = 0;
293 }
294 else continue;
295
296 while (c != '(')
297 {
298 if (c < 0)
299 goto eof;
300 c = getc (infile);
301 }
302
303 c = getc (infile);
304 if (c != '"')
305 continue;
306 c = read_c_string (infile, -1);
307
308 if (defunflag)
309 commas = 5;
84128dee
JB
310 else if (defvarperbufferflag)
311 commas = 2;
f2cc4248
RS
312 else if (defvarflag)
313 commas = 1;
314 else /* For DEFSIMPLE and DEFPRED */
315 commas = 2;
316
317 while (commas)
318 {
319 if (c == ',')
320 {
321 commas--;
322 if (defunflag && (commas == 1 || commas == 2))
323 {
324 do
325 c = getc (infile);
326 while (c == ' ' || c == '\n' || c == '\t');
327 if (c < 0)
328 goto eof;
329 ungetc (c, infile);
330 if (commas == 2) /* pick up minargs */
331 fscanf (infile, "%d", &minargs);
332 else /* pick up maxargs */
333 if (c == 'M' || c == 'U') /* MANY || UNEVALLED */
334 maxargs = -1;
335 else
336 fscanf (infile, "%d", &maxargs);
337 }
338 }
339 if (c < 0)
340 goto eof;
341 c = getc (infile);
342 }
343 while (c == ' ' || c == '\n' || c == '\t')
344 c = getc (infile);
345 if (c == '"')
346 c = read_c_string (infile, 0);
347 while (c != ',')
348 c = getc (infile);
349 c = getc (infile);
350 while (c == ' ' || c == '\n' || c == '\t')
351 c = getc (infile);
352
353 if (c == '"')
354 {
355 putc (037, outfile);
356 putc (defvarflag ? 'V' : 'F', outfile);
357 fprintf (outfile, "%s\n", buf);
772e2009
JB
358 c = read_c_string (infile, 1);
359
360 /* If this is a defun, find the arguments and print them. If
361 this function takes MANY or UNEVALLED args, then the C source
362 won't give the names of the arguments, so we shouldn't bother
363 trying to find them. */
364 if (defunflag && maxargs != -1)
f2cc4248
RS
365 {
366 char argbuf[1024], *p = argbuf;
367 while (c != ')')
368 {
369 if (c < 0)
370 goto eof;
371 c = getc (infile);
372 }
373 /* Skip into arguments. */
374 while (c != '(')
375 {
376 if (c < 0)
377 goto eof;
378 c = getc (infile);
379 }
380 /* Copy arguments into ARGBUF. */
381 *p++ = c;
382 do
383 *p++ = c = getc (infile);
384 while (c != ')');
385 *p = '\0';
386 /* Output them. */
387 fprintf (outfile, "\n\n");
388 write_c_args (outfile, argbuf, minargs, maxargs);
389 }
390 }
391 }
392 eof:
393 fclose (infile);
394 return 0;
395}
396\f
397/* Read a file of Lisp code, compiled or interpreted.
398 Looks for
399 (defun NAME ARGS DOCSTRING ...)
23d6b5a6
JB
400 (defmacro NAME ARGS DOCSTRING ...)
401 (autoload (quote NAME) FILE DOCSTRING ...)
f2cc4248
RS
402 (defvar NAME VALUE DOCSTRING)
403 (defconst NAME VALUE DOCSTRING)
23d6b5a6
JB
404 (fset (quote NAME) (make-byte-code ... DOCSTRING ...))
405 (fset (quote NAME) #[... DOCSTRING ...])
2d6e2619 406 (defalias (quote NAME) #[... DOCSTRING ...])
f2cc4248 407 starting in column zero.
23d6b5a6
JB
408 (quote NAME) may appear as 'NAME as well.
409 For defun, defmacro, and autoload, we know how to skip over the arglist.
410 For defvar, defconst, and fset we skip to the docstring with a klugey
411 formatting convention: all docstrings must appear on the same line as the
412 initial open-paren (the one in column zero) and must contain a backslash
413 and a double-quote immediately after the initial double-quote. No newlines
414 must appear between the beginning of the form and the first double-quote.
415 The only source file that must follow this convention is loaddefs.el; aside
416 from that, it is always the .elc file that we look at, and they are no
417 problem because byte-compiler output follows this convention.
f2cc4248
RS
418 The NAME and DOCSTRING are output.
419 NAME is preceded by `F' for a function or `V' for a variable.
420 An entry is output only if DOCSTRING has \ newline just after the opening "
421 */
422
23d6b5a6
JB
423void
424skip_white (infile)
425 FILE *infile;
426{
427 char c = ' ';
428 while (c == ' ' || c == '\t' || c == '\n')
429 c = getc (infile);
430 ungetc (c, infile);
431}
432
433void
434read_lisp_symbol (infile, buffer)
435 FILE *infile;
436 char *buffer;
437{
438 char c;
439 char *fillp = buffer;
440
441 skip_white (infile);
442 while (1)
443 {
444 c = getc (infile);
445 if (c == '\\')
446 *(++fillp) = getc (infile);
447 else if (c == ' ' || c == '\t' || c == '\n' || c == '(' || c == ')')
448 {
449 ungetc (c, infile);
450 *fillp = 0;
451 break;
452 }
453 else
454 *fillp++ = c;
455 }
456
457 if (! buffer[0])
458 fprintf (stderr, "## expected a symbol, got '%c'\n", c);
459
460 skip_white (infile);
461}
462
463
f2cc4248
RS
464scan_lisp_file (filename)
465 char *filename;
466{
467 FILE *infile;
468 register int c;
f2cc4248
RS
469
470 infile = fopen (filename, "r");
471 if (infile == NULL)
472 {
473 perror (filename);
474 return 0; /* No error */
475 }
476
477 c = '\n';
478 while (!feof (infile))
479 {
23d6b5a6
JB
480 char buffer [BUFSIZ];
481 char *fillp = buffer;
482 char type;
483
f2cc4248
RS
484 if (c != '\n')
485 {
486 c = getc (infile);
487 continue;
488 }
489 c = getc (infile);
490 if (c != '(')
491 continue;
a8a7afbe 492
23d6b5a6
JB
493 read_lisp_symbol (infile, buffer);
494
495 if (! strcmp (buffer, "defun") ||
496 ! strcmp (buffer, "defmacro"))
f2cc4248 497 {
23d6b5a6
JB
498 type = 'F';
499 read_lisp_symbol (infile, buffer);
f2cc4248 500
23d6b5a6 501 /* Skip the arguments: either "nil" or a list in parens */
f2cc4248 502
23d6b5a6
JB
503 c = getc (infile);
504 if (c == 'n') /* nil */
f2cc4248 505 {
23d6b5a6
JB
506 if ((c = getc (infile)) != 'i' ||
507 (c = getc (infile)) != 'l')
508 {
509 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
510 buffer, filename);
511 continue;
512 }
f2cc4248 513 }
23d6b5a6 514 else if (c != '(')
f2cc4248 515 {
23d6b5a6
JB
516 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
517 buffer, filename);
518 continue;
f2cc4248 519 }
23d6b5a6
JB
520 else
521 while (c != ')')
f2cc4248 522 c = getc (infile);
23d6b5a6
JB
523 skip_white (infile);
524
525 /* If the next three characters aren't `dquote bslash newline'
526 then we're not reading a docstring.
527 */
528 if ((c = getc (infile)) != '"' ||
529 (c = getc (infile)) != '\\' ||
530 (c = getc (infile)) != '\n')
f2cc4248 531 {
23d6b5a6
JB
532#ifdef DEBUG
533 fprintf (stderr, "## non-docstring in %s (%s)\n",
534 buffer, filename);
535#endif
536 continue;
f2cc4248 537 }
f2cc4248 538 }
a8a7afbe 539
23d6b5a6
JB
540 else if (! strcmp (buffer, "defvar") ||
541 ! strcmp (buffer, "defconst"))
f2cc4248 542 {
23d6b5a6
JB
543 char c1 = 0, c2 = 0;
544 type = 'V';
545 read_lisp_symbol (infile, buffer);
a8a7afbe 546
23d6b5a6
JB
547 /* Skip until the first newline; remember the two previous chars. */
548 while (c != '\n' && c >= 0)
f2cc4248 549 {
23d6b5a6
JB
550 c2 = c1;
551 c1 = c;
f2cc4248 552 c = getc (infile);
f2cc4248 553 }
23d6b5a6
JB
554
555 /* If two previous characters were " and \,
556 this is a doc string. Otherwise, there is none. */
557 if (c2 != '"' || c1 != '\\')
f2cc4248 558 {
23d6b5a6
JB
559#ifdef DEBUG
560 fprintf (stderr, "## non-docstring in %s (%s)\n",
561 buffer, filename);
562#endif
563 continue;
f2cc4248 564 }
23d6b5a6
JB
565 }
566
2d6e2619 567 else if (! strcmp (buffer, "fset") || ! strcmp (buffer, "defalias"))
23d6b5a6
JB
568 {
569 char c1 = 0, c2 = 0;
570 type = 'F';
a8a7afbe 571
23d6b5a6
JB
572 c = getc (infile);
573 if (c == '\'')
574 read_lisp_symbol (infile, buffer);
575 else
f2cc4248 576 {
23d6b5a6
JB
577 if (c != '(')
578 {
579 fprintf (stderr, "## unparsable name in fset in %s\n",
580 filename);
581 continue;
582 }
583 read_lisp_symbol (infile, buffer);
584 if (strcmp (buffer, "quote"))
585 {
586 fprintf (stderr, "## unparsable name in fset in %s\n",
587 filename);
588 continue;
589 }
590 read_lisp_symbol (infile, buffer);
f2cc4248 591 c = getc (infile);
23d6b5a6
JB
592 if (c != ')')
593 {
594 fprintf (stderr,
595 "## unparsable quoted name in fset in %s\n",
596 filename);
597 continue;
598 }
f2cc4248 599 }
f2cc4248 600
23d6b5a6
JB
601 /* Skip until the first newline; remember the two previous chars. */
602 while (c != '\n' && c >= 0)
f2cc4248 603 {
23d6b5a6
JB
604 c2 = c1;
605 c1 = c;
f2cc4248
RS
606 c = getc (infile);
607 }
23d6b5a6
JB
608
609 /* If two previous characters were " and \,
610 this is a doc string. Otherwise, there is none. */
611 if (c2 != '"' || c1 != '\\')
612 {
613#ifdef DEBUG
614 fprintf (stderr, "## non-docstring in %s (%s)\n",
615 buffer, filename);
616#endif
617 continue;
618 }
619 }
f2cc4248 620
23d6b5a6
JB
621 else if (! strcmp (buffer, "autoload"))
622 {
623 type = 'F';
624 c = getc (infile);
625 if (c == '\'')
626 read_lisp_symbol (infile, buffer);
627 else
f2cc4248 628 {
23d6b5a6 629 if (c != '(')
f2cc4248 630 {
23d6b5a6
JB
631 fprintf (stderr, "## unparsable name in autoload in %s\n",
632 filename);
633 continue;
f2cc4248 634 }
23d6b5a6
JB
635 read_lisp_symbol (infile, buffer);
636 if (strcmp (buffer, "quote"))
f2cc4248 637 {
23d6b5a6
JB
638 fprintf (stderr, "## unparsable name in autoload in %s\n",
639 filename);
640 continue;
f2cc4248 641 }
23d6b5a6 642 read_lisp_symbol (infile, buffer);
f2cc4248 643 c = getc (infile);
23d6b5a6 644 if (c != ')')
f2cc4248 645 {
23d6b5a6
JB
646 fprintf (stderr,
647 "## unparsable quoted name in autoload in %s\n",
648 filename);
649 continue;
f2cc4248 650 }
23d6b5a6
JB
651 }
652 skip_white (infile);
653 if ((c = getc (infile)) != '\"')
654 {
655 fprintf (stderr, "## autoload of %s unparsable (%s)\n",
656 buffer, filename);
f2cc4248
RS
657 continue;
658 }
23d6b5a6
JB
659 read_c_string (infile, 0);
660 skip_white (infile);
661
662 /* If the next three characters aren't `dquote bslash newline'
663 then we're not reading a docstring.
664 */
665 if ((c = getc (infile)) != '"' ||
666 (c = getc (infile)) != '\\' ||
667 (c = getc (infile)) != '\n')
a8a7afbe 668 {
23d6b5a6
JB
669#ifdef DEBUG
670 fprintf (stderr, "## non-docstring in %s (%s)\n",
671 buffer, filename);
672#endif
673 continue;
a8a7afbe 674 }
a8a7afbe 675 }
f2cc4248 676
23d6b5a6
JB
677#ifdef DEBUG
678 else if (! strcmp (buffer, "if") ||
679 ! strcmp (buffer, "byte-code"))
680 ;
681#endif
f2cc4248 682
23d6b5a6
JB
683 else
684 {
685#ifdef DEBUG
686 fprintf (stderr, "## unrecognised top-level form, %s (%s)\n",
687 buffer, filename);
688#endif
689 continue;
690 }
f2cc4248 691
23d6b5a6
JB
692 /* At this point, there is a docstring that we should gobble.
693 The opening quote (and leading backslash-newline) have already
694 been read.
695 */
696 putc ('\n', outfile);
f2cc4248 697 putc (037, outfile);
23d6b5a6
JB
698 putc (type, outfile);
699 fprintf (outfile, "%s\n", buffer);
f2cc4248
RS
700 read_c_string (infile, 1);
701 }
702 fclose (infile);
703 return 0;
704}