entered into RCS
[bpt/emacs.git] / lib-src / make-docfile.c
CommitLineData
f2cc4248
RS
1/* Generate doc-string file for GNU Emacs from source files.
2 Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is distributed in the hope that it will be useful,
7but without any warranty. No author or distributor
8accepts responsibility to anyone for the consequences of using it
9or for whether it serves any particular purpose or works at all,
10unless he says so in writing.
11
12Everyone is granted permission to copy, modify and redistribute
13GNU Emacs, but only under the conditions described in the
14document "GNU Emacs copying permission notice". An exact copy
15of the document is supposed to have been given to you along with
16GNU Emacs so that you can know how you may redistribute it all.
17It should be in a file named COPYING. Among other things, the
18copyright notice and this notice must be preserved on all copies. */
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
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
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 ".
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
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
150 fprintf (out, "arguments:");
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 == ' ');
169 putc (c, out);
170 }
171 putc ('\n', out);
172}
173\f
174/* Read through a c file. If a .o file is named,
175 the corresponding .c file is read instead.
176 Looks for DEFUN constructs such as are defined in ../src/lisp.h.
177 Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */
178
179scan_c_file (filename)
180 char *filename;
181{
182 FILE *infile;
183 register int c;
184 register int commas;
185 register int defunflag;
186 register int defvarflag;
187 int minargs, maxargs;
188
189 if (filename[strlen (filename) - 1] == 'o')
190 filename[strlen (filename) - 1] = 'c';
191
192 infile = fopen (filename, "r");
193
194 /* No error if non-ex input file */
195 if (infile == NULL)
196 {
197 perror (filename);
198 return 0;
199 }
200
201 c = '\n';
202 while (!feof (infile))
203 {
204 if (c != '\n')
205 {
206 c = getc (infile);
207 continue;
208 }
209 c = getc (infile);
210 if (c == ' ')
211 {
212 while (c == ' ')
213 c = getc (infile);
214 if (c != 'D')
215 continue;
216 c = getc (infile);
217 if (c != 'E')
218 continue;
219 c = getc (infile);
220 if (c != 'F')
221 continue;
222 c = getc (infile);
223 if (c != 'V')
224 continue;
225 defvarflag = 1;
226 defunflag = 0;
227 c = getc (infile);
228 }
229 else if (c == 'D')
230 {
231 c = getc (infile);
232 if (c != 'E')
233 continue;
234 c = getc (infile);
235 if (c != 'F')
236 continue;
237 c = getc (infile);
238 defunflag = c == 'U';
239 defvarflag = 0;
240 }
241 else continue;
242
243 while (c != '(')
244 {
245 if (c < 0)
246 goto eof;
247 c = getc (infile);
248 }
249
250 c = getc (infile);
251 if (c != '"')
252 continue;
253 c = read_c_string (infile, -1);
254
255 if (defunflag)
256 commas = 5;
257 else if (defvarflag)
258 commas = 1;
259 else /* For DEFSIMPLE and DEFPRED */
260 commas = 2;
261
262 while (commas)
263 {
264 if (c == ',')
265 {
266 commas--;
267 if (defunflag && (commas == 1 || commas == 2))
268 {
269 do
270 c = getc (infile);
271 while (c == ' ' || c == '\n' || c == '\t');
272 if (c < 0)
273 goto eof;
274 ungetc (c, infile);
275 if (commas == 2) /* pick up minargs */
276 fscanf (infile, "%d", &minargs);
277 else /* pick up maxargs */
278 if (c == 'M' || c == 'U') /* MANY || UNEVALLED */
279 maxargs = -1;
280 else
281 fscanf (infile, "%d", &maxargs);
282 }
283 }
284 if (c < 0)
285 goto eof;
286 c = getc (infile);
287 }
288 while (c == ' ' || c == '\n' || c == '\t')
289 c = getc (infile);
290 if (c == '"')
291 c = read_c_string (infile, 0);
292 while (c != ',')
293 c = getc (infile);
294 c = getc (infile);
295 while (c == ' ' || c == '\n' || c == '\t')
296 c = getc (infile);
297
298 if (c == '"')
299 {
300 putc (037, outfile);
301 putc (defvarflag ? 'V' : 'F', outfile);
302 fprintf (outfile, "%s\n", buf);
303 read_c_string (infile, 1);
304 if (defunflag)
305 {
306 char argbuf[1024], *p = argbuf;
307 while (c != ')')
308 {
309 if (c < 0)
310 goto eof;
311 c = getc (infile);
312 }
313 /* Skip into arguments. */
314 while (c != '(')
315 {
316 if (c < 0)
317 goto eof;
318 c = getc (infile);
319 }
320 /* Copy arguments into ARGBUF. */
321 *p++ = c;
322 do
323 *p++ = c = getc (infile);
324 while (c != ')');
325 *p = '\0';
326 /* Output them. */
327 fprintf (outfile, "\n\n");
328 write_c_args (outfile, argbuf, minargs, maxargs);
329 }
330 }
331 }
332 eof:
333 fclose (infile);
334 return 0;
335}
336\f
337/* Read a file of Lisp code, compiled or interpreted.
338 Looks for
339 (defun NAME ARGS DOCSTRING ...)
340 (autoload 'NAME FILE DOCSTRING ...)
341 (defvar NAME VALUE DOCSTRING)
342 (defconst NAME VALUE DOCSTRING)
343 starting in column zero.
344 ARGS, FILE or VALUE is ignored. We do not know how to parse Lisp code
345 so we use a kludge to skip them:
346 In a function definition, the form of ARGS of FILE is known, and we
347 can skip it.
348 In a variable definition, we use a formatting convention:
349 the DOCSTRING, if present, must be followed by a closeparen and a newline,
350 and no newline must appear between the defvar or defconst and the docstring,
351 The only source file that must follow this convention is loaddefs.el;
352 aside from that, it is always the .elc file that we look at, and
353 they are no problem because byte-compiler output follows this convention.
354 The NAME and DOCSTRING are output.
355 NAME is preceded by `F' for a function or `V' for a variable.
356 An entry is output only if DOCSTRING has \ newline just after the opening "
357 */
358
359scan_lisp_file (filename)
360 char *filename;
361{
362 FILE *infile;
363 register int c;
364 register int commas;
365 register char *p;
366 int defvarflag;
367
368 infile = fopen (filename, "r");
369 if (infile == NULL)
370 {
371 perror (filename);
372 return 0; /* No error */
373 }
374
375 c = '\n';
376 while (!feof (infile))
377 {
378 if (c != '\n')
379 {
380 c = getc (infile);
381 continue;
382 }
383 c = getc (infile);
384 if (c != '(')
385 continue;
386 c = getc (infile);
387 if (c == 'a')
388 {
389 c = getc (infile);
390 if (c != 'u')
391 continue;
392 c = getc (infile);
393 if (c != 't')
394 continue;
395 c = getc (infile);
396 if (c != 'o')
397 continue;
398 c = getc (infile);
399 if (c != 'l')
400 continue;
401 c = getc (infile);
402 if (c != 'o')
403 continue;
404 c = getc (infile);
405 if (c != 'a')
406 continue;
407 c = getc (infile);
408 if (c != 'd')
409 continue;
410
411 c = getc (infile);
412 while (c == ' ')
413 c = getc (infile);
414
415 if (c == '\'')
416 {
417 c = getc (infile);
418 }
419 else
420 {
421 if (c != '(')
422 continue;
423 c = getc (infile);
424 if (c != 'q')
425 continue;
426 c = getc (infile);
427 if (c != 'u')
428 continue;
429 c = getc (infile);
430 if (c != 'o')
431 continue;
432 c = getc (infile);
433 if (c != 't')
434 continue;
435 c = getc (infile);
436 if (c != 'e')
437 continue;
438 c = getc (infile);
439 if (c != ' ')
440 continue;
441 while (c == ' ')
442 c = getc (infile);
443 }
444
445 p = buf;
446 while (c != ' ' && c != ')')
447 {
448 if (c == EOF)
449 return 1;
450 if (c == '\\')
451 c = getc (infile);
452 *p++ = c;
453 c = getc (infile);
454 }
455 *p = 0;
456
457 while (c != '"')
458 {
459 if (c == EOF)
460 return 1;
461 c = getc (infile);
462 }
463 c = read_c_string (infile, 0);
464 }
465 else if (c == 'd')
466 {
467 c = getc (infile);
468 if (c != 'e')
469 continue;
470 c = getc (infile);
471 if (c != 'f')
472 continue;
473 c = getc (infile);
474 if (c == 'u')
475 {
476 c = getc (infile);
477 if (c != 'n')
478 continue;
479 defvarflag = 0;
480 }
481 else if (c == 'v')
482 {
483 c = getc (infile);
484 if (c != 'a')
485 continue;
486 c = getc (infile);
487 if (c != 'r')
488 continue;
489 defvarflag = 1;
490 }
491 else if (c == 'c')
492 {
493 c = getc (infile);
494 if (c != 'o')
495 continue;
496 c = getc (infile);
497 if (c != 'n')
498 continue;
499 c = getc (infile);
500 if (c != 's')
501 continue;
502 c = getc (infile);
503 if (c != 't')
504 continue;
505 defvarflag = 1;
506 }
507 else
508 continue;
509
510 /* Now we have seen "defun" or "defvar" or "defconst". */
511
512 while (c != ' ' && c != '\n' && c != '\t')
513 c = getc (infile);
514
515 while (c == ' ' || c == '\n' || c == '\t')
516 c = getc (infile);
517
518 /* Read and store name of function or variable being defined
519 Discard backslashes that are for quoting. */
520 p = buf;
521 while (c != ' ' && c != '\n' && c != '\t')
522 {
523 if (c == '\\')
524 c = getc (infile);
525 *p++ = c;
526 c = getc (infile);
527 }
528 *p = 0;
529
530 while (c == ' ' || c == '\n' || c == '\t')
531 c = getc (infile);
532
533 if (! defvarflag)
534 {
535 /* A function: */
536 /* Skip the arguments: either "nil" or a list in parens */
537 if (c == 'n')
538 {
539 while (c != ' ' && c != '\n' && c != '\t')
540 c = getc (infile);
541 }
542 else
543 {
544 while (c != '(')
545 c = getc (infile);
546 while (c != ')')
547 c = getc (infile);
548 }
549 c = getc (infile);
550 }
551 else
552 {
553 /* A variable: */
554
555 /* Skip until the first newline; remember
556 the two previous characters. */
557 char c1 = 0, c2 = 0;
558
559 while (c != '\n' && c >= 0)
560 {
561 c2 = c1;
562 c1 = c;
563 c = getc (infile);
564 }
565
566 /* If two previous characters were " and \,
567 this is a doc string. Otherwise, there is none. */
568 if (c2 == '"' && c1 == '\\')
569 {
570 putc (037, outfile);
571 putc ('V', outfile);
572 fprintf (outfile, "%s\n", buf);
573 read_c_string (infile, 1);
574 }
575 continue;
576 }
577 }
578 else
579 continue;
580
581 /* Here for a function definition.
582 We have skipped the file name or arguments
583 and arrived at where the doc string is,
584 if there is a doc string. */
585
586 /* Skip whitespace */
587
588 while (c == ' ' || c == '\n' || c == '\t')
589 c = getc (infile);
590
591 /* " followed by \ and newline means a doc string we should gobble */
592 if (c != '"')
593 continue;
594 c = getc (infile);
595 if (c != '\\')
596 continue;
597 c = getc (infile);
598 if (c != '\n')
599 continue;
600
601 putc (037, outfile);
602 putc ('F', outfile);
603 fprintf (outfile, "%s\n", buf);
604 read_c_string (infile, 1);
605 }
606 fclose (infile);
607 return 0;
608}