(read_c_string_or_comment): Renamed from
[bpt/emacs.git] / lib-src / make-docfile.c
CommitLineData
f2cc4248 1/* Generate doc-string file for GNU Emacs from source files.
291c7e74
GM
2 Copyright (C) 1985, 86, 92, 93, 94, 97, 1999, 2000, 2001
3 Free Software Foundation, Inc.
f2cc4248
RS
4
5This file is part of GNU Emacs.
6
93320c23
JA
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
e065a56e 9the Free Software Foundation; either version 2, or (at your option)
93320c23
JA
10any later version.
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
JA
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
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.
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
34b4ece5 36#define NO_SHORTNAMES /* Tell config not to load remap.h */
433d333d
RS
37#include <config.h>
38
39/* defined to be emacs_main, sys_fopen, etc. in config.h */
40#undef main
41#undef fopen
42#undef chdir
34b4ece5 43
f2cc4248 44#include <stdio.h>
e3938952
RS
45#ifdef MSDOS
46#include <fcntl.h>
47#endif /* MSDOS */
86b0513a
RS
48#ifdef WINDOWSNT
49#include <stdlib.h>
50#include <fcntl.h>
51#include <direct.h>
52#endif /* WINDOWSNT */
e3938952 53
86b0513a 54#ifdef DOS_NT
e3938952
RS
55#define READ_TEXT "rt"
56#define READ_BINARY "rb"
86b0513a 57#else /* not DOS_NT */
e3938952
RS
58#define READ_TEXT "r"
59#define READ_BINARY "r"
86b0513a 60#endif /* not DOS_NT */
f2cc4248 61
340ff9de
DM
62int scan_file ();
63int scan_lisp_file ();
64int scan_c_file ();
65
2d1985a2
KH
66#ifdef MSDOS
67/* s/msdos.h defines this as sys_chdir, but we're not linking with the
68 file where that function is defined. */
69#undef chdir
70#endif
71
a0613c61
AS
72#ifdef HAVE_UNISTD_H
73#include <unistd.h>
74#endif
75
b5ff43cc 76/* Stdio stream for output to the DOC file. */
f2cc4248
RS
77FILE *outfile;
78
b5ff43cc
RS
79/* Name this program was invoked with. */
80char *progname;
81
82/* Print error message. `s1' is printf control string, `s2' is arg for it. */
83
84/* VARARGS1 */
85void
86error (s1, s2)
87 char *s1, *s2;
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 */
97void
98fatal (s1, s2)
99 char *s1, *s2;
100{
101 error (s1, s2);
102 exit (1);
103}
104
105/* Like malloc but get fatal error if memory is exhausted. */
106
34b4ece5 107long *
b5ff43cc
RS
108xmalloc (size)
109 unsigned int size;
110{
34b4ece5 111 long *result = (long *) malloc (size);
b5ff43cc
RS
112 if (result == NULL)
113 fatal ("virtual memory exhausted", 0);
114 return result;
115}
116\f
340ff9de 117int
f2cc4248
RS
118main (argc, argv)
119 int argc;
120 char **argv;
121{
122 int i;
123 int err_count = 0;
a27897c9 124 int first_infile;
f2cc4248 125
b5ff43cc
RS
126 progname = argv[0];
127
4e043ed3
RS
128 outfile = stdout;
129
86b0513a 130 /* Don't put CRs in the DOC file. */
e3938952 131#ifdef MSDOS
5281dea4 132 _fmode = O_BINARY;
4e043ed3
RS
133#if 0 /* Suspicion is that this causes hanging.
134 So instead we require people to use -o on MSDOS. */
e3938952
RS
135 (stdout)->_flag &= ~_IOTEXT;
136 _setmode (fileno (stdout), O_BINARY);
4e043ed3
RS
137#endif
138 outfile = 0;
e3938952 139#endif /* MSDOS */
86b0513a
RS
140#ifdef WINDOWSNT
141 _fmode = O_BINARY;
142 _setmode (fileno (stdout), O_BINARY);
143#endif /* WINDOWSNT */
144
f2cc4248
RS
145 /* If first two args are -o FILE, output to FILE. */
146 i = 1;
147 if (argc > i + 1 && !strcmp (argv[i], "-o"))
148 {
149 outfile = fopen (argv[i + 1], "w");
150 i += 2;
151 }
152 if (argc > i + 1 && !strcmp (argv[i], "-a"))
153 {
154 outfile = fopen (argv[i + 1], "a");
155 i += 2;
156 }
d2d92f7a
JB
157 if (argc > i + 1 && !strcmp (argv[i], "-d"))
158 {
159 chdir (argv[i + 1]);
160 i += 2;
161 }
f2cc4248 162
4e043ed3
RS
163 if (outfile == 0)
164 fatal ("No output file specified", "");
165
a27897c9 166 first_infile = i;
f2cc4248 167 for (; i < argc; i++)
a27897c9
RS
168 {
169 int j;
170 /* Don't process one file twice. */
171 for (j = first_infile; j < i; j++)
172 if (! strcmp (argv[i], argv[j]))
173 break;
174 if (j == i)
175 err_count += scan_file (argv[i]);
176 }
f2cc4248 177#ifndef VMS
a27897c9 178 exit (err_count > 0);
a706b808 179#endif /* VMS */
a27897c9 180 return err_count > 0;
f2cc4248
RS
181}
182
a8a7afbe 183/* Read file FILENAME and output its doc strings to outfile. */
f2cc4248
RS
184/* Return 1 if file is not found, 0 if it is found. */
185
340ff9de 186int
f2cc4248
RS
187scan_file (filename)
188 char *filename;
189{
190 int len = strlen (filename);
dc61cb9d 191 if (len > 4 && !strcmp (filename + len - 4, ".elc"))
e3938952 192 return scan_lisp_file (filename, READ_BINARY);
dc61cb9d 193 else if (len > 3 && !strcmp (filename + len - 3, ".el"))
e3938952 194 return scan_lisp_file (filename, READ_TEXT);
f2cc4248 195 else
e3938952 196 return scan_c_file (filename, READ_TEXT);
f2cc4248
RS
197}
198\f
199char buf[128];
200
74c55c82
GM
201/* Skip a C string or C-style comment from INFILE, and return the
202 character that follows. COMMENT non-zero means skip a comment. If
203 PRINTFLAG is positive, output string contents to outfile. If it is
204 negative, store contents in buf. Convert escape sequences \n and
205 \t to newline and tab; discard \ followed by newline. */
f2cc4248 206
340ff9de 207int
74c55c82 208read_c_string_or_comment (infile, printflag, comment)
f2cc4248
RS
209 FILE *infile;
210 int printflag;
211{
212 register int c;
213 char *p = buf;
214
74c55c82
GM
215 if (comment)
216 {
217 while ((c = getc (infile)) != EOF
218 && (c == '\n' || c == '\r' || c == '\t' || c == ' '))
219 ;
220 }
221 else
222 c = getc (infile);
223
f2cc4248
RS
224 while (c != EOF)
225 {
74c55c82 226 while (c != EOF && (comment ? c != '*' : c != '"'))
f2cc4248
RS
227 {
228 if (c == '\\')
229 {
230 c = getc (infile);
433d333d 231 if (c == '\n' || c == '\r')
f2cc4248
RS
232 {
233 c = getc (infile);
234 continue;
235 }
236 if (c == 'n')
237 c = '\n';
238 if (c == 't')
239 c = '\t';
240 }
74c55c82 241
f2cc4248
RS
242 if (printflag > 0)
243 putc (c, outfile);
244 else if (printflag < 0)
245 *p++ = c;
246 c = getc (infile);
247 }
74c55c82 248
f2cc4248 249 c = getc (infile);
f2cc4248 250
74c55c82
GM
251 if (comment)
252 {
253 if (c == '/')
254 {
255 c = getc (infile);
256 break;
257 }
258 }
259 else
260 {
261 if (c != '"')
262 break;
263
264 /* If we had a "", concatenate the two strings. */
265 c = getc (infile);
266 }
267 }
268
f2cc4248
RS
269 if (printflag < 0)
270 *p = 0;
271
272 return c;
273}
74c55c82
GM
274
275
f2cc4248 276\f
069ad9ea 277/* Write to file OUT the argument names of function FUNC, whose text is in BUF.
f2cc4248
RS
278 MINARGS and MAXARGS are the minimum and maximum number of arguments. */
279
340ff9de 280void
069ad9ea 281write_c_args (out, func, buf, minargs, maxargs)
f2cc4248 282 FILE *out;
069ad9ea 283 char *func, *buf;
f2cc4248
RS
284 int minargs, maxargs;
285{
f125a9e8 286 register char *p;
30e4c427
JB
287 int in_ident = 0;
288 int just_spaced = 0;
069ad9ea 289 int need_space = 1;
f2cc4248 290
069ad9ea
RM
291 fprintf (out, "(%s", func);
292
293 if (*buf == '(')
294 ++buf;
f2cc4248 295
f125a9e8 296 for (p = buf; *p; p++)
f2cc4248 297 {
30e4c427 298 char c = *p;
3941a179 299 int ident_start = 0;
30e4c427
JB
300
301 /* Notice when we start printing a new identifier. */
302 if ((('A' <= c && c <= 'Z')
303 || ('a' <= c && c <= 'z')
304 || ('0' <= c && c <= '9')
305 || c == '_')
306 != in_ident)
f2cc4248 307 {
30e4c427
JB
308 if (!in_ident)
309 {
310 in_ident = 1;
3941a179 311 ident_start = 1;
f125a9e8 312
069ad9ea
RM
313 if (need_space)
314 putc (' ', out);
315
30e4c427
JB
316 if (minargs == 0 && maxargs > 0)
317 fprintf (out, "&optional ");
318 just_spaced = 1;
f125a9e8 319
30e4c427
JB
320 minargs--;
321 maxargs--;
322 }
323 else
324 in_ident = 0;
f2cc4248 325 }
30e4c427
JB
326
327 /* Print the C argument list as it would appear in lisp:
291c7e74
GM
328 print underscores as hyphens, and print commas and newlines
329 as spaces. Collapse adjacent spaces into one. */
330 if (c == '_')
331 c = '-';
332 else if (c == ',' || c == '\n')
333 c = ' ';
30e4c427 334
3941a179
JB
335 /* In C code, `default' is a reserved word, so we spell it
336 `defalt'; unmangle that here. */
337 if (ident_start
338 && strncmp (p, "defalt", 6) == 0
339 && ! (('A' <= p[6] && p[6] <= 'Z')
340 || ('a' <= p[6] && p[6] <= 'z')
341 || ('0' <= p[6] && p[6] <= '9')
342 || p[6] == '_'))
343 {
4607ea99 344 fprintf (out, "DEFAULT");
3941a179
JB
345 p += 5;
346 in_ident = 0;
347 just_spaced = 0;
348 }
291c7e74 349 else if (c != ' ' || !just_spaced)
069ad9ea
RM
350 {
351 if (c >= 'a' && c <= 'z')
352 /* Upcase the letter. */
353 c += 'A' - 'a';
354 putc (c, out);
355 }
30e4c427 356
291c7e74 357 just_spaced = c == ' ';
069ad9ea 358 need_space = 0;
f2cc4248 359 }
f2cc4248
RS
360}
361\f
362/* Read through a c file. If a .o file is named,
363 the corresponding .c file is read instead.
364 Looks for DEFUN constructs such as are defined in ../src/lisp.h.
365 Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED. */
366
340ff9de 367int
e3938952
RS
368scan_c_file (filename, mode)
369 char *filename, *mode;
f2cc4248
RS
370{
371 FILE *infile;
372 register int c;
373 register int commas;
374 register int defunflag;
84128dee 375 register int defvarperbufferflag;
f2cc4248
RS
376 register int defvarflag;
377 int minargs, maxargs;
1feb8ae1 378 int extension = filename[strlen (filename) - 1];
f2cc4248 379
1feb8ae1 380 if (extension == 'o')
f2cc4248
RS
381 filename[strlen (filename) - 1] = 'c';
382
e3938952 383 infile = fopen (filename, mode);
f2cc4248
RS
384
385 /* No error if non-ex input file */
386 if (infile == NULL)
387 {
388 perror (filename);
389 return 0;
390 }
391
1feb8ae1
RS
392 /* Reset extension to be able to detect duplicate files. */
393 filename[strlen (filename) - 1] = extension;
394
f2cc4248
RS
395 c = '\n';
396 while (!feof (infile))
397 {
433d333d 398 if (c != '\n' && c != '\r')
f2cc4248
RS
399 {
400 c = getc (infile);
401 continue;
402 }
403 c = getc (infile);
404 if (c == ' ')
405 {
406 while (c == ' ')
407 c = getc (infile);
408 if (c != 'D')
409 continue;
410 c = getc (infile);
411 if (c != 'E')
412 continue;
413 c = getc (infile);
414 if (c != 'F')
415 continue;
416 c = getc (infile);
417 if (c != 'V')
418 continue;
84128dee
JB
419 c = getc (infile);
420 if (c != 'A')
421 continue;
422 c = getc (infile);
423 if (c != 'R')
424 continue;
425 c = getc (infile);
426 if (c != '_')
427 continue;
428
f2cc4248
RS
429 defvarflag = 1;
430 defunflag = 0;
84128dee
JB
431
432 c = getc (infile);
433 defvarperbufferflag = (c == 'P');
434
f2cc4248
RS
435 c = getc (infile);
436 }
437 else if (c == 'D')
438 {
439 c = getc (infile);
440 if (c != 'E')
441 continue;
442 c = getc (infile);
443 if (c != 'F')
444 continue;
445 c = getc (infile);
446 defunflag = c == 'U';
447 defvarflag = 0;
448 }
449 else continue;
450
451 while (c != '(')
452 {
453 if (c < 0)
454 goto eof;
455 c = getc (infile);
456 }
457
74c55c82 458 /* Lisp variable or function name. */
f2cc4248
RS
459 c = getc (infile);
460 if (c != '"')
461 continue;
74c55c82
GM
462 c = read_c_string_or_comment (infile, -1, 0);
463
464 /* DEFVAR_LISP ("name", addr /\* doc *\/)
465 DEFVAR_LISP ("name", addr, doc) */
f2cc4248
RS
466
467 if (defunflag)
468 commas = 5;
84128dee
JB
469 else if (defvarperbufferflag)
470 commas = 2;
f2cc4248
RS
471 else if (defvarflag)
472 commas = 1;
473 else /* For DEFSIMPLE and DEFPRED */
474 commas = 2;
475
476 while (commas)
477 {
478 if (c == ',')
479 {
480 commas--;
74c55c82 481
f2cc4248
RS
482 if (defunflag && (commas == 1 || commas == 2))
483 {
484 do
485 c = getc (infile);
433d333d 486 while (c == ' ' || c == '\n' || c == '\r' || c == '\t');
f2cc4248
RS
487 if (c < 0)
488 goto eof;
489 ungetc (c, infile);
490 if (commas == 2) /* pick up minargs */
491 fscanf (infile, "%d", &minargs);
492 else /* pick up maxargs */
493 if (c == 'M' || c == 'U') /* MANY || UNEVALLED */
494 maxargs = -1;
495 else
496 fscanf (infile, "%d", &maxargs);
497 }
498 }
74c55c82
GM
499
500 if (c == EOF)
f2cc4248
RS
501 goto eof;
502 c = getc (infile);
503 }
74c55c82 504
433d333d 505 while (c == ' ' || c == '\n' || c == '\r' || c == '\t')
f2cc4248 506 c = getc (infile);
74c55c82 507
f2cc4248 508 if (c == '"')
74c55c82
GM
509 c = read_c_string_or_comment (infile, 0, 0);
510
511 while (c != EOF && c != ',' && c != '/')
f2cc4248 512 c = getc (infile);
74c55c82
GM
513 if (c == ',')
514 {
515 c = getc (infile);
516 while (c == ' ' || c == '\n' || c == '\r' || c == '\t')
517 c = getc (infile);
518 }
f2cc4248 519
74c55c82
GM
520 if (c == '"'
521 || (c == '/'
522 && (c = getc (infile),
523 ungetc (c, infile),
524 c == '*')))
f2cc4248 525 {
74c55c82
GM
526 int comment = c != '"';
527
f2cc4248
RS
528 putc (037, outfile);
529 putc (defvarflag ? 'V' : 'F', outfile);
530 fprintf (outfile, "%s\n", buf);
74c55c82
GM
531
532 if (comment)
533 getc (infile); /* Skip past `*' */
534 c = read_c_string_or_comment (infile, 1, comment);
772e2009
JB
535
536 /* If this is a defun, find the arguments and print them. If
537 this function takes MANY or UNEVALLED args, then the C source
538 won't give the names of the arguments, so we shouldn't bother
74c55c82
GM
539 trying to find them.
540
541 Old: DEFUN (..., "DOC") (args)
542 New: DEFUN (..., /\* DOC *\/ (args)) */
772e2009 543 if (defunflag && maxargs != -1)
f2cc4248
RS
544 {
545 char argbuf[1024], *p = argbuf;
74c55c82
GM
546
547 if (!comment)
548 while (c != ')')
549 {
550 if (c < 0)
551 goto eof;
552 c = getc (infile);
553 }
554
f2cc4248
RS
555 /* Skip into arguments. */
556 while (c != '(')
557 {
558 if (c < 0)
559 goto eof;
560 c = getc (infile);
561 }
562 /* Copy arguments into ARGBUF. */
563 *p++ = c;
564 do
565 *p++ = c = getc (infile);
566 while (c != ')');
567 *p = '\0';
568 /* Output them. */
569 fprintf (outfile, "\n\n");
069ad9ea 570 write_c_args (outfile, buf, argbuf, minargs, maxargs);
f2cc4248
RS
571 }
572 }
573 }
574 eof:
575 fclose (infile);
576 return 0;
577}
578\f
579/* Read a file of Lisp code, compiled or interpreted.
580 Looks for
581 (defun NAME ARGS DOCSTRING ...)
23d6b5a6 582 (defmacro NAME ARGS DOCSTRING ...)
34e778a6 583 (defsubst NAME ARGS DOCSTRING ...)
23d6b5a6 584 (autoload (quote NAME) FILE DOCSTRING ...)
f2cc4248
RS
585 (defvar NAME VALUE DOCSTRING)
586 (defconst NAME VALUE DOCSTRING)
23d6b5a6
JB
587 (fset (quote NAME) (make-byte-code ... DOCSTRING ...))
588 (fset (quote NAME) #[... DOCSTRING ...])
2d6e2619 589 (defalias (quote NAME) #[... DOCSTRING ...])
3fe77f98 590 (custom-declare-variable (quote NAME) VALUE DOCSTRING ...)
f2cc4248 591 starting in column zero.
23d6b5a6 592 (quote NAME) may appear as 'NAME as well.
b5ff43cc
RS
593
594 We also look for #@LENGTH CONTENTS^_ at the beginning of the line.
595 When we find that, we save it for the following defining-form,
596 and we use that instead of reading a doc string within that defining-form.
597
eb8c3be9 598 For defvar, defconst, and fset we skip to the docstring with a kludgy
23d6b5a6
JB
599 formatting convention: all docstrings must appear on the same line as the
600 initial open-paren (the one in column zero) and must contain a backslash
b0f08a24 601 and a newline immediately after the initial double-quote. No newlines
23d6b5a6 602 must appear between the beginning of the form and the first double-quote.
b0f08a24
DL
603 For defun, defmacro, and autoload, we know how to skip over the
604 arglist, but the doc string must still have a backslash and newline
605 immediately after the double quote.
606 The only source files that must follow this convention are preloaded
607 uncompiled ones like loaddefs.el and bindings.el; aside
23d6b5a6
JB
608 from that, it is always the .elc file that we look at, and they are no
609 problem because byte-compiler output follows this convention.
f2cc4248
RS
610 The NAME and DOCSTRING are output.
611 NAME is preceded by `F' for a function or `V' for a variable.
612 An entry is output only if DOCSTRING has \ newline just after the opening "
613 */
614
23d6b5a6
JB
615void
616skip_white (infile)
617 FILE *infile;
618{
619 char c = ' ';
433d333d 620 while (c == ' ' || c == '\t' || c == '\n' || c == '\r')
23d6b5a6
JB
621 c = getc (infile);
622 ungetc (c, infile);
623}
624
625void
626read_lisp_symbol (infile, buffer)
627 FILE *infile;
628 char *buffer;
629{
630 char c;
631 char *fillp = buffer;
632
633 skip_white (infile);
634 while (1)
635 {
636 c = getc (infile);
637 if (c == '\\')
638 *(++fillp) = getc (infile);
433d333d 639 else if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '(' || c == ')')
23d6b5a6
JB
640 {
641 ungetc (c, infile);
642 *fillp = 0;
643 break;
644 }
645 else
646 *fillp++ = c;
647 }
648
649 if (! buffer[0])
650 fprintf (stderr, "## expected a symbol, got '%c'\n", c);
651
652 skip_white (infile);
653}
654
340ff9de 655int
e3938952
RS
656scan_lisp_file (filename, mode)
657 char *filename, *mode;
f2cc4248
RS
658{
659 FILE *infile;
660 register int c;
b5ff43cc 661 char *saved_string = 0;
f2cc4248 662
e3938952 663 infile = fopen (filename, mode);
f2cc4248
RS
664 if (infile == NULL)
665 {
666 perror (filename);
667 return 0; /* No error */
668 }
669
670 c = '\n';
671 while (!feof (infile))
672 {
b5ff43cc 673 char buffer[BUFSIZ];
23d6b5a6
JB
674 char type;
675
66f54605 676 /* If not at end of line, skip till we get to one. */
433d333d 677 if (c != '\n' && c != '\r')
f2cc4248
RS
678 {
679 c = getc (infile);
680 continue;
681 }
66f54605 682 /* Skip the line break. */
7e6972e9 683 while (c == '\n' || c == '\r')
66f54605 684 c = getc (infile);
b5ff43cc
RS
685 /* Detect a dynamic doc string and save it for the next expression. */
686 if (c == '#')
687 {
688 c = getc (infile);
689 if (c == '@')
690 {
691 int length = 0;
692 int i;
693
694 /* Read the length. */
695 while ((c = getc (infile),
696 c >= '0' && c <= '9'))
697 {
698 length *= 10;
699 length += c - '0';
700 }
701
702 /* The next character is a space that is counted in the length
703 but not part of the doc string.
704 We already read it, so just ignore it. */
705 length--;
706
707 /* Read in the contents. */
708 if (saved_string != 0)
709 free (saved_string);
710 saved_string = (char *) malloc (length);
711 for (i = 0; i < length; i++)
712 saved_string[i] = getc (infile);
713 /* The last character is a ^_.
714 That is needed in the .elc file
715 but it is redundant in DOC. So get rid of it here. */
716 saved_string[length - 1] = 0;
66f54605
PR
717 /* Skip the line break. */
718 while (c == '\n' && c == '\r')
719 c = getc (infile);
720 /* Skip the following line. */
433d333d 721 while (c != '\n' && c != '\r')
b5ff43cc
RS
722 c = getc (infile);
723 }
724 continue;
725 }
726
f2cc4248
RS
727 if (c != '(')
728 continue;
a8a7afbe 729
23d6b5a6
JB
730 read_lisp_symbol (infile, buffer);
731
66f54605 732 if (! strcmp (buffer, "defun")
34e778a6
AS
733 || ! strcmp (buffer, "defmacro")
734 || ! strcmp (buffer, "defsubst"))
f2cc4248 735 {
23d6b5a6
JB
736 type = 'F';
737 read_lisp_symbol (infile, buffer);
f2cc4248 738
23d6b5a6 739 /* Skip the arguments: either "nil" or a list in parens */
f2cc4248 740
23d6b5a6
JB
741 c = getc (infile);
742 if (c == 'n') /* nil */
f2cc4248 743 {
66f54605
PR
744 if ((c = getc (infile)) != 'i'
745 || (c = getc (infile)) != 'l')
23d6b5a6
JB
746 {
747 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
748 buffer, filename);
749 continue;
750 }
f2cc4248 751 }
23d6b5a6 752 else if (c != '(')
f2cc4248 753 {
23d6b5a6
JB
754 fprintf (stderr, "## unparsable arglist in %s (%s)\n",
755 buffer, filename);
756 continue;
f2cc4248 757 }
23d6b5a6
JB
758 else
759 while (c != ')')
f2cc4248 760 c = getc (infile);
23d6b5a6
JB
761 skip_white (infile);
762
763 /* If the next three characters aren't `dquote bslash newline'
764 then we're not reading a docstring.
765 */
66f54605
PR
766 if ((c = getc (infile)) != '"'
767 || (c = getc (infile)) != '\\'
768 || ((c = getc (infile)) != '\n' && c != '\r'))
f2cc4248 769 {
23d6b5a6
JB
770#ifdef DEBUG
771 fprintf (stderr, "## non-docstring in %s (%s)\n",
772 buffer, filename);
773#endif
774 continue;
f2cc4248 775 }
f2cc4248 776 }
a8a7afbe 777
66f54605
PR
778 else if (! strcmp (buffer, "defvar")
779 || ! strcmp (buffer, "defconst"))
f2cc4248 780 {
23d6b5a6
JB
781 char c1 = 0, c2 = 0;
782 type = 'V';
783 read_lisp_symbol (infile, buffer);
a8a7afbe 784
b5ff43cc 785 if (saved_string == 0)
f2cc4248 786 {
b5ff43cc 787
66f54605 788 /* Skip until the end of line; remember two previous chars. */
433d333d 789 while (c != '\n' && c != '\r' && c >= 0)
b5ff43cc
RS
790 {
791 c2 = c1;
792 c1 = c;
793 c = getc (infile);
794 }
23d6b5a6 795
b5ff43cc
RS
796 /* If two previous characters were " and \,
797 this is a doc string. Otherwise, there is none. */
798 if (c2 != '"' || c1 != '\\')
799 {
23d6b5a6 800#ifdef DEBUG
b5ff43cc
RS
801 fprintf (stderr, "## non-docstring in %s (%s)\n",
802 buffer, filename);
23d6b5a6 803#endif
b5ff43cc
RS
804 continue;
805 }
f2cc4248 806 }
23d6b5a6
JB
807 }
808
3fe77f98
RS
809 else if (! strcmp (buffer, "custom-declare-variable"))
810 {
811 char c1 = 0, c2 = 0;
812 type = 'V';
813
814 c = getc (infile);
815 if (c == '\'')
816 read_lisp_symbol (infile, buffer);
817 else
818 {
819 if (c != '(')
820 {
821 fprintf (stderr,
822 "## unparsable name in custom-declare-variable in %s\n",
823 filename);
824 continue;
825 }
826 read_lisp_symbol (infile, buffer);
827 if (strcmp (buffer, "quote"))
828 {
829 fprintf (stderr,
830 "## unparsable name in custom-declare-variable in %s\n",
831 filename);
832 continue;
833 }
834 read_lisp_symbol (infile, buffer);
835 c = getc (infile);
836 if (c != ')')
837 {
838 fprintf (stderr,
839 "## unparsable quoted name in custom-declare-variable in %s\n",
840 filename);
841 continue;
842 }
843 }
844
845 if (saved_string == 0)
846 {
66f54605 847 /* Skip to end of line; remember the two previous chars. */
433d333d 848 while (c != '\n' && c != '\r' && c >= 0)
3fe77f98
RS
849 {
850 c2 = c1;
851 c1 = c;
852 c = getc (infile);
853 }
854
855 /* If two previous characters were " and \,
856 this is a doc string. Otherwise, there is none. */
857 if (c2 != '"' || c1 != '\\')
858 {
859#ifdef DEBUG
860 fprintf (stderr, "## non-docstring in %s (%s)\n",
861 buffer, filename);
862#endif
863 continue;
864 }
865 }
866 }
867
2d6e2619 868 else if (! strcmp (buffer, "fset") || ! strcmp (buffer, "defalias"))
23d6b5a6
JB
869 {
870 char c1 = 0, c2 = 0;
871 type = 'F';
a8a7afbe 872
23d6b5a6
JB
873 c = getc (infile);
874 if (c == '\'')
875 read_lisp_symbol (infile, buffer);
876 else
f2cc4248 877 {
23d6b5a6
JB
878 if (c != '(')
879 {
880 fprintf (stderr, "## unparsable name in fset in %s\n",
881 filename);
882 continue;
883 }
884 read_lisp_symbol (infile, buffer);
885 if (strcmp (buffer, "quote"))
886 {
887 fprintf (stderr, "## unparsable name in fset in %s\n",
888 filename);
889 continue;
890 }
891 read_lisp_symbol (infile, buffer);
f2cc4248 892 c = getc (infile);
23d6b5a6
JB
893 if (c != ')')
894 {
895 fprintf (stderr,
896 "## unparsable quoted name in fset in %s\n",
897 filename);
898 continue;
899 }
f2cc4248 900 }
f2cc4248 901
b5ff43cc 902 if (saved_string == 0)
f2cc4248 903 {
66f54605 904 /* Skip to end of line; remember the two previous chars. */
433d333d 905 while (c != '\n' && c != '\r' && c >= 0)
b5ff43cc
RS
906 {
907 c2 = c1;
908 c1 = c;
909 c = getc (infile);
910 }
23d6b5a6 911
b5ff43cc
RS
912 /* If two previous characters were " and \,
913 this is a doc string. Otherwise, there is none. */
914 if (c2 != '"' || c1 != '\\')
915 {
23d6b5a6 916#ifdef DEBUG
b5ff43cc
RS
917 fprintf (stderr, "## non-docstring in %s (%s)\n",
918 buffer, filename);
23d6b5a6 919#endif
b5ff43cc
RS
920 continue;
921 }
23d6b5a6
JB
922 }
923 }
f2cc4248 924
23d6b5a6
JB
925 else if (! strcmp (buffer, "autoload"))
926 {
927 type = 'F';
928 c = getc (infile);
929 if (c == '\'')
930 read_lisp_symbol (infile, buffer);
931 else
f2cc4248 932 {
23d6b5a6 933 if (c != '(')
f2cc4248 934 {
23d6b5a6
JB
935 fprintf (stderr, "## unparsable name in autoload in %s\n",
936 filename);
937 continue;
f2cc4248 938 }
23d6b5a6
JB
939 read_lisp_symbol (infile, buffer);
940 if (strcmp (buffer, "quote"))
f2cc4248 941 {
23d6b5a6
JB
942 fprintf (stderr, "## unparsable name in autoload in %s\n",
943 filename);
944 continue;
f2cc4248 945 }
23d6b5a6 946 read_lisp_symbol (infile, buffer);
f2cc4248 947 c = getc (infile);
23d6b5a6 948 if (c != ')')
f2cc4248 949 {
23d6b5a6
JB
950 fprintf (stderr,
951 "## unparsable quoted name in autoload in %s\n",
952 filename);
953 continue;
f2cc4248 954 }
23d6b5a6
JB
955 }
956 skip_white (infile);
957 if ((c = getc (infile)) != '\"')
958 {
959 fprintf (stderr, "## autoload of %s unparsable (%s)\n",
960 buffer, filename);
f2cc4248
RS
961 continue;
962 }
74c55c82 963 read_c_string_or_comment (infile, 0, 0);
23d6b5a6
JB
964 skip_white (infile);
965
b5ff43cc 966 if (saved_string == 0)
a8a7afbe 967 {
b5ff43cc
RS
968 /* If the next three characters aren't `dquote bslash newline'
969 then we're not reading a docstring. */
66f54605
PR
970 if ((c = getc (infile)) != '"'
971 || (c = getc (infile)) != '\\'
972 || ((c = getc (infile)) != '\n' && c != '\r'))
b5ff43cc 973 {
23d6b5a6 974#ifdef DEBUG
b5ff43cc
RS
975 fprintf (stderr, "## non-docstring in %s (%s)\n",
976 buffer, filename);
23d6b5a6 977#endif
b5ff43cc
RS
978 continue;
979 }
a8a7afbe 980 }
a8a7afbe 981 }
f2cc4248 982
23d6b5a6 983#ifdef DEBUG
66f54605
PR
984 else if (! strcmp (buffer, "if")
985 || ! strcmp (buffer, "byte-code"))
23d6b5a6
JB
986 ;
987#endif
f2cc4248 988
23d6b5a6
JB
989 else
990 {
991#ifdef DEBUG
992 fprintf (stderr, "## unrecognised top-level form, %s (%s)\n",
993 buffer, filename);
994#endif
995 continue;
996 }
f2cc4248 997
b5ff43cc
RS
998 /* At this point, we should either use the previous
999 dynamic doc string in saved_string
1000 or gobble a doc string from the input file.
1001
1002 In the latter case, the opening quote (and leading
1003 backslash-newline) have already been read. */
1004
f2cc4248 1005 putc (037, outfile);
23d6b5a6
JB
1006 putc (type, outfile);
1007 fprintf (outfile, "%s\n", buffer);
b5ff43cc
RS
1008 if (saved_string)
1009 {
1010 fputs (saved_string, outfile);
1011 /* Don't use one dynamic doc string twice. */
1012 free (saved_string);
1013 saved_string = 0;
1014 }
1015 else
74c55c82 1016 read_c_string_or_comment (infile, 1, 0);
f2cc4248
RS
1017 }
1018 fclose (infile);
1019 return 0;
1020}