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