Commit | Line | Data |
---|---|---|
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 | |
4 | This file is part of GNU Emacs. | |
5 | ||
93320c23 JA |
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 | |
e065a56e | 8 | the Free Software Foundation; either version 2, or (at your option) |
93320c23 JA |
9 | any later version. |
10 | ||
f2cc4248 | 11 | GNU Emacs is distributed in the hope that it will be useful, |
93320c23 JA |
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. | |
f2cc4248 | 15 | |
93320c23 JA |
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. */ | |
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 | ||
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 | ||
a8a7afbe | 67 | /* Read file FILENAME and output its doc strings to outfile. */ |
f2cc4248 RS |
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 | \f | |
82 | char buf[128]; | |
83 | ||
84 | /* Skip a C string from INFILE, | |
85 | and return the character that follows the closing ". | |
a8a7afbe | 86 | If printflag is positive, output string contents to outfile. |
f2cc4248 RS |
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 | \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 | ||
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 | ||
772e2009 | 150 | fprintf (out, "arguments: "); |
f2cc4248 RS |
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 == ' '); | |
e065a56e JB |
169 | |
170 | /* Print the C arguments as they would appear in Elisp; | |
171 | print underscores as hyphens. */ | |
172 | if (c == '_') | |
173 | putc ('-'); | |
174 | else | |
175 | putc (c, out); | |
f2cc4248 RS |
176 | } |
177 | putc ('\n', out); | |
178 | } | |
179 | \f | |
180 | /* Read through a c file. If a .o file is named, | |
181 | the corresponding .c file is read instead. | |
182 | Looks for DEFUN constructs such as are defined in ../src/lisp.h. | |
183 | Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */ | |
184 | ||
185 | scan_c_file (filename) | |
186 | char *filename; | |
187 | { | |
188 | FILE *infile; | |
189 | register int c; | |
190 | register int commas; | |
191 | register int defunflag; | |
192 | register int defvarflag; | |
193 | int minargs, maxargs; | |
194 | ||
195 | if (filename[strlen (filename) - 1] == 'o') | |
196 | filename[strlen (filename) - 1] = 'c'; | |
197 | ||
198 | infile = fopen (filename, "r"); | |
199 | ||
200 | /* No error if non-ex input file */ | |
201 | if (infile == NULL) | |
202 | { | |
203 | perror (filename); | |
204 | return 0; | |
205 | } | |
206 | ||
207 | c = '\n'; | |
208 | while (!feof (infile)) | |
209 | { | |
210 | if (c != '\n') | |
211 | { | |
212 | c = getc (infile); | |
213 | continue; | |
214 | } | |
215 | c = getc (infile); | |
216 | if (c == ' ') | |
217 | { | |
218 | while (c == ' ') | |
219 | c = getc (infile); | |
220 | if (c != 'D') | |
221 | continue; | |
222 | c = getc (infile); | |
223 | if (c != 'E') | |
224 | continue; | |
225 | c = getc (infile); | |
226 | if (c != 'F') | |
227 | continue; | |
228 | c = getc (infile); | |
229 | if (c != 'V') | |
230 | continue; | |
231 | defvarflag = 1; | |
232 | defunflag = 0; | |
233 | c = getc (infile); | |
234 | } | |
235 | else if (c == 'D') | |
236 | { | |
237 | c = getc (infile); | |
238 | if (c != 'E') | |
239 | continue; | |
240 | c = getc (infile); | |
241 | if (c != 'F') | |
242 | continue; | |
243 | c = getc (infile); | |
244 | defunflag = c == 'U'; | |
245 | defvarflag = 0; | |
246 | } | |
247 | else continue; | |
248 | ||
249 | while (c != '(') | |
250 | { | |
251 | if (c < 0) | |
252 | goto eof; | |
253 | c = getc (infile); | |
254 | } | |
255 | ||
256 | c = getc (infile); | |
257 | if (c != '"') | |
258 | continue; | |
259 | c = read_c_string (infile, -1); | |
260 | ||
261 | if (defunflag) | |
262 | commas = 5; | |
263 | else if (defvarflag) | |
264 | commas = 1; | |
265 | else /* For DEFSIMPLE and DEFPRED */ | |
266 | commas = 2; | |
267 | ||
268 | while (commas) | |
269 | { | |
270 | if (c == ',') | |
271 | { | |
272 | commas--; | |
273 | if (defunflag && (commas == 1 || commas == 2)) | |
274 | { | |
275 | do | |
276 | c = getc (infile); | |
277 | while (c == ' ' || c == '\n' || c == '\t'); | |
278 | if (c < 0) | |
279 | goto eof; | |
280 | ungetc (c, infile); | |
281 | if (commas == 2) /* pick up minargs */ | |
282 | fscanf (infile, "%d", &minargs); | |
283 | else /* pick up maxargs */ | |
284 | if (c == 'M' || c == 'U') /* MANY || UNEVALLED */ | |
285 | maxargs = -1; | |
286 | else | |
287 | fscanf (infile, "%d", &maxargs); | |
288 | } | |
289 | } | |
290 | if (c < 0) | |
291 | goto eof; | |
292 | c = getc (infile); | |
293 | } | |
294 | while (c == ' ' || c == '\n' || c == '\t') | |
295 | c = getc (infile); | |
296 | if (c == '"') | |
297 | c = read_c_string (infile, 0); | |
298 | while (c != ',') | |
299 | c = getc (infile); | |
300 | c = getc (infile); | |
301 | while (c == ' ' || c == '\n' || c == '\t') | |
302 | c = getc (infile); | |
303 | ||
304 | if (c == '"') | |
305 | { | |
306 | putc (037, outfile); | |
307 | putc (defvarflag ? 'V' : 'F', outfile); | |
308 | fprintf (outfile, "%s\n", buf); | |
772e2009 JB |
309 | c = read_c_string (infile, 1); |
310 | ||
311 | /* If this is a defun, find the arguments and print them. If | |
312 | this function takes MANY or UNEVALLED args, then the C source | |
313 | won't give the names of the arguments, so we shouldn't bother | |
314 | trying to find them. */ | |
315 | if (defunflag && maxargs != -1) | |
f2cc4248 RS |
316 | { |
317 | char argbuf[1024], *p = argbuf; | |
318 | while (c != ')') | |
319 | { | |
320 | if (c < 0) | |
321 | goto eof; | |
322 | c = getc (infile); | |
323 | } | |
324 | /* Skip into arguments. */ | |
325 | while (c != '(') | |
326 | { | |
327 | if (c < 0) | |
328 | goto eof; | |
329 | c = getc (infile); | |
330 | } | |
331 | /* Copy arguments into ARGBUF. */ | |
332 | *p++ = c; | |
333 | do | |
334 | *p++ = c = getc (infile); | |
335 | while (c != ')'); | |
336 | *p = '\0'; | |
337 | /* Output them. */ | |
338 | fprintf (outfile, "\n\n"); | |
339 | write_c_args (outfile, argbuf, minargs, maxargs); | |
340 | } | |
341 | } | |
342 | } | |
343 | eof: | |
344 | fclose (infile); | |
345 | return 0; | |
346 | } | |
347 | \f | |
348 | /* Read a file of Lisp code, compiled or interpreted. | |
349 | Looks for | |
350 | (defun NAME ARGS DOCSTRING ...) | |
351 | (autoload 'NAME FILE DOCSTRING ...) | |
352 | (defvar NAME VALUE DOCSTRING) | |
353 | (defconst NAME VALUE DOCSTRING) | |
5aafeb12 | 354 | (fset (quote NAME) (make-byte-code (quote ARGS) ... "\ |
a8a7afbe | 355 | DOCSTRING") |
f2cc4248 RS |
356 | starting in column zero. |
357 | ARGS, FILE or VALUE is ignored. We do not know how to parse Lisp code | |
358 | so we use a kludge to skip them: | |
359 | In a function definition, the form of ARGS of FILE is known, and we | |
360 | can skip it. | |
361 | In a variable definition, we use a formatting convention: | |
362 | the DOCSTRING, if present, must be followed by a closeparen and a newline, | |
363 | and no newline must appear between the defvar or defconst and the docstring, | |
364 | The only source file that must follow this convention is loaddefs.el; | |
365 | aside from that, it is always the .elc file that we look at, and | |
366 | they are no problem because byte-compiler output follows this convention. | |
367 | The NAME and DOCSTRING are output. | |
368 | NAME is preceded by `F' for a function or `V' for a variable. | |
369 | An entry is output only if DOCSTRING has \ newline just after the opening " | |
370 | */ | |
371 | ||
372 | scan_lisp_file (filename) | |
373 | char *filename; | |
374 | { | |
375 | FILE *infile; | |
376 | register int c; | |
377 | register int commas; | |
378 | register char *p; | |
379 | int defvarflag; | |
380 | ||
381 | infile = fopen (filename, "r"); | |
382 | if (infile == NULL) | |
383 | { | |
384 | perror (filename); | |
385 | return 0; /* No error */ | |
386 | } | |
387 | ||
388 | c = '\n'; | |
389 | while (!feof (infile)) | |
390 | { | |
391 | if (c != '\n') | |
392 | { | |
393 | c = getc (infile); | |
394 | continue; | |
395 | } | |
396 | c = getc (infile); | |
397 | if (c != '(') | |
398 | continue; | |
a8a7afbe JB |
399 | |
400 | /* Handle an autoload. */ | |
f2cc4248 RS |
401 | c = getc (infile); |
402 | if (c == 'a') | |
403 | { | |
404 | c = getc (infile); | |
405 | if (c != 'u') | |
406 | continue; | |
407 | c = getc (infile); | |
408 | if (c != 't') | |
409 | continue; | |
410 | c = getc (infile); | |
411 | if (c != 'o') | |
412 | continue; | |
413 | c = getc (infile); | |
414 | if (c != 'l') | |
415 | continue; | |
416 | c = getc (infile); | |
417 | if (c != 'o') | |
418 | continue; | |
419 | c = getc (infile); | |
420 | if (c != 'a') | |
421 | continue; | |
422 | c = getc (infile); | |
423 | if (c != 'd') | |
424 | continue; | |
425 | ||
426 | c = getc (infile); | |
427 | while (c == ' ') | |
428 | c = getc (infile); | |
429 | ||
430 | if (c == '\'') | |
431 | { | |
432 | c = getc (infile); | |
433 | } | |
434 | else | |
435 | { | |
436 | if (c != '(') | |
437 | continue; | |
438 | c = getc (infile); | |
439 | if (c != 'q') | |
440 | continue; | |
441 | c = getc (infile); | |
442 | if (c != 'u') | |
443 | continue; | |
444 | c = getc (infile); | |
445 | if (c != 'o') | |
446 | continue; | |
447 | c = getc (infile); | |
448 | if (c != 't') | |
449 | continue; | |
450 | c = getc (infile); | |
451 | if (c != 'e') | |
452 | continue; | |
453 | c = getc (infile); | |
454 | if (c != ' ') | |
455 | continue; | |
456 | while (c == ' ') | |
457 | c = getc (infile); | |
458 | } | |
459 | ||
460 | p = buf; | |
461 | while (c != ' ' && c != ')') | |
462 | { | |
463 | if (c == EOF) | |
464 | return 1; | |
465 | if (c == '\\') | |
466 | c = getc (infile); | |
467 | *p++ = c; | |
468 | c = getc (infile); | |
469 | } | |
470 | *p = 0; | |
471 | ||
472 | while (c != '"') | |
473 | { | |
474 | if (c == EOF) | |
475 | return 1; | |
476 | c = getc (infile); | |
477 | } | |
478 | c = read_c_string (infile, 0); | |
479 | } | |
a8a7afbe JB |
480 | |
481 | /* Handle def* clauses. */ | |
f2cc4248 RS |
482 | else if (c == 'd') |
483 | { | |
484 | c = getc (infile); | |
485 | if (c != 'e') | |
486 | continue; | |
487 | c = getc (infile); | |
488 | if (c != 'f') | |
489 | continue; | |
490 | c = getc (infile); | |
a8a7afbe JB |
491 | |
492 | /* Is this a defun? */ | |
f2cc4248 RS |
493 | if (c == 'u') |
494 | { | |
495 | c = getc (infile); | |
496 | if (c != 'n') | |
497 | continue; | |
498 | defvarflag = 0; | |
499 | } | |
a8a7afbe JB |
500 | |
501 | /* Or a defvar? */ | |
f2cc4248 RS |
502 | else if (c == 'v') |
503 | { | |
504 | c = getc (infile); | |
505 | if (c != 'a') | |
506 | continue; | |
507 | c = getc (infile); | |
508 | if (c != 'r') | |
509 | continue; | |
510 | defvarflag = 1; | |
511 | } | |
a8a7afbe JB |
512 | |
513 | /* Or a defconst? */ | |
f2cc4248 RS |
514 | else if (c == 'c') |
515 | { | |
516 | c = getc (infile); | |
517 | if (c != 'o') | |
518 | continue; | |
519 | c = getc (infile); | |
520 | if (c != 'n') | |
521 | continue; | |
522 | c = getc (infile); | |
523 | if (c != 's') | |
524 | continue; | |
525 | c = getc (infile); | |
526 | if (c != 't') | |
527 | continue; | |
528 | defvarflag = 1; | |
529 | } | |
530 | else | |
531 | continue; | |
532 | ||
533 | /* Now we have seen "defun" or "defvar" or "defconst". */ | |
534 | ||
535 | while (c != ' ' && c != '\n' && c != '\t') | |
536 | c = getc (infile); | |
537 | ||
538 | while (c == ' ' || c == '\n' || c == '\t') | |
539 | c = getc (infile); | |
540 | ||
541 | /* Read and store name of function or variable being defined | |
542 | Discard backslashes that are for quoting. */ | |
543 | p = buf; | |
544 | while (c != ' ' && c != '\n' && c != '\t') | |
545 | { | |
546 | if (c == '\\') | |
547 | c = getc (infile); | |
548 | *p++ = c; | |
549 | c = getc (infile); | |
550 | } | |
551 | *p = 0; | |
552 | ||
553 | while (c == ' ' || c == '\n' || c == '\t') | |
554 | c = getc (infile); | |
555 | ||
556 | if (! defvarflag) | |
557 | { | |
558 | /* A function: */ | |
559 | /* Skip the arguments: either "nil" or a list in parens */ | |
560 | if (c == 'n') | |
561 | { | |
562 | while (c != ' ' && c != '\n' && c != '\t') | |
563 | c = getc (infile); | |
564 | } | |
565 | else | |
566 | { | |
567 | while (c != '(') | |
568 | c = getc (infile); | |
569 | while (c != ')') | |
570 | c = getc (infile); | |
571 | } | |
572 | c = getc (infile); | |
573 | } | |
574 | else | |
575 | { | |
576 | /* A variable: */ | |
577 | ||
578 | /* Skip until the first newline; remember | |
579 | the two previous characters. */ | |
580 | char c1 = 0, c2 = 0; | |
581 | ||
582 | while (c != '\n' && c >= 0) | |
583 | { | |
584 | c2 = c1; | |
585 | c1 = c; | |
586 | c = getc (infile); | |
587 | } | |
588 | ||
589 | /* If two previous characters were " and \, | |
590 | this is a doc string. Otherwise, there is none. */ | |
591 | if (c2 == '"' && c1 == '\\') | |
592 | { | |
593 | putc (037, outfile); | |
594 | putc ('V', outfile); | |
595 | fprintf (outfile, "%s\n", buf); | |
596 | read_c_string (infile, 1); | |
597 | } | |
598 | continue; | |
599 | } | |
600 | } | |
a8a7afbe JB |
601 | |
602 | /* Handle an fset clause. */ | |
603 | else if (c == 'f') | |
604 | { | |
605 | c = getc (infile); | |
606 | if (c != 's') | |
607 | continue; | |
608 | c = getc (infile); | |
609 | if (c != 'e') | |
610 | continue; | |
611 | c = getc (infile); | |
612 | if (c != 't') | |
613 | continue; | |
614 | ||
615 | /* Skip white space */ | |
616 | do | |
617 | c = getc (infile); | |
618 | while (c == ' ' || c == '\n' || c == '\t'); | |
619 | ||
620 | /* Recognize "(quote". */ | |
621 | if (c != '(') | |
622 | continue; | |
623 | c = getc (infile); | |
624 | if (c != 'q') | |
625 | continue; | |
626 | c = getc (infile); | |
627 | if (c != 'u') | |
628 | continue; | |
629 | c = getc (infile); | |
630 | if (c != 'o') | |
631 | continue; | |
632 | c = getc (infile); | |
633 | if (c != 't') | |
634 | continue; | |
635 | c = getc (infile); | |
636 | if (c != 'e') | |
637 | continue; | |
638 | ||
639 | /* Skip white space */ | |
640 | do | |
641 | c = getc (infile); | |
642 | while (c == ' ' || c == '\n' || c == '\t'); | |
643 | ||
644 | /* Read and store name of function or variable being defined | |
645 | Discard backslashes that are for quoting. */ | |
646 | p = buf; | |
647 | while (c != ')' && c != ' ' && c != '\n' && c != '\t') | |
648 | { | |
649 | if (c == '\\') | |
650 | c = getc (infile); | |
651 | *p++ = c; | |
652 | c = getc (infile); | |
653 | } | |
654 | *p = '\0'; | |
655 | ||
656 | /* Skip white space */ | |
657 | do | |
658 | c = getc (infile); | |
659 | while (c == ' ' || c == '\n' || c == '\t'); | |
660 | ||
661 | /* Recognize "(make-byte-code". */ | |
662 | if (c != '(') | |
663 | continue; | |
664 | c = getc (infile); | |
665 | if (c != 'm') | |
666 | continue; | |
667 | c = getc (infile); | |
668 | if (c != 'a') | |
669 | continue; | |
670 | c = getc (infile); | |
671 | if (c != 'k') | |
672 | continue; | |
673 | c = getc (infile); | |
674 | if (c != 'e') | |
675 | continue; | |
676 | c = getc (infile); | |
677 | if (c != '-') | |
678 | continue; | |
679 | c = getc (infile); | |
680 | if (c != 'b') | |
681 | continue; | |
682 | c = getc (infile); | |
683 | if (c != 'y') | |
684 | continue; | |
685 | c = getc (infile); | |
686 | if (c != 't') | |
687 | continue; | |
688 | c = getc (infile); | |
689 | if (c != 'e') | |
690 | continue; | |
691 | c = getc (infile); | |
692 | if (c != '-') | |
693 | continue; | |
694 | c = getc (infile); | |
695 | if (c != 'c') | |
696 | continue; | |
697 | c = getc (infile); | |
698 | if (c != 'o') | |
699 | continue; | |
700 | c = getc (infile); | |
701 | if (c != 'd') | |
702 | continue; | |
703 | c = getc (infile); | |
704 | if (c != 'e') | |
705 | continue; | |
706 | ||
707 | /* Scan for a \" followed by a newline, or for )) followed by | |
708 | a newline. If we find the latter first, this function has | |
709 | no docstring. */ | |
710 | { | |
711 | char c1 = 0, c2 = 0; | |
712 | ||
713 | for (;;) | |
714 | { | |
715 | ||
716 | /* Find newlines, and remember the two previous characters. */ | |
717 | for (;;) | |
718 | { | |
719 | c = getc (infile); | |
720 | ||
721 | if (c == '\n' || c < 0) | |
722 | break; | |
723 | ||
724 | c2 = c1; | |
725 | c1 = c; | |
726 | } | |
727 | ||
728 | /* If we've hit eof, quit. */ | |
729 | if (c == EOF) | |
730 | break; | |
731 | ||
732 | /* If the last two characters were \", this is a docstring. */ | |
733 | else if (c2 == '"' && c1 == '\\') | |
734 | { | |
735 | putc (037, outfile); | |
736 | putc ('F', outfile); | |
737 | fprintf (outfile, "%s\n", buf); | |
738 | read_c_string (infile, 1); | |
739 | break; | |
740 | } | |
741 | ||
742 | /* If the last two characters were )), there is no | |
743 | docstring. */ | |
744 | else if (c2 == ')' && c1 == ')') | |
745 | break; | |
746 | } | |
747 | continue; | |
748 | } | |
749 | } | |
f2cc4248 RS |
750 | else |
751 | continue; | |
752 | ||
753 | /* Here for a function definition. | |
754 | We have skipped the file name or arguments | |
755 | and arrived at where the doc string is, | |
756 | if there is a doc string. */ | |
757 | ||
758 | /* Skip whitespace */ | |
759 | ||
760 | while (c == ' ' || c == '\n' || c == '\t') | |
761 | c = getc (infile); | |
762 | ||
763 | /* " followed by \ and newline means a doc string we should gobble */ | |
764 | if (c != '"') | |
765 | continue; | |
766 | c = getc (infile); | |
767 | if (c != '\\') | |
768 | continue; | |
769 | c = getc (infile); | |
770 | if (c != '\n') | |
771 | continue; | |
772 | ||
773 | putc (037, outfile); | |
774 | putc ('F', outfile); | |
775 | fprintf (outfile, "%s\n", buf); | |
776 | read_c_string (infile, 1); | |
777 | } | |
778 | fclose (infile); | |
779 | return 0; | |
780 | } |