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