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