Eliminate some -Wall warnings.
[bpt/emacs.git] / lib-src / make-docfile.c
1 /* Generate doc-string file for GNU Emacs from source files.
2 Copyright (C) 1985, 1986, 1992, 1993, 1994 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 2, 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 #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 */
46
47 int scan_file ();
48 int scan_lisp_file ();
49 int scan_c_file ();
50
51 FILE *outfile;
52
53 int
54 main (argc, argv)
55 int argc;
56 char **argv;
57 {
58 int i;
59 int err_count = 0;
60
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 */
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 }
80 if (argc > i + 1 && !strcmp (argv[i], "-d"))
81 {
82 chdir (argv[i + 1]);
83 i += 2;
84 }
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 */
90 #endif /* VMS */
91 return err_count;
92 }
93
94 /* Read file FILENAME and output its doc strings to outfile. */
95 /* Return 1 if file is not found, 0 if it is found. */
96
97 int
98 scan_file (filename)
99 char *filename;
100 {
101 int len = strlen (filename);
102 if (!strcmp (filename + len - 4, ".elc"))
103 return scan_lisp_file (filename, READ_BINARY);
104 else if (!strcmp (filename + len - 3, ".el"))
105 return scan_lisp_file (filename, READ_TEXT);
106 else
107 return scan_c_file (filename, READ_TEXT);
108 }
109 \f
110 char buf[128];
111
112 /* Skip a C string from INFILE,
113 and return the character that follows the closing ".
114 If printflag is positive, output string contents to outfile.
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
119 int
120 read_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;
154 /* If we had a "", concatenate the two strings. */
155 c = getc (infile);
156 }
157
158 if (printflag < 0)
159 *p = 0;
160
161 return c;
162 }
163 \f
164 /* Write to file OUT the argument names of function FUNC, whose text is in BUF.
165 MINARGS and MAXARGS are the minimum and maximum number of arguments. */
166
167 void
168 write_c_args (out, func, buf, minargs, maxargs)
169 FILE *out;
170 char *func, *buf;
171 int minargs, maxargs;
172 {
173 register char *p;
174 int in_ident = 0;
175 int just_spaced = 0;
176 int need_space = 1;
177
178 fprintf (out, "(%s", func);
179
180 if (*buf == '(')
181 ++buf;
182
183 for (p = buf; *p; p++)
184 {
185 char c = *p;
186 int ident_start = 0;
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)
194 {
195 if (!in_ident)
196 {
197 in_ident = 1;
198 ident_start = 1;
199
200 if (need_space)
201 putc (' ', out);
202
203 if (minargs == 0 && maxargs > 0)
204 fprintf (out, "&optional ");
205 just_spaced = 1;
206
207 minargs--;
208 maxargs--;
209 }
210 else
211 in_ident = 0;
212 }
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
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 {
229 fprintf (out, "DEFAULT");
230 p += 5;
231 in_ident = 0;
232 just_spaced = 0;
233 }
234 else if (c != ' ' || ! just_spaced)
235 {
236 if (c >= 'a' && c <= 'z')
237 /* Upcase the letter. */
238 c += 'A' - 'a';
239 putc (c, out);
240 }
241
242 just_spaced = (c == ' ');
243 need_space = 0;
244 }
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
252 int
253 scan_c_file (filename, mode)
254 char *filename, *mode;
255 {
256 FILE *infile;
257 register int c;
258 register int commas;
259 register int defunflag;
260 register int defvarperbufferflag;
261 register int defvarflag;
262 int minargs, maxargs;
263
264 if (filename[strlen (filename) - 1] == 'o')
265 filename[strlen (filename) - 1] = 'c';
266
267 infile = fopen (filename, mode);
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;
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
310 defvarflag = 1;
311 defunflag = 0;
312
313 c = getc (infile);
314 defvarperbufferflag = (c == 'P');
315
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;
346 else if (defvarperbufferflag)
347 commas = 2;
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);
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)
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");
424 write_c_args (outfile, buf, argbuf, minargs, maxargs);
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 ...)
436 (defmacro NAME ARGS DOCSTRING ...)
437 (autoload (quote NAME) FILE DOCSTRING ...)
438 (defvar NAME VALUE DOCSTRING)
439 (defconst NAME VALUE DOCSTRING)
440 (fset (quote NAME) (make-byte-code ... DOCSTRING ...))
441 (fset (quote NAME) #[... DOCSTRING ...])
442 (defalias (quote NAME) #[... DOCSTRING ...])
443 starting in column zero.
444 (quote NAME) may appear as 'NAME as well.
445 For defun, defmacro, and autoload, we know how to skip over the arglist.
446 For defvar, defconst, and fset we skip to the docstring with a kludgy
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.
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
459 void
460 skip_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
469 void
470 read_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
499 int
500 scan_lisp_file (filename, mode)
501 char *filename, *mode;
502 {
503 FILE *infile;
504 register int c;
505
506 infile = fopen (filename, mode);
507 if (infile == NULL)
508 {
509 perror (filename);
510 return 0; /* No error */
511 }
512
513 c = '\n';
514 while (!feof (infile))
515 {
516 char buffer [BUFSIZ];
517 char type;
518
519 if (c != '\n')
520 {
521 c = getc (infile);
522 continue;
523 }
524 c = getc (infile);
525 if (c != '(')
526 continue;
527
528 read_lisp_symbol (infile, buffer);
529
530 if (! strcmp (buffer, "defun") ||
531 ! strcmp (buffer, "defmacro"))
532 {
533 type = 'F';
534 read_lisp_symbol (infile, buffer);
535
536 /* Skip the arguments: either "nil" or a list in parens */
537
538 c = getc (infile);
539 if (c == 'n') /* nil */
540 {
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 }
548 }
549 else if (c != '(')
550 {
551 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
552 buffer, filename);
553 continue;
554 }
555 else
556 while (c != ')')
557 c = getc (infile);
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')
566 {
567 #ifdef DEBUG
568 fprintf (stderr, "## non-docstring in %s (%s)\n",
569 buffer, filename);
570 #endif
571 continue;
572 }
573 }
574
575 else if (! strcmp (buffer, "defvar") ||
576 ! strcmp (buffer, "defconst"))
577 {
578 char c1 = 0, c2 = 0;
579 type = 'V';
580 read_lisp_symbol (infile, buffer);
581
582 /* Skip until the first newline; remember the two previous chars. */
583 while (c != '\n' && c >= 0)
584 {
585 c2 = c1;
586 c1 = c;
587 c = getc (infile);
588 }
589
590 /* If two previous characters were " and \,
591 this is a doc string. Otherwise, there is none. */
592 if (c2 != '"' || c1 != '\\')
593 {
594 #ifdef DEBUG
595 fprintf (stderr, "## non-docstring in %s (%s)\n",
596 buffer, filename);
597 #endif
598 continue;
599 }
600 }
601
602 else if (! strcmp (buffer, "fset") || ! strcmp (buffer, "defalias"))
603 {
604 char c1 = 0, c2 = 0;
605 type = 'F';
606
607 c = getc (infile);
608 if (c == '\'')
609 read_lisp_symbol (infile, buffer);
610 else
611 {
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);
626 c = getc (infile);
627 if (c != ')')
628 {
629 fprintf (stderr,
630 "## unparsable quoted name in fset in %s\n",
631 filename);
632 continue;
633 }
634 }
635
636 /* Skip until the first newline; remember the two previous chars. */
637 while (c != '\n' && c >= 0)
638 {
639 c2 = c1;
640 c1 = c;
641 c = getc (infile);
642 }
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 }
655
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
663 {
664 if (c != '(')
665 {
666 fprintf (stderr, "## unparsable name in autoload in %s\n",
667 filename);
668 continue;
669 }
670 read_lisp_symbol (infile, buffer);
671 if (strcmp (buffer, "quote"))
672 {
673 fprintf (stderr, "## unparsable name in autoload in %s\n",
674 filename);
675 continue;
676 }
677 read_lisp_symbol (infile, buffer);
678 c = getc (infile);
679 if (c != ')')
680 {
681 fprintf (stderr,
682 "## unparsable quoted name in autoload in %s\n",
683 filename);
684 continue;
685 }
686 }
687 skip_white (infile);
688 if ((c = getc (infile)) != '\"')
689 {
690 fprintf (stderr, "## autoload of %s unparsable (%s)\n",
691 buffer, filename);
692 continue;
693 }
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')
703 {
704 #ifdef DEBUG
705 fprintf (stderr, "## non-docstring in %s (%s)\n",
706 buffer, filename);
707 #endif
708 continue;
709 }
710 }
711
712 #ifdef DEBUG
713 else if (! strcmp (buffer, "if") ||
714 ! strcmp (buffer, "byte-code"))
715 ;
716 #endif
717
718 else
719 {
720 #ifdef DEBUG
721 fprintf (stderr, "## unrecognised top-level form, %s (%s)\n",
722 buffer, filename);
723 #endif
724 continue;
725 }
726
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 */
731 putc (037, outfile);
732 putc (type, outfile);
733 fprintf (outfile, "%s\n", buffer);
734 read_c_string (infile, 1);
735 }
736 fclose (infile);
737 return 0;
738 }