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