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