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