The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/scripts/docproc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 is scanned for
   14  *              any symbols that are exported via these macros:
   15  *                      EXPORT_SYMBOL(), EXPORT_SYMBOL_GPL(), &
   16  *                      EXPORT_SYMBOL_GPL_FUTURE()
   17  *              This is used to create proper -function and
   18  *              -nofunction arguments in calls to kernel-doc.
   19  *              Usage: docproc doc file.tmpl
   20  *
   21  *      dependency-generator:
   22  *              Scans the template file and list all files
   23  *              referenced in a format recognized by make.
   24  *              Usage:  docproc depend file.tmpl
   25  *              Writes dependency information to stdout
   26  *              in the following format:
   27  *              file.tmpl src.c src2.c
   28  *              The filenames are obtained from the following constructs:
   29  *              !Efilename
   30  *              !Ifilename
   31  *              !Dfilename
   32  *              !Ffilename
   33  *              !Pfilename
   34  *
   35  */
   36 
   37 #define _GNU_SOURCE
   38 #include <stdio.h>
   39 #include <stdlib.h>
   40 #include <string.h>
   41 #include <ctype.h>
   42 #include <unistd.h>
   43 #include <limits.h>
   44 #include <errno.h>
   45 #include <sys/types.h>
   46 #include <sys/wait.h>
   47 
   48 /* exitstatus is used to keep track of any failing calls to kernel-doc,
   49  * but execution continues. */
   50 int exitstatus = 0;
   51 
   52 typedef void DFL(char *);
   53 DFL *defaultline;
   54 
   55 typedef void FILEONLY(char * file);
   56 FILEONLY *internalfunctions;
   57 FILEONLY *externalfunctions;
   58 FILEONLY *symbolsonly;
   59 FILEONLY *findall;
   60 
   61 typedef void FILELINE(char * file, char * line);
   62 FILELINE * singlefunctions;
   63 FILELINE * entity_system;
   64 FILELINE * docsection;
   65 
   66 #define MAXLINESZ     2048
   67 #define MAXFILES      250
   68 #define KERNELDOCPATH "scripts/"
   69 #define KERNELDOC     "kernel-doc"
   70 #define DOCBOOK       "-docbook"
   71 #define LIST          "-list"
   72 #define FUNCTION      "-function"
   73 #define NOFUNCTION    "-nofunction"
   74 #define NODOCSECTIONS "-no-doc-sections"
   75 
   76 static char *srctree, *kernsrctree;
   77 
   78 static char **all_list = NULL;
   79 static int all_list_len = 0;
   80 
   81 static void consume_symbol(const char *sym)
   82 {
   83         int i;
   84 
   85         for (i = 0; i < all_list_len; i++) {
   86                 if (!all_list[i])
   87                         continue;
   88                 if (strcmp(sym, all_list[i]))
   89                         continue;
   90                 all_list[i] = NULL;
   91                 break;
   92         }
   93 }
   94 
   95 static void usage (void)
   96 {
   97         fprintf(stderr, "Usage: docproc {doc|depend} file\n");
   98         fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
   99         fprintf(stderr, "doc: frontend when generating kernel documentation\n");
  100         fprintf(stderr, "depend: generate list of files referenced within file\n");
  101         fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n");
  102         fprintf(stderr, "                     KBUILD_SRC: absolute path to kernel source tree.\n");
  103 }
  104 
  105 /*
  106  * Execute kernel-doc with parameters given in svec
  107  */
  108 static void exec_kernel_doc(char **svec)
  109 {
  110         pid_t pid;
  111         int ret;
  112         char real_filename[PATH_MAX + 1];
  113         /* Make sure output generated so far are flushed */
  114         fflush(stdout);
  115         switch (pid=fork()) {
  116                 case -1:
  117                         perror("fork");
  118                         exit(1);
  119                 case  0:
  120                         memset(real_filename, 0, sizeof(real_filename));
  121                         strncat(real_filename, kernsrctree, PATH_MAX);
  122                         strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
  123                                         PATH_MAX - strlen(real_filename));
  124                         execvp(real_filename, svec);
  125                         fprintf(stderr, "exec ");
  126                         perror(real_filename);
  127                         exit(1);
  128                 default:
  129                         waitpid(pid, &ret ,0);
  130         }
  131         if (WIFEXITED(ret))
  132                 exitstatus |= WEXITSTATUS(ret);
  133         else
  134                 exitstatus = 0xff;
  135 }
  136 
  137 /* Types used to create list of all exported symbols in a number of files */
  138 struct symbols
  139 {
  140         char *name;
  141 };
  142 
  143 struct symfile
  144 {
  145         char *filename;
  146         struct symbols *symbollist;
  147         int symbolcnt;
  148 };
  149 
  150 struct symfile symfilelist[MAXFILES];
  151 int symfilecnt = 0;
  152 
  153 static void add_new_symbol(struct symfile *sym, char * symname)
  154 {
  155         sym->symbollist =
  156           realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
  157         sym->symbollist[sym->symbolcnt++].name = strdup(symname);
  158 }
  159 
  160 /* Add a filename to the list */
  161 static struct symfile * add_new_file(char * filename)
  162 {
  163         symfilelist[symfilecnt++].filename = strdup(filename);
  164         return &symfilelist[symfilecnt - 1];
  165 }
  166 
  167 /* Check if file already are present in the list */
  168 static struct symfile * filename_exist(char * filename)
  169 {
  170         int i;
  171         for (i=0; i < symfilecnt; i++)
  172                 if (strcmp(symfilelist[i].filename, filename) == 0)
  173                         return &symfilelist[i];
  174         return NULL;
  175 }
  176 
  177 /*
  178  * List all files referenced within the template file.
  179  * Files are separated by tabs.
  180  */
  181 static void adddep(char * file)            { printf("\t%s", file); }
  182 static void adddep2(char * file, char * line)     { line = line; adddep(file); }
  183 static void noaction(char * line)                  { line = line; }
  184 static void noaction2(char * file, char * line)   { file = file; line = line; }
  185 
  186 /* Echo the line without further action */
  187 static void printline(char * line)               { printf("%s", line); }
  188 
  189 /*
  190  * Find all symbols in filename that are exported with EXPORT_SYMBOL &
  191  * EXPORT_SYMBOL_GPL (& EXPORT_SYMBOL_GPL_FUTURE implicitly).
  192  * All symbols located are stored in symfilelist.
  193  */
  194 static void find_export_symbols(char * filename)
  195 {
  196         FILE * fp;
  197         struct symfile *sym;
  198         char line[MAXLINESZ];
  199         if (filename_exist(filename) == NULL) {
  200                 char real_filename[PATH_MAX + 1];
  201                 memset(real_filename, 0, sizeof(real_filename));
  202                 strncat(real_filename, srctree, PATH_MAX);
  203                 strncat(real_filename, "/", PATH_MAX - strlen(real_filename));
  204                 strncat(real_filename, filename,
  205                                 PATH_MAX - strlen(real_filename));
  206                 sym = add_new_file(filename);
  207                 fp = fopen(real_filename, "r");
  208                 if (fp == NULL) {
  209                         fprintf(stderr, "docproc: ");
  210                         perror(real_filename);
  211                         exit(1);
  212                 }
  213                 while (fgets(line, MAXLINESZ, fp)) {
  214                         char *p;
  215                         char *e;
  216                         if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) ||
  217                             ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) {
  218                                 /* Skip EXPORT_SYMBOL{_GPL} */
  219                                 while (isalnum(*p) || *p == '_')
  220                                         p++;
  221                                 /* Remove parentheses & additional whitespace */
  222                                 while (isspace(*p))
  223                                         p++;
  224                                 if (*p != '(')
  225                                         continue; /* Syntax error? */
  226                                 else
  227                                         p++;
  228                                 while (isspace(*p))
  229                                         p++;
  230                                 e = p;
  231                                 while (isalnum(*e) || *e == '_')
  232                                         e++;
  233                                 *e = '\0';
  234                                 add_new_symbol(sym, p);
  235                         }
  236                 }
  237                 fclose(fp);
  238         }
  239 }
  240 
  241 /*
  242  * Document all external or internal functions in a file.
  243  * Call kernel-doc with following parameters:
  244  * kernel-doc -docbook -nofunction function_name1 filename
  245  * Function names are obtained from all the src files
  246  * by find_export_symbols.
  247  * intfunc uses -nofunction
  248  * extfunc uses -function
  249  */
  250 static void docfunctions(char * filename, char * type)
  251 {
  252         int i,j;
  253         int symcnt = 0;
  254         int idx = 0;
  255         char **vec;
  256 
  257         for (i=0; i <= symfilecnt; i++)
  258                 symcnt += symfilelist[i].symbolcnt;
  259         vec = malloc((2 + 2 * symcnt + 3) * sizeof(char *));
  260         if (vec == NULL) {
  261                 perror("docproc: ");
  262                 exit(1);
  263         }
  264         vec[idx++] = KERNELDOC;
  265         vec[idx++] = DOCBOOK;
  266         vec[idx++] = NODOCSECTIONS;
  267         for (i=0; i < symfilecnt; i++) {
  268                 struct symfile * sym = &symfilelist[i];
  269                 for (j=0; j < sym->symbolcnt; j++) {
  270                         vec[idx++]     = type;
  271                         consume_symbol(sym->symbollist[j].name);
  272                         vec[idx++] = sym->symbollist[j].name;
  273                 }
  274         }
  275         vec[idx++]     = filename;
  276         vec[idx] = NULL;
  277         printf("<!-- %s -->\n", filename);
  278         exec_kernel_doc(vec);
  279         fflush(stdout);
  280         free(vec);
  281 }
  282 static void intfunc(char * filename) {  docfunctions(filename, NOFUNCTION); }
  283 static void extfunc(char * filename) { docfunctions(filename, FUNCTION);   }
  284 
  285 /*
  286  * Document specific function(s) in a file.
  287  * Call kernel-doc with the following parameters:
  288  * kernel-doc -docbook -function function1 [-function function2]
  289  */
  290 static void singfunc(char * filename, char * line)
  291 {
  292         char *vec[200]; /* Enough for specific functions */
  293         int i, idx = 0;
  294         int startofsym = 1;
  295         vec[idx++] = KERNELDOC;
  296         vec[idx++] = DOCBOOK;
  297 
  298         /* Split line up in individual parameters preceded by FUNCTION */
  299         for (i=0; line[i]; i++) {
  300                 if (isspace(line[i])) {
  301                         line[i] = '\0';
  302                         startofsym = 1;
  303                         continue;
  304                 }
  305                 if (startofsym) {
  306                         startofsym = 0;
  307                         vec[idx++] = FUNCTION;
  308                         vec[idx++] = &line[i];
  309                 }
  310         }
  311         for (i = 0; i < idx; i++) {
  312                 if (strcmp(vec[i], FUNCTION))
  313                         continue;
  314                 consume_symbol(vec[i + 1]);
  315         }
  316         vec[idx++] = filename;
  317         vec[idx] = NULL;
  318         exec_kernel_doc(vec);
  319 }
  320 
  321 /*
  322  * Insert specific documentation section from a file.
  323  * Call kernel-doc with the following parameters:
  324  * kernel-doc -docbook -function "doc section" filename
  325  */
  326 static void docsect(char *filename, char *line)
  327 {
  328         char *vec[6]; /* kerneldoc -docbook -function "section" file NULL */
  329         char *s;
  330 
  331         for (s = line; *s; s++)
  332                 if (*s == '\n')
  333                         *s = '\0';
  334 
  335         if (asprintf(&s, "DOC: %s", line) < 0) {
  336                 perror("asprintf");
  337                 exit(1);
  338         }
  339         consume_symbol(s);
  340         free(s);
  341 
  342         vec[0] = KERNELDOC;
  343         vec[1] = DOCBOOK;
  344         vec[2] = FUNCTION;
  345         vec[3] = line;
  346         vec[4] = filename;
  347         vec[5] = NULL;
  348         exec_kernel_doc(vec);
  349 }
  350 
  351 static void find_all_symbols(char *filename)
  352 {
  353         char *vec[4]; /* kerneldoc -list file NULL */
  354         pid_t pid;
  355         int ret, i, count, start;
  356         char real_filename[PATH_MAX + 1];
  357         int pipefd[2];
  358         char *data, *str;
  359         size_t data_len = 0;
  360 
  361         vec[0] = KERNELDOC;
  362         vec[1] = LIST;
  363         vec[2] = filename;
  364         vec[3] = NULL;
  365 
  366         if (pipe(pipefd)) {
  367                 perror("pipe");
  368                 exit(1);
  369         }
  370 
  371         switch (pid=fork()) {
  372                 case -1:
  373                         perror("fork");
  374                         exit(1);
  375                 case  0:
  376                         close(pipefd[0]);
  377                         dup2(pipefd[1], 1);
  378                         memset(real_filename, 0, sizeof(real_filename));
  379                         strncat(real_filename, kernsrctree, PATH_MAX);
  380                         strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
  381                                         PATH_MAX - strlen(real_filename));
  382                         execvp(real_filename, vec);
  383                         fprintf(stderr, "exec ");
  384                         perror(real_filename);
  385                         exit(1);
  386                 default:
  387                         close(pipefd[1]);
  388                         data = malloc(4096);
  389                         do {
  390                                 while ((ret = read(pipefd[0],
  391                                                    data + data_len,
  392                                                    4096)) > 0) {
  393                                         data_len += ret;
  394                                         data = realloc(data, data_len + 4096);
  395                                 }
  396                         } while (ret == -EAGAIN);
  397                         if (ret != 0) {
  398                                 perror("read");
  399                                 exit(1);
  400                         }
  401                         waitpid(pid, &ret ,0);
  402         }
  403         if (WIFEXITED(ret))
  404                 exitstatus |= WEXITSTATUS(ret);
  405         else
  406                 exitstatus = 0xff;
  407 
  408         count = 0;
  409         /* poor man's strtok, but with counting */
  410         for (i = 0; i < data_len; i++) {
  411                 if (data[i] == '\n') {
  412                         count++;
  413                         data[i] = '\0';
  414                 }
  415         }
  416         start = all_list_len;
  417         all_list_len += count;
  418         all_list = realloc(all_list, sizeof(char *) * all_list_len);
  419         str = data;
  420         for (i = 0; i < data_len && start != all_list_len; i++) {
  421                 if (data[i] == '\0') {
  422                         all_list[start] = str;
  423                         str = data + i + 1;
  424                         start++;
  425                 }
  426         }
  427 }
  428 
  429 /*
  430  * Parse file, calling action specific functions for:
  431  * 1) Lines containing !E
  432  * 2) Lines containing !I
  433  * 3) Lines containing !D
  434  * 4) Lines containing !F
  435  * 5) Lines containing !P
  436  * 6) Lines containing !C
  437  * 7) Default lines - lines not matching the above
  438  */
  439 static void parse_file(FILE *infile)
  440 {
  441         char line[MAXLINESZ];
  442         char * s;
  443         while (fgets(line, MAXLINESZ, infile)) {
  444                 if (line[0] == '!') {
  445                         s = line + 2;
  446                         switch (line[1]) {
  447                                 case 'E':
  448                                         while (*s && !isspace(*s)) s++;
  449                                         *s = '\0';
  450                                         externalfunctions(line+2);
  451                                         break;
  452                                 case 'I':
  453                                         while (*s && !isspace(*s)) s++;
  454                                         *s = '\0';
  455                                         internalfunctions(line+2);
  456                                         break;
  457                                 case 'D':
  458                                         while (*s && !isspace(*s)) s++;
  459                                         *s = '\0';
  460                                         symbolsonly(line+2);
  461                                         break;
  462                                 case 'F':
  463                                         /* filename */
  464                                         while (*s && !isspace(*s)) s++;
  465                                         *s++ = '\0';
  466                                         /* function names */
  467                                         while (isspace(*s))
  468                                                 s++;
  469                                         singlefunctions(line +2, s);
  470                                         break;
  471                                 case 'P':
  472                                         /* filename */
  473                                         while (*s && !isspace(*s)) s++;
  474                                         *s++ = '\0';
  475                                         /* DOC: section name */
  476                                         while (isspace(*s))
  477                                                 s++;
  478                                         docsection(line + 2, s);
  479                                         break;
  480                                 case 'C':
  481                                         while (*s && !isspace(*s)) s++;
  482                                         *s = '\0';
  483                                         if (findall)
  484                                                 findall(line+2);
  485                                         break;
  486                                 default:
  487                                         defaultline(line);
  488                         }
  489                 } else {
  490                         defaultline(line);
  491                 }
  492         }
  493         fflush(stdout);
  494 }
  495 
  496 
  497 int main(int argc, char *argv[])
  498 {
  499         FILE * infile;
  500         int i;
  501 
  502         srctree = getenv("SRCTREE");
  503         if (!srctree)
  504                 srctree = getcwd(NULL, 0);
  505         kernsrctree = getenv("KBUILD_SRC");
  506         if (!kernsrctree || !*kernsrctree)
  507                 kernsrctree = srctree;
  508         if (argc != 3) {
  509                 usage();
  510                 exit(1);
  511         }
  512         /* Open file, exit on error */
  513         infile = fopen(argv[2], "r");
  514         if (infile == NULL) {
  515                 fprintf(stderr, "docproc: ");
  516                 perror(argv[2]);
  517                 exit(2);
  518         }
  519 
  520         if (strcmp("doc", argv[1]) == 0) {
  521                 /* Need to do this in two passes.
  522                  * First pass is used to collect all symbols exported
  523                  * in the various files;
  524                  * Second pass generate the documentation.
  525                  * This is required because some functions are declared
  526                  * and exported in different files :-((
  527                  */
  528                 /* Collect symbols */
  529                 defaultline       = noaction;
  530                 internalfunctions = find_export_symbols;
  531                 externalfunctions = find_export_symbols;
  532                 symbolsonly       = find_export_symbols;
  533                 singlefunctions   = noaction2;
  534                 docsection        = noaction2;
  535                 findall           = find_all_symbols;
  536                 parse_file(infile);
  537 
  538                 /* Rewind to start from beginning of file again */
  539                 fseek(infile, 0, SEEK_SET);
  540                 defaultline       = printline;
  541                 internalfunctions = intfunc;
  542                 externalfunctions = extfunc;
  543                 symbolsonly       = printline;
  544                 singlefunctions   = singfunc;
  545                 docsection        = docsect;
  546                 findall           = NULL;
  547 
  548                 parse_file(infile);
  549 
  550                 for (i = 0; i < all_list_len; i++) {
  551                         if (!all_list[i])
  552                                 continue;
  553                         fprintf(stderr, "Warning: didn't use docs for %s\n",
  554                                 all_list[i]);
  555                 }
  556         } else if (strcmp("depend", argv[1]) == 0) {
  557                 /* Create first part of dependency chain
  558                  * file.tmpl */
  559                 printf("%s\t", argv[2]);
  560                 defaultline       = noaction;
  561                 internalfunctions = adddep;
  562                 externalfunctions = adddep;
  563                 symbolsonly       = adddep;
  564                 singlefunctions   = adddep2;
  565                 docsection        = adddep2;
  566                 findall           = adddep;
  567                 parse_file(infile);
  568                 printf("\n");
  569         } else {
  570                 fprintf(stderr, "Unknown option: %s\n", argv[1]);
  571                 exit(1);
  572         }
  573         fclose(infile);
  574         fflush(stdout);
  575         return exitstatus;
  576 }

Cache object: e0a79dd93213ebb1b46e1f0c5b481999


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.