1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * docproc is a simple preprocessor for the template files
3*4882a593Smuzhiyun * used as placeholders for the kernel internal documentation.
4*4882a593Smuzhiyun * docproc is used for documentation-frontend and
5*4882a593Smuzhiyun * dependency-generator.
6*4882a593Smuzhiyun * The two usages have in common that they require
7*4882a593Smuzhiyun * some knowledge of the .tmpl syntax, therefore they
8*4882a593Smuzhiyun * are kept together.
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * documentation-frontend
11*4882a593Smuzhiyun * Scans the template file and call kernel-doc for
12*4882a593Smuzhiyun * all occurrences of ![EIF]file
13*4882a593Smuzhiyun * Beforehand each referenced file is scanned for
14*4882a593Smuzhiyun * any symbols that are exported via these macros:
15*4882a593Smuzhiyun * EXPORT_SYMBOL(), EXPORT_SYMBOL_GPL(), &
16*4882a593Smuzhiyun * EXPORT_SYMBOL_GPL_FUTURE()
17*4882a593Smuzhiyun * This is used to create proper -function and
18*4882a593Smuzhiyun * -nofunction arguments in calls to kernel-doc.
19*4882a593Smuzhiyun * Usage: docproc doc file.tmpl
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * dependency-generator:
22*4882a593Smuzhiyun * Scans the template file and list all files
23*4882a593Smuzhiyun * referenced in a format recognized by make.
24*4882a593Smuzhiyun * Usage: docproc depend file.tmpl
25*4882a593Smuzhiyun * Writes dependency information to stdout
26*4882a593Smuzhiyun * in the following format:
27*4882a593Smuzhiyun * file.tmpl src.c src2.c
28*4882a593Smuzhiyun * The filenames are obtained from the following constructs:
29*4882a593Smuzhiyun * !Efilename
30*4882a593Smuzhiyun * !Ifilename
31*4882a593Smuzhiyun * !Dfilename
32*4882a593Smuzhiyun * !Ffilename
33*4882a593Smuzhiyun * !Pfilename
34*4882a593Smuzhiyun *
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define _GNU_SOURCE
38*4882a593Smuzhiyun #include <stdio.h>
39*4882a593Smuzhiyun #include <stdlib.h>
40*4882a593Smuzhiyun #include <string.h>
41*4882a593Smuzhiyun #include <ctype.h>
42*4882a593Smuzhiyun #include <unistd.h>
43*4882a593Smuzhiyun #include <limits.h>
44*4882a593Smuzhiyun #include <errno.h>
45*4882a593Smuzhiyun #include <sys/types.h>
46*4882a593Smuzhiyun #include <sys/wait.h>
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /* exitstatus is used to keep track of any failing calls to kernel-doc,
49*4882a593Smuzhiyun * but execution continues. */
50*4882a593Smuzhiyun int exitstatus = 0;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun typedef void DFL(char *);
53*4882a593Smuzhiyun DFL *defaultline;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun typedef void FILEONLY(char * file);
56*4882a593Smuzhiyun FILEONLY *internalfunctions;
57*4882a593Smuzhiyun FILEONLY *externalfunctions;
58*4882a593Smuzhiyun FILEONLY *symbolsonly;
59*4882a593Smuzhiyun FILEONLY *findall;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun typedef void FILELINE(char * file, char * line);
62*4882a593Smuzhiyun FILELINE * singlefunctions;
63*4882a593Smuzhiyun FILELINE * entity_system;
64*4882a593Smuzhiyun FILELINE * docsection;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun #define MAXLINESZ 2048
67*4882a593Smuzhiyun #define MAXFILES 250
68*4882a593Smuzhiyun #define KERNELDOCPATH "scripts/"
69*4882a593Smuzhiyun #define KERNELDOC "kernel-doc"
70*4882a593Smuzhiyun #define DOCBOOK "-docbook"
71*4882a593Smuzhiyun #define LIST "-list"
72*4882a593Smuzhiyun #define FUNCTION "-function"
73*4882a593Smuzhiyun #define NOFUNCTION "-nofunction"
74*4882a593Smuzhiyun #define NODOCSECTIONS "-no-doc-sections"
75*4882a593Smuzhiyun #define SHOWNOTFOUND "-show-not-found"
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun static char *srctree, *kernsrctree;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun static char **all_list = NULL;
80*4882a593Smuzhiyun static int all_list_len = 0;
81*4882a593Smuzhiyun
consume_symbol(const char * sym)82*4882a593Smuzhiyun static void consume_symbol(const char *sym)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun int i;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun for (i = 0; i < all_list_len; i++) {
87*4882a593Smuzhiyun if (!all_list[i])
88*4882a593Smuzhiyun continue;
89*4882a593Smuzhiyun if (strcmp(sym, all_list[i]))
90*4882a593Smuzhiyun continue;
91*4882a593Smuzhiyun all_list[i] = NULL;
92*4882a593Smuzhiyun break;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
usage(void)96*4882a593Smuzhiyun static void usage (void)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun fprintf(stderr, "Usage: docproc {doc|depend} file\n");
99*4882a593Smuzhiyun fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
100*4882a593Smuzhiyun fprintf(stderr, "doc: frontend when generating kernel documentation\n");
101*4882a593Smuzhiyun fprintf(stderr, "depend: generate list of files referenced within file\n");
102*4882a593Smuzhiyun fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n");
103*4882a593Smuzhiyun fprintf(stderr, " KBUILD_SRC: absolute path to kernel source tree.\n");
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /*
107*4882a593Smuzhiyun * Execute kernel-doc with parameters given in svec
108*4882a593Smuzhiyun */
exec_kernel_doc(char ** svec)109*4882a593Smuzhiyun static void exec_kernel_doc(char **svec)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun pid_t pid;
112*4882a593Smuzhiyun int ret;
113*4882a593Smuzhiyun char real_filename[PATH_MAX + 1];
114*4882a593Smuzhiyun /* Make sure output generated so far are flushed */
115*4882a593Smuzhiyun fflush(stdout);
116*4882a593Smuzhiyun switch (pid=fork()) {
117*4882a593Smuzhiyun case -1:
118*4882a593Smuzhiyun perror("fork");
119*4882a593Smuzhiyun exit(1);
120*4882a593Smuzhiyun case 0:
121*4882a593Smuzhiyun memset(real_filename, 0, sizeof(real_filename));
122*4882a593Smuzhiyun strncat(real_filename, kernsrctree, PATH_MAX);
123*4882a593Smuzhiyun strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
124*4882a593Smuzhiyun PATH_MAX - strlen(real_filename));
125*4882a593Smuzhiyun execvp(real_filename, svec);
126*4882a593Smuzhiyun fprintf(stderr, "exec ");
127*4882a593Smuzhiyun perror(real_filename);
128*4882a593Smuzhiyun exit(1);
129*4882a593Smuzhiyun default:
130*4882a593Smuzhiyun waitpid(pid, &ret ,0);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun if (WIFEXITED(ret))
133*4882a593Smuzhiyun exitstatus |= WEXITSTATUS(ret);
134*4882a593Smuzhiyun else
135*4882a593Smuzhiyun exitstatus = 0xff;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* Types used to create list of all exported symbols in a number of files */
139*4882a593Smuzhiyun struct symbols
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun char *name;
142*4882a593Smuzhiyun };
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun struct symfile
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun char *filename;
147*4882a593Smuzhiyun struct symbols *symbollist;
148*4882a593Smuzhiyun int symbolcnt;
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun struct symfile symfilelist[MAXFILES];
152*4882a593Smuzhiyun int symfilecnt = 0;
153*4882a593Smuzhiyun
add_new_symbol(struct symfile * sym,char * symname)154*4882a593Smuzhiyun static void add_new_symbol(struct symfile *sym, char * symname)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun sym->symbollist =
157*4882a593Smuzhiyun realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
158*4882a593Smuzhiyun sym->symbollist[sym->symbolcnt++].name = strdup(symname);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun /* Add a filename to the list */
add_new_file(char * filename)162*4882a593Smuzhiyun static struct symfile * add_new_file(char * filename)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun symfilelist[symfilecnt++].filename = strdup(filename);
165*4882a593Smuzhiyun return &symfilelist[symfilecnt - 1];
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /* Check if file already are present in the list */
filename_exist(char * filename)169*4882a593Smuzhiyun static struct symfile * filename_exist(char * filename)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun int i;
172*4882a593Smuzhiyun for (i=0; i < symfilecnt; i++)
173*4882a593Smuzhiyun if (strcmp(symfilelist[i].filename, filename) == 0)
174*4882a593Smuzhiyun return &symfilelist[i];
175*4882a593Smuzhiyun return NULL;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /*
179*4882a593Smuzhiyun * List all files referenced within the template file.
180*4882a593Smuzhiyun * Files are separated by tabs.
181*4882a593Smuzhiyun */
adddep(char * file)182*4882a593Smuzhiyun static void adddep(char * file) { printf("\t%s", file); }
adddep2(char * file,char * line)183*4882a593Smuzhiyun static void adddep2(char * file, char * line) { line = line; adddep(file); }
noaction(char * line)184*4882a593Smuzhiyun static void noaction(char * line) { line = line; }
noaction2(char * file,char * line)185*4882a593Smuzhiyun static void noaction2(char * file, char * line) { file = file; line = line; }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /* Echo the line without further action */
printline(char * line)188*4882a593Smuzhiyun static void printline(char * line) { printf("%s", line); }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /*
191*4882a593Smuzhiyun * Find all symbols in filename that are exported with EXPORT_SYMBOL &
192*4882a593Smuzhiyun * EXPORT_SYMBOL_GPL (& EXPORT_SYMBOL_GPL_FUTURE implicitly).
193*4882a593Smuzhiyun * All symbols located are stored in symfilelist.
194*4882a593Smuzhiyun */
find_export_symbols(char * filename)195*4882a593Smuzhiyun static void find_export_symbols(char * filename)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun FILE * fp;
198*4882a593Smuzhiyun struct symfile *sym;
199*4882a593Smuzhiyun char line[MAXLINESZ];
200*4882a593Smuzhiyun if (filename_exist(filename) == NULL) {
201*4882a593Smuzhiyun char real_filename[PATH_MAX + 1];
202*4882a593Smuzhiyun memset(real_filename, 0, sizeof(real_filename));
203*4882a593Smuzhiyun strncat(real_filename, srctree, PATH_MAX);
204*4882a593Smuzhiyun strncat(real_filename, "/", PATH_MAX - strlen(real_filename));
205*4882a593Smuzhiyun strncat(real_filename, filename,
206*4882a593Smuzhiyun PATH_MAX - strlen(real_filename));
207*4882a593Smuzhiyun sym = add_new_file(filename);
208*4882a593Smuzhiyun fp = fopen(real_filename, "r");
209*4882a593Smuzhiyun if (fp == NULL) {
210*4882a593Smuzhiyun fprintf(stderr, "docproc: ");
211*4882a593Smuzhiyun perror(real_filename);
212*4882a593Smuzhiyun exit(1);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun while (fgets(line, MAXLINESZ, fp)) {
215*4882a593Smuzhiyun char *p;
216*4882a593Smuzhiyun char *e;
217*4882a593Smuzhiyun if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) ||
218*4882a593Smuzhiyun ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) {
219*4882a593Smuzhiyun /* Skip EXPORT_SYMBOL{_GPL} */
220*4882a593Smuzhiyun while (isalnum(*p) || *p == '_')
221*4882a593Smuzhiyun p++;
222*4882a593Smuzhiyun /* Remove parentheses & additional whitespace */
223*4882a593Smuzhiyun while (isspace(*p))
224*4882a593Smuzhiyun p++;
225*4882a593Smuzhiyun if (*p != '(')
226*4882a593Smuzhiyun continue; /* Syntax error? */
227*4882a593Smuzhiyun else
228*4882a593Smuzhiyun p++;
229*4882a593Smuzhiyun while (isspace(*p))
230*4882a593Smuzhiyun p++;
231*4882a593Smuzhiyun e = p;
232*4882a593Smuzhiyun while (isalnum(*e) || *e == '_')
233*4882a593Smuzhiyun e++;
234*4882a593Smuzhiyun *e = '\0';
235*4882a593Smuzhiyun add_new_symbol(sym, p);
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun fclose(fp);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /*
243*4882a593Smuzhiyun * Document all external or internal functions in a file.
244*4882a593Smuzhiyun * Call kernel-doc with following parameters:
245*4882a593Smuzhiyun * kernel-doc -docbook -nofunction function_name1 filename
246*4882a593Smuzhiyun * Function names are obtained from all the src files
247*4882a593Smuzhiyun * by find_export_symbols.
248*4882a593Smuzhiyun * intfunc uses -nofunction
249*4882a593Smuzhiyun * extfunc uses -function
250*4882a593Smuzhiyun */
docfunctions(char * filename,char * type)251*4882a593Smuzhiyun static void docfunctions(char * filename, char * type)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun int i,j;
254*4882a593Smuzhiyun int symcnt = 0;
255*4882a593Smuzhiyun int idx = 0;
256*4882a593Smuzhiyun char **vec;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun for (i=0; i <= symfilecnt; i++)
259*4882a593Smuzhiyun symcnt += symfilelist[i].symbolcnt;
260*4882a593Smuzhiyun vec = malloc((2 + 2 * symcnt + 3) * sizeof(char *));
261*4882a593Smuzhiyun if (vec == NULL) {
262*4882a593Smuzhiyun perror("docproc: ");
263*4882a593Smuzhiyun exit(1);
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun vec[idx++] = KERNELDOC;
266*4882a593Smuzhiyun vec[idx++] = DOCBOOK;
267*4882a593Smuzhiyun vec[idx++] = NODOCSECTIONS;
268*4882a593Smuzhiyun for (i=0; i < symfilecnt; i++) {
269*4882a593Smuzhiyun struct symfile * sym = &symfilelist[i];
270*4882a593Smuzhiyun for (j=0; j < sym->symbolcnt; j++) {
271*4882a593Smuzhiyun vec[idx++] = type;
272*4882a593Smuzhiyun consume_symbol(sym->symbollist[j].name);
273*4882a593Smuzhiyun vec[idx++] = sym->symbollist[j].name;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun vec[idx++] = filename;
277*4882a593Smuzhiyun vec[idx] = NULL;
278*4882a593Smuzhiyun printf("<!-- %s -->\n", filename);
279*4882a593Smuzhiyun exec_kernel_doc(vec);
280*4882a593Smuzhiyun fflush(stdout);
281*4882a593Smuzhiyun free(vec);
282*4882a593Smuzhiyun }
intfunc(char * filename)283*4882a593Smuzhiyun static void intfunc(char * filename) { docfunctions(filename, NOFUNCTION); }
extfunc(char * filename)284*4882a593Smuzhiyun static void extfunc(char * filename) { docfunctions(filename, FUNCTION); }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /*
287*4882a593Smuzhiyun * Document specific function(s) in a file.
288*4882a593Smuzhiyun * Call kernel-doc with the following parameters:
289*4882a593Smuzhiyun * kernel-doc -docbook -function function1 [-function function2]
290*4882a593Smuzhiyun */
singfunc(char * filename,char * line)291*4882a593Smuzhiyun static void singfunc(char * filename, char * line)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun char *vec[200]; /* Enough for specific functions */
294*4882a593Smuzhiyun int i, idx = 0;
295*4882a593Smuzhiyun int startofsym = 1;
296*4882a593Smuzhiyun vec[idx++] = KERNELDOC;
297*4882a593Smuzhiyun vec[idx++] = DOCBOOK;
298*4882a593Smuzhiyun vec[idx++] = SHOWNOTFOUND;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /* Split line up in individual parameters preceded by FUNCTION */
301*4882a593Smuzhiyun for (i=0; line[i]; i++) {
302*4882a593Smuzhiyun if (isspace(line[i])) {
303*4882a593Smuzhiyun line[i] = '\0';
304*4882a593Smuzhiyun startofsym = 1;
305*4882a593Smuzhiyun continue;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun if (startofsym) {
308*4882a593Smuzhiyun startofsym = 0;
309*4882a593Smuzhiyun vec[idx++] = FUNCTION;
310*4882a593Smuzhiyun vec[idx++] = &line[i];
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun for (i = 0; i < idx; i++) {
314*4882a593Smuzhiyun if (strcmp(vec[i], FUNCTION))
315*4882a593Smuzhiyun continue;
316*4882a593Smuzhiyun consume_symbol(vec[i + 1]);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun vec[idx++] = filename;
319*4882a593Smuzhiyun vec[idx] = NULL;
320*4882a593Smuzhiyun exec_kernel_doc(vec);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun /*
324*4882a593Smuzhiyun * Insert specific documentation section from a file.
325*4882a593Smuzhiyun * Call kernel-doc with the following parameters:
326*4882a593Smuzhiyun * kernel-doc -docbook -function "doc section" filename
327*4882a593Smuzhiyun */
docsect(char * filename,char * line)328*4882a593Smuzhiyun static void docsect(char *filename, char *line)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun /* kerneldoc -docbook -show-not-found -function "section" file NULL */
331*4882a593Smuzhiyun char *vec[7];
332*4882a593Smuzhiyun char *s;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun for (s = line; *s; s++)
335*4882a593Smuzhiyun if (*s == '\n')
336*4882a593Smuzhiyun *s = '\0';
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (asprintf(&s, "DOC: %s", line) < 0) {
339*4882a593Smuzhiyun perror("asprintf");
340*4882a593Smuzhiyun exit(1);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun consume_symbol(s);
343*4882a593Smuzhiyun free(s);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun vec[0] = KERNELDOC;
346*4882a593Smuzhiyun vec[1] = DOCBOOK;
347*4882a593Smuzhiyun vec[2] = SHOWNOTFOUND;
348*4882a593Smuzhiyun vec[3] = FUNCTION;
349*4882a593Smuzhiyun vec[4] = line;
350*4882a593Smuzhiyun vec[5] = filename;
351*4882a593Smuzhiyun vec[6] = NULL;
352*4882a593Smuzhiyun exec_kernel_doc(vec);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
find_all_symbols(char * filename)355*4882a593Smuzhiyun static void find_all_symbols(char *filename)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun char *vec[4]; /* kerneldoc -list file NULL */
358*4882a593Smuzhiyun pid_t pid;
359*4882a593Smuzhiyun int ret, i, count, start;
360*4882a593Smuzhiyun char real_filename[PATH_MAX + 1];
361*4882a593Smuzhiyun int pipefd[2];
362*4882a593Smuzhiyun char *data, *str;
363*4882a593Smuzhiyun size_t data_len = 0;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun vec[0] = KERNELDOC;
366*4882a593Smuzhiyun vec[1] = LIST;
367*4882a593Smuzhiyun vec[2] = filename;
368*4882a593Smuzhiyun vec[3] = NULL;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun if (pipe(pipefd)) {
371*4882a593Smuzhiyun perror("pipe");
372*4882a593Smuzhiyun exit(1);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun switch (pid=fork()) {
376*4882a593Smuzhiyun case -1:
377*4882a593Smuzhiyun perror("fork");
378*4882a593Smuzhiyun exit(1);
379*4882a593Smuzhiyun case 0:
380*4882a593Smuzhiyun close(pipefd[0]);
381*4882a593Smuzhiyun dup2(pipefd[1], 1);
382*4882a593Smuzhiyun memset(real_filename, 0, sizeof(real_filename));
383*4882a593Smuzhiyun strncat(real_filename, kernsrctree, PATH_MAX);
384*4882a593Smuzhiyun strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
385*4882a593Smuzhiyun PATH_MAX - strlen(real_filename));
386*4882a593Smuzhiyun execvp(real_filename, vec);
387*4882a593Smuzhiyun fprintf(stderr, "exec ");
388*4882a593Smuzhiyun perror(real_filename);
389*4882a593Smuzhiyun exit(1);
390*4882a593Smuzhiyun default:
391*4882a593Smuzhiyun close(pipefd[1]);
392*4882a593Smuzhiyun data = malloc(4096);
393*4882a593Smuzhiyun do {
394*4882a593Smuzhiyun while ((ret = read(pipefd[0],
395*4882a593Smuzhiyun data + data_len,
396*4882a593Smuzhiyun 4096)) > 0) {
397*4882a593Smuzhiyun data_len += ret;
398*4882a593Smuzhiyun data = realloc(data, data_len + 4096);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun } while (ret == -EAGAIN);
401*4882a593Smuzhiyun if (ret != 0) {
402*4882a593Smuzhiyun perror("read");
403*4882a593Smuzhiyun exit(1);
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun waitpid(pid, &ret ,0);
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun if (WIFEXITED(ret))
408*4882a593Smuzhiyun exitstatus |= WEXITSTATUS(ret);
409*4882a593Smuzhiyun else
410*4882a593Smuzhiyun exitstatus = 0xff;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun count = 0;
413*4882a593Smuzhiyun /* poor man's strtok, but with counting */
414*4882a593Smuzhiyun for (i = 0; i < data_len; i++) {
415*4882a593Smuzhiyun if (data[i] == '\n') {
416*4882a593Smuzhiyun count++;
417*4882a593Smuzhiyun data[i] = '\0';
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun start = all_list_len;
421*4882a593Smuzhiyun all_list_len += count;
422*4882a593Smuzhiyun all_list = realloc(all_list, sizeof(char *) * all_list_len);
423*4882a593Smuzhiyun str = data;
424*4882a593Smuzhiyun for (i = 0; i < data_len && start != all_list_len; i++) {
425*4882a593Smuzhiyun if (data[i] == '\0') {
426*4882a593Smuzhiyun all_list[start] = str;
427*4882a593Smuzhiyun str = data + i + 1;
428*4882a593Smuzhiyun start++;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun /*
434*4882a593Smuzhiyun * Parse file, calling action specific functions for:
435*4882a593Smuzhiyun * 1) Lines containing !E
436*4882a593Smuzhiyun * 2) Lines containing !I
437*4882a593Smuzhiyun * 3) Lines containing !D
438*4882a593Smuzhiyun * 4) Lines containing !F
439*4882a593Smuzhiyun * 5) Lines containing !P
440*4882a593Smuzhiyun * 6) Lines containing !C
441*4882a593Smuzhiyun * 7) Default lines - lines not matching the above
442*4882a593Smuzhiyun */
parse_file(FILE * infile)443*4882a593Smuzhiyun static void parse_file(FILE *infile)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun char line[MAXLINESZ];
446*4882a593Smuzhiyun char * s;
447*4882a593Smuzhiyun while (fgets(line, MAXLINESZ, infile)) {
448*4882a593Smuzhiyun if (line[0] == '!') {
449*4882a593Smuzhiyun s = line + 2;
450*4882a593Smuzhiyun switch (line[1]) {
451*4882a593Smuzhiyun case 'E':
452*4882a593Smuzhiyun while (*s && !isspace(*s)) s++;
453*4882a593Smuzhiyun *s = '\0';
454*4882a593Smuzhiyun externalfunctions(line+2);
455*4882a593Smuzhiyun break;
456*4882a593Smuzhiyun case 'I':
457*4882a593Smuzhiyun while (*s && !isspace(*s)) s++;
458*4882a593Smuzhiyun *s = '\0';
459*4882a593Smuzhiyun internalfunctions(line+2);
460*4882a593Smuzhiyun break;
461*4882a593Smuzhiyun case 'D':
462*4882a593Smuzhiyun while (*s && !isspace(*s)) s++;
463*4882a593Smuzhiyun *s = '\0';
464*4882a593Smuzhiyun symbolsonly(line+2);
465*4882a593Smuzhiyun break;
466*4882a593Smuzhiyun case 'F':
467*4882a593Smuzhiyun /* filename */
468*4882a593Smuzhiyun while (*s && !isspace(*s)) s++;
469*4882a593Smuzhiyun *s++ = '\0';
470*4882a593Smuzhiyun /* function names */
471*4882a593Smuzhiyun while (isspace(*s))
472*4882a593Smuzhiyun s++;
473*4882a593Smuzhiyun singlefunctions(line +2, s);
474*4882a593Smuzhiyun break;
475*4882a593Smuzhiyun case 'P':
476*4882a593Smuzhiyun /* filename */
477*4882a593Smuzhiyun while (*s && !isspace(*s)) s++;
478*4882a593Smuzhiyun *s++ = '\0';
479*4882a593Smuzhiyun /* DOC: section name */
480*4882a593Smuzhiyun while (isspace(*s))
481*4882a593Smuzhiyun s++;
482*4882a593Smuzhiyun docsection(line + 2, s);
483*4882a593Smuzhiyun break;
484*4882a593Smuzhiyun case 'C':
485*4882a593Smuzhiyun while (*s && !isspace(*s)) s++;
486*4882a593Smuzhiyun *s = '\0';
487*4882a593Smuzhiyun if (findall)
488*4882a593Smuzhiyun findall(line+2);
489*4882a593Smuzhiyun break;
490*4882a593Smuzhiyun default:
491*4882a593Smuzhiyun defaultline(line);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun } else {
494*4882a593Smuzhiyun defaultline(line);
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun fflush(stdout);
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun
main(int argc,char * argv[])501*4882a593Smuzhiyun int main(int argc, char *argv[])
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun FILE * infile;
504*4882a593Smuzhiyun int i;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun srctree = getenv("SRCTREE");
507*4882a593Smuzhiyun if (!srctree)
508*4882a593Smuzhiyun srctree = getcwd(NULL, 0);
509*4882a593Smuzhiyun kernsrctree = getenv("KBUILD_SRC");
510*4882a593Smuzhiyun if (!kernsrctree || !*kernsrctree)
511*4882a593Smuzhiyun kernsrctree = srctree;
512*4882a593Smuzhiyun if (argc != 3) {
513*4882a593Smuzhiyun usage();
514*4882a593Smuzhiyun exit(1);
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun /* Open file, exit on error */
517*4882a593Smuzhiyun infile = fopen(argv[2], "r");
518*4882a593Smuzhiyun if (infile == NULL) {
519*4882a593Smuzhiyun fprintf(stderr, "docproc: ");
520*4882a593Smuzhiyun perror(argv[2]);
521*4882a593Smuzhiyun exit(2);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun if (strcmp("doc", argv[1]) == 0) {
525*4882a593Smuzhiyun /* Need to do this in two passes.
526*4882a593Smuzhiyun * First pass is used to collect all symbols exported
527*4882a593Smuzhiyun * in the various files;
528*4882a593Smuzhiyun * Second pass generate the documentation.
529*4882a593Smuzhiyun * This is required because some functions are declared
530*4882a593Smuzhiyun * and exported in different files :-((
531*4882a593Smuzhiyun */
532*4882a593Smuzhiyun /* Collect symbols */
533*4882a593Smuzhiyun defaultline = noaction;
534*4882a593Smuzhiyun internalfunctions = find_export_symbols;
535*4882a593Smuzhiyun externalfunctions = find_export_symbols;
536*4882a593Smuzhiyun symbolsonly = find_export_symbols;
537*4882a593Smuzhiyun singlefunctions = noaction2;
538*4882a593Smuzhiyun docsection = noaction2;
539*4882a593Smuzhiyun findall = find_all_symbols;
540*4882a593Smuzhiyun parse_file(infile);
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun /* Rewind to start from beginning of file again */
543*4882a593Smuzhiyun fseek(infile, 0, SEEK_SET);
544*4882a593Smuzhiyun defaultline = printline;
545*4882a593Smuzhiyun internalfunctions = intfunc;
546*4882a593Smuzhiyun externalfunctions = extfunc;
547*4882a593Smuzhiyun symbolsonly = printline;
548*4882a593Smuzhiyun singlefunctions = singfunc;
549*4882a593Smuzhiyun docsection = docsect;
550*4882a593Smuzhiyun findall = NULL;
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun parse_file(infile);
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun for (i = 0; i < all_list_len; i++) {
555*4882a593Smuzhiyun if (!all_list[i])
556*4882a593Smuzhiyun continue;
557*4882a593Smuzhiyun fprintf(stderr, "Warning: didn't use docs for %s\n",
558*4882a593Smuzhiyun all_list[i]);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun } else if (strcmp("depend", argv[1]) == 0) {
561*4882a593Smuzhiyun /* Create first part of dependency chain
562*4882a593Smuzhiyun * file.tmpl */
563*4882a593Smuzhiyun printf("%s\t", argv[2]);
564*4882a593Smuzhiyun defaultline = noaction;
565*4882a593Smuzhiyun internalfunctions = adddep;
566*4882a593Smuzhiyun externalfunctions = adddep;
567*4882a593Smuzhiyun symbolsonly = adddep;
568*4882a593Smuzhiyun singlefunctions = adddep2;
569*4882a593Smuzhiyun docsection = adddep2;
570*4882a593Smuzhiyun findall = adddep;
571*4882a593Smuzhiyun parse_file(infile);
572*4882a593Smuzhiyun printf("\n");
573*4882a593Smuzhiyun } else {
574*4882a593Smuzhiyun fprintf(stderr, "Unknown option: %s\n", argv[1]);
575*4882a593Smuzhiyun exit(1);
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun fclose(infile);
578*4882a593Smuzhiyun fflush(stdout);
579*4882a593Smuzhiyun return exitstatus;
580*4882a593Smuzhiyun }
581