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