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