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