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