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