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