Fixes: debbugs:11380
[bpt/emacs.git] / lib-src / make-docfile.c
CommitLineData
f2cc4248 1/* Generate doc-string file for GNU Emacs from source files.
acaf905b 2 Copyright (C) 1985-1986, 1992-1994, 1997, 1999-2012
a5b68355 3 Free Software Foundation, Inc.
f2cc4248
RS
4
5This file is part of GNU Emacs.
6
294981c7 7GNU Emacs is free software: you can redistribute it and/or modify
93320c23 8it under the terms of the GNU General Public License as published by
294981c7
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
93320c23 11
f2cc4248 12GNU Emacs is distributed in the hope that it will be useful,
93320c23
JA
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
f2cc4248 16
93320c23 17You should have received a copy of the GNU General Public License
294981c7
GM
18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
f2cc4248
RS
20
21/* The arguments given to this program are all the C and Lisp source files
22 of GNU Emacs. .elc and .el and .c files are allowed.
23 A .o file can also be specified; the .c file it was made from is used.
24 This helps the makefile pass the correct list of files.
08a39b83 25 Option -d DIR means change to DIR before looking for files.
f2cc4248
RS
26
27 The results, which go to standard output or to a file
28 specified with -a or -o (-a to append, -o to start from nothing),
29 are entries containing function or variable names and their documentation.
30 Each entry starts with a ^_ character.
31 Then comes F for a function or V for a variable.
32 Then comes the function or variable name, terminated with a newline.
33 Then comes the documentation for that function or variable.
34 */
35
433d333d
RS
36#include <config.h>
37
38/* defined to be emacs_main, sys_fopen, etc. in config.h */
39#undef main
40#undef fopen
41#undef chdir
34b4ece5 42
f2cc4248 43#include <stdio.h>
00b3c7ac 44#include <stdlib.h>
e3938952
RS
45#ifdef MSDOS
46#include <fcntl.h>
47#endif /* MSDOS */
86b0513a 48#ifdef WINDOWSNT
86b0513a
RS
49#include <fcntl.h>
50#include <direct.h>
51#endif /* WINDOWSNT */
e3938952 52
86b0513a 53#ifdef DOS_NT
e3938952
RS
54#define READ_TEXT "rt"
55#define READ_BINARY "rb"
86b0513a 56#else /* not DOS_NT */
e3938952
RS
57#define READ_TEXT "r"
58#define READ_BINARY "r"
86b0513a 59#endif /* not DOS_NT */
f2cc4248 60
ef7c480d 61#ifndef DIRECTORY_SEP
ef7c480d 62#define DIRECTORY_SEP '/'
ef7c480d
YM
63#endif
64
b09c5608 65#ifndef IS_DIRECTORY_SEP
ef7c480d 66#define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
b09c5608
EZ
67#endif
68
8e48d7bc
PE
69/* Use this to suppress gcc's `...may be used before initialized' warnings. */
70#ifdef lint
71# define IF_LINT(Code) Code
72#else
73# define IF_LINT(Code) /* empty */
74#endif
75
b23b5a5b
PE
76static int scan_file (char *filename);
77static int scan_lisp_file (const char *filename, const char *mode);
78static int scan_c_file (char *filename, const char *mode);
79static void fatal (const char *s1, const char *s2) NO_RETURN;
80static void start_globals (void);
81static void write_globals (void);
340ff9de 82
2d1985a2
KH
83#ifdef MSDOS
84/* s/msdos.h defines this as sys_chdir, but we're not linking with the
85 file where that function is defined. */
86#undef chdir
87#endif
88
a0613c61 89#include <unistd.h>
a0613c61 90
b5ff43cc 91/* Stdio stream for output to the DOC file. */
f2cc4248
RS
92FILE *outfile;
93
b5ff43cc
RS
94/* Name this program was invoked with. */
95char *progname;
96
00b3c7ac
TT
97/* Nonzero if this invocation is generating globals.h. */
98int generate_globals;
99
fb2d3129 100/* Print error message. `s1' is printf control string, `s2' is arg for it. */
b5ff43cc
RS
101
102/* VARARGS1 */
b23b5a5b 103static void
988e88ab 104error (const char *s1, const char *s2)
b5ff43cc
RS
105{
106 fprintf (stderr, "%s: ", progname);
107 fprintf (stderr, s1, s2);
108 fprintf (stderr, "\n");
109}
110
111/* Print error message and exit. */
112
113/* VARARGS1 */
b23b5a5b 114static void
988e88ab 115fatal (const char *s1, const char *s2)
b5ff43cc
RS
116{
117 error (s1, s2);
65396510 118 exit (EXIT_FAILURE);
b5ff43cc
RS
119}
120
121/* Like malloc but get fatal error if memory is exhausted. */
122
b23b5a5b 123static void *
873fbd0b 124xmalloc (unsigned int size)
b5ff43cc 125{
d5d66b7e 126 void *result = (void *) malloc (size);
b5ff43cc
RS
127 if (result == NULL)
128 fatal ("virtual memory exhausted", 0);
129 return result;
130}
00b3c7ac
TT
131
132/* Like realloc but get fatal error if memory is exhausted. */
133
b23b5a5b 134static void *
00b3c7ac
TT
135xrealloc (void *arg, unsigned int size)
136{
137 void *result = (void *) realloc (arg, size);
138 if (result == NULL)
139 fatal ("virtual memory exhausted", 0);
140 return result;
141}
142
b5ff43cc 143\f
340ff9de 144int
873fbd0b 145main (int argc, char **argv)
f2cc4248
RS
146{
147 int i;
148 int err_count = 0;
a27897c9 149 int first_infile;
f2cc4248 150
b5ff43cc
RS
151 progname = argv[0];
152
4e043ed3
RS
153 outfile = stdout;
154
86b0513a 155 /* Don't put CRs in the DOC file. */
e3938952 156#ifdef MSDOS
5281dea4 157 _fmode = O_BINARY;
4e043ed3
RS
158#if 0 /* Suspicion is that this causes hanging.
159 So instead we require people to use -o on MSDOS. */
e3938952
RS
160 (stdout)->_flag &= ~_IOTEXT;
161 _setmode (fileno (stdout), O_BINARY);
4e043ed3
RS
162#endif
163 outfile = 0;
e3938952 164#endif /* MSDOS */
86b0513a
RS
165#ifdef WINDOWSNT
166 _fmode = O_BINARY;
167 _setmode (fileno (stdout), O_BINARY);
168#endif /* WINDOWSNT */
169
f2cc4248
RS
170 /* If first two args are -o FILE, output to FILE. */
171 i = 1;
172 if (argc > i + 1 && !strcmp (argv[i], "-o"))
173 {
174 outfile = fopen (argv[i + 1], "w");
175 i += 2;
176 }
177 if (argc > i + 1 && !strcmp (argv[i], "-a"))
178 {
179 outfile = fopen (argv[i + 1], "a");
180 i += 2;
181 }
d2d92f7a
JB
182 if (argc > i + 1 && !strcmp (argv[i], "-d"))
183 {
9055082e
PE
184 if (chdir (argv[i + 1]) != 0)
185 {
186 perror (argv[i + 1]);
187 return EXIT_FAILURE;
188 }
d2d92f7a
JB
189 i += 2;
190 }
00b3c7ac
TT
191 if (argc > i && !strcmp (argv[i], "-g"))
192 {
193 generate_globals = 1;
194 ++i;
195 }
f2cc4248 196
4e043ed3
RS
197 if (outfile == 0)
198 fatal ("No output file specified", "");
199
00b3c7ac
TT
200 if (generate_globals)
201 start_globals ();
202
a27897c9 203 first_infile = i;
f2cc4248 204 for (; i < argc; i++)
a27897c9
RS
205 {
206 int j;
207 /* Don't process one file twice. */
208 for (j = first_infile; j < i; j++)
209 if (! strcmp (argv[i], argv[j]))
210 break;
211 if (j == i)
212 err_count += scan_file (argv[i]);
213 }
00b3c7ac
TT
214
215 if (err_count == 0 && generate_globals)
216 write_globals ();
217
08a39b83 218 return (err_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
f2cc4248
RS
219}
220
d5d66b7e 221/* Add a source file name boundary marker in the output file. */
b23b5a5b 222static void
873fbd0b 223put_filename (char *filename)
d5d66b7e 224{
b09c5608
EZ
225 char *tmp;
226
227 for (tmp = filename; *tmp; tmp++)
228 {
229 if (IS_DIRECTORY_SEP(*tmp))
230 filename = tmp + 1;
231 }
d5d66b7e
SM
232
233 putc (037, outfile);
234 putc ('S', outfile);
235 fprintf (outfile, "%s\n", filename);
236}
237
a8a7afbe 238/* Read file FILENAME and output its doc strings to outfile. */
f2cc4248
RS
239/* Return 1 if file is not found, 0 if it is found. */
240
b23b5a5b 241static int
873fbd0b 242scan_file (char *filename)
f2cc4248 243{
728a982d
DN
244
245 size_t len = strlen (filename);
d5d66b7e 246
00b3c7ac
TT
247 if (!generate_globals)
248 put_filename (filename);
dc61cb9d 249 if (len > 4 && !strcmp (filename + len - 4, ".elc"))
e3938952 250 return scan_lisp_file (filename, READ_BINARY);
dc61cb9d 251 else if (len > 3 && !strcmp (filename + len - 3, ".el"))
e3938952 252 return scan_lisp_file (filename, READ_TEXT);
f2cc4248 253 else
e3938952 254 return scan_c_file (filename, READ_TEXT);
f2cc4248 255}
00b3c7ac 256
b23b5a5b 257static void
00b3c7ac
TT
258start_globals (void)
259{
260 fprintf (outfile, "/* This file was auto-generated by make-docfile. */\n");
261 fprintf (outfile, "/* DO NOT EDIT. */\n");
262 fprintf (outfile, "struct emacs_globals {\n");
263}
f2cc4248 264\f
4df52042 265static char input_buffer[128];
f2cc4248 266
52d8c529
MB
267/* Some state during the execution of `read_c_string_or_comment'. */
268struct rcsoc_state
269{
fb2d3129 270 /* A count of spaces and newlines that have been read, but not output. */
52d8c529
MB
271 unsigned pending_spaces, pending_newlines;
272
273 /* Where we're reading from. */
274 FILE *in_file;
275
276 /* If non-zero, a buffer into which to copy characters. */
277 char *buf_ptr;
278 /* If non-zero, a file into which to copy characters. */
279 FILE *out_file;
280
281 /* A keyword we look for at the beginning of lines. If found, it is
282 not copied, and SAW_KEYWORD is set to true. */
988e88ab 283 const char *keyword;
33972e80 284 /* The current point we've reached in an occurrence of KEYWORD in
52d8c529 285 the input stream. */
988e88ab 286 const char *cur_keyword_ptr;
33972e80 287 /* Set to true if we saw an occurrence of KEYWORD. */
52d8c529
MB
288 int saw_keyword;
289};
290
291/* Output CH to the file or buffer in STATE. Any pending newlines or
292 spaces are output first. */
0c82822c 293
55d4c1b2 294static inline void
873fbd0b 295put_char (int ch, struct rcsoc_state *state)
0c82822c
MB
296{
297 int out_ch;
298 do
299 {
52d8c529 300 if (state->pending_newlines > 0)
0c82822c 301 {
52d8c529 302 state->pending_newlines--;
0c82822c
MB
303 out_ch = '\n';
304 }
52d8c529 305 else if (state->pending_spaces > 0)
0c82822c 306 {
52d8c529 307 state->pending_spaces--;
0c82822c
MB
308 out_ch = ' ';
309 }
310 else
311 out_ch = ch;
312
52d8c529
MB
313 if (state->out_file)
314 putc (out_ch, state->out_file);
315 if (state->buf_ptr)
316 *state->buf_ptr++ = out_ch;
0c82822c
MB
317 }
318 while (out_ch != ch);
319}
320
52d8c529
MB
321/* If in the middle of scanning a keyword, continue scanning with
322 character CH, otherwise output CH to the file or buffer in STATE.
323 Any pending newlines or spaces are output first, as well as any
324 previously scanned characters that were thought to be part of a
325 keyword, but were in fact not. */
326
327static void
873fbd0b 328scan_keyword_or_put_char (int ch, struct rcsoc_state *state)
52d8c529
MB
329{
330 if (state->keyword
331 && *state->cur_keyword_ptr == ch
332 && (state->cur_keyword_ptr > state->keyword
333 || state->pending_newlines > 0))
334 /* We might be looking at STATE->keyword at some point.
335 Keep looking until we know for sure. */
336 {
337 if (*++state->cur_keyword_ptr == '\0')
338 /* Saw the whole keyword. Set SAW_KEYWORD flag to true. */
339 {
340 state->saw_keyword = 1;
341
342 /* Reset the scanning pointer. */
343 state->cur_keyword_ptr = state->keyword;
344
fb2d3129 345 /* Canonicalize whitespace preceding a usage string. */
52d8c529
MB
346 state->pending_newlines = 2;
347 state->pending_spaces = 0;
348
349 /* Skip any whitespace between the keyword and the
350 usage string. */
351 do
352 ch = getc (state->in_file);
353 while (ch == ' ' || ch == '\n');
354
56cf5162
SM
355 /* Output the open-paren we just read. */
356 put_char (ch, state);
357
358 /* Skip the function name and replace it with `fn'. */
359 do
360 ch = getc (state->in_file);
361 while (ch != ' ' && ch != ')');
362 put_char ('f', state);
363 put_char ('n', state);
177c0ea7 364
56cf5162 365 /* Put back the last character. */
52d8c529
MB
366 ungetc (ch, state->in_file);
367 }
368 }
369 else
370 {
371 if (state->keyword && state->cur_keyword_ptr > state->keyword)
372 /* We scanned the beginning of a potential usage
373 keyword, but it was a false alarm. Output the
374 part we scanned. */
375 {
988e88ab 376 const char *p;
52d8c529
MB
377
378 for (p = state->keyword; p < state->cur_keyword_ptr; p++)
379 put_char (*p, state);
380
381 state->cur_keyword_ptr = state->keyword;
382 }
383
384 put_char (ch, state);
385 }
386}
387
388
74c55c82
GM
389/* Skip a C string or C-style comment from INFILE, and return the
390 character that follows. COMMENT non-zero means skip a comment. If
391 PRINTFLAG is positive, output string contents to outfile. If it is
392 negative, store contents in buf. Convert escape sequences \n and
d097ad57 393 \t to newline and tab; discard \ followed by newline.
33972e80 394 If SAW_USAGE is non-zero, then any occurrences of the string `usage:'
d097ad57
MB
395 at the beginning of a line will be removed, and *SAW_USAGE set to
396 true if any were encountered. */
f2cc4248 397
b23b5a5b 398static int
873fbd0b 399read_c_string_or_comment (FILE *infile, int printflag, int comment, int *saw_usage)
f2cc4248
RS
400{
401 register int c;
52d8c529
MB
402 struct rcsoc_state state;
403
404 state.in_file = infile;
4df52042 405 state.buf_ptr = (printflag < 0 ? input_buffer : 0);
52d8c529
MB
406 state.out_file = (printflag > 0 ? outfile : 0);
407 state.pending_spaces = 0;
408 state.pending_newlines = 0;
409 state.keyword = (saw_usage ? "usage:" : 0);
410 state.cur_keyword_ptr = state.keyword;
411 state.saw_keyword = 0;
412
413 c = getc (infile);
74c55c82 414 if (comment)
52d8c529
MB
415 while (c == '\n' || c == '\r' || c == '\t' || c == ' ')
416 c = getc (infile);
d097ad57 417
f2cc4248
RS
418 while (c != EOF)
419 {
74c55c82 420 while (c != EOF && (comment ? c != '*' : c != '"'))
f2cc4248
RS
421 {
422 if (c == '\\')
423 {
424 c = getc (infile);
433d333d 425 if (c == '\n' || c == '\r')
f2cc4248
RS
426 {
427 c = getc (infile);
428 continue;
429 }
430 if (c == 'n')
431 c = '\n';
432 if (c == 't')
433 c = '\t';
434 }
a00e9335 435
0c82822c 436 if (c == ' ')
52d8c529 437 state.pending_spaces++;
0c82822c
MB
438 else if (c == '\n')
439 {
52d8c529
MB
440 state.pending_newlines++;
441 state.pending_spaces = 0;
0c82822c
MB
442 }
443 else
52d8c529 444 scan_keyword_or_put_char (c, &state);
0c82822c 445
f2cc4248
RS
446 c = getc (infile);
447 }
74c55c82 448
7dfd439c
GM
449 if (c != EOF)
450 c = getc (infile);
f2cc4248 451
74c55c82
GM
452 if (comment)
453 {
454 if (c == '/')
455 {
456 c = getc (infile);
457 break;
458 }
a00e9335 459
52d8c529 460 scan_keyword_or_put_char ('*', &state);
74c55c82
GM
461 }
462 else
463 {
464 if (c != '"')
465 break;
a00e9335 466
74c55c82
GM
467 /* If we had a "", concatenate the two strings. */
468 c = getc (infile);
469 }
470 }
a00e9335 471
f2cc4248 472 if (printflag < 0)
52d8c529
MB
473 *state.buf_ptr = 0;
474
475 if (saw_usage)
476 *saw_usage = state.saw_keyword;
f2cc4248
RS
477
478 return c;
479}
74c55c82
GM
480
481
f2cc4248 482\f
069ad9ea 483/* Write to file OUT the argument names of function FUNC, whose text is in BUF.
f2cc4248
RS
484 MINARGS and MAXARGS are the minimum and maximum number of arguments. */
485
b23b5a5b 486static void
873fbd0b 487write_c_args (FILE *out, char *func, char *buf, int minargs, int maxargs)
f2cc4248 488{
f125a9e8 489 register char *p;
30e4c427 490 int in_ident = 0;
8e48d7bc 491 char *ident_start IF_LINT (= NULL);
728a982d 492 size_t ident_length = 0;
f2cc4248 493
56cf5162 494 fprintf (out, "(fn");
069ad9ea
RM
495
496 if (*buf == '(')
497 ++buf;
f2cc4248 498
f125a9e8 499 for (p = buf; *p; p++)
f2cc4248 500 {
91a7f76d 501 char c = *p;
30e4c427 502
91a7f76d 503 /* Notice when a new identifier starts. */
30e4c427
JB
504 if ((('A' <= c && c <= 'Z')
505 || ('a' <= c && c <= 'z')
506 || ('0' <= c && c <= '9')
507 || c == '_')
508 != in_ident)
f2cc4248 509 {
30e4c427
JB
510 if (!in_ident)
511 {
512 in_ident = 1;
91a7f76d 513 ident_start = p;
30e4c427
JB
514 }
515 else
91a7f76d
AS
516 {
517 in_ident = 0;
518 ident_length = p - ident_start;
519 }
f2cc4248 520 }
30e4c427 521
91a7f76d
AS
522 /* Found the end of an argument, write out the last seen
523 identifier. */
524 if (c == ',' || c == ')')
3941a179 525 {
a94a477d
JB
526 if (ident_length == 0)
527 {
528 error ("empty arg list for `%s' should be (void), not ()", func);
529 continue;
530 }
531
91a7f76d
AS
532 if (strncmp (ident_start, "void", ident_length) == 0)
533 continue;
534
535 putc (' ', out);
536
537 if (minargs == 0 && maxargs > 0)
538 fprintf (out, "&optional ");
30e4c427 539
91a7f76d
AS
540 minargs--;
541 maxargs--;
542
543 /* In C code, `default' is a reserved word, so we spell it
22bcf204 544 `defalt'; demangle that here. */
554d39be 545 if (ident_length == 6 && strncmp (ident_start, "defalt", 6) == 0)
91a7f76d
AS
546 fprintf (out, "DEFAULT");
547 else
548 while (ident_length-- > 0)
549 {
550 c = *ident_start++;
551 if (c >= 'a' && c <= 'z')
552 /* Upcase the letter. */
553 c += 'A' - 'a';
554 else if (c == '_')
555 /* Print underscore as hyphen. */
556 c = '-';
557 putc (c, out);
558 }
559 }
f2cc4248 560 }
91a7f76d
AS
561
562 putc (')', out);
f2cc4248
RS
563}
564\f
00b3c7ac
TT
565/* The types of globals. */
566enum global_type
567{
64df8c10 568 EMACS_INTEGER,
00b3c7ac
TT
569 BOOLEAN,
570 LISP_OBJECT,
571 INVALID
572};
573
574/* A single global. */
575struct global
576{
577 enum global_type type;
578 char *name;
579};
580
581/* All the variable names we saw while scanning C sources in `-g'
582 mode. */
583int num_globals;
584int num_globals_allocated;
585struct global *globals;
586
587static void
588add_global (enum global_type type, char *name)
589{
590 /* Ignore the one non-symbol that can occur. */
591 if (strcmp (name, "..."))
592 {
593 ++num_globals;
594
595 if (num_globals_allocated == 0)
596 {
597 num_globals_allocated = 100;
598 globals = xmalloc (num_globals_allocated * sizeof (struct global));
599 }
600 else if (num_globals == num_globals_allocated)
601 {
602 num_globals_allocated *= 2;
603 globals = xrealloc (globals,
604 num_globals_allocated * sizeof (struct global));
605 }
606
607 globals[num_globals - 1].type = type;
608 globals[num_globals - 1].name = name;
609 }
610}
611
612static int
613compare_globals (const void *a, const void *b)
614{
615 const struct global *ga = a;
616 const struct global *gb = b;
617 return strcmp (ga->name, gb->name);
618}
619
b23b5a5b 620static void
00b3c7ac
TT
621write_globals (void)
622{
623 int i;
624 qsort (globals, num_globals, sizeof (struct global), compare_globals);
625 for (i = 0; i < num_globals; ++i)
626 {
564ff1f2 627 char const *type;
00b3c7ac
TT
628
629 switch (globals[i].type)
630 {
64df8c10 631 case EMACS_INTEGER:
00b3c7ac
TT
632 type = "EMACS_INT";
633 break;
634 case BOOLEAN:
635 type = "int";
636 break;
637 case LISP_OBJECT:
638 type = "Lisp_Object";
639 break;
640 default:
641 fatal ("not a recognized DEFVAR_", 0);
642 }
643
644 fprintf (outfile, " %s f_%s;\n", type, globals[i].name);
645 fprintf (outfile, "#define %s globals.f_%s\n",
646 globals[i].name, globals[i].name);
647 while (i + 1 < num_globals
648 && !strcmp (globals[i].name, globals[i + 1].name))
649 ++i;
650 }
651
652 fprintf (outfile, "};\n");
653 fprintf (outfile, "extern struct emacs_globals globals;\n");
654}
655
656\f
f2cc4248 657/* Read through a c file. If a .o file is named,
edfda783 658 the corresponding .c or .m file is read instead.
f2cc4248
RS
659 Looks for DEFUN constructs such as are defined in ../src/lisp.h.
660 Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */
661
b23b5a5b 662static int
988e88ab 663scan_c_file (char *filename, const char *mode)
f2cc4248
RS
664{
665 FILE *infile;
666 register int c;
667 register int commas;
f2cc4248 668 int minargs, maxargs;
1feb8ae1 669 int extension = filename[strlen (filename) - 1];
f2cc4248 670
1feb8ae1 671 if (extension == 'o')
f2cc4248
RS
672 filename[strlen (filename) - 1] = 'c';
673
e3938952 674 infile = fopen (filename, mode);
f2cc4248 675
edfda783
AR
676 if (infile == NULL && extension == 'o')
677 {
678 /* try .m */
679 filename[strlen (filename) - 1] = 'm';
680 infile = fopen (filename, mode);
681 if (infile == NULL)
682 filename[strlen (filename) - 1] = 'c'; /* don't confuse people */
683 }
684
f2cc4248
RS
685 /* No error if non-ex input file */
686 if (infile == NULL)
687 {
688 perror (filename);
689 return 0;
690 }
691
fb2d3129 692 /* Reset extension to be able to detect duplicate files. */
1feb8ae1
RS
693 filename[strlen (filename) - 1] = extension;
694
f2cc4248
RS
695 c = '\n';
696 while (!feof (infile))
697 {
a5979c0e 698 int doc_keyword = 0;
8dfa32f6
PE
699 int defunflag = 0;
700 int defvarperbufferflag = 0;
701 int defvarflag = 0;
702 enum global_type type = INVALID;
a5979c0e 703
433d333d 704 if (c != '\n' && c != '\r')
f2cc4248
RS
705 {
706 c = getc (infile);
707 continue;
708 }
709 c = getc (infile);
710 if (c == ' ')
711 {
712 while (c == ' ')
713 c = getc (infile);
714 if (c != 'D')
715 continue;
716 c = getc (infile);
717 if (c != 'E')
718 continue;
719 c = getc (infile);
720 if (c != 'F')
721 continue;
722 c = getc (infile);
723 if (c != 'V')
724 continue;
84128dee
JB
725 c = getc (infile);
726 if (c != 'A')
727 continue;
728 c = getc (infile);
729 if (c != 'R')
730 continue;
731 c = getc (infile);
732 if (c != '_')
733 continue;
734
f2cc4248 735 defvarflag = 1;
84128dee
JB
736
737 c = getc (infile);
738 defvarperbufferflag = (c == 'P');
00b3c7ac
TT
739 if (generate_globals)
740 {
741 if (c == 'I')
64df8c10 742 type = EMACS_INTEGER;
00b3c7ac
TT
743 else if (c == 'L')
744 type = LISP_OBJECT;
745 else if (c == 'B')
746 type = BOOLEAN;
00b3c7ac 747 }
84128dee 748
f2cc4248 749 c = getc (infile);
00b3c7ac
TT
750 /* We need to distinguish between DEFVAR_BOOL and
751 DEFVAR_BUFFER_DEFAULTS. */
752 if (generate_globals && type == BOOLEAN && c != 'O')
753 type = INVALID;
f2cc4248
RS
754 }
755 else if (c == 'D')
756 {
757 c = getc (infile);
758 if (c != 'E')
759 continue;
760 c = getc (infile);
761 if (c != 'F')
762 continue;
763 c = getc (infile);
764 defunflag = c == 'U';
f2cc4248
RS
765 }
766 else continue;
767
00b3c7ac
TT
768 if (generate_globals && (!defvarflag || defvarperbufferflag
769 || type == INVALID))
770 continue;
771
f2cc4248
RS
772 while (c != '(')
773 {
774 if (c < 0)
775 goto eof;
776 c = getc (infile);
777 }
778
74c55c82 779 /* Lisp variable or function name. */
f2cc4248
RS
780 c = getc (infile);
781 if (c != '"')
782 continue;
d097ad57 783 c = read_c_string_or_comment (infile, -1, 0, 0);
74c55c82 784
00b3c7ac
TT
785 if (generate_globals)
786 {
787 int i = 0;
788 char *name;
789
790 /* Skip "," and whitespace. */
791 do
792 {
793 c = getc (infile);
794 }
795 while (c == ',' || c == ' ' || c == '\t' || c == '\n' || c == '\r');
796
797 /* Read in the identifier. */
798 do
799 {
4df52042 800 input_buffer[i++] = c;
00b3c7ac
TT
801 c = getc (infile);
802 }
803 while (! (c == ',' || c == ' ' || c == '\t' ||
804 c == '\n' || c == '\r'));
4df52042 805 input_buffer[i] = '\0';
00b3c7ac
TT
806
807 name = xmalloc (i + 1);
4df52042 808 memcpy (name, input_buffer, i + 1);
00b3c7ac
TT
809 add_global (type, name);
810 continue;
811 }
812
a5979c0e
MB
813 /* DEFVAR_LISP ("name", addr, "doc")
814 DEFVAR_LISP ("name", addr /\* doc *\/)
815 DEFVAR_LISP ("name", addr, doc: /\* doc *\/) */
f2cc4248
RS
816
817 if (defunflag)
818 commas = 5;
84128dee 819 else if (defvarperbufferflag)
6ca1c3b4 820 commas = 3;
f2cc4248
RS
821 else if (defvarflag)
822 commas = 1;
823 else /* For DEFSIMPLE and DEFPRED */
824 commas = 2;
825
826 while (commas)
827 {
828 if (c == ',')
829 {
830 commas--;
74c55c82 831
f2cc4248
RS
832 if (defunflag && (commas == 1 || commas == 2))
833 {
9055082e 834 int scanned = 0;
f2cc4248
RS
835 do
836 c = getc (infile);
433d333d 837 while (c == ' ' || c == '\n' || c == '\r' || c == '\t');
f2cc4248
RS
838 if (c < 0)
839 goto eof;
840 ungetc (c, infile);
841 if (commas == 2) /* pick up minargs */
9055082e 842 scanned = fscanf (infile, "%d", &minargs);
f2cc4248
RS
843 else /* pick up maxargs */
844 if (c == 'M' || c == 'U') /* MANY || UNEVALLED */
845 maxargs = -1;
846 else
9055082e
PE
847 scanned = fscanf (infile, "%d", &maxargs);
848 if (scanned < 0)
849 goto eof;
f2cc4248
RS
850 }
851 }
74c55c82
GM
852
853 if (c == EOF)
f2cc4248
RS
854 goto eof;
855 c = getc (infile);
856 }
a5979c0e 857
433d333d 858 while (c == ' ' || c == '\n' || c == '\r' || c == '\t')
f2cc4248 859 c = getc (infile);
a00e9335 860
f2cc4248 861 if (c == '"')
d097ad57 862 c = read_c_string_or_comment (infile, 0, 0, 0);
a00e9335 863
74c55c82 864 while (c != EOF && c != ',' && c != '/')
f2cc4248 865 c = getc (infile);
74c55c82
GM
866 if (c == ',')
867 {
a5979c0e
MB
868 c = getc (infile);
869 while (c == ' ' || c == '\n' || c == '\r' || c == '\t')
870 c = getc (infile);
871 while ((c >= 'a' && c <= 'z') || (c >= 'Z' && c <= 'Z'))
872 c = getc (infile);
873 if (c == ':')
874 {
875 doc_keyword = 1;
876 c = getc (infile);
877 while (c == ' ' || c == '\n' || c == '\r' || c == '\t')
878 c = getc (infile);
879 }
74c55c82 880 }
f2cc4248 881
74c55c82
GM
882 if (c == '"'
883 || (c == '/'
884 && (c = getc (infile),
885 ungetc (c, infile),
886 c == '*')))
f2cc4248 887 {
74c55c82 888 int comment = c != '"';
d097ad57 889 int saw_usage;
a00e9335 890
f2cc4248
RS
891 putc (037, outfile);
892 putc (defvarflag ? 'V' : 'F', outfile);
4df52042 893 fprintf (outfile, "%s\n", input_buffer);
74c55c82
GM
894
895 if (comment)
896 getc (infile); /* Skip past `*' */
d097ad57 897 c = read_c_string_or_comment (infile, 1, comment, &saw_usage);
772e2009
JB
898
899 /* If this is a defun, find the arguments and print them. If
900 this function takes MANY or UNEVALLED args, then the C source
901 won't give the names of the arguments, so we shouldn't bother
74c55c82
GM
902 trying to find them.
903
a5979c0e
MB
904 Various doc-string styles:
905 0: DEFUN (..., "DOC") (args) [!comment]
906 1: DEFUN (..., /\* DOC *\/ (args)) [comment && !doc_keyword]
907 2: DEFUN (..., doc: /\* DOC *\/) (args) [comment && doc_keyword]
908 */
d097ad57 909 if (defunflag && maxargs != -1 && !saw_usage)
f2cc4248
RS
910 {
911 char argbuf[1024], *p = argbuf;
74c55c82 912
a5979c0e 913 if (!comment || doc_keyword)
74c55c82
GM
914 while (c != ')')
915 {
916 if (c < 0)
917 goto eof;
918 c = getc (infile);
919 }
a00e9335 920
f2cc4248
RS
921 /* Skip into arguments. */
922 while (c != '(')
923 {
924 if (c < 0)
925 goto eof;
926 c = getc (infile);
927 }
928 /* Copy arguments into ARGBUF. */
929 *p++ = c;
930 do
931 *p++ = c = getc (infile);
932 while (c != ')');
933 *p = '\0';
934 /* Output them. */
935 fprintf (outfile, "\n\n");
4df52042 936 write_c_args (outfile, input_buffer, argbuf, minargs, maxargs);
f2cc4248 937 }
1e042160
SM
938 else if (defunflag && maxargs == -1 && !saw_usage)
939 /* The DOC should provide the usage form. */
4df52042
PE
940 fprintf (stderr, "Missing `usage' for function `%s'.\n",
941 input_buffer);
f2cc4248
RS
942 }
943 }
944 eof:
945 fclose (infile);
946 return 0;
947}
948\f
949/* Read a file of Lisp code, compiled or interpreted.
950 Looks for
951 (defun NAME ARGS DOCSTRING ...)
23d6b5a6 952 (defmacro NAME ARGS DOCSTRING ...)
34e778a6 953 (defsubst NAME ARGS DOCSTRING ...)
23d6b5a6 954 (autoload (quote NAME) FILE DOCSTRING ...)
f2cc4248
RS
955 (defvar NAME VALUE DOCSTRING)
956 (defconst NAME VALUE DOCSTRING)
23d6b5a6
JB
957 (fset (quote NAME) (make-byte-code ... DOCSTRING ...))
958 (fset (quote NAME) #[... DOCSTRING ...])
2d6e2619 959 (defalias (quote NAME) #[... DOCSTRING ...])
3fe77f98 960 (custom-declare-variable (quote NAME) VALUE DOCSTRING ...)
f2cc4248 961 starting in column zero.
23d6b5a6 962 (quote NAME) may appear as 'NAME as well.
b5ff43cc
RS
963
964 We also look for #@LENGTH CONTENTS^_ at the beginning of the line.
965 When we find that, we save it for the following defining-form,
966 and we use that instead of reading a doc string within that defining-form.
967
a00e9335 968 For defvar, defconst, and fset we skip to the docstring with a kludgy
23d6b5a6 969 formatting convention: all docstrings must appear on the same line as the
a00e9335 970 initial open-paren (the one in column zero) and must contain a backslash
b0f08a24 971 and a newline immediately after the initial double-quote. No newlines
23d6b5a6 972 must appear between the beginning of the form and the first double-quote.
b0f08a24
DL
973 For defun, defmacro, and autoload, we know how to skip over the
974 arglist, but the doc string must still have a backslash and newline
a00e9335 975 immediately after the double quote.
b0f08a24
DL
976 The only source files that must follow this convention are preloaded
977 uncompiled ones like loaddefs.el and bindings.el; aside
23d6b5a6
JB
978 from that, it is always the .elc file that we look at, and they are no
979 problem because byte-compiler output follows this convention.
f2cc4248
RS
980 The NAME and DOCSTRING are output.
981 NAME is preceded by `F' for a function or `V' for a variable.
982 An entry is output only if DOCSTRING has \ newline just after the opening "
983 */
984
b23b5a5b 985static void
873fbd0b 986skip_white (FILE *infile)
23d6b5a6
JB
987{
988 char c = ' ';
433d333d 989 while (c == ' ' || c == '\t' || c == '\n' || c == '\r')
23d6b5a6
JB
990 c = getc (infile);
991 ungetc (c, infile);
992}
993
b23b5a5b 994static void
873fbd0b 995read_lisp_symbol (FILE *infile, char *buffer)
23d6b5a6
JB
996{
997 char c;
998 char *fillp = buffer;
999
1000 skip_white (infile);
1001 while (1)
1002 {
1003 c = getc (infile);
1004 if (c == '\\')
1005 *(++fillp) = getc (infile);
433d333d 1006 else if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '(' || c == ')')
23d6b5a6
JB
1007 {
1008 ungetc (c, infile);
1009 *fillp = 0;
1010 break;
1011 }
1012 else
1013 *fillp++ = c;
1014 }
1015
1016 if (! buffer[0])
1017 fprintf (stderr, "## expected a symbol, got '%c'\n", c);
a00e9335 1018
23d6b5a6
JB
1019 skip_white (infile);
1020}
1021
b23b5a5b 1022static int
988e88ab 1023scan_lisp_file (const char *filename, const char *mode)
f2cc4248
RS
1024{
1025 FILE *infile;
1026 register int c;
b5ff43cc 1027 char *saved_string = 0;
f2cc4248 1028
00b3c7ac
TT
1029 if (generate_globals)
1030 fatal ("scanning lisp file when -g specified", 0);
1031
e3938952 1032 infile = fopen (filename, mode);
f2cc4248
RS
1033 if (infile == NULL)
1034 {
1035 perror (filename);
1036 return 0; /* No error */
1037 }
1038
1039 c = '\n';
1040 while (!feof (infile))
1041 {
b5ff43cc 1042 char buffer[BUFSIZ];
23d6b5a6
JB
1043 char type;
1044
66f54605 1045 /* If not at end of line, skip till we get to one. */
433d333d 1046 if (c != '\n' && c != '\r')
f2cc4248
RS
1047 {
1048 c = getc (infile);
1049 continue;
1050 }
66f54605 1051 /* Skip the line break. */
7e6972e9 1052 while (c == '\n' || c == '\r')
66f54605 1053 c = getc (infile);
b5ff43cc
RS
1054 /* Detect a dynamic doc string and save it for the next expression. */
1055 if (c == '#')
1056 {
1057 c = getc (infile);
1058 if (c == '@')
1059 {
8aec9916
JM
1060 size_t length = 0;
1061 size_t i;
b5ff43cc
RS
1062
1063 /* Read the length. */
1064 while ((c = getc (infile),
1065 c >= '0' && c <= '9'))
1066 {
1067 length *= 10;
1068 length += c - '0';
1069 }
1070
8aec9916
JM
1071 if (length <= 1)
1072 fatal ("invalid dynamic doc string length", "");
1073
1074 if (c != ' ')
1075 fatal ("space not found after dynamic doc string length", "");
1076
b5ff43cc
RS
1077 /* The next character is a space that is counted in the length
1078 but not part of the doc string.
1079 We already read it, so just ignore it. */
1080 length--;
1081
1082 /* Read in the contents. */
e0f59195 1083 free (saved_string);
938ebc4f 1084 saved_string = (char *) xmalloc (length);
b5ff43cc
RS
1085 for (i = 0; i < length; i++)
1086 saved_string[i] = getc (infile);
1087 /* The last character is a ^_.
1088 That is needed in the .elc file
1089 but it is redundant in DOC. So get rid of it here. */
1090 saved_string[length - 1] = 0;
66f54605 1091 /* Skip the line break. */
8aec9916 1092 while (c == '\n' || c == '\r')
66f54605
PR
1093 c = getc (infile);
1094 /* Skip the following line. */
433d333d 1095 while (c != '\n' && c != '\r')
b5ff43cc
RS
1096 c = getc (infile);
1097 }
1098 continue;
1099 }
1100
f2cc4248
RS
1101 if (c != '(')
1102 continue;
a8a7afbe 1103
23d6b5a6
JB
1104 read_lisp_symbol (infile, buffer);
1105
66f54605 1106 if (! strcmp (buffer, "defun")
34e778a6
AS
1107 || ! strcmp (buffer, "defmacro")
1108 || ! strcmp (buffer, "defsubst"))
f2cc4248 1109 {
23d6b5a6
JB
1110 type = 'F';
1111 read_lisp_symbol (infile, buffer);
f2cc4248 1112
23d6b5a6 1113 /* Skip the arguments: either "nil" or a list in parens */
f2cc4248 1114
23d6b5a6
JB
1115 c = getc (infile);
1116 if (c == 'n') /* nil */
f2cc4248 1117 {
66f54605
PR
1118 if ((c = getc (infile)) != 'i'
1119 || (c = getc (infile)) != 'l')
23d6b5a6
JB
1120 {
1121 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
1122 buffer, filename);
1123 continue;
1124 }
f2cc4248 1125 }
23d6b5a6 1126 else if (c != '(')
f2cc4248 1127 {
23d6b5a6
JB
1128 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
1129 buffer, filename);
1130 continue;
f2cc4248 1131 }
23d6b5a6
JB
1132 else
1133 while (c != ')')
f2cc4248 1134 c = getc (infile);
23d6b5a6
JB
1135 skip_white (infile);
1136
1137 /* If the next three characters aren't `dquote bslash newline'
1138 then we're not reading a docstring.
1139 */
66f54605
PR
1140 if ((c = getc (infile)) != '"'
1141 || (c = getc (infile)) != '\\'
1142 || ((c = getc (infile)) != '\n' && c != '\r'))
f2cc4248 1143 {
23d6b5a6
JB
1144#ifdef DEBUG
1145 fprintf (stderr, "## non-docstring in %s (%s)\n",
1146 buffer, filename);
1147#endif
1148 continue;
f2cc4248 1149 }
f2cc4248 1150 }
a8a7afbe 1151
420b63ad 1152 /* defcustom can only occur in uncompiled Lisp files. */
66f54605 1153 else if (! strcmp (buffer, "defvar")
420b63ad
GM
1154 || ! strcmp (buffer, "defconst")
1155 || ! strcmp (buffer, "defcustom"))
f2cc4248 1156 {
23d6b5a6
JB
1157 char c1 = 0, c2 = 0;
1158 type = 'V';
1159 read_lisp_symbol (infile, buffer);
a8a7afbe 1160
b5ff43cc 1161 if (saved_string == 0)
f2cc4248 1162 {
b5ff43cc 1163
66f54605 1164 /* Skip until the end of line; remember two previous chars. */
433d333d 1165 while (c != '\n' && c != '\r' && c >= 0)
b5ff43cc
RS
1166 {
1167 c2 = c1;
1168 c1 = c;
1169 c = getc (infile);
1170 }
a00e9335 1171
b5ff43cc
RS
1172 /* If two previous characters were " and \,
1173 this is a doc string. Otherwise, there is none. */
1174 if (c2 != '"' || c1 != '\\')
1175 {
23d6b5a6 1176#ifdef DEBUG
b5ff43cc
RS
1177 fprintf (stderr, "## non-docstring in %s (%s)\n",
1178 buffer, filename);
23d6b5a6 1179#endif
b5ff43cc
RS
1180 continue;
1181 }
f2cc4248 1182 }
23d6b5a6
JB
1183 }
1184
f6195dfb
DN
1185 else if (! strcmp (buffer, "custom-declare-variable")
1186 || ! strcmp (buffer, "defvaralias")
1187 )
3fe77f98
RS
1188 {
1189 char c1 = 0, c2 = 0;
1190 type = 'V';
1191
1192 c = getc (infile);
1193 if (c == '\'')
1194 read_lisp_symbol (infile, buffer);
1195 else
1196 {
1197 if (c != '(')
1198 {
1199 fprintf (stderr,
1200 "## unparsable name in custom-declare-variable in %s\n",
1201 filename);
1202 continue;
1203 }
1204 read_lisp_symbol (infile, buffer);
1205 if (strcmp (buffer, "quote"))
1206 {
1207 fprintf (stderr,
1208 "## unparsable name in custom-declare-variable in %s\n",
1209 filename);
1210 continue;
1211 }
1212 read_lisp_symbol (infile, buffer);
1213 c = getc (infile);
1214 if (c != ')')
1215 {
1216 fprintf (stderr,
1217 "## unparsable quoted name in custom-declare-variable in %s\n",
1218 filename);
1219 continue;
1220 }
1221 }
1222
1223 if (saved_string == 0)
1224 {
66f54605 1225 /* Skip to end of line; remember the two previous chars. */
433d333d 1226 while (c != '\n' && c != '\r' && c >= 0)
3fe77f98
RS
1227 {
1228 c2 = c1;
1229 c1 = c;
1230 c = getc (infile);
1231 }
a00e9335 1232
3fe77f98
RS
1233 /* If two previous characters were " and \,
1234 this is a doc string. Otherwise, there is none. */
1235 if (c2 != '"' || c1 != '\\')
1236 {
1237#ifdef DEBUG
1238 fprintf (stderr, "## non-docstring in %s (%s)\n",
1239 buffer, filename);
1240#endif
1241 continue;
1242 }
1243 }
1244 }
1245
2d6e2619 1246 else if (! strcmp (buffer, "fset") || ! strcmp (buffer, "defalias"))
23d6b5a6
JB
1247 {
1248 char c1 = 0, c2 = 0;
1249 type = 'F';
a8a7afbe 1250
23d6b5a6
JB
1251 c = getc (infile);
1252 if (c == '\'')
1253 read_lisp_symbol (infile, buffer);
1254 else
f2cc4248 1255 {
23d6b5a6
JB
1256 if (c != '(')
1257 {
1258 fprintf (stderr, "## unparsable name in fset in %s\n",
1259 filename);
1260 continue;
1261 }
1262 read_lisp_symbol (infile, buffer);
1263 if (strcmp (buffer, "quote"))
1264 {
1265 fprintf (stderr, "## unparsable name in fset in %s\n",
1266 filename);
1267 continue;
1268 }
1269 read_lisp_symbol (infile, buffer);
f2cc4248 1270 c = getc (infile);
23d6b5a6
JB
1271 if (c != ')')
1272 {
1273 fprintf (stderr,
1274 "## unparsable quoted name in fset in %s\n",
1275 filename);
1276 continue;
1277 }
f2cc4248 1278 }
f2cc4248 1279
b5ff43cc 1280 if (saved_string == 0)
f2cc4248 1281 {
66f54605 1282 /* Skip to end of line; remember the two previous chars. */
433d333d 1283 while (c != '\n' && c != '\r' && c >= 0)
b5ff43cc
RS
1284 {
1285 c2 = c1;
1286 c1 = c;
1287 c = getc (infile);
1288 }
a00e9335 1289
b5ff43cc
RS
1290 /* If two previous characters were " and \,
1291 this is a doc string. Otherwise, there is none. */
1292 if (c2 != '"' || c1 != '\\')
1293 {
23d6b5a6 1294#ifdef DEBUG
b5ff43cc
RS
1295 fprintf (stderr, "## non-docstring in %s (%s)\n",
1296 buffer, filename);
23d6b5a6 1297#endif
b5ff43cc
RS
1298 continue;
1299 }
23d6b5a6
JB
1300 }
1301 }
f2cc4248 1302
23d6b5a6
JB
1303 else if (! strcmp (buffer, "autoload"))
1304 {
1305 type = 'F';
1306 c = getc (infile);
1307 if (c == '\'')
1308 read_lisp_symbol (infile, buffer);
1309 else
f2cc4248 1310 {
23d6b5a6 1311 if (c != '(')
f2cc4248 1312 {
23d6b5a6
JB
1313 fprintf (stderr, "## unparsable name in autoload in %s\n",
1314 filename);
1315 continue;
f2cc4248 1316 }
23d6b5a6
JB
1317 read_lisp_symbol (infile, buffer);
1318 if (strcmp (buffer, "quote"))
f2cc4248 1319 {
23d6b5a6
JB
1320 fprintf (stderr, "## unparsable name in autoload in %s\n",
1321 filename);
1322 continue;
f2cc4248 1323 }
23d6b5a6 1324 read_lisp_symbol (infile, buffer);
f2cc4248 1325 c = getc (infile);
23d6b5a6 1326 if (c != ')')
f2cc4248 1327 {
23d6b5a6
JB
1328 fprintf (stderr,
1329 "## unparsable quoted name in autoload in %s\n",
1330 filename);
1331 continue;
f2cc4248 1332 }
23d6b5a6
JB
1333 }
1334 skip_white (infile);
1335 if ((c = getc (infile)) != '\"')
1336 {
1337 fprintf (stderr, "## autoload of %s unparsable (%s)\n",
1338 buffer, filename);
f2cc4248
RS
1339 continue;
1340 }
d097ad57 1341 read_c_string_or_comment (infile, 0, 0, 0);
23d6b5a6
JB
1342 skip_white (infile);
1343
b5ff43cc 1344 if (saved_string == 0)
a8a7afbe 1345 {
b5ff43cc
RS
1346 /* If the next three characters aren't `dquote bslash newline'
1347 then we're not reading a docstring. */
66f54605
PR
1348 if ((c = getc (infile)) != '"'
1349 || (c = getc (infile)) != '\\'
1350 || ((c = getc (infile)) != '\n' && c != '\r'))
b5ff43cc 1351 {
23d6b5a6 1352#ifdef DEBUG
b5ff43cc
RS
1353 fprintf (stderr, "## non-docstring in %s (%s)\n",
1354 buffer, filename);
23d6b5a6 1355#endif
b5ff43cc
RS
1356 continue;
1357 }
a8a7afbe 1358 }
a8a7afbe 1359 }
f2cc4248 1360
23d6b5a6 1361#ifdef DEBUG
66f54605
PR
1362 else if (! strcmp (buffer, "if")
1363 || ! strcmp (buffer, "byte-code"))
a706a3bc 1364 continue;
23d6b5a6 1365#endif
f2cc4248 1366
23d6b5a6
JB
1367 else
1368 {
1369#ifdef DEBUG
bcfce2c7 1370 fprintf (stderr, "## unrecognized top-level form, %s (%s)\n",
23d6b5a6
JB
1371 buffer, filename);
1372#endif
1373 continue;
1374 }
f2cc4248 1375
b5ff43cc
RS
1376 /* At this point, we should either use the previous
1377 dynamic doc string in saved_string
1378 or gobble a doc string from the input file.
1379
1380 In the latter case, the opening quote (and leading
1381 backslash-newline) have already been read. */
1382
f2cc4248 1383 putc (037, outfile);
23d6b5a6
JB
1384 putc (type, outfile);
1385 fprintf (outfile, "%s\n", buffer);
b5ff43cc
RS
1386 if (saved_string)
1387 {
1388 fputs (saved_string, outfile);
1389 /* Don't use one dynamic doc string twice. */
1390 free (saved_string);
1391 saved_string = 0;
1392 }
1393 else
d097ad57 1394 read_c_string_or_comment (infile, 1, 0, 0);
f2cc4248
RS
1395 }
1396 fclose (infile);
1397 return 0;
1398}
ab5796a9 1399
65396510
TTN
1400
1401/* make-docfile.c ends here */