XEmacs 21.2.41 "Polyhymnia".
[chise/xemacs-chise.git.1] / lib-src / sorted-doc.c
1 /* Give this program DOCSTR.mm.nn as standard input
2    and it outputs to standard output
3    a file of texinfo input containing the doc strings.
4    
5    This version sorts the output by function name.
6    */
7
8 /* Synched up with: FSF 19.28. */
9
10 #include <config.h>
11
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <stdlib.h> /* for qsort() and malloc() */
15 #include <string.h>
16 static void *xmalloc (size_t);
17
18 #define NUL     '\0'
19 #define MARKER '\037'
20
21 #define DEBUG 0
22
23 typedef struct LINE LINE;
24
25 struct LINE
26 {
27   LINE *next;                   /* ptr to next or NULL */
28   char *line;                   /* text of the line */
29 };
30
31 typedef struct docstr DOCSTR;
32
33 struct docstr                   /* Allocated thing for an entry. */
34 {
35   DOCSTR *next;                 /* next in the chain */
36   char *name;                   /* name of the function or var */
37   LINE *first;                  /* first line of doc text. */
38   char type;                    /* 'F' for function, 'V' for variable */
39 };
40
41 \f
42 /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
43
44 static void
45 error (char *s1, char *s2)
46 {
47   fprintf (stderr, "sorted-doc: ");
48   fprintf (stderr, s1, s2);
49   fprintf (stderr, "\n");
50 }
51
52 /* Print error message and exit.  */
53
54 static void
55 fatal (char *s1, char *s2)
56 {
57   error (s1, s2);
58   exit (1);
59 }
60
61 /* Like malloc but get fatal error if memory is exhausted.  */
62
63 static void *
64 xmalloc (size_t size)
65 {
66   void *result = malloc (size);
67   if (result == NULL)
68     fatal ("%s", "virtual memory exhausted");
69   return result;
70 }
71
72 static char *
73 strsav (char *str)
74 {
75   char *buf = (char *) xmalloc (strlen (str) + 1);
76   strcpy (buf, str);
77   return buf;
78 }
79
80 /* Comparison function for qsort to call.  */
81
82 static int
83 cmpdoc (DOCSTR **a, DOCSTR **b)
84 {
85   register int val = strcmp ((*a)->name, (*b)->name);
86   if (val) return val;
87   return (*a)->type - (*b)->type;
88 }
89
90
91 enum state
92 {
93   WAITING, BEG_NAME, NAME_GET, BEG_DESC, DESC_GET
94 };
95
96 const char *states[] =
97 {
98   "WAITING", "BEG_NAME", "NAME_GET", "BEG_DESC", "DESC_GET"
99 };
100     
101 int
102 main (int argc, char *argv[])
103 {
104   register DOCSTR *dp = NULL;   /* allocated DOCSTR */
105   register LINE *lp = NULL;     /* allocated line */
106   register char *bp = 0;        /* ptr inside line buffer */
107   /* int notfirst = 0;          / * set after read something */
108   register enum state state = WAITING; /* state at start */
109   int cnt = 0;                  /* number of DOCSTRs read */
110
111   DOCSTR *docs = 0;             /* chain of allocated DOCSTRS */
112   char buf[512];                /* line buffer */
113     
114   while (1)                     /* process one char at a time */
115     {
116       /* this char from the DOCSTR file */
117       register int ch = getchar ();
118
119       /* Beginnings */
120
121       if (state == WAITING)
122         {
123           if (ch == MARKER)
124             state = BEG_NAME;
125         }
126       else if (state == BEG_NAME)
127         {
128           cnt++;
129           if (dp == NULL)       /* first dp allocated */
130             {
131               docs = dp = (DOCSTR*) xmalloc (sizeof (DOCSTR));
132             }
133           else                  /* all the rest */
134             {
135               dp->next = (DOCSTR*) xmalloc (sizeof (DOCSTR));
136               dp = dp->next;
137             }
138           lp = NULL;
139           dp->next = NULL;
140           bp = buf;
141           state = NAME_GET;
142           /* Record whether function or variable.  */
143           dp->type = ch;
144           ch = getchar ();
145         }
146       else if (state == BEG_DESC)
147         {
148           if (lp == NULL)       /* first line for dp */
149             {
150               dp->first = lp = (LINE*)xmalloc (sizeof (LINE));
151             }
152           else                  /* continuing lines */
153             {
154               lp->next = (LINE*)xmalloc (sizeof (LINE));
155               lp = lp->next;
156             }
157           lp->next = NULL;
158           bp = buf;
159           state = DESC_GET;
160         }
161         
162       /* process gets */
163
164       if (state == NAME_GET || state == DESC_GET)
165         {
166           if (ch != MARKER && ch != '\n' && ch != EOF)
167             {
168               *bp++ = ch;
169             }
170           else                  /* saving and changing state */
171             {
172               *bp = NUL;
173               bp = strsav (buf);
174
175               if (state == NAME_GET)
176                 dp->name = bp;
177               else
178                 lp->line = bp;
179
180               bp = buf;
181               state =  (ch == MARKER) ? BEG_NAME : BEG_DESC;
182             }
183         }                       /* NAME_GET || DESC_GET */
184       if (ch == EOF)
185         break;
186     }
187
188   {
189     DOCSTR **array;
190     register int i;             /* counter */
191
192     /* build array of ptrs to DOCSTRs */
193
194     array = (DOCSTR**)xmalloc (cnt * sizeof (*array));
195     for (dp = docs, i = 0; dp != NULL ; dp = dp->next)
196       array[i++] = dp;
197
198     /* sort the array by name; within each name, by type */
199
200     qsort ((char*)array, cnt, sizeof (DOCSTR*),
201            (int (*)(const void *, const void *)) cmpdoc);
202
203     /* write the output header */
204
205     printf ("\\input texinfo  @c -*-texinfo-*-\n");
206     printf ("@setfilename ../info/summary\n");
207     printf ("@settitle Command Summary for GNU Emacs\n");
208     printf ("@unnumbered Command Summary for GNU Emacs\n");
209     printf ("@table @asis\n");
210     printf ("\n");
211     printf ("@iftex\n");
212     printf ("@global@let@ITEM=@item\n");
213     printf ("@def@item{@filbreak@vskip5pt@ITEM}\n");
214     printf ("@font@tensy cmsy10 scaled @magstephalf\n");
215     printf ("@font@teni cmmi10 scaled @magstephalf\n");
216     printf ("@def\\{{@tensy@char110}}\n"); /* this backslash goes with cmr10 */
217     printf ("@def|{{@tensy@char106}}\n");
218     printf ("@def@{{{@tensy@char102}}\n");
219     printf ("@def@}{{@tensy@char103}}\n");
220     printf ("@def<{{@teni@char62}}\n");
221     printf ("@def>{{@teni@char60}}\n");
222     printf ("@chardef@@64\n");
223     printf ("@catcode43=12\n");
224     printf ("@tableindent-0.2in\n");
225     printf ("@end iftex\n");
226
227     /* print each function from the array */
228
229     for (i = 0; i < cnt; i++)
230       {
231         printf ("\n@item %s @code{%s}\n@display\n",
232                 array[i]->type == 'F' ? "Function" : "Variable",
233                 array[i]->name);
234
235         for (lp = array[i]->first; lp != NULL ; lp = lp->next)
236           {
237             for (bp = lp->line; *bp; bp++)
238               {
239                 /* the characters "@{}" need special treatment */
240                 if (*bp == '@' || *bp == '{' || *bp == '}')
241                   {
242                     putchar('@');
243                   }
244                 putchar(*bp);
245               }
246             putchar ('\n');
247           }
248         printf("@end display\n");
249         if ( i%200 == 0 && i != 0 ) printf("@end table\n\n@table @asis\n");
250       }
251
252     printf ("@end table\n");
253     printf ("@bye\n");
254   }
255
256   return 0;
257 }