This source file includes following definitions.
- ATTRIBUTE_FORMAT_PRINTF
- ATTRIBUTE_FORMAT_PRINTF
- ATTRIBUTE_FORMAT_PRINTF
- memory_exhausted
- xmalloc
- xrealloc
- main
- put_filename
- scan_file
- start_globals
- put_char
- scan_keyword_or_put_char
- read_c_string_or_comment
- write_c_args
- add_global
- compare_globals
- close_emacs_globals
- write_globals
- scan_c_file
- stream_match
- scan_c_stream
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 #include <config.h>
38
39 #include <stdarg.h>
40 #include <stddef.h>
41 #include <stdint.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 #include <attribute.h>
46 #include <binary-io.h>
47 #include <c-ctype.h>
48 #include <intprops.h>
49 #include <min-max.h>
50 #include <unlocked-io.h>
51
52 #ifdef WINDOWSNT
53
54
55 #undef fopen
56 #include <direct.h>
57 #endif
58
59 #ifdef DOS_NT
60
61
62
63
64
65 #undef chdir
66 #endif
67
68 static void scan_file (char *filename);
69 static void scan_c_file (char *filename, const char *mode);
70 static void scan_c_stream (FILE *infile);
71 static void start_globals (void);
72 static void write_globals (void);
73
74 #include <unistd.h>
75
76
77 static char *progname;
78
79
80 static bool generate_globals;
81
82
83
84 static void ATTRIBUTE_FORMAT_PRINTF (1, 0)
85 verror (char const *m, va_list ap)
86 {
87 fprintf (stderr, "%s: ", progname);
88 vfprintf (stderr, m, ap);
89 fprintf (stderr, "\n");
90 }
91
92
93
94 static void ATTRIBUTE_FORMAT_PRINTF (1, 2)
95 error (char const *m, ...)
96 {
97 va_list ap;
98 va_start (ap, m);
99 verror (m, ap);
100 va_end (ap);
101 }
102
103
104
105 static _Noreturn void ATTRIBUTE_FORMAT_PRINTF (1, 2)
106 fatal (char const *m, ...)
107 {
108 va_list ap;
109 va_start (ap, m);
110 verror (m, ap);
111 va_end (ap);
112 exit (EXIT_FAILURE);
113 }
114
115 static _Noreturn void
116 memory_exhausted (void)
117 {
118 fatal ("virtual memory exhausted");
119 }
120
121
122
123 static void * ATTRIBUTE_MALLOC
124 xmalloc (ptrdiff_t size)
125 {
126 void *result = malloc (size);
127 if (result == NULL)
128 memory_exhausted ();
129 return result;
130 }
131
132
133
134 static void *
135 xrealloc (void *arg, ptrdiff_t size)
136 {
137 void *result = realloc (arg, size);
138 if (result == NULL)
139 memory_exhausted ();
140 return result;
141 }
142
143
144 int
145 main (int argc, char **argv)
146 {
147 int i;
148
149 progname = argv[0];
150
151
152 i = 1;
153 if (argc > i + 1 && !strcmp (argv[i], "-o"))
154 {
155 if (! freopen (argv[i + 1], "w", stdout))
156 {
157 perror (argv[i + 1]);
158 return EXIT_FAILURE;
159 }
160 i += 2;
161 }
162 if (argc > i + 1 && !strcmp (argv[i], "-a"))
163 {
164 if (! freopen (argv[i + 1], "a", stdout))
165 {
166 perror (argv[i + 1]);
167 return EXIT_FAILURE;
168 }
169 i += 2;
170 }
171 if (argc > i + 1 && !strcmp (argv[i], "-d"))
172 {
173 if (chdir (argv[i + 1]) != 0)
174 {
175 perror (argv[i + 1]);
176 return EXIT_FAILURE;
177 }
178 i += 2;
179 }
180 if (argc > i && !strcmp (argv[i], "-g"))
181 {
182 generate_globals = true;
183 ++i;
184 }
185
186 set_binary_mode (fileno (stdout), O_BINARY);
187
188 if (generate_globals)
189 start_globals ();
190
191 if (argc <= i)
192 scan_c_stream (stdin);
193 else
194 {
195 int first_infile = i;
196 for (; i < argc; i++)
197 {
198 int j;
199
200 for (j = first_infile; j < i; j++)
201 if (strcmp (argv[i], argv[j]) == 0)
202 break;
203 if (j == i)
204 scan_file (argv[i]);
205 }
206 }
207
208 if (generate_globals)
209 write_globals ();
210
211 if (ferror (stdout) || fclose (stdout) != 0)
212 fatal ("write error");
213
214 return EXIT_SUCCESS;
215 }
216
217
218 static void
219 put_filename (char *filename)
220 {
221 char *tmp;
222
223 for (tmp = filename; *tmp; tmp++)
224 {
225 if (IS_DIRECTORY_SEP (*tmp))
226 filename = tmp + 1;
227 }
228
229 printf ("\037S%s\n", filename);
230 }
231
232
233
234
235 static void
236 scan_file (char *filename)
237 {
238 if (!generate_globals)
239 put_filename (filename);
240 scan_c_file (filename, "r");
241 }
242
243 static void
244 start_globals (void)
245 {
246 puts ("/* This file was auto-generated by make-docfile. */");
247 puts ("/* DO NOT EDIT. */");
248 puts ("struct emacs_globals {");
249 }
250
251 static char input_buffer[128];
252
253
254 struct rcsoc_state
255 {
256
257 intmax_t pending_spaces, pending_newlines;
258
259
260 FILE *in_file;
261
262
263 char *buf_ptr;
264
265 FILE *out_file;
266
267
268
269 const char *keyword;
270
271
272 const char *cur_keyword_ptr;
273
274 bool saw_keyword;
275 };
276
277
278
279
280 static void
281 put_char (char ch, struct rcsoc_state *state)
282 {
283 char out_ch;
284 do
285 {
286 if (state->pending_newlines > 0)
287 {
288 state->pending_newlines--;
289 out_ch = '\n';
290 }
291 else if (state->pending_spaces > 0)
292 {
293 state->pending_spaces--;
294 out_ch = ' ';
295 }
296 else
297 out_ch = ch;
298
299 if (state->out_file)
300 putc (out_ch, state->out_file);
301 if (state->buf_ptr)
302 *state->buf_ptr++ = out_ch;
303 }
304 while (out_ch != ch);
305 }
306
307
308
309
310
311
312
313 static void
314 scan_keyword_or_put_char (char ch, struct rcsoc_state *state)
315 {
316 if (state->keyword
317 && *state->cur_keyword_ptr == ch
318 && (state->cur_keyword_ptr > state->keyword
319 || state->pending_newlines > 0))
320
321
322 {
323 if (*++state->cur_keyword_ptr == '\0')
324
325 {
326 state->saw_keyword = true;
327
328
329 state->cur_keyword_ptr = state->keyword;
330
331
332 state->pending_newlines = 2;
333 state->pending_spaces = 0;
334
335
336
337 int c;
338 do
339 c = getc (state->in_file);
340 while (c == ' ' || c == '\n');
341
342
343 if (c != '(')
344 fatal ("Missing '(' after keyword");
345 put_char (c, state);
346
347
348 do
349 {
350 c = getc (state->in_file);
351 if (c == EOF)
352 fatal ("Unexpected EOF after keyword");
353 }
354 while (c != ' ' && c != ')');
355
356 put_char ('f', state);
357 put_char ('n', state);
358
359
360 ungetc (c, state->in_file);
361 }
362 }
363 else
364 {
365 if (state->keyword && state->cur_keyword_ptr > state->keyword)
366
367
368
369 {
370 const char *p;
371
372 for (p = state->keyword; p < state->cur_keyword_ptr; p++)
373 put_char (*p, state);
374
375 state->cur_keyword_ptr = state->keyword;
376 }
377
378 put_char (ch, state);
379 }
380 }
381
382
383
384
385
386
387
388
389
390
391
392 static int
393 read_c_string_or_comment (FILE *infile, int printflag, bool comment,
394 bool *saw_usage)
395 {
396 int c;
397 struct rcsoc_state state;
398
399 state.in_file = infile;
400 state.buf_ptr = (printflag < 0 ? input_buffer : 0);
401 state.out_file = (printflag > 0 ? stdout : 0);
402 state.pending_spaces = 0;
403 state.pending_newlines = 0;
404 state.keyword = (saw_usage ? "usage:" : 0);
405 state.cur_keyword_ptr = state.keyword;
406 state.saw_keyword = false;
407
408 c = getc (infile);
409 if (comment)
410 while (c_isspace (c))
411 c = getc (infile);
412
413 while (c != EOF)
414 {
415 while (c != EOF && (comment ? c != '*' : c != '"'))
416 {
417 if (c == '\\')
418 {
419 c = getc (infile);
420 switch (c)
421 {
422 case '\n': case '\r':
423 c = getc (infile);
424 continue;
425 case 'n': c = '\n'; break;
426 case 't': c = '\t'; break;
427 }
428 }
429
430 if (c == ' ')
431 state.pending_spaces++;
432 else if (c == '\n')
433 {
434 state.pending_newlines++;
435 state.pending_spaces = 0;
436 }
437 else
438 scan_keyword_or_put_char (c, &state);
439
440 c = getc (infile);
441 }
442
443 if (c != EOF)
444 c = getc (infile);
445
446 if (comment)
447 {
448 if (c == '/')
449 {
450 c = getc (infile);
451 break;
452 }
453
454 scan_keyword_or_put_char ('*', &state);
455 }
456 else
457 {
458 if (c != '"')
459 break;
460
461
462 c = getc (infile);
463 }
464 }
465
466 if (printflag < 0)
467 *state.buf_ptr = 0;
468
469 if (saw_usage)
470 *saw_usage = state.saw_keyword;
471
472 return c;
473 }
474
475
476
477
478
479
480 static void
481 write_c_args (char *func, char *buf, int minargs, int maxargs)
482 {
483 char *p;
484 bool in_ident = false;
485 char *ident_start UNINIT;
486 ptrdiff_t ident_length = 0;
487
488 fputs ("(fn", stdout);
489
490 if (*buf == '(')
491 ++buf;
492
493 for (p = buf; *p; p++)
494 {
495 char c = *p;
496
497
498 if ((c_isalnum (c) || c == '_')
499 != in_ident)
500 {
501 if (!in_ident)
502 {
503 in_ident = true;
504 ident_start = p;
505 }
506 else
507 {
508 in_ident = false;
509 ident_length = p - ident_start;
510 }
511 }
512
513
514
515 if (c == ',' || c == ')')
516 {
517 if (ident_length == 0)
518 {
519 error ("empty arg list for '%s' should be (void), not ()", func);
520 continue;
521 }
522
523 if (strncmp (ident_start, "void", ident_length) == 0)
524 continue;
525
526 putchar (' ');
527
528 if (minargs == 0 && maxargs > 0)
529 fputs ("&optional ", stdout);
530
531 minargs--;
532 maxargs--;
533
534
535
536 if (ident_length == 6 && memcmp (ident_start, "defalt", 6) == 0)
537 fputs ("DEFAULT", stdout);
538 else
539 while (ident_length-- > 0)
540 {
541 c = c_toupper (*ident_start++);
542 if (c == '_')
543
544 c = '-';
545 putchar (c);
546 }
547 }
548 }
549
550 putchar (')');
551 }
552
553
554
555
556 enum global_type
557 {
558 INVALID,
559 LISP_OBJECT,
560 EMACS_INTEGER,
561 BOOLEAN,
562 SYMBOL,
563 FUNCTION
564 };
565
566
567 struct global
568 {
569 enum global_type type;
570 char *name;
571 int flags;
572 union
573 {
574 int value;
575 char const *svalue;
576 } v;
577 };
578
579
580 enum { DEFUN_noreturn = 1, DEFUN_const = 2, DEFUN_noinline = 4 };
581
582
583
584 static ptrdiff_t num_globals;
585 static ptrdiff_t num_globals_allocated;
586 static struct global *globals;
587
588 static struct global *
589 add_global (enum global_type type, char const *name, int value,
590 char const *svalue)
591 {
592
593 if (strcmp (name, "..."))
594 {
595 if (num_globals == num_globals_allocated)
596 {
597 ptrdiff_t num_globals_max = (min (PTRDIFF_MAX, SIZE_MAX)
598 / sizeof *globals);
599 if (num_globals_allocated == num_globals_max)
600 memory_exhausted ();
601 if (num_globals_allocated < num_globals_max / 2)
602 num_globals_allocated = 2 * num_globals_allocated + 1;
603 else
604 num_globals_allocated = num_globals_max;
605 globals = xrealloc (globals, num_globals_allocated * sizeof *globals);
606 }
607
608 ++num_globals;
609
610 ptrdiff_t namesize = strlen (name) + 1;
611 char *buf = xmalloc (namesize + (svalue ? strlen (svalue) + 1 : 0));
612 globals[num_globals - 1].type = type;
613 globals[num_globals - 1].name = strcpy (buf, name);
614 if (svalue)
615 globals[num_globals - 1].v.svalue = strcpy (buf + namesize, svalue);
616 else
617 globals[num_globals - 1].v.value = value;
618 globals[num_globals - 1].flags = 0;
619 return globals + num_globals - 1;
620 }
621 return NULL;
622 }
623
624 static int
625 compare_globals (const void *a, const void *b)
626 {
627 const struct global *ga = a;
628 const struct global *gb = b;
629
630 if (ga->type != gb->type)
631 return ga->type - gb->type;
632
633
634
635
636 if (ga->type == SYMBOL)
637 {
638
639 static char const commonsym[][8]
640 = { "nil", "t", "unbound", "error", "lambda" };
641 int ncommonsym = sizeof commonsym / sizeof *commonsym;
642 int ai = ncommonsym, bi = ncommonsym;
643 for (int i = 0; i < ncommonsym; i++)
644 {
645 if (ga->name[0] == 'Q' && strcmp (ga->name + 1, commonsym[i]) == 0)
646 ai = i;
647 if (gb->name[0] == 'Q' && strcmp (gb->name + 1, commonsym[i]) == 0)
648 bi = i;
649 }
650 if (! (ai == ncommonsym && bi == ncommonsym))
651 return ai - bi;
652 }
653
654 return strcmp (ga->name, gb->name);
655 }
656
657 static void
658 close_emacs_globals (ptrdiff_t num_symbols)
659 {
660 printf (("};\n"
661 "extern struct emacs_globals globals;\n"
662 "\n"
663 "#ifndef DEFINE_SYMBOLS\n"
664 "extern\n"
665 "#endif\n"
666 "struct Lisp_Symbol lispsym[%td];\n"),
667 num_symbols);
668 }
669
670 static void
671 write_globals (void)
672 {
673 ptrdiff_t i, j;
674 bool seen_defun = false;
675 ptrdiff_t symnum = 0;
676 ptrdiff_t num_symbols = 0;
677 qsort (globals, num_globals, sizeof (struct global), compare_globals);
678
679 j = 0;
680 for (i = 0; i < num_globals; i++)
681 {
682 while (i + 1 < num_globals
683 && strcmp (globals[i].name, globals[i + 1].name) == 0)
684 {
685 if (globals[i].type == FUNCTION
686 && globals[i].v.value != globals[i + 1].v.value)
687 error ("function '%s' defined twice with differing signatures",
688 globals[i].name);
689 free (globals[i].name);
690 i++;
691 }
692 num_symbols += globals[i].type == SYMBOL;
693 globals[j++] = globals[i];
694 }
695 num_globals = j;
696
697 for (i = 0; i < num_globals; ++i)
698 {
699 char const *type = 0;
700
701 switch (globals[i].type)
702 {
703 case EMACS_INTEGER:
704 type = "intmax_t";
705 break;
706 case BOOLEAN:
707 type = "bool";
708 break;
709 case LISP_OBJECT:
710 type = "Lisp_Object";
711 break;
712 case SYMBOL:
713 case FUNCTION:
714 if (!seen_defun)
715 {
716 close_emacs_globals (num_symbols);
717 putchar ('\n');
718 seen_defun = true;
719 }
720 break;
721 default:
722 fatal ("not a recognized DEFVAR_");
723 }
724
725 if (type)
726 {
727 printf (" %s f_%s;\n", type, globals[i].name);
728 printf ("#define %s globals.f_%s\n",
729 globals[i].name, globals[i].name);
730 }
731 else if (globals[i].type == SYMBOL)
732 printf (("#define i%s %td\n"
733 "DEFINE_LISP_SYMBOL (%s)\n"),
734 globals[i].name, symnum++, globals[i].name);
735 else
736 {
737 if (globals[i].flags & DEFUN_noreturn)
738 fputs ("_Noreturn ", stdout);
739 if (globals[i].flags & DEFUN_noinline)
740 fputs ("NO_INLINE ", stdout);
741
742 printf ("EXFUN (%s, ", globals[i].name);
743 if (globals[i].v.value == -1)
744 fputs ("MANY", stdout);
745 else if (globals[i].v.value == -2)
746 fputs ("UNEVALLED", stdout);
747 else
748 printf ("%d", globals[i].v.value);
749 putchar (')');
750
751 if (globals[i].flags & DEFUN_noreturn)
752 fputs (" ATTRIBUTE_COLD", stdout);
753 if (globals[i].flags & DEFUN_const)
754 fputs (" ATTRIBUTE_CONST", stdout);
755
756 puts (";");
757 }
758 }
759
760 if (!seen_defun)
761 close_emacs_globals (num_symbols);
762
763 puts ("#ifdef DEFINE_SYMBOLS");
764 puts ("static char const *const defsym_name[] = {");
765 for (ptrdiff_t i = 0; i < num_globals; i++)
766 if (globals[i].type == SYMBOL)
767 printf ("\t\"%s\",\n", globals[i].v.svalue);
768 puts ("};");
769 puts ("#endif");
770
771 puts ("#define Qnil builtin_lisp_symbol (0)");
772 puts ("#if DEFINE_NON_NIL_Q_SYMBOL_MACROS");
773 num_symbols = 0;
774 for (ptrdiff_t i = 0; i < num_globals; i++)
775 if (globals[i].type == SYMBOL && num_symbols++ != 0)
776 printf ("# define %s builtin_lisp_symbol (%td)\n",
777 globals[i].name, num_symbols - 1);
778 puts ("#endif");
779 }
780
781
782
783
784
785
786
787 static void
788 scan_c_file (char *filename, const char *mode)
789 {
790 FILE *infile;
791 char extension = filename[strlen (filename) - 1];
792
793 if (extension == 'o')
794 filename[strlen (filename) - 1] = 'c';
795
796 infile = fopen (filename, mode);
797
798 if (infile == NULL && extension == 'o')
799 {
800
801 filename[strlen (filename) - 1] = 'm';
802 infile = fopen (filename, mode);
803 if (infile == NULL)
804 filename[strlen (filename) - 1] = 'c';
805 }
806
807 if (infile == NULL)
808 {
809 perror (filename);
810 exit (EXIT_FAILURE);
811 }
812
813
814 filename[strlen (filename) - 1] = extension;
815 scan_c_stream (infile);
816 }
817
818
819
820
821 static int
822 stream_match (FILE *infile, const char *p)
823 {
824 for (; *p; p++)
825 {
826 int c = getc (infile);
827 if (c == EOF)
828 return -1;
829 if (c != *p)
830 return 0;
831 }
832 return 1;
833 }
834
835 static void
836 scan_c_stream (FILE *infile)
837 {
838 int commas, minargs, maxargs;
839 int c = '\n';
840
841 while (!feof (infile))
842 {
843 bool doc_keyword = false;
844 bool defunflag = false;
845 bool defvarperbufferflag = false;
846 bool defvarflag = false;
847 enum global_type type = INVALID;
848 static char name[sizeof input_buffer];
849
850 if (c != '\n' && c != '\r')
851 {
852 c = getc (infile);
853 continue;
854 }
855 c = getc (infile);
856 if (c == ' ')
857 {
858 while (c == ' ')
859 c = getc (infile);
860 if (c != 'D')
861 continue;
862 c = getc (infile);
863 if (c != 'E')
864 continue;
865 c = getc (infile);
866 if (c != 'F')
867 continue;
868 c = getc (infile);
869 if (c == 'S')
870 {
871 c = getc (infile);
872 if (c != 'Y')
873 continue;
874 c = getc (infile);
875 if (c != 'M')
876 continue;
877 c = getc (infile);
878 if (c != ' ' && c != '\t' && c != '(')
879 continue;
880 type = SYMBOL;
881 }
882 else if (c == 'V')
883 {
884 c = getc (infile);
885 if (c != 'A')
886 continue;
887 c = getc (infile);
888 if (c != 'R')
889 continue;
890 c = getc (infile);
891 if (c != '_')
892 continue;
893
894 defvarflag = true;
895
896 c = getc (infile);
897 defvarperbufferflag = (c == 'P');
898 if (generate_globals)
899 {
900 if (c == 'I')
901 type = EMACS_INTEGER;
902 else if (c == 'L')
903 type = LISP_OBJECT;
904 else if (c == 'B')
905 type = BOOLEAN;
906 }
907
908 c = getc (infile);
909
910
911 if (generate_globals && type == BOOLEAN && c != 'O')
912 type = INVALID;
913 }
914 else
915 continue;
916 }
917 else if (c == 'D')
918 {
919 c = getc (infile);
920 if (c != 'E')
921 continue;
922 c = getc (infile);
923 if (c != 'F')
924 continue;
925 c = getc (infile);
926 defunflag = c == 'U';
927 }
928 else continue;
929
930 if (generate_globals
931 && (!defvarflag || defvarperbufferflag || type == INVALID)
932 && !defunflag && type != SYMBOL)
933 continue;
934
935 while (c != '(')
936 {
937 if (c < 0)
938 goto eof;
939 c = getc (infile);
940 }
941
942 if (type != SYMBOL)
943 {
944
945 c = getc (infile);
946 if (c != '"')
947 continue;
948 c = read_c_string_or_comment (infile, -1, false, 0);
949 }
950
951 if (generate_globals)
952 {
953 ptrdiff_t i = 0;
954 char const *svalue = 0;
955
956
957 do
958 {
959 c = getc (infile);
960 }
961 while (c == ',' || c_isspace (c));
962
963
964 do
965 {
966 if (c < 0)
967 goto eof;
968 input_buffer[i++] = c;
969 if (sizeof input_buffer <= i)
970 fatal ("identifier too long");
971 c = getc (infile);
972 }
973 while (! (c == ',' || c_isspace (c)));
974
975 input_buffer[i] = '\0';
976 memcpy (name, input_buffer, i + 1);
977
978 if (type == SYMBOL)
979 {
980 do
981 c = getc (infile);
982 while (c_isspace (c));
983
984 if (c != '"')
985 continue;
986 c = read_c_string_or_comment (infile, -1, false, 0);
987 svalue = input_buffer;
988 }
989
990 if (!defunflag)
991 {
992 add_global (type, name, 0, svalue);
993 continue;
994 }
995 }
996
997 if (type == SYMBOL)
998 continue;
999
1000
1001
1002
1003
1004 if (defunflag)
1005 commas = generate_globals ? 4 : 5;
1006 else if (defvarperbufferflag)
1007 commas = 3;
1008 else if (defvarflag)
1009 commas = 1;
1010 else
1011 commas = 2;
1012
1013 while (commas)
1014 {
1015 if (c == ',')
1016 {
1017 commas--;
1018
1019 if (defunflag && (commas == 1 || commas == 2))
1020 {
1021 int scanned = 0;
1022 do
1023 c = getc (infile);
1024 while (c_isspace (c));
1025
1026 if (c < 0)
1027 goto eof;
1028 ungetc (c, infile);
1029 if (commas == 2)
1030 scanned = fscanf (infile, "%d", &minargs);
1031 else
1032 if (c == 'M' || c == 'U')
1033 {
1034 if (generate_globals)
1035 maxargs = (c == 'M') ? -1 : -2;
1036 else
1037 maxargs = -1;
1038 }
1039 else
1040 scanned = fscanf (infile, "%d", &maxargs);
1041 if (scanned < 0)
1042 goto eof;
1043 }
1044 }
1045
1046 if (c == EOF)
1047 goto eof;
1048 c = getc (infile);
1049 }
1050
1051 if (generate_globals)
1052 {
1053 struct global *g = add_global (FUNCTION, name, maxargs, 0);
1054 if (!g)
1055 continue;
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069 c = getc (infile);
1070 if (c == EOF)
1071 goto eof;
1072 int d = getc (infile);
1073 if (d == EOF)
1074 goto eof;
1075 while (true)
1076 {
1077 if (c == '*' && d == '/')
1078 break;
1079 c = d, d = getc (infile);
1080 if (d == EOF)
1081 goto eof;
1082 }
1083
1084 do
1085 {
1086 c = getc (infile);
1087 if (c == EOF)
1088 goto eof;
1089 }
1090 while (c_isspace (c));
1091
1092
1093 if (c == 'a' && stream_match (infile, "ttributes:"))
1094 {
1095 char *p = input_buffer;
1096
1097 while (true)
1098 {
1099 c = getc (infile);
1100 if (c == EOF)
1101 goto eof;
1102 if (c == ')')
1103 break;
1104 if (p - input_buffer > sizeof (input_buffer))
1105 abort ();
1106 *p++ = c;
1107 }
1108 *p = 0;
1109 if (strstr (input_buffer, "noreturn"))
1110 g->flags |= DEFUN_noreturn;
1111 if (strstr (input_buffer, "const"))
1112 g->flags |= DEFUN_const;
1113
1114
1115
1116 if (strstr (input_buffer, "noinline"))
1117 g->flags |= DEFUN_noinline;
1118 }
1119 continue;
1120 }
1121
1122 while (c_isspace (c))
1123 c = getc (infile);
1124
1125 if (c == '"')
1126 c = read_c_string_or_comment (infile, 0, false, 0);
1127
1128 while (c != EOF && c != ',' && c != '/')
1129 c = getc (infile);
1130 if (c == ',')
1131 {
1132 do
1133 c = getc (infile);
1134 while (c_isspace (c));
1135
1136 while (c_isalpha (c))
1137 c = getc (infile);
1138 if (c == ':')
1139 {
1140 doc_keyword = true;
1141 do
1142 c = getc (infile);
1143 while (c_isspace (c));
1144 }
1145 }
1146
1147 if (c == '"'
1148 || (c == '/'
1149 && (c = getc (infile),
1150 ungetc (c, infile),
1151 c == '*')))
1152 {
1153 bool comment = c != '"';
1154 bool saw_usage;
1155
1156 printf ("\037%c%s\n", defvarflag ? 'V' : 'F', input_buffer);
1157
1158 if (comment)
1159 getc (infile);
1160 c = read_c_string_or_comment (infile, 1, comment, &saw_usage);
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172 if (defunflag && maxargs != -1 && !saw_usage)
1173 {
1174 char argbuf[1024], *p = argbuf;
1175
1176 if (!comment || doc_keyword)
1177 while (c != ')')
1178 {
1179 if (c < 0)
1180 goto eof;
1181 c = getc (infile);
1182 }
1183
1184
1185 while (c != '(')
1186 {
1187 if (c < 0)
1188 goto eof;
1189 c = getc (infile);
1190 }
1191
1192 *p++ = c;
1193 do
1194 {
1195 c = getc (infile);
1196 if (c < 0)
1197 goto eof;
1198 *p++ = c;
1199 }
1200 while (c != ')');
1201
1202 *p = '\0';
1203
1204 fputs ("\n\n", stdout);
1205 write_c_args (input_buffer, argbuf, minargs, maxargs);
1206 }
1207 else if (defunflag && maxargs == -1 && !saw_usage)
1208
1209 fprintf (stderr, "Missing 'usage' for function '%s'.\n",
1210 input_buffer);
1211 }
1212 }
1213 eof:
1214 if (ferror (infile) || fclose (infile) != 0)
1215 fatal ("read error");
1216 }
1217
1218