source: branches/3.2/mindi-busybox/scripts/basic/docproc.c @ 3232

Last change on this file since 3232 was 3232, checked in by bruno, 5 years ago
  • Update mindi-busybox to 1.21.1
  • Property svn:eol-style set to native
File size: 9.6 KB
Line 
1/*
2 *  docproc is a simple preprocessor for the template files
3 *      used as placeholders for the kernel internal documentation.
4 *  docproc is used for documentation-frontend and
5 *      dependency-generator.
6 *  The two usages have in common that they require
7 *  some knowledge of the .tmpl syntax, therefore they
8 *  are kept together.
9 *
10 *  documentation-frontend
11 *      Scans the template file and call kernel-doc for
12 *      all occurrences of ![EIF]file
13 *      Beforehand each referenced file are scanned for
14 *      any exported sympols "EXPORT_SYMBOL()" statements.
15 *      This is used to create proper -function and
16 *      -nofunction arguments in calls to kernel-doc.
17 *      Usage: docproc doc file.tmpl
18 *
19 *  dependency-generator:
20 *      Scans the template file and list all files
21 *      referenced in a format recognized by make.
22 *      Usage:  docproc depend file.tmpl
23 *      Writes dependency information to stdout
24 *      in the following format:
25 *      file.tmpl src.c src2.c
26 *      The filenames are obtained from the following constructs:
27 *      !Efilename
28 *      !Ifilename
29 *      !Dfilename
30 *      !Ffilename
31 *
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <ctype.h>
38#include <unistd.h>
39#include <limits.h>
40#include <sys/types.h>
41#include <sys/wait.h>
42#include <alloca.h>
43
44/* exitstatus is used to keep track of any failing calls to kernel-doc,
45 * but execution continues. */
46int exitstatus = 0;
47
48typedef void DFL(char *);
49DFL *defaultline;
50
51typedef void FILEONLY(char * file);
52FILEONLY *internalfunctions;
53FILEONLY *externalfunctions;
54FILEONLY *symbolsonly;
55
56typedef void FILELINE(char * file, char * line);
57FILELINE * singlefunctions;
58FILELINE * entity_system;
59
60#define MAXLINESZ     2048
61#define MAXFILES      250
62#define KERNELDOCPATH "scripts/"
63#define KERNELDOC     "kernel-doc"
64#define DOCBOOK       "-docbook"
65#define FUNCTION      "-function"
66#define NOFUNCTION    "-nofunction"
67
68void usage (void)
69{
70    fprintf(stderr, "Usage: docproc {doc|depend} file\n");
71    fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
72    fprintf(stderr, "doc: frontend when generating kernel documentation\n");
73    fprintf(stderr, "depend: generate list of files referenced within file\n");
74}
75
76/*
77 * Execute kernel-doc with parameters givin in svec
78 */
79void exec_kernel_doc(char **svec)
80{
81    pid_t pid;
82    int ret;
83    char *real_filename;
84    int rflen;
85
86    /* Make sure output generated so far are flushed */
87    fflush(stdout);
88    switch(pid=fork()) {
89        case -1:
90            perror("vfork"+1);
91            exit(1);
92        case  0:
93            rflen  = strlen(getenv("SRCTREE"));
94            rflen += strlen(KERNELDOCPATH KERNELDOC);
95            real_filename = alloca(rflen + 1);
96            strcpy(real_filename, getenv("SRCTREE"));
97            strcat(real_filename, KERNELDOCPATH KERNELDOC);
98            execvp(real_filename, svec);
99            fprintf(stderr, "exec ");
100            perror(real_filename);
101            exit(1);
102        default:
103            waitpid(pid, &ret ,0);
104    }
105    if (WIFEXITED(ret))
106        exitstatus |= WEXITSTATUS(ret);
107    else
108        exitstatus = 0xff;
109}
110
111/* Types used to create list of all exported symbols in a number of files */
112struct symbols
113{
114    char *name;
115};
116
117struct symfile
118{
119    char *filename;
120    struct symbols *symbollist;
121    int symbolcnt;
122};
123
124struct symfile symfilelist[MAXFILES];
125int symfilecnt = 0;
126
127void add_new_symbol(struct symfile *sym, char * symname)
128{
129    sym->symbollist =
130      realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
131    sym->symbollist[sym->symbolcnt++].name = strdup(symname);
132}
133
134/* Add a filename to the list */
135struct symfile * add_new_file(char * filename)
136{
137    symfilelist[symfilecnt++].filename = strdup(filename);
138    return &symfilelist[symfilecnt - 1];
139}
140/* Check if file already are present in the list */
141struct symfile * filename_exist(char * filename)
142{
143    int i;
144    for (i=0; i < symfilecnt; i++)
145        if (strcmp(symfilelist[i].filename, filename) == 0)
146            return &symfilelist[i];
147    return NULL;
148}
149
150/*
151 * List all files referenced within the template file.
152 * Files are separated by tabs.
153 */
154void adddep(char * file)           { printf("\t%s", file); }
155void adddep2(char * file, char * line)     { line = line; adddep(file); }
156void noaction(char * line)         { line = line; }
157void noaction2(char * file, char * line)   { file = file; line = line; }
158
159/* Echo the line without further action */
160void printline(char * line)               { printf("%s", line); }
161
162/*
163 * Find all symbols exported with EXPORT_SYMBOL and EXPORT_SYMBOL_GPL
164 * in filename.
165 * All symbols located are stored in symfilelist.
166 */
167void find_export_symbols(char * filename)
168{
169    FILE * fp;
170    struct symfile *sym;
171    char line[MAXLINESZ];
172    if (filename_exist(filename) == NULL) {
173        int rflen = strlen(getenv("SRCTREE")) + strlen(filename);
174        char *real_filename = alloca(rflen + 1);
175        strcpy(real_filename, getenv("SRCTREE"));
176        strcat(real_filename, filename);
177        sym = add_new_file(filename);
178        fp = fopen(real_filename, "r");
179        if (fp == NULL)
180        {
181            fprintf(stderr, "docproc: ");
182            perror(real_filename);
183        }
184        while (fgets(line, MAXLINESZ, fp)) {
185            char *p;
186            char *e;
187            if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) ||
188                ((p = strstr(line, "EXPORT_SYMBOL")) != 0)) {
189                /* Skip EXPORT_SYMBOL{_GPL} */
190                while (isalnum(*p) || *p == '_')
191                    p++;
192                /* Remove paranteses and additional ws */
193                while (isspace(*p))
194                    p++;
195                if (*p != '(')
196                    continue; /* Syntax error? */
197                else
198                    p++;
199                while (isspace(*p))
200                    p++;
201                e = p;
202                while (isalnum(*e) || *e == '_')
203                    e++;
204                *e = '\0';
205                add_new_symbol(sym, p);
206            }
207        }
208        fclose(fp);
209    }
210}
211
212/*
213 * Document all external or internal functions in a file.
214 * Call kernel-doc with following parameters:
215 * kernel-doc -docbook -nofunction function_name1 filename
216 * function names are obtained from all the src files
217 * by find_export_symbols.
218 * intfunc uses -nofunction
219 * extfunc uses -function
220 */
221void docfunctions(char * filename, char * type)
222{
223    int i,j;
224    int symcnt = 0;
225    int idx = 0;
226    char **vec;
227
228    for (i=0; i <= symfilecnt; i++)
229        symcnt += symfilelist[i].symbolcnt;
230    vec = malloc((2 + 2 * symcnt + 2) * sizeof(char*));
231    if (vec == NULL) {
232        perror("docproc: ");
233        exit(1);
234    }
235    vec[idx++] = KERNELDOC;
236    vec[idx++] = DOCBOOK;
237    for (i=0; i < symfilecnt; i++) {
238        struct symfile * sym = &symfilelist[i];
239        for (j=0; j < sym->symbolcnt; j++) {
240            vec[idx++]     = type;
241            vec[idx++] = sym->symbollist[j].name;
242        }
243    }
244    vec[idx++]     = filename;
245    vec[idx] = NULL;
246    printf("<!-- %s -->\n", filename);
247    exec_kernel_doc(vec);
248    fflush(stdout);
249    free(vec);
250}
251void intfunc(char * filename) { docfunctions(filename, NOFUNCTION); }
252void extfunc(char * filename) { docfunctions(filename, FUNCTION);   }
253
254/*
255 * Document specific function(s) in a file.
256 * Call kernel-doc with the following parameters:
257 * kernel-doc -docbook -function function1 [-function function2]
258 */
259void singfunc(char * filename, char * line)
260{
261    char *vec[200]; /* Enough for specific functions */
262    int i, idx = 0;
263    int startofsym = 1;
264    vec[idx++] = KERNELDOC;
265    vec[idx++] = DOCBOOK;
266
267    /* Split line up in individual parameters preceeded by FUNCTION */
268    for (i=0; line[i]; i++) {
269        if (isspace(line[i])) {
270            line[i] = '\0';
271            startofsym = 1;
272            continue;
273        }
274        if (startofsym) {
275            startofsym = 0;
276            vec[idx++] = FUNCTION;
277            vec[idx++] = &line[i];
278        }
279    }
280    vec[idx++] = filename;
281    vec[idx] = NULL;
282    exec_kernel_doc(vec);
283}
284
285/*
286 * Parse file, calling action specific functions for:
287 * 1) Lines containing !E
288 * 2) Lines containing !I
289 * 3) Lines containing !D
290 * 4) Lines containing !F
291 * 5) Default lines - lines not matching the above
292 */
293void parse_file(FILE *infile)
294{
295    char line[MAXLINESZ];
296    char * s;
297    while (fgets(line, MAXLINESZ, infile)) {
298        if (line[0] == '!') {
299            s = line + 2;
300            switch (line[1]) {
301                case 'E':
302                    while (*s && !isspace(*s)) s++;
303                    *s = '\0';
304                    externalfunctions(line+2);
305                    break;
306                case 'I':
307                    while (*s && !isspace(*s)) s++;
308                    *s = '\0';
309                    internalfunctions(line+2);
310                    break;
311                case 'D':
312                    while (*s && !isspace(*s)) s++;
313                    *s = '\0';
314                    symbolsonly(line+2);
315                    break;
316                case 'F':
317                    /* filename */
318                    while (*s && !isspace(*s)) s++;
319                    *s++ = '\0';
320                    /* function names */
321                    while (isspace(*s))
322                        s++;
323                    singlefunctions(line +2, s);
324                    break;
325                default:
326                    defaultline(line);
327            }
328        }
329        else {
330            defaultline(line);
331        }
332    }
333    fflush(stdout);
334}
335
336
337int main(int argc, char **argv)
338{
339    FILE * infile;
340    if (argc != 3) {
341        usage();
342        exit(1);
343    }
344    /* Open file, exit on error */
345    infile = fopen(argv[2], "r");
346    if (infile == NULL) {
347        fprintf(stderr, "docproc: ");
348        perror(argv[2]);
349        exit(2);
350    }
351
352    if (strcmp("doc", argv[1]) == 0)
353    {
354        /* Need to do this in two passes.
355         * First pass is used to collect all symbols exported
356         * in the various files.
357         * Second pass generate the documentation.
358         * This is required because function are declared
359         * and exported in different files :-((
360         */
361        /* Collect symbols */
362        defaultline       = noaction;
363        internalfunctions = find_export_symbols;
364        externalfunctions = find_export_symbols;
365        symbolsonly       = find_export_symbols;
366        singlefunctions   = noaction2;
367        parse_file(infile);
368
369        /* Rewind to start from beginning of file again */
370        fseek(infile, 0, SEEK_SET);
371        defaultline       = printline;
372        internalfunctions = intfunc;
373        externalfunctions = extfunc;
374        symbolsonly       = printline;
375        singlefunctions   = singfunc;
376
377        parse_file(infile);
378    }
379    else if (strcmp("depend", argv[1]) == 0)
380    {
381        /* Create first part of dependency chain
382         * file.tmpl */
383        printf("%s\t", argv[2]);
384        defaultline       = noaction;
385        internalfunctions = adddep;
386        externalfunctions = adddep;
387        symbolsonly       = adddep;
388        singlefunctions   = adddep2;
389        parse_file(infile);
390        printf("\n");
391    }
392    else
393    {
394        fprintf(stderr, "Unknown option: %s\n", argv[1]);
395        exit(1);
396    }
397    fclose(infile);
398    fflush(stdout);
399    return exitstatus;
400}
Note: See TracBrowser for help on using the repository browser.