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