home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / src / linux-headers-2.6.17-6-686 / scripts / basic / docproc.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-08-11  |  10.0 KB  |  399 lines

  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. */
  45. int exitstatus = 0;
  46.  
  47. typedef void DFL(char *);
  48. DFL *defaultline;
  49.  
  50. typedef void FILEONLY(char * file);
  51. FILEONLY *internalfunctions;
  52. FILEONLY *externalfunctions;
  53. FILEONLY *symbolsonly;
  54.  
  55. typedef void FILELINE(char * file, char * line);
  56. FILELINE * singlefunctions;
  57. FILELINE * 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.  
  67. void 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.  */
  78. void 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 */
  108. struct symbols
  109. {
  110.     char *name;
  111. };
  112.  
  113. struct symfile
  114. {
  115.     char *filename;
  116.     struct symbols *symbollist;
  117.     int symbolcnt;
  118. };
  119.  
  120. struct symfile symfilelist[MAXFILES];
  121. int symfilecnt = 0;
  122.  
  123. void 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 */
  131. struct 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 */
  137. struct 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.  */
  150. void adddep(char * file)           { printf("\t%s", file); }
  151. void adddep2(char * file, char * line)     { line = line; adddep(file); }
  152. void noaction(char * line)           { line = line; }
  153. void noaction2(char * file, char * line)   { file = file; line = line; }
  154.  
  155. /* Echo the line without further action */
  156. void 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.  */
  163. void 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.  */
  218. void 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. }
  248. void intfunc(char * filename) {    docfunctions(filename, NOFUNCTION); }
  249. void 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.  */
  256. void 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.  */
  290. void 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.  
  334. int 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.