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