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//bbox disabled: #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                        unsigned char *p;
 186                        unsigned char *e;
 187                        if (((p = (unsigned char *)strstr(line, "EXPORT_SYMBOL_GPL")) != 0) ||
 188                            ((p = (unsigned char *)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, (char*)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 preceded by FUNCTION */
 268        for (i=0; line[i]; i++) {
 269                if (isspace((unsigned char) 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        unsigned char * s;
 297        while (fgets(line, MAXLINESZ, infile)) {
 298                if (line[0] == '!') {
 299                        s = (unsigned char *)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, (char*)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}
 401