18fac9c7bSMasahiro Yamada /* 28fac9c7bSMasahiro Yamada * docproc is a simple preprocessor for the template files 38fac9c7bSMasahiro Yamada * used as placeholders for the kernel internal documentation. 48fac9c7bSMasahiro Yamada * docproc is used for documentation-frontend and 58fac9c7bSMasahiro Yamada * dependency-generator. 68fac9c7bSMasahiro Yamada * The two usages have in common that they require 78fac9c7bSMasahiro Yamada * some knowledge of the .tmpl syntax, therefore they 88fac9c7bSMasahiro Yamada * are kept together. 98fac9c7bSMasahiro Yamada * 108fac9c7bSMasahiro Yamada * documentation-frontend 118fac9c7bSMasahiro Yamada * Scans the template file and call kernel-doc for 128fac9c7bSMasahiro Yamada * all occurrences of ![EIF]file 138fac9c7bSMasahiro Yamada * Beforehand each referenced file is scanned for 148fac9c7bSMasahiro Yamada * any symbols that are exported via these macros: 158fac9c7bSMasahiro Yamada * EXPORT_SYMBOL(), EXPORT_SYMBOL_GPL(), & 168fac9c7bSMasahiro Yamada * EXPORT_SYMBOL_GPL_FUTURE() 178fac9c7bSMasahiro Yamada * This is used to create proper -function and 188fac9c7bSMasahiro Yamada * -nofunction arguments in calls to kernel-doc. 198fac9c7bSMasahiro Yamada * Usage: docproc doc file.tmpl 208fac9c7bSMasahiro Yamada * 218fac9c7bSMasahiro Yamada * dependency-generator: 228fac9c7bSMasahiro Yamada * Scans the template file and list all files 238fac9c7bSMasahiro Yamada * referenced in a format recognized by make. 248fac9c7bSMasahiro Yamada * Usage: docproc depend file.tmpl 258fac9c7bSMasahiro Yamada * Writes dependency information to stdout 268fac9c7bSMasahiro Yamada * in the following format: 278fac9c7bSMasahiro Yamada * file.tmpl src.c src2.c 288fac9c7bSMasahiro Yamada * The filenames are obtained from the following constructs: 298fac9c7bSMasahiro Yamada * !Efilename 308fac9c7bSMasahiro Yamada * !Ifilename 318fac9c7bSMasahiro Yamada * !Dfilename 328fac9c7bSMasahiro Yamada * !Ffilename 338fac9c7bSMasahiro Yamada * !Pfilename 348fac9c7bSMasahiro Yamada * 358fac9c7bSMasahiro Yamada */ 368fac9c7bSMasahiro Yamada 378fac9c7bSMasahiro Yamada #define _GNU_SOURCE 388fac9c7bSMasahiro Yamada #include <stdio.h> 398fac9c7bSMasahiro Yamada #include <stdlib.h> 408fac9c7bSMasahiro Yamada #include <string.h> 418fac9c7bSMasahiro Yamada #include <ctype.h> 428fac9c7bSMasahiro Yamada #include <unistd.h> 438fac9c7bSMasahiro Yamada #include <limits.h> 448fac9c7bSMasahiro Yamada #include <errno.h> 458fac9c7bSMasahiro Yamada #include <sys/types.h> 468fac9c7bSMasahiro Yamada #include <sys/wait.h> 478fac9c7bSMasahiro Yamada 488fac9c7bSMasahiro Yamada /* exitstatus is used to keep track of any failing calls to kernel-doc, 498fac9c7bSMasahiro Yamada * but execution continues. */ 508fac9c7bSMasahiro Yamada int exitstatus = 0; 518fac9c7bSMasahiro Yamada 528fac9c7bSMasahiro Yamada typedef void DFL(char *); 538fac9c7bSMasahiro Yamada DFL *defaultline; 548fac9c7bSMasahiro Yamada 558fac9c7bSMasahiro Yamada typedef void FILEONLY(char * file); 568fac9c7bSMasahiro Yamada FILEONLY *internalfunctions; 578fac9c7bSMasahiro Yamada FILEONLY *externalfunctions; 588fac9c7bSMasahiro Yamada FILEONLY *symbolsonly; 598fac9c7bSMasahiro Yamada FILEONLY *findall; 608fac9c7bSMasahiro Yamada 618fac9c7bSMasahiro Yamada typedef void FILELINE(char * file, char * line); 628fac9c7bSMasahiro Yamada FILELINE * singlefunctions; 638fac9c7bSMasahiro Yamada FILELINE * entity_system; 648fac9c7bSMasahiro Yamada FILELINE * docsection; 658fac9c7bSMasahiro Yamada 668fac9c7bSMasahiro Yamada #define MAXLINESZ 2048 678fac9c7bSMasahiro Yamada #define MAXFILES 250 688fac9c7bSMasahiro Yamada #define KERNELDOCPATH "scripts/" 698fac9c7bSMasahiro Yamada #define KERNELDOC "kernel-doc" 708fac9c7bSMasahiro Yamada #define DOCBOOK "-docbook" 718fac9c7bSMasahiro Yamada #define LIST "-list" 728fac9c7bSMasahiro Yamada #define FUNCTION "-function" 738fac9c7bSMasahiro Yamada #define NOFUNCTION "-nofunction" 748fac9c7bSMasahiro Yamada #define NODOCSECTIONS "-no-doc-sections" 75*ced03298SMasahiro Yamada #define SHOWNOTFOUND "-show-not-found" 768fac9c7bSMasahiro Yamada 778fac9c7bSMasahiro Yamada static char *srctree, *kernsrctree; 788fac9c7bSMasahiro Yamada 798fac9c7bSMasahiro Yamada static char **all_list = NULL; 808fac9c7bSMasahiro Yamada static int all_list_len = 0; 818fac9c7bSMasahiro Yamada 828fac9c7bSMasahiro Yamada static void consume_symbol(const char *sym) 838fac9c7bSMasahiro Yamada { 848fac9c7bSMasahiro Yamada int i; 858fac9c7bSMasahiro Yamada 868fac9c7bSMasahiro Yamada for (i = 0; i < all_list_len; i++) { 878fac9c7bSMasahiro Yamada if (!all_list[i]) 888fac9c7bSMasahiro Yamada continue; 898fac9c7bSMasahiro Yamada if (strcmp(sym, all_list[i])) 908fac9c7bSMasahiro Yamada continue; 918fac9c7bSMasahiro Yamada all_list[i] = NULL; 928fac9c7bSMasahiro Yamada break; 938fac9c7bSMasahiro Yamada } 948fac9c7bSMasahiro Yamada } 958fac9c7bSMasahiro Yamada 968fac9c7bSMasahiro Yamada static void usage (void) 978fac9c7bSMasahiro Yamada { 988fac9c7bSMasahiro Yamada fprintf(stderr, "Usage: docproc {doc|depend} file\n"); 998fac9c7bSMasahiro Yamada fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n"); 1008fac9c7bSMasahiro Yamada fprintf(stderr, "doc: frontend when generating kernel documentation\n"); 1018fac9c7bSMasahiro Yamada fprintf(stderr, "depend: generate list of files referenced within file\n"); 1028fac9c7bSMasahiro Yamada fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n"); 1038fac9c7bSMasahiro Yamada fprintf(stderr, " KBUILD_SRC: absolute path to kernel source tree.\n"); 1048fac9c7bSMasahiro Yamada } 1058fac9c7bSMasahiro Yamada 1068fac9c7bSMasahiro Yamada /* 1078fac9c7bSMasahiro Yamada * Execute kernel-doc with parameters given in svec 1088fac9c7bSMasahiro Yamada */ 1098fac9c7bSMasahiro Yamada static void exec_kernel_doc(char **svec) 1108fac9c7bSMasahiro Yamada { 1118fac9c7bSMasahiro Yamada pid_t pid; 1128fac9c7bSMasahiro Yamada int ret; 1138fac9c7bSMasahiro Yamada char real_filename[PATH_MAX + 1]; 1148fac9c7bSMasahiro Yamada /* Make sure output generated so far are flushed */ 1158fac9c7bSMasahiro Yamada fflush(stdout); 1168fac9c7bSMasahiro Yamada switch (pid=fork()) { 1178fac9c7bSMasahiro Yamada case -1: 1188fac9c7bSMasahiro Yamada perror("fork"); 1198fac9c7bSMasahiro Yamada exit(1); 1208fac9c7bSMasahiro Yamada case 0: 1218fac9c7bSMasahiro Yamada memset(real_filename, 0, sizeof(real_filename)); 1228fac9c7bSMasahiro Yamada strncat(real_filename, kernsrctree, PATH_MAX); 1238fac9c7bSMasahiro Yamada strncat(real_filename, "/" KERNELDOCPATH KERNELDOC, 1248fac9c7bSMasahiro Yamada PATH_MAX - strlen(real_filename)); 1258fac9c7bSMasahiro Yamada execvp(real_filename, svec); 1268fac9c7bSMasahiro Yamada fprintf(stderr, "exec "); 1278fac9c7bSMasahiro Yamada perror(real_filename); 1288fac9c7bSMasahiro Yamada exit(1); 1298fac9c7bSMasahiro Yamada default: 1308fac9c7bSMasahiro Yamada waitpid(pid, &ret ,0); 1318fac9c7bSMasahiro Yamada } 1328fac9c7bSMasahiro Yamada if (WIFEXITED(ret)) 1338fac9c7bSMasahiro Yamada exitstatus |= WEXITSTATUS(ret); 1348fac9c7bSMasahiro Yamada else 1358fac9c7bSMasahiro Yamada exitstatus = 0xff; 1368fac9c7bSMasahiro Yamada } 1378fac9c7bSMasahiro Yamada 1388fac9c7bSMasahiro Yamada /* Types used to create list of all exported symbols in a number of files */ 1398fac9c7bSMasahiro Yamada struct symbols 1408fac9c7bSMasahiro Yamada { 1418fac9c7bSMasahiro Yamada char *name; 1428fac9c7bSMasahiro Yamada }; 1438fac9c7bSMasahiro Yamada 1448fac9c7bSMasahiro Yamada struct symfile 1458fac9c7bSMasahiro Yamada { 1468fac9c7bSMasahiro Yamada char *filename; 1478fac9c7bSMasahiro Yamada struct symbols *symbollist; 1488fac9c7bSMasahiro Yamada int symbolcnt; 1498fac9c7bSMasahiro Yamada }; 1508fac9c7bSMasahiro Yamada 1518fac9c7bSMasahiro Yamada struct symfile symfilelist[MAXFILES]; 1528fac9c7bSMasahiro Yamada int symfilecnt = 0; 1538fac9c7bSMasahiro Yamada 1548fac9c7bSMasahiro Yamada static void add_new_symbol(struct symfile *sym, char * symname) 1558fac9c7bSMasahiro Yamada { 1568fac9c7bSMasahiro Yamada sym->symbollist = 1578fac9c7bSMasahiro Yamada realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *)); 1588fac9c7bSMasahiro Yamada sym->symbollist[sym->symbolcnt++].name = strdup(symname); 1598fac9c7bSMasahiro Yamada } 1608fac9c7bSMasahiro Yamada 1618fac9c7bSMasahiro Yamada /* Add a filename to the list */ 1628fac9c7bSMasahiro Yamada static struct symfile * add_new_file(char * filename) 1638fac9c7bSMasahiro Yamada { 1648fac9c7bSMasahiro Yamada symfilelist[symfilecnt++].filename = strdup(filename); 1658fac9c7bSMasahiro Yamada return &symfilelist[symfilecnt - 1]; 1668fac9c7bSMasahiro Yamada } 1678fac9c7bSMasahiro Yamada 1688fac9c7bSMasahiro Yamada /* Check if file already are present in the list */ 1698fac9c7bSMasahiro Yamada static struct symfile * filename_exist(char * filename) 1708fac9c7bSMasahiro Yamada { 1718fac9c7bSMasahiro Yamada int i; 1728fac9c7bSMasahiro Yamada for (i=0; i < symfilecnt; i++) 1738fac9c7bSMasahiro Yamada if (strcmp(symfilelist[i].filename, filename) == 0) 1748fac9c7bSMasahiro Yamada return &symfilelist[i]; 1758fac9c7bSMasahiro Yamada return NULL; 1768fac9c7bSMasahiro Yamada } 1778fac9c7bSMasahiro Yamada 1788fac9c7bSMasahiro Yamada /* 1798fac9c7bSMasahiro Yamada * List all files referenced within the template file. 1808fac9c7bSMasahiro Yamada * Files are separated by tabs. 1818fac9c7bSMasahiro Yamada */ 1828fac9c7bSMasahiro Yamada static void adddep(char * file) { printf("\t%s", file); } 1838fac9c7bSMasahiro Yamada static void adddep2(char * file, char * line) { line = line; adddep(file); } 1848fac9c7bSMasahiro Yamada static void noaction(char * line) { line = line; } 1858fac9c7bSMasahiro Yamada static void noaction2(char * file, char * line) { file = file; line = line; } 1868fac9c7bSMasahiro Yamada 1878fac9c7bSMasahiro Yamada /* Echo the line without further action */ 1888fac9c7bSMasahiro Yamada static void printline(char * line) { printf("%s", line); } 1898fac9c7bSMasahiro Yamada 1908fac9c7bSMasahiro Yamada /* 1918fac9c7bSMasahiro Yamada * Find all symbols in filename that are exported with EXPORT_SYMBOL & 1928fac9c7bSMasahiro Yamada * EXPORT_SYMBOL_GPL (& EXPORT_SYMBOL_GPL_FUTURE implicitly). 1938fac9c7bSMasahiro Yamada * All symbols located are stored in symfilelist. 1948fac9c7bSMasahiro Yamada */ 1958fac9c7bSMasahiro Yamada static void find_export_symbols(char * filename) 1968fac9c7bSMasahiro Yamada { 1978fac9c7bSMasahiro Yamada FILE * fp; 1988fac9c7bSMasahiro Yamada struct symfile *sym; 1998fac9c7bSMasahiro Yamada char line[MAXLINESZ]; 2008fac9c7bSMasahiro Yamada if (filename_exist(filename) == NULL) { 2018fac9c7bSMasahiro Yamada char real_filename[PATH_MAX + 1]; 2028fac9c7bSMasahiro Yamada memset(real_filename, 0, sizeof(real_filename)); 2038fac9c7bSMasahiro Yamada strncat(real_filename, srctree, PATH_MAX); 2048fac9c7bSMasahiro Yamada strncat(real_filename, "/", PATH_MAX - strlen(real_filename)); 2058fac9c7bSMasahiro Yamada strncat(real_filename, filename, 2068fac9c7bSMasahiro Yamada PATH_MAX - strlen(real_filename)); 2078fac9c7bSMasahiro Yamada sym = add_new_file(filename); 2088fac9c7bSMasahiro Yamada fp = fopen(real_filename, "r"); 2098fac9c7bSMasahiro Yamada if (fp == NULL) { 2108fac9c7bSMasahiro Yamada fprintf(stderr, "docproc: "); 2118fac9c7bSMasahiro Yamada perror(real_filename); 2128fac9c7bSMasahiro Yamada exit(1); 2138fac9c7bSMasahiro Yamada } 2148fac9c7bSMasahiro Yamada while (fgets(line, MAXLINESZ, fp)) { 2158fac9c7bSMasahiro Yamada char *p; 2168fac9c7bSMasahiro Yamada char *e; 2178fac9c7bSMasahiro Yamada if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) || 2188fac9c7bSMasahiro Yamada ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) { 2198fac9c7bSMasahiro Yamada /* Skip EXPORT_SYMBOL{_GPL} */ 2208fac9c7bSMasahiro Yamada while (isalnum(*p) || *p == '_') 2218fac9c7bSMasahiro Yamada p++; 2228fac9c7bSMasahiro Yamada /* Remove parentheses & additional whitespace */ 2238fac9c7bSMasahiro Yamada while (isspace(*p)) 2248fac9c7bSMasahiro Yamada p++; 2258fac9c7bSMasahiro Yamada if (*p != '(') 2268fac9c7bSMasahiro Yamada continue; /* Syntax error? */ 2278fac9c7bSMasahiro Yamada else 2288fac9c7bSMasahiro Yamada p++; 2298fac9c7bSMasahiro Yamada while (isspace(*p)) 2308fac9c7bSMasahiro Yamada p++; 2318fac9c7bSMasahiro Yamada e = p; 2328fac9c7bSMasahiro Yamada while (isalnum(*e) || *e == '_') 2338fac9c7bSMasahiro Yamada e++; 2348fac9c7bSMasahiro Yamada *e = '\0'; 2358fac9c7bSMasahiro Yamada add_new_symbol(sym, p); 2368fac9c7bSMasahiro Yamada } 2378fac9c7bSMasahiro Yamada } 2388fac9c7bSMasahiro Yamada fclose(fp); 2398fac9c7bSMasahiro Yamada } 2408fac9c7bSMasahiro Yamada } 2418fac9c7bSMasahiro Yamada 2428fac9c7bSMasahiro Yamada /* 2438fac9c7bSMasahiro Yamada * Document all external or internal functions in a file. 2448fac9c7bSMasahiro Yamada * Call kernel-doc with following parameters: 2458fac9c7bSMasahiro Yamada * kernel-doc -docbook -nofunction function_name1 filename 2468fac9c7bSMasahiro Yamada * Function names are obtained from all the src files 2478fac9c7bSMasahiro Yamada * by find_export_symbols. 2488fac9c7bSMasahiro Yamada * intfunc uses -nofunction 2498fac9c7bSMasahiro Yamada * extfunc uses -function 2508fac9c7bSMasahiro Yamada */ 2518fac9c7bSMasahiro Yamada static void docfunctions(char * filename, char * type) 2528fac9c7bSMasahiro Yamada { 2538fac9c7bSMasahiro Yamada int i,j; 2548fac9c7bSMasahiro Yamada int symcnt = 0; 2558fac9c7bSMasahiro Yamada int idx = 0; 2568fac9c7bSMasahiro Yamada char **vec; 2578fac9c7bSMasahiro Yamada 2588fac9c7bSMasahiro Yamada for (i=0; i <= symfilecnt; i++) 2598fac9c7bSMasahiro Yamada symcnt += symfilelist[i].symbolcnt; 2608fac9c7bSMasahiro Yamada vec = malloc((2 + 2 * symcnt + 3) * sizeof(char *)); 2618fac9c7bSMasahiro Yamada if (vec == NULL) { 2628fac9c7bSMasahiro Yamada perror("docproc: "); 2638fac9c7bSMasahiro Yamada exit(1); 2648fac9c7bSMasahiro Yamada } 2658fac9c7bSMasahiro Yamada vec[idx++] = KERNELDOC; 2668fac9c7bSMasahiro Yamada vec[idx++] = DOCBOOK; 2678fac9c7bSMasahiro Yamada vec[idx++] = NODOCSECTIONS; 2688fac9c7bSMasahiro Yamada for (i=0; i < symfilecnt; i++) { 2698fac9c7bSMasahiro Yamada struct symfile * sym = &symfilelist[i]; 2708fac9c7bSMasahiro Yamada for (j=0; j < sym->symbolcnt; j++) { 2718fac9c7bSMasahiro Yamada vec[idx++] = type; 2728fac9c7bSMasahiro Yamada consume_symbol(sym->symbollist[j].name); 2738fac9c7bSMasahiro Yamada vec[idx++] = sym->symbollist[j].name; 2748fac9c7bSMasahiro Yamada } 2758fac9c7bSMasahiro Yamada } 2768fac9c7bSMasahiro Yamada vec[idx++] = filename; 2778fac9c7bSMasahiro Yamada vec[idx] = NULL; 2788fac9c7bSMasahiro Yamada printf("<!-- %s -->\n", filename); 2798fac9c7bSMasahiro Yamada exec_kernel_doc(vec); 2808fac9c7bSMasahiro Yamada fflush(stdout); 2818fac9c7bSMasahiro Yamada free(vec); 2828fac9c7bSMasahiro Yamada } 2838fac9c7bSMasahiro Yamada static void intfunc(char * filename) { docfunctions(filename, NOFUNCTION); } 2848fac9c7bSMasahiro Yamada static void extfunc(char * filename) { docfunctions(filename, FUNCTION); } 2858fac9c7bSMasahiro Yamada 2868fac9c7bSMasahiro Yamada /* 2878fac9c7bSMasahiro Yamada * Document specific function(s) in a file. 2888fac9c7bSMasahiro Yamada * Call kernel-doc with the following parameters: 2898fac9c7bSMasahiro Yamada * kernel-doc -docbook -function function1 [-function function2] 2908fac9c7bSMasahiro Yamada */ 2918fac9c7bSMasahiro Yamada static void singfunc(char * filename, char * line) 2928fac9c7bSMasahiro Yamada { 2938fac9c7bSMasahiro Yamada char *vec[200]; /* Enough for specific functions */ 2948fac9c7bSMasahiro Yamada int i, idx = 0; 2958fac9c7bSMasahiro Yamada int startofsym = 1; 2968fac9c7bSMasahiro Yamada vec[idx++] = KERNELDOC; 2978fac9c7bSMasahiro Yamada vec[idx++] = DOCBOOK; 298*ced03298SMasahiro Yamada vec[idx++] = SHOWNOTFOUND; 2998fac9c7bSMasahiro Yamada 3008fac9c7bSMasahiro Yamada /* Split line up in individual parameters preceded by FUNCTION */ 3018fac9c7bSMasahiro Yamada for (i=0; line[i]; i++) { 3028fac9c7bSMasahiro Yamada if (isspace(line[i])) { 3038fac9c7bSMasahiro Yamada line[i] = '\0'; 3048fac9c7bSMasahiro Yamada startofsym = 1; 3058fac9c7bSMasahiro Yamada continue; 3068fac9c7bSMasahiro Yamada } 3078fac9c7bSMasahiro Yamada if (startofsym) { 3088fac9c7bSMasahiro Yamada startofsym = 0; 3098fac9c7bSMasahiro Yamada vec[idx++] = FUNCTION; 3108fac9c7bSMasahiro Yamada vec[idx++] = &line[i]; 3118fac9c7bSMasahiro Yamada } 3128fac9c7bSMasahiro Yamada } 3138fac9c7bSMasahiro Yamada for (i = 0; i < idx; i++) { 3148fac9c7bSMasahiro Yamada if (strcmp(vec[i], FUNCTION)) 3158fac9c7bSMasahiro Yamada continue; 3168fac9c7bSMasahiro Yamada consume_symbol(vec[i + 1]); 3178fac9c7bSMasahiro Yamada } 3188fac9c7bSMasahiro Yamada vec[idx++] = filename; 3198fac9c7bSMasahiro Yamada vec[idx] = NULL; 3208fac9c7bSMasahiro Yamada exec_kernel_doc(vec); 3218fac9c7bSMasahiro Yamada } 3228fac9c7bSMasahiro Yamada 3238fac9c7bSMasahiro Yamada /* 3248fac9c7bSMasahiro Yamada * Insert specific documentation section from a file. 3258fac9c7bSMasahiro Yamada * Call kernel-doc with the following parameters: 3268fac9c7bSMasahiro Yamada * kernel-doc -docbook -function "doc section" filename 3278fac9c7bSMasahiro Yamada */ 3288fac9c7bSMasahiro Yamada static void docsect(char *filename, char *line) 3298fac9c7bSMasahiro Yamada { 330*ced03298SMasahiro Yamada /* kerneldoc -docbook -show-not-found -function "section" file NULL */ 331*ced03298SMasahiro Yamada char *vec[7]; 3328fac9c7bSMasahiro Yamada char *s; 3338fac9c7bSMasahiro Yamada 3348fac9c7bSMasahiro Yamada for (s = line; *s; s++) 3358fac9c7bSMasahiro Yamada if (*s == '\n') 3368fac9c7bSMasahiro Yamada *s = '\0'; 3378fac9c7bSMasahiro Yamada 3388fac9c7bSMasahiro Yamada if (asprintf(&s, "DOC: %s", line) < 0) { 3398fac9c7bSMasahiro Yamada perror("asprintf"); 3408fac9c7bSMasahiro Yamada exit(1); 3418fac9c7bSMasahiro Yamada } 3428fac9c7bSMasahiro Yamada consume_symbol(s); 3438fac9c7bSMasahiro Yamada free(s); 3448fac9c7bSMasahiro Yamada 3458fac9c7bSMasahiro Yamada vec[0] = KERNELDOC; 3468fac9c7bSMasahiro Yamada vec[1] = DOCBOOK; 347*ced03298SMasahiro Yamada vec[2] = SHOWNOTFOUND; 348*ced03298SMasahiro Yamada vec[3] = FUNCTION; 349*ced03298SMasahiro Yamada vec[4] = line; 350*ced03298SMasahiro Yamada vec[5] = filename; 351*ced03298SMasahiro Yamada vec[6] = NULL; 3528fac9c7bSMasahiro Yamada exec_kernel_doc(vec); 3538fac9c7bSMasahiro Yamada } 3548fac9c7bSMasahiro Yamada 3558fac9c7bSMasahiro Yamada static void find_all_symbols(char *filename) 3568fac9c7bSMasahiro Yamada { 3578fac9c7bSMasahiro Yamada char *vec[4]; /* kerneldoc -list file NULL */ 3588fac9c7bSMasahiro Yamada pid_t pid; 3598fac9c7bSMasahiro Yamada int ret, i, count, start; 3608fac9c7bSMasahiro Yamada char real_filename[PATH_MAX + 1]; 3618fac9c7bSMasahiro Yamada int pipefd[2]; 3628fac9c7bSMasahiro Yamada char *data, *str; 3638fac9c7bSMasahiro Yamada size_t data_len = 0; 3648fac9c7bSMasahiro Yamada 3658fac9c7bSMasahiro Yamada vec[0] = KERNELDOC; 3668fac9c7bSMasahiro Yamada vec[1] = LIST; 3678fac9c7bSMasahiro Yamada vec[2] = filename; 3688fac9c7bSMasahiro Yamada vec[3] = NULL; 3698fac9c7bSMasahiro Yamada 3708fac9c7bSMasahiro Yamada if (pipe(pipefd)) { 3718fac9c7bSMasahiro Yamada perror("pipe"); 3728fac9c7bSMasahiro Yamada exit(1); 3738fac9c7bSMasahiro Yamada } 3748fac9c7bSMasahiro Yamada 3758fac9c7bSMasahiro Yamada switch (pid=fork()) { 3768fac9c7bSMasahiro Yamada case -1: 3778fac9c7bSMasahiro Yamada perror("fork"); 3788fac9c7bSMasahiro Yamada exit(1); 3798fac9c7bSMasahiro Yamada case 0: 3808fac9c7bSMasahiro Yamada close(pipefd[0]); 3818fac9c7bSMasahiro Yamada dup2(pipefd[1], 1); 3828fac9c7bSMasahiro Yamada memset(real_filename, 0, sizeof(real_filename)); 3838fac9c7bSMasahiro Yamada strncat(real_filename, kernsrctree, PATH_MAX); 3848fac9c7bSMasahiro Yamada strncat(real_filename, "/" KERNELDOCPATH KERNELDOC, 3858fac9c7bSMasahiro Yamada PATH_MAX - strlen(real_filename)); 3868fac9c7bSMasahiro Yamada execvp(real_filename, vec); 3878fac9c7bSMasahiro Yamada fprintf(stderr, "exec "); 3888fac9c7bSMasahiro Yamada perror(real_filename); 3898fac9c7bSMasahiro Yamada exit(1); 3908fac9c7bSMasahiro Yamada default: 3918fac9c7bSMasahiro Yamada close(pipefd[1]); 3928fac9c7bSMasahiro Yamada data = malloc(4096); 3938fac9c7bSMasahiro Yamada do { 3948fac9c7bSMasahiro Yamada while ((ret = read(pipefd[0], 3958fac9c7bSMasahiro Yamada data + data_len, 3968fac9c7bSMasahiro Yamada 4096)) > 0) { 3978fac9c7bSMasahiro Yamada data_len += ret; 3988fac9c7bSMasahiro Yamada data = realloc(data, data_len + 4096); 3998fac9c7bSMasahiro Yamada } 4008fac9c7bSMasahiro Yamada } while (ret == -EAGAIN); 4018fac9c7bSMasahiro Yamada if (ret != 0) { 4028fac9c7bSMasahiro Yamada perror("read"); 4038fac9c7bSMasahiro Yamada exit(1); 4048fac9c7bSMasahiro Yamada } 4058fac9c7bSMasahiro Yamada waitpid(pid, &ret ,0); 4068fac9c7bSMasahiro Yamada } 4078fac9c7bSMasahiro Yamada if (WIFEXITED(ret)) 4088fac9c7bSMasahiro Yamada exitstatus |= WEXITSTATUS(ret); 4098fac9c7bSMasahiro Yamada else 4108fac9c7bSMasahiro Yamada exitstatus = 0xff; 4118fac9c7bSMasahiro Yamada 4128fac9c7bSMasahiro Yamada count = 0; 4138fac9c7bSMasahiro Yamada /* poor man's strtok, but with counting */ 4148fac9c7bSMasahiro Yamada for (i = 0; i < data_len; i++) { 4158fac9c7bSMasahiro Yamada if (data[i] == '\n') { 4168fac9c7bSMasahiro Yamada count++; 4178fac9c7bSMasahiro Yamada data[i] = '\0'; 4188fac9c7bSMasahiro Yamada } 4198fac9c7bSMasahiro Yamada } 4208fac9c7bSMasahiro Yamada start = all_list_len; 4218fac9c7bSMasahiro Yamada all_list_len += count; 4228fac9c7bSMasahiro Yamada all_list = realloc(all_list, sizeof(char *) * all_list_len); 4238fac9c7bSMasahiro Yamada str = data; 4248fac9c7bSMasahiro Yamada for (i = 0; i < data_len && start != all_list_len; i++) { 4258fac9c7bSMasahiro Yamada if (data[i] == '\0') { 4268fac9c7bSMasahiro Yamada all_list[start] = str; 4278fac9c7bSMasahiro Yamada str = data + i + 1; 4288fac9c7bSMasahiro Yamada start++; 4298fac9c7bSMasahiro Yamada } 4308fac9c7bSMasahiro Yamada } 4318fac9c7bSMasahiro Yamada } 4328fac9c7bSMasahiro Yamada 4338fac9c7bSMasahiro Yamada /* 4348fac9c7bSMasahiro Yamada * Parse file, calling action specific functions for: 4358fac9c7bSMasahiro Yamada * 1) Lines containing !E 4368fac9c7bSMasahiro Yamada * 2) Lines containing !I 4378fac9c7bSMasahiro Yamada * 3) Lines containing !D 4388fac9c7bSMasahiro Yamada * 4) Lines containing !F 4398fac9c7bSMasahiro Yamada * 5) Lines containing !P 4408fac9c7bSMasahiro Yamada * 6) Lines containing !C 4418fac9c7bSMasahiro Yamada * 7) Default lines - lines not matching the above 4428fac9c7bSMasahiro Yamada */ 4438fac9c7bSMasahiro Yamada static void parse_file(FILE *infile) 4448fac9c7bSMasahiro Yamada { 4458fac9c7bSMasahiro Yamada char line[MAXLINESZ]; 4468fac9c7bSMasahiro Yamada char * s; 4478fac9c7bSMasahiro Yamada while (fgets(line, MAXLINESZ, infile)) { 4488fac9c7bSMasahiro Yamada if (line[0] == '!') { 4498fac9c7bSMasahiro Yamada s = line + 2; 4508fac9c7bSMasahiro Yamada switch (line[1]) { 4518fac9c7bSMasahiro Yamada case 'E': 4528fac9c7bSMasahiro Yamada while (*s && !isspace(*s)) s++; 4538fac9c7bSMasahiro Yamada *s = '\0'; 4548fac9c7bSMasahiro Yamada externalfunctions(line+2); 4558fac9c7bSMasahiro Yamada break; 4568fac9c7bSMasahiro Yamada case 'I': 4578fac9c7bSMasahiro Yamada while (*s && !isspace(*s)) s++; 4588fac9c7bSMasahiro Yamada *s = '\0'; 4598fac9c7bSMasahiro Yamada internalfunctions(line+2); 4608fac9c7bSMasahiro Yamada break; 4618fac9c7bSMasahiro Yamada case 'D': 4628fac9c7bSMasahiro Yamada while (*s && !isspace(*s)) s++; 4638fac9c7bSMasahiro Yamada *s = '\0'; 4648fac9c7bSMasahiro Yamada symbolsonly(line+2); 4658fac9c7bSMasahiro Yamada break; 4668fac9c7bSMasahiro Yamada case 'F': 4678fac9c7bSMasahiro Yamada /* filename */ 4688fac9c7bSMasahiro Yamada while (*s && !isspace(*s)) s++; 4698fac9c7bSMasahiro Yamada *s++ = '\0'; 4708fac9c7bSMasahiro Yamada /* function names */ 4718fac9c7bSMasahiro Yamada while (isspace(*s)) 4728fac9c7bSMasahiro Yamada s++; 4738fac9c7bSMasahiro Yamada singlefunctions(line +2, s); 4748fac9c7bSMasahiro Yamada break; 4758fac9c7bSMasahiro Yamada case 'P': 4768fac9c7bSMasahiro Yamada /* filename */ 4778fac9c7bSMasahiro Yamada while (*s && !isspace(*s)) s++; 4788fac9c7bSMasahiro Yamada *s++ = '\0'; 4798fac9c7bSMasahiro Yamada /* DOC: section name */ 4808fac9c7bSMasahiro Yamada while (isspace(*s)) 4818fac9c7bSMasahiro Yamada s++; 4828fac9c7bSMasahiro Yamada docsection(line + 2, s); 4838fac9c7bSMasahiro Yamada break; 4848fac9c7bSMasahiro Yamada case 'C': 4858fac9c7bSMasahiro Yamada while (*s && !isspace(*s)) s++; 4868fac9c7bSMasahiro Yamada *s = '\0'; 4878fac9c7bSMasahiro Yamada if (findall) 4888fac9c7bSMasahiro Yamada findall(line+2); 4898fac9c7bSMasahiro Yamada break; 4908fac9c7bSMasahiro Yamada default: 4918fac9c7bSMasahiro Yamada defaultline(line); 4928fac9c7bSMasahiro Yamada } 4938fac9c7bSMasahiro Yamada } else { 4948fac9c7bSMasahiro Yamada defaultline(line); 4958fac9c7bSMasahiro Yamada } 4968fac9c7bSMasahiro Yamada } 4978fac9c7bSMasahiro Yamada fflush(stdout); 4988fac9c7bSMasahiro Yamada } 4998fac9c7bSMasahiro Yamada 5008fac9c7bSMasahiro Yamada 5018fac9c7bSMasahiro Yamada int main(int argc, char *argv[]) 5028fac9c7bSMasahiro Yamada { 5038fac9c7bSMasahiro Yamada FILE * infile; 5048fac9c7bSMasahiro Yamada int i; 5058fac9c7bSMasahiro Yamada 5068fac9c7bSMasahiro Yamada srctree = getenv("SRCTREE"); 5078fac9c7bSMasahiro Yamada if (!srctree) 5088fac9c7bSMasahiro Yamada srctree = getcwd(NULL, 0); 5098fac9c7bSMasahiro Yamada kernsrctree = getenv("KBUILD_SRC"); 5108fac9c7bSMasahiro Yamada if (!kernsrctree || !*kernsrctree) 5118fac9c7bSMasahiro Yamada kernsrctree = srctree; 5128fac9c7bSMasahiro Yamada if (argc != 3) { 5138fac9c7bSMasahiro Yamada usage(); 5148fac9c7bSMasahiro Yamada exit(1); 5158fac9c7bSMasahiro Yamada } 5168fac9c7bSMasahiro Yamada /* Open file, exit on error */ 5178fac9c7bSMasahiro Yamada infile = fopen(argv[2], "r"); 5188fac9c7bSMasahiro Yamada if (infile == NULL) { 5198fac9c7bSMasahiro Yamada fprintf(stderr, "docproc: "); 5208fac9c7bSMasahiro Yamada perror(argv[2]); 5218fac9c7bSMasahiro Yamada exit(2); 5228fac9c7bSMasahiro Yamada } 5238fac9c7bSMasahiro Yamada 5248fac9c7bSMasahiro Yamada if (strcmp("doc", argv[1]) == 0) { 5258fac9c7bSMasahiro Yamada /* Need to do this in two passes. 5268fac9c7bSMasahiro Yamada * First pass is used to collect all symbols exported 5278fac9c7bSMasahiro Yamada * in the various files; 5288fac9c7bSMasahiro Yamada * Second pass generate the documentation. 5298fac9c7bSMasahiro Yamada * This is required because some functions are declared 5308fac9c7bSMasahiro Yamada * and exported in different files :-(( 5318fac9c7bSMasahiro Yamada */ 5328fac9c7bSMasahiro Yamada /* Collect symbols */ 5338fac9c7bSMasahiro Yamada defaultline = noaction; 5348fac9c7bSMasahiro Yamada internalfunctions = find_export_symbols; 5358fac9c7bSMasahiro Yamada externalfunctions = find_export_symbols; 5368fac9c7bSMasahiro Yamada symbolsonly = find_export_symbols; 5378fac9c7bSMasahiro Yamada singlefunctions = noaction2; 5388fac9c7bSMasahiro Yamada docsection = noaction2; 5398fac9c7bSMasahiro Yamada findall = find_all_symbols; 5408fac9c7bSMasahiro Yamada parse_file(infile); 5418fac9c7bSMasahiro Yamada 5428fac9c7bSMasahiro Yamada /* Rewind to start from beginning of file again */ 5438fac9c7bSMasahiro Yamada fseek(infile, 0, SEEK_SET); 5448fac9c7bSMasahiro Yamada defaultline = printline; 5458fac9c7bSMasahiro Yamada internalfunctions = intfunc; 5468fac9c7bSMasahiro Yamada externalfunctions = extfunc; 5478fac9c7bSMasahiro Yamada symbolsonly = printline; 5488fac9c7bSMasahiro Yamada singlefunctions = singfunc; 5498fac9c7bSMasahiro Yamada docsection = docsect; 5508fac9c7bSMasahiro Yamada findall = NULL; 5518fac9c7bSMasahiro Yamada 5528fac9c7bSMasahiro Yamada parse_file(infile); 5538fac9c7bSMasahiro Yamada 5548fac9c7bSMasahiro Yamada for (i = 0; i < all_list_len; i++) { 5558fac9c7bSMasahiro Yamada if (!all_list[i]) 5568fac9c7bSMasahiro Yamada continue; 5578fac9c7bSMasahiro Yamada fprintf(stderr, "Warning: didn't use docs for %s\n", 5588fac9c7bSMasahiro Yamada all_list[i]); 5598fac9c7bSMasahiro Yamada } 5608fac9c7bSMasahiro Yamada } else if (strcmp("depend", argv[1]) == 0) { 5618fac9c7bSMasahiro Yamada /* Create first part of dependency chain 5628fac9c7bSMasahiro Yamada * file.tmpl */ 5638fac9c7bSMasahiro Yamada printf("%s\t", argv[2]); 5648fac9c7bSMasahiro Yamada defaultline = noaction; 5658fac9c7bSMasahiro Yamada internalfunctions = adddep; 5668fac9c7bSMasahiro Yamada externalfunctions = adddep; 5678fac9c7bSMasahiro Yamada symbolsonly = adddep; 5688fac9c7bSMasahiro Yamada singlefunctions = adddep2; 5698fac9c7bSMasahiro Yamada docsection = adddep2; 5708fac9c7bSMasahiro Yamada findall = adddep; 5718fac9c7bSMasahiro Yamada parse_file(infile); 5728fac9c7bSMasahiro Yamada printf("\n"); 5738fac9c7bSMasahiro Yamada } else { 5748fac9c7bSMasahiro Yamada fprintf(stderr, "Unknown option: %s\n", argv[1]); 5758fac9c7bSMasahiro Yamada exit(1); 5768fac9c7bSMasahiro Yamada } 5778fac9c7bSMasahiro Yamada fclose(infile); 5788fac9c7bSMasahiro Yamada fflush(stdout); 5798fac9c7bSMasahiro Yamada return exitstatus; 5808fac9c7bSMasahiro Yamada } 581