Mercurial > emacs
comparison lib-src/make-docfile.c @ 24:2354a499c504
Initial revision
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Mon, 08 May 1989 21:10:27 +0000 |
parents | |
children | 056b931d312b |
comparison
equal
deleted
inserted
replaced
23:b437d0778a66 | 24:2354a499c504 |
---|---|
1 /* Generate doc-string file for GNU Emacs from source files. | |
2 Copyright (C) 1985, 1986 Free Software Foundation, Inc. | |
3 | |
4 This file is part of GNU Emacs. | |
5 | |
6 GNU Emacs is distributed in the hope that it will be useful, | |
7 but without any warranty. No author or distributor | |
8 accepts responsibility to anyone for the consequences of using it | |
9 or for whether it serves any particular purpose or works at all, | |
10 unless he says so in writing. | |
11 | |
12 Everyone is granted permission to copy, modify and redistribute | |
13 GNU Emacs, but only under the conditions described in the | |
14 document "GNU Emacs copying permission notice". An exact copy | |
15 of the document is supposed to have been given to you along with | |
16 GNU Emacs so that you can know how you may redistribute it all. | |
17 It should be in a file named COPYING. Among other things, the | |
18 copyright 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 | |
36 FILE *outfile; | |
37 | |
38 main (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 | |
70 scan_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 | |
82 char 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 | |
91 read_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 | |
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 | |
141 write_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 | |
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 | |
179 scan_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 | |
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 | |
359 scan_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 } |