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