root/trunk/lib-src/make-docfile.c

Revision 4220, 28.0 kB (checked in by miyoshi, 5 months ago)

Sync up with Emacs22.2.

  • Property svn:eol-style set to native
Line 
1 /* Generate doc-string file for GNU Emacs from source files.
2    Copyright (C) 1985, 1986, 1992, 1993, 1994, 1997, 1999, 2000, 2001,
3                  2002, 2003, 2004, 2005, 2006, 2007, 2008
4                  Free Software 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, or (at your option)
11 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; see the file COPYING.  If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.  */
22
23 /* The arguments given to this program are all the C and Lisp source files
24  of GNU Emacs.  .elc and .el and .c files are allowed.
25  A .o file can also be specified; the .c file it was made from is used.
26  This helps the makefile pass the correct list of files.
27  Option -d DIR means change to DIR before looking for files.
28
29  The results, which go to standard output or to a file
30  specified with -a or -o (-a to append, -o to start from nothing),
31  are entries containing function or variable names and their documentation.
32  Each entry starts with a ^_ character.
33  Then comes F for a function or V for a variable.
34  Then comes the function or variable name, terminated with a newline.
35  Then comes the documentation for that function or variable.
36  */
37
38 #define NO_SHORTNAMES   /* Tell config not to load remap.h */
39 #include <config.h>
40
41 /* defined to be emacs_main, sys_fopen, etc. in config.h */
42 #ifndef MEADOW
43 #undef main
44 #undef fopen
45 #undef chdir
46 #endif /* MEADOW */
47
48 #include <stdio.h>
49 #ifdef MSDOS
50 #include <fcntl.h>
51 #endif /* MSDOS */
52 #ifdef WINDOWSNT
53 #include <stdlib.h>
54 #include <fcntl.h>
55 #include <direct.h>
56 #endif /* WINDOWSNT */
57
58 #ifdef DOS_NT
59 #define READ_TEXT "rt"
60 #define READ_BINARY "rb"
61 #else  /* not DOS_NT */
62 #define READ_TEXT "r"
63 #define READ_BINARY "r"
64 #endif /* not DOS_NT */
65
66 #ifndef DIRECTORY_SEP
67 #ifdef MAC_OS8
68 #define DIRECTORY_SEP ':'
69 #else  /* not MAC_OS8 */
70 #define DIRECTORY_SEP '/'
71 #endif  /* not MAC_OS8 */
72 #endif
73
74 #ifndef IS_DIRECTORY_SEP
75 #define IS_DIRECTORY_SEP(_c_) ((_c_) == DIRECTORY_SEP)
76 #endif
77
78 int scan_file ();
79 int scan_lisp_file ();
80 int scan_c_file ();
81
82 #ifdef MSDOS
83 /* s/msdos.h defines this as sys_chdir, but we're not linking with the
84    file where that function is defined.  */
85 #undef chdir
86 #endif
87
88 #ifdef HAVE_UNISTD_H
89 #include <unistd.h>
90 #endif
91
92 /* Stdio stream for output to the DOC file.  */
93 FILE *outfile;
94
95 /* Name this program was invoked with.  */
96 char *progname;
97
98 /* Print error message.  `s1' is printf control string, `s2' is arg for it.  */
99
100 /* VARARGS1 */
101 void
102 error (s1, s2)
103      char *s1, *s2;
104 {
105   fprintf (stderr, "%s: ", progname);
106   fprintf (stderr, s1, s2);
107   fprintf (stderr, "\n");
108 }
109
110 /* Print error message and exit.  */
111
112 /* VARARGS1 */
113 void
114 fatal (s1, s2)
115      char *s1, *s2;
116 {
117   error (s1, s2);
118   exit (EXIT_FAILURE);
119 }
120
121 /* Like malloc but get fatal error if memory is exhausted.  */
122
123 void *
124 xmalloc (size)
125      unsigned int size;
126 {
127   void *result = (void *) malloc (size);
128   if (result == NULL)
129     fatal ("virtual memory exhausted", 0);
130   return result;
131 }
132
133 int
134 main (argc, argv)
135      int argc;
136      char **argv;
137 {
138   int i;
139   int err_count = 0;
140   int first_infile;
141
142   progname = argv[0];
143
144   outfile = stdout;
145
146   /* Don't put CRs in the DOC file.  */
147 #ifdef MSDOS
148   _fmode = O_BINARY;
149 #if 0  /* Suspicion is that this causes hanging.
150           So instead we require people to use -o on MSDOS.  */
151   (stdout)->_flag &= ~_IOTEXT;
152   _setmode (fileno (stdout), O_BINARY);
153 #endif
154   outfile = 0;
155 #endif /* MSDOS */
156 #ifdef WINDOWSNT
157   _fmode = O_BINARY;
158   _setmode (fileno (stdout), O_BINARY);
159 #endif /* WINDOWSNT */
160
161   /* If first two args are -o FILE, output to FILE.  */
162   i = 1;
163   if (argc > i + 1 && !strcmp (argv[i], "-o"))
164     {
165       outfile = fopen (argv[i + 1], "w");
166       i += 2;
167     }
168   if (argc > i + 1 && !strcmp (argv[i], "-a"))
169     {
170       outfile = fopen (argv[i + 1], "a");
171       i += 2;
172     }
173   if (argc > i + 1 && !strcmp (argv[i], "-d"))
174     {
175       chdir (argv[i + 1]);
176       i += 2;
177     }
178
179   if (outfile == 0)
180     fatal ("No output file specified", "");
181
182   first_infile = i;
183   for (; i < argc; i++)
184     {
185       int j;
186       /* Don't process one file twice.  */
187       for (j = first_infile; j < i; j++)
188         if (! strcmp (argv[i], argv[j]))
189           break;
190       if (j == i)
191         err_count += scan_file (argv[i]);
192     }
193   return (err_count > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
194 }
195
196 /* Add a source file name boundary marker in the output file.  */
197 void
198 put_filename (filename)
199      char *filename;
200 {
201   char *tmp;
202
203   for (tmp = filename; *tmp; tmp++)
204     {
205       if (IS_DIRECTORY_SEP(*tmp))
206         filename = tmp + 1;
207     }
208
209   putc (037, outfile);
210   putc ('S', outfile);
211   fprintf (outfile, "%s\n", filename);
212 }
213
214 /* Read file FILENAME and output its doc strings to outfile.  */
215 /* Return 1 if file is not found, 0 if it is found.  */
216
217 int
218 scan_file (filename)
219      char *filename;
220 {
221   int len = strlen (filename);
222
223   put_filename (filename);
224   if (len > 4 && !strcmp (filename + len - 4, ".elc"))
225     return scan_lisp_file (filename, READ_BINARY);
226   else if (len > 3 && !strcmp (filename + len - 3, ".el"))
227     return scan_lisp_file (filename, READ_TEXT);
228   else
229     return scan_c_file (filename, READ_TEXT);
230 }
231
232 char buf[128];
233
234 /* Some state during the execution of `read_c_string_or_comment'.  */
235 struct rcsoc_state
236 {
237   /* A count of spaces and newlines that have been read, but not output.  */
238   unsigned pending_spaces, pending_newlines;
239
240   /* Where we're reading from.  */
241   FILE *in_file;
242
243   /* If non-zero, a buffer into which to copy characters.  */
244   char *buf_ptr;
245   /* If non-zero, a file into which to copy characters.  */
246   FILE *out_file;
247
248   /* A keyword we look for at the beginning of lines.  If found, it is
249      not copied, and SAW_KEYWORD is set to true.  */
250   char *keyword;
251   /* The current point we've reached in an occurance of KEYWORD in
252      the input stream.  */
253   char *cur_keyword_ptr;
254   /* Set to true if we saw an occurance of KEYWORD.  */
255   int saw_keyword;
256 };
257
258 /* Output CH to the file or buffer in STATE.  Any pending newlines or
259    spaces are output first.  */
260
261 static INLINE void
262 put_char (ch, state)
263      int ch;
264      struct rcsoc_state *state;
265 {
266   int out_ch;
267   do
268     {
269       if (state->pending_newlines > 0)
270         {
271           state->pending_newlines--;
272           out_ch = '\n';
273         }
274       else if (state->pending_spaces > 0)
275         {
276           state->pending_spaces--;
277           out_ch = ' ';
278         }
279       else
280         out_ch = ch;
281
282       if (state->out_file)
283         putc (out_ch, state->out_file);
284       if (state->buf_ptr)
285         *state->buf_ptr++ = out_ch;
286     }
287   while (out_ch != ch);
288 }
289
290 /* If in the middle of scanning a keyword, continue scanning with
291    character CH, otherwise output CH to the file or buffer in STATE.
292    Any pending newlines or spaces are output first, as well as any
293    previously scanned characters that were thought to be part of a
294    keyword, but were in fact not.  */
295
296 static void
297 scan_keyword_or_put_char (ch, state)
298      int ch;
299      struct rcsoc_state *state;
300 {
301   if (state->keyword
302       && *state->cur_keyword_ptr == ch
303       && (state->cur_keyword_ptr > state->keyword
304           || state->pending_newlines > 0))
305     /* We might be looking at STATE->keyword at some point.
306        Keep looking until we know for sure.  */
307     {
308       if (*++state->cur_keyword_ptr == '\0')
309         /* Saw the whole keyword.  Set SAW_KEYWORD flag to true.  */
310         {
311           state->saw_keyword = 1;
312
313           /* Reset the scanning pointer.  */
314           state->cur_keyword_ptr = state->keyword;
315
316           /* Canonicalize whitespace preceding a usage string.  */
317           state->pending_newlines = 2;
318           state->pending_spaces = 0;
319
320           /* Skip any whitespace between the keyword and the
321              usage string.  */
322           do
323             ch = getc (state->in_file);
324           while (ch == ' ' || ch == '\n');
325
326           /* Output the open-paren we just read.  */
327           put_char (ch, state);
328
329           /* Skip the function name and replace it with `fn'.  */
330           do
331             ch = getc (state->in_file);
332           while (ch != ' ' && ch != ')');
333           put_char ('f', state);
334           put_char ('n', state);
335
336           /* Put back the last character.  */
337           ungetc (ch, state->in_file);
338         }
339     }
340   else
341     {
342       if (state->keyword && state->cur_keyword_ptr > state->keyword)
343         /* We scanned the beginning of a potential usage
344            keyword, but it was a false alarm.  Output the
345            part we scanned.  */
346         {
347           char *p;
348
349           for (p = state->keyword; p < state->cur_keyword_ptr; p++)
350             put_char (*p, state);
351
352           state->cur_keyword_ptr = state->keyword;
353         }
354
355       put_char (ch, state);
356     }
357 }
358
359
360 /* Skip a C string or C-style comment from INFILE, and return the
361    character that follows.  COMMENT non-zero means skip a comment.  If
362    PRINTFLAG is positive, output string contents to outfile.  If it is
363    negative, store contents in buf.  Convert escape sequences \n and
364    \t to newline and tab; discard \ followed by newline.
365    If SAW_USAGE is non-zero, then any occurances of the string `usage:'
366    at the beginning of a line will be removed, and *SAW_USAGE set to
367    true if any were encountered.  */
368
369 int
370 read_c_string_or_comment (infile, printflag, comment, saw_usage)
371      FILE *infile;
372      int printflag;
373      int *saw_usage;
374      int comment;
375 {
376   register int c;
377   struct rcsoc_state state;
378
379   state.in_file = infile;
380   state.buf_ptr = (printflag < 0 ? buf : 0);
381   state.out_file = (printflag > 0 ? outfile : 0);
382   state.pending_spaces = 0;
383   state.pending_newlines = 0;
384   state.keyword = (saw_usage ? "usage:" : 0);
385   state.cur_keyword_ptr = state.keyword;
386   state.saw_keyword = 0;
387
388   c = getc (infile);
389   if (comment)
390     while (c == '\n' || c == '\r' || c == '\t' || c == ' ')
391       c = getc (infile);
392
393   while (c != EOF)
394     {
395       while (c != EOF && (comment ? c != '*' : c != '"'))
396         {
397           if (c == '\\')
398             {
399               c = getc (infile);
400               if (c == '\n' || c == '\r')
401                 {
402                   c = getc (infile);
403                   continue;
404                 }
405               if (c == 'n')
406                 c = '\n';
407               if (c == 't')
408                 c = '\t';
409             }
410
411           if (c == ' ')
412             state.pending_spaces++;
413           else if (c == '\n')
414             {
415               state.pending_newlines++;
416               state.pending_spaces = 0;
417             }
418           else
419             scan_keyword_or_put_char (c, &state);
420
421           c = getc (infile);
422         }
423
424       if (c != EOF)
425         c = getc (infile);
426
427       if (comment)
428         {
429           if (c == '/')
430             {
431               c = getc (infile);
432               break;
433             }
434
435           scan_keyword_or_put_char ('*', &state);
436         }
437       else
438         {
439           if (c != '"')
440             break;
441
442           /* If we had a "", concatenate the two strings.  */
443           c = getc (infile);
444         }
445     }
446
447   if (printflag < 0)
448     *state.buf_ptr = 0;
449
450   if (saw_usage)
451     *saw_usage = state.saw_keyword;
452
453   return c;
454 }
455
456
457
458 /* Write to file OUT the argument names of function FUNC, whose text is in BUF.
459    MINARGS and MAXARGS are the minimum and maximum number of arguments.  */
460
461 void
462 write_c_args (out, func, buf, minargs, maxargs)
463      FILE *out;
464      char *func, *buf;
465      int minargs, maxargs;
466 {
467   register char *p;
468   int in_ident = 0;
469   int just_spaced = 0;
470   int need_space = 1;
471
472   fprintf (out, "(fn");
473
474   if (*buf == '(')
475     ++buf;
476
477   for (p = buf; *p; p++)
478     {
479       char c = *p;
480       int ident_start = 0;
481
482       /* Notice when we start printing a new identifier.  */
483       if ((('A' <= c && c <= 'Z')
484            || ('a' <= c && c <= 'z')
485            || ('0' <= c && c <= '9')
486            || c == '_')
487           != in_ident)
488         {
489           if (!in_ident)
490             {
491               in_ident = 1;
492               ident_start = 1;
493
494               if (need_space)
495                 putc (' ', out);
496
497               if (minargs == 0 && maxargs > 0)
498                 fprintf (out, "&optional ");
499               just_spaced = 1;
500
501               minargs--;
502               maxargs--;
503             }
504           else
505             in_ident = 0;
506         }
507
508       /* Print the C argument list as it would appear in lisp:
509          print underscores as hyphens, and print commas and newlines
510          as spaces.  Collapse adjacent spaces into one.  */
511       if (c == '_')
512         c = '-';
513       else if (c == ',' || c == '\n')
514         c = ' ';
515
516       /* In C code, `default' is a reserved word, so we spell it
517          `defalt'; unmangle that here.  */
518       if (ident_start
519           && strncmp (p, "defalt", 6) == 0
520           && ! (('A' <= p[6] && p[6] <= 'Z')
521                 || ('a' <= p[6] && p[6] <= 'z')
522                 || ('0' <= p[6] && p[6] <= '9')
523                 || p[6] == '_'))
524         {
525           fprintf (out, "DEFAULT");
526           p += 5;
527           in_ident = 0;
528           just_spaced = 0;
529         }
530       else if (c != ' ' || !just_spaced)
531         {
532           if (c >= 'a' && c <= 'z')
533             /* Upcase the letter.  */
534             c += 'A' - 'a';
535           putc (c, out);
536         }
537
538       just_spaced = c == ' ';
539       need_space = 0;
540     }
541 }
542
543 /* Read through a c file.  If a .o file is named,
544    the corresponding .c file is read instead.
545    Looks for DEFUN constructs such as are defined in ../src/lisp.h.
546    Accepts any word starting DEF... so it finds DEFSIMPLE and DEFPRED.  */
547
548 int
549 scan_c_file (filename, mode)
550      char *filename, *mode;
551 {
552   FILE *infile;
553   register int c;
554   register int commas;
555   register int defunflag;
556   register int defvarperbufferflag;
557   register int defvarflag;
558   int minargs, maxargs;
559   int extension = filename[strlen (filename) - 1];
560
561   if (extension == 'o')
562     filename[strlen (filename) - 1] = 'c';
563
564   infile = fopen (filename, mode);
565
566   /* No error if non-ex input file */
567   if (infile == NULL)
568     {
569       perror (filename);
570       return 0;
571     }
572
573   /* Reset extension to be able to detect duplicate files.  */
574   filename[strlen (filename) - 1] = extension;
575
576   c = '\n';
577   while (!feof (infile))
578     {
579       int doc_keyword = 0;
580
581       if (c != '\n' && c != '\r')
582         {
583           c = getc (infile);
584           continue;
585         }
586       c = getc (infile);
587       if (c == ' ')
588         {
589           while (c == ' ')
590             c = getc (infile);
591           if (c != 'D')
592             continue;
593           c = getc (infile);
594           if (c != 'E')
595             continue;
596           c = getc (infile);
597           if (c != 'F')
598             continue;
599           c = getc (infile);
600           if (c != 'V')
601             continue;
602           c = getc (infile);
603           if (c != 'A')
604             continue;
605           c = getc (infile);
606           if (c != 'R')
607             continue;
608           c = getc (infile);
609           if (c != '_')
610             continue;
611
612           defvarflag = 1;
613           defunflag = 0;
614
615           c = getc (infile);
616           defvarperbufferflag = (c == 'P'