blob: 9babfd108d2ea57a08532dd88203b7f4066a6446 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Randy Dunlap6dd16f42007-09-04 21:23:22 -070013 * 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()
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 * 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
Johannes Berge662af42007-10-24 15:08:48 -070033 * !Pfilename
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 *
35 */
36
Johannes Bergeda603f2010-09-11 15:55:22 -070037#define _GNU_SOURCE
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <ctype.h>
42#include <unistd.h>
43#include <limits.h>
Johannes Bergeda603f2010-09-11 15:55:22 -070044#include <errno.h>
Jani Nikula064669b2016-05-12 16:15:43 +030045#include <getopt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <sys/types.h>
47#include <sys/wait.h>
48
49/* exitstatus is used to keep track of any failing calls to kernel-doc,
50 * but execution continues. */
51int exitstatus = 0;
52
53typedef void DFL(char *);
54DFL *defaultline;
55
56typedef void FILEONLY(char * file);
57FILEONLY *internalfunctions;
58FILEONLY *externalfunctions;
59FILEONLY *symbolsonly;
Johannes Bergeda603f2010-09-11 15:55:22 -070060FILEONLY *findall;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
J.A. Magallon48b9d032005-06-25 14:59:22 -070062typedef void FILELINE(char * file, char * line);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063FILELINE * singlefunctions;
64FILELINE * entity_system;
Johannes Berge662af42007-10-24 15:08:48 -070065FILELINE * docsection;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#define MAXLINESZ 2048
68#define MAXFILES 250
69#define KERNELDOCPATH "scripts/"
70#define KERNELDOC "kernel-doc"
71#define DOCBOOK "-docbook"
Jani Nikula064669b2016-05-12 16:15:43 +030072#define RST "-rst"
Johannes Bergeda603f2010-09-11 15:55:22 -070073#define LIST "-list"
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define FUNCTION "-function"
75#define NOFUNCTION "-nofunction"
Johannes Berg2e959722007-10-24 15:08:48 -070076#define NODOCSECTIONS "-no-doc-sections"
Johannes Berge946c43a2013-11-12 15:11:12 -080077#define SHOWNOTFOUND "-show-not-found"
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Jani Nikula064669b2016-05-12 16:15:43 +030079enum file_format {
80 FORMAT_AUTO,
81 FORMAT_DOCBOOK,
82 FORMAT_RST,
83};
84
85static enum file_format file_format = FORMAT_AUTO;
86
87#define KERNELDOC_FORMAT (file_format == FORMAT_RST ? RST : DOCBOOK)
88
Jiri Slaby2d510052009-05-31 18:05:34 +020089static char *srctree, *kernsrctree;
Rob Landleybb13be52007-10-09 01:25:18 -050090
Johannes Bergeda603f2010-09-11 15:55:22 -070091static char **all_list = NULL;
92static int all_list_len = 0;
93
94static void consume_symbol(const char *sym)
95{
96 int i;
97
98 for (i = 0; i < all_list_len; i++) {
99 if (!all_list[i])
100 continue;
101 if (strcmp(sym, all_list[i]))
102 continue;
103 all_list[i] = NULL;
104 break;
105 }
106}
107
Trevor Keith4356f482009-09-18 12:49:23 -0700108static void usage (void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
Jani Nikula064669b2016-05-12 16:15:43 +0300110 fprintf(stderr, "Usage: docproc [{--docbook|--rst}] {doc|depend} file\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
112 fprintf(stderr, "doc: frontend when generating kernel documentation\n");
113 fprintf(stderr, "depend: generate list of files referenced within file\n");
Jiri Slaby2d510052009-05-31 18:05:34 +0200114 fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n");
115 fprintf(stderr, " KBUILD_SRC: absolute path to kernel source tree.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116}
117
118/*
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700119 * Execute kernel-doc with parameters given in svec
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 */
Trevor Keith4356f482009-09-18 12:49:23 -0700121static void exec_kernel_doc(char **svec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
123 pid_t pid;
124 int ret;
125 char real_filename[PATH_MAX + 1];
126 /* Make sure output generated so far are flushed */
127 fflush(stdout);
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700128 switch (pid=fork()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 case -1:
130 perror("fork");
131 exit(1);
132 case 0:
133 memset(real_filename, 0, sizeof(real_filename));
Jiri Slaby2d510052009-05-31 18:05:34 +0200134 strncat(real_filename, kernsrctree, PATH_MAX);
135 strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 PATH_MAX - strlen(real_filename));
137 execvp(real_filename, svec);
138 fprintf(stderr, "exec ");
139 perror(real_filename);
140 exit(1);
141 default:
142 waitpid(pid, &ret ,0);
143 }
144 if (WIFEXITED(ret))
145 exitstatus |= WEXITSTATUS(ret);
146 else
147 exitstatus = 0xff;
148}
149
150/* Types used to create list of all exported symbols in a number of files */
151struct symbols
152{
153 char *name;
154};
155
156struct symfile
157{
158 char *filename;
159 struct symbols *symbollist;
160 int symbolcnt;
161};
162
163struct symfile symfilelist[MAXFILES];
164int symfilecnt = 0;
165
Trevor Keith4356f482009-09-18 12:49:23 -0700166static void add_new_symbol(struct symfile *sym, char * symname)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167{
168 sym->symbollist =
Masahiro Yamadabb66fc62014-06-10 19:08:13 +0900169 realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 sym->symbollist[sym->symbolcnt++].name = strdup(symname);
171}
172
173/* Add a filename to the list */
Trevor Keith4356f482009-09-18 12:49:23 -0700174static struct symfile * add_new_file(char * filename)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175{
176 symfilelist[symfilecnt++].filename = strdup(filename);
177 return &symfilelist[symfilecnt - 1];
178}
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180/* Check if file already are present in the list */
Trevor Keith4356f482009-09-18 12:49:23 -0700181static struct symfile * filename_exist(char * filename)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182{
183 int i;
184 for (i=0; i < symfilecnt; i++)
185 if (strcmp(symfilelist[i].filename, filename) == 0)
186 return &symfilelist[i];
187 return NULL;
188}
189
190/*
191 * List all files referenced within the template file.
192 * Files are separated by tabs.
193 */
Trevor Keith4356f482009-09-18 12:49:23 -0700194static void adddep(char * file) { printf("\t%s", file); }
195static void adddep2(char * file, char * line) { line = line; adddep(file); }
196static void noaction(char * line) { line = line; }
197static void noaction2(char * file, char * line) { file = file; line = line; }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199/* Echo the line without further action */
Trevor Keith4356f482009-09-18 12:49:23 -0700200static void printline(char * line) { printf("%s", line); }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202/*
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700203 * Find all symbols in filename that are exported with EXPORT_SYMBOL &
204 * EXPORT_SYMBOL_GPL (& EXPORT_SYMBOL_GPL_FUTURE implicitly).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 * All symbols located are stored in symfilelist.
206 */
Trevor Keith4356f482009-09-18 12:49:23 -0700207static void find_export_symbols(char * filename)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 FILE * fp;
210 struct symfile *sym;
211 char line[MAXLINESZ];
212 if (filename_exist(filename) == NULL) {
213 char real_filename[PATH_MAX + 1];
214 memset(real_filename, 0, sizeof(real_filename));
Rob Landleybb13be52007-10-09 01:25:18 -0500215 strncat(real_filename, srctree, PATH_MAX);
Jiri Slaby2d510052009-05-31 18:05:34 +0200216 strncat(real_filename, "/", PATH_MAX - strlen(real_filename));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 strncat(real_filename, filename,
218 PATH_MAX - strlen(real_filename));
219 sym = add_new_file(filename);
220 fp = fopen(real_filename, "r");
Jesper Juhlf0f3ca82011-06-15 11:53:13 +0200221 if (fp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 fprintf(stderr, "docproc: ");
223 perror(real_filename);
Henrik Kretzschmar074a5dd2006-09-29 02:00:56 -0700224 exit(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 }
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700226 while (fgets(line, MAXLINESZ, fp)) {
J.A. Magallon48b9d032005-06-25 14:59:22 -0700227 char *p;
228 char *e;
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700229 if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) ||
Masahiro Yamadabb66fc62014-06-10 19:08:13 +0900230 ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 /* Skip EXPORT_SYMBOL{_GPL} */
232 while (isalnum(*p) || *p == '_')
233 p++;
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700234 /* Remove parentheses & additional whitespace */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 while (isspace(*p))
236 p++;
237 if (*p != '(')
238 continue; /* Syntax error? */
239 else
240 p++;
241 while (isspace(*p))
242 p++;
243 e = p;
244 while (isalnum(*e) || *e == '_')
245 e++;
246 *e = '\0';
247 add_new_symbol(sym, p);
248 }
249 }
250 fclose(fp);
251 }
252}
253
254/*
255 * Document all external or internal functions in a file.
256 * Call kernel-doc with following parameters:
Jani Nikula064669b2016-05-12 16:15:43 +0300257 * kernel-doc [-docbook|-rst] -nofunction function_name1 filename
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700258 * Function names are obtained from all the src files
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 * by find_export_symbols.
260 * intfunc uses -nofunction
261 * extfunc uses -function
262 */
Trevor Keith4356f482009-09-18 12:49:23 -0700263static void docfunctions(char * filename, char * type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 int i,j;
266 int symcnt = 0;
267 int idx = 0;
268 char **vec;
269
270 for (i=0; i <= symfilecnt; i++)
271 symcnt += symfilelist[i].symbolcnt;
Johannes Berg2e959722007-10-24 15:08:48 -0700272 vec = malloc((2 + 2 * symcnt + 3) * sizeof(char *));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 if (vec == NULL) {
274 perror("docproc: ");
275 exit(1);
276 }
277 vec[idx++] = KERNELDOC;
Jani Nikula064669b2016-05-12 16:15:43 +0300278 vec[idx++] = KERNELDOC_FORMAT;
Johannes Berg2e959722007-10-24 15:08:48 -0700279 vec[idx++] = NODOCSECTIONS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 for (i=0; i < symfilecnt; i++) {
281 struct symfile * sym = &symfilelist[i];
282 for (j=0; j < sym->symbolcnt; j++) {
283 vec[idx++] = type;
Johannes Bergeda603f2010-09-11 15:55:22 -0700284 consume_symbol(sym->symbollist[j].name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 vec[idx++] = sym->symbollist[j].name;
286 }
287 }
288 vec[idx++] = filename;
289 vec[idx] = NULL;
Jani Nikula064669b2016-05-12 16:15:43 +0300290 if (file_format == FORMAT_RST)
291 printf(".. %s\n", filename);
292 else
293 printf("<!-- %s -->\n", filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 exec_kernel_doc(vec);
295 fflush(stdout);
296 free(vec);
297}
Trevor Keith4356f482009-09-18 12:49:23 -0700298static void intfunc(char * filename) { docfunctions(filename, NOFUNCTION); }
299static void extfunc(char * filename) { docfunctions(filename, FUNCTION); }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301/*
Randy Dunlapc6120932006-11-02 22:07:01 -0800302 * Document specific function(s) in a file.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 * Call kernel-doc with the following parameters:
304 * kernel-doc -docbook -function function1 [-function function2]
305 */
Trevor Keith4356f482009-09-18 12:49:23 -0700306static void singfunc(char * filename, char * line)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307{
308 char *vec[200]; /* Enough for specific functions */
Masahiro Yamadabb66fc62014-06-10 19:08:13 +0900309 int i, idx = 0;
310 int startofsym = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 vec[idx++] = KERNELDOC;
Jani Nikula064669b2016-05-12 16:15:43 +0300312 vec[idx++] = KERNELDOC_FORMAT;
Johannes Berge946c43a2013-11-12 15:11:12 -0800313 vec[idx++] = SHOWNOTFOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
Masahiro Yamadabb66fc62014-06-10 19:08:13 +0900315 /* Split line up in individual parameters preceded by FUNCTION */
316 for (i=0; line[i]; i++) {
317 if (isspace(line[i])) {
318 line[i] = '\0';
319 startofsym = 1;
320 continue;
321 }
322 if (startofsym) {
323 startofsym = 0;
324 vec[idx++] = FUNCTION;
325 vec[idx++] = &line[i];
326 }
327 }
Johannes Bergeda603f2010-09-11 15:55:22 -0700328 for (i = 0; i < idx; i++) {
Masahiro Yamadabb66fc62014-06-10 19:08:13 +0900329 if (strcmp(vec[i], FUNCTION))
330 continue;
Johannes Bergeda603f2010-09-11 15:55:22 -0700331 consume_symbol(vec[i + 1]);
332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 vec[idx++] = filename;
334 vec[idx] = NULL;
335 exec_kernel_doc(vec);
336}
337
338/*
Johannes Berge662af42007-10-24 15:08:48 -0700339 * Insert specific documentation section from a file.
340 * Call kernel-doc with the following parameters:
341 * kernel-doc -docbook -function "doc section" filename
342 */
Trevor Keith4356f482009-09-18 12:49:23 -0700343static void docsect(char *filename, char *line)
Johannes Berge662af42007-10-24 15:08:48 -0700344{
Johannes Berge946c43a2013-11-12 15:11:12 -0800345 /* kerneldoc -docbook -show-not-found -function "section" file NULL */
346 char *vec[7];
Johannes Berge662af42007-10-24 15:08:48 -0700347 char *s;
348
349 for (s = line; *s; s++)
350 if (*s == '\n')
351 *s = '\0';
352
Namhyung Kimd0f95c72010-10-22 23:32:10 +0900353 if (asprintf(&s, "DOC: %s", line) < 0) {
354 perror("asprintf");
355 exit(1);
356 }
Johannes Bergeda603f2010-09-11 15:55:22 -0700357 consume_symbol(s);
358 free(s);
359
Johannes Berge662af42007-10-24 15:08:48 -0700360 vec[0] = KERNELDOC;
Jani Nikula064669b2016-05-12 16:15:43 +0300361 vec[1] = KERNELDOC_FORMAT;
Johannes Berge946c43a2013-11-12 15:11:12 -0800362 vec[2] = SHOWNOTFOUND;
363 vec[3] = FUNCTION;
364 vec[4] = line;
365 vec[5] = filename;
366 vec[6] = NULL;
Johannes Berge662af42007-10-24 15:08:48 -0700367 exec_kernel_doc(vec);
368}
369
Johannes Bergeda603f2010-09-11 15:55:22 -0700370static void find_all_symbols(char *filename)
371{
372 char *vec[4]; /* kerneldoc -list file NULL */
373 pid_t pid;
374 int ret, i, count, start;
375 char real_filename[PATH_MAX + 1];
376 int pipefd[2];
377 char *data, *str;
378 size_t data_len = 0;
379
380 vec[0] = KERNELDOC;
381 vec[1] = LIST;
382 vec[2] = filename;
383 vec[3] = NULL;
384
385 if (pipe(pipefd)) {
386 perror("pipe");
387 exit(1);
388 }
389
390 switch (pid=fork()) {
391 case -1:
392 perror("fork");
393 exit(1);
394 case 0:
395 close(pipefd[0]);
396 dup2(pipefd[1], 1);
397 memset(real_filename, 0, sizeof(real_filename));
398 strncat(real_filename, kernsrctree, PATH_MAX);
399 strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
400 PATH_MAX - strlen(real_filename));
401 execvp(real_filename, vec);
402 fprintf(stderr, "exec ");
403 perror(real_filename);
404 exit(1);
405 default:
406 close(pipefd[1]);
407 data = malloc(4096);
408 do {
409 while ((ret = read(pipefd[0],
410 data + data_len,
411 4096)) > 0) {
412 data_len += ret;
413 data = realloc(data, data_len + 4096);
414 }
415 } while (ret == -EAGAIN);
416 if (ret != 0) {
417 perror("read");
418 exit(1);
419 }
420 waitpid(pid, &ret ,0);
421 }
422 if (WIFEXITED(ret))
423 exitstatus |= WEXITSTATUS(ret);
424 else
425 exitstatus = 0xff;
426
427 count = 0;
428 /* poor man's strtok, but with counting */
429 for (i = 0; i < data_len; i++) {
430 if (data[i] == '\n') {
431 count++;
432 data[i] = '\0';
433 }
434 }
435 start = all_list_len;
436 all_list_len += count;
437 all_list = realloc(all_list, sizeof(char *) * all_list_len);
438 str = data;
439 for (i = 0; i < data_len && start != all_list_len; i++) {
440 if (data[i] == '\0') {
441 all_list[start] = str;
442 str = data + i + 1;
443 start++;
444 }
445 }
446}
447
Jani Nikula1dcdad02016-05-12 16:15:42 +0300448/*
449 * Terminate s at first space, if any. If there was a space, return pointer to
450 * the character after that. Otherwise, return pointer to the terminating NUL.
451 */
452static char *chomp(char *s)
453{
454 while (*s && !isspace(*s))
455 s++;
456
457 if (*s)
458 *s++ = '\0';
459
460 return s;
461}
462
Jani Nikulaa48dc452016-05-12 16:15:41 +0300463/* Return pointer to directive content, or NULL if not a directive. */
464static char *is_directive(char *line)
465{
Jani Nikula064669b2016-05-12 16:15:43 +0300466 if (file_format == FORMAT_DOCBOOK && line[0] == '!')
Jani Nikulaa48dc452016-05-12 16:15:41 +0300467 return line + 1;
Jani Nikula064669b2016-05-12 16:15:43 +0300468 else if (file_format == FORMAT_RST && !strncmp(line, ".. !", 4))
469 return line + 4;
Jani Nikulaa48dc452016-05-12 16:15:41 +0300470
471 return NULL;
472}
473
Johannes Berge662af42007-10-24 15:08:48 -0700474/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 * Parse file, calling action specific functions for:
476 * 1) Lines containing !E
477 * 2) Lines containing !I
478 * 3) Lines containing !D
479 * 4) Lines containing !F
Johannes Berge662af42007-10-24 15:08:48 -0700480 * 5) Lines containing !P
Johannes Bergeda603f2010-09-11 15:55:22 -0700481 * 6) Lines containing !C
482 * 7) Default lines - lines not matching the above
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 */
Trevor Keith4356f482009-09-18 12:49:23 -0700484static void parse_file(FILE *infile)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
486 char line[MAXLINESZ];
Jani Nikulaa48dc452016-05-12 16:15:41 +0300487 char *p, *s;
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700488 while (fgets(line, MAXLINESZ, infile)) {
Jani Nikulaa48dc452016-05-12 16:15:41 +0300489 p = is_directive(line);
490 if (!p) {
Jani Nikula868fb192016-05-12 16:15:40 +0300491 defaultline(line);
492 continue;
493 }
494
Jani Nikulaa48dc452016-05-12 16:15:41 +0300495 switch (*p++) {
Jani Nikula868fb192016-05-12 16:15:40 +0300496 case 'E':
Jani Nikula1dcdad02016-05-12 16:15:42 +0300497 chomp(p);
Jani Nikulaa48dc452016-05-12 16:15:41 +0300498 externalfunctions(p);
Jani Nikula868fb192016-05-12 16:15:40 +0300499 break;
500 case 'I':
Jani Nikula1dcdad02016-05-12 16:15:42 +0300501 chomp(p);
Jani Nikulaa48dc452016-05-12 16:15:41 +0300502 internalfunctions(p);
Jani Nikula868fb192016-05-12 16:15:40 +0300503 break;
504 case 'D':
Jani Nikula1dcdad02016-05-12 16:15:42 +0300505 chomp(p);
Jani Nikulaa48dc452016-05-12 16:15:41 +0300506 symbolsonly(p);
Jani Nikula868fb192016-05-12 16:15:40 +0300507 break;
508 case 'F':
509 /* filename */
Jani Nikula1dcdad02016-05-12 16:15:42 +0300510 s = chomp(p);
Jani Nikula868fb192016-05-12 16:15:40 +0300511 /* function names */
512 while (isspace(*s))
513 s++;
Jani Nikulaa48dc452016-05-12 16:15:41 +0300514 singlefunctions(p, s);
Jani Nikula868fb192016-05-12 16:15:40 +0300515 break;
516 case 'P':
517 /* filename */
Jani Nikula1dcdad02016-05-12 16:15:42 +0300518 s = chomp(p);
Jani Nikula868fb192016-05-12 16:15:40 +0300519 /* DOC: section name */
520 while (isspace(*s))
521 s++;
Jani Nikulaa48dc452016-05-12 16:15:41 +0300522 docsection(p, s);
Jani Nikula868fb192016-05-12 16:15:40 +0300523 break;
524 case 'C':
Jani Nikula1dcdad02016-05-12 16:15:42 +0300525 chomp(p);
Jani Nikula868fb192016-05-12 16:15:40 +0300526 if (findall)
Jani Nikulaa48dc452016-05-12 16:15:41 +0300527 findall(p);
Jani Nikula868fb192016-05-12 16:15:40 +0300528 break;
529 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 defaultline(line);
531 }
532 }
533 fflush(stdout);
534}
535
Jani Nikula064669b2016-05-12 16:15:43 +0300536/*
537 * Is this a RestructuredText template? Answer the question by seeing if its
538 * name ends in ".rst".
539 */
540static int is_rst(const char *file)
541{
542 char *dot = strrchr(file, '.');
543
544 return dot && !strcmp(dot + 1, "rst");
545}
546
547enum opts {
548 OPT_DOCBOOK,
549 OPT_RST,
550 OPT_HELP,
551};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553int main(int argc, char *argv[])
554{
Jani Nikula568fb2d2016-05-12 16:15:39 +0300555 const char *subcommand, *filename;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 FILE * infile;
Johannes Bergeda603f2010-09-11 15:55:22 -0700557 int i;
Rob Landleybb13be52007-10-09 01:25:18 -0500558
559 srctree = getenv("SRCTREE");
560 if (!srctree)
561 srctree = getcwd(NULL, 0);
Jiri Slaby2d510052009-05-31 18:05:34 +0200562 kernsrctree = getenv("KBUILD_SRC");
Amerigo Wangb767b902009-06-19 03:06:54 -0400563 if (!kernsrctree || !*kernsrctree)
Jiri Slaby2d510052009-05-31 18:05:34 +0200564 kernsrctree = srctree;
Jani Nikula064669b2016-05-12 16:15:43 +0300565
566 for (;;) {
567 int c;
568 struct option opts[] = {
569 { "docbook", no_argument, NULL, OPT_DOCBOOK },
570 { "rst", no_argument, NULL, OPT_RST },
571 { "help", no_argument, NULL, OPT_HELP },
572 {}
573 };
574
575 c = getopt_long_only(argc, argv, "", opts, NULL);
576 if (c == -1)
577 break;
578
579 switch (c) {
580 case OPT_DOCBOOK:
581 file_format = FORMAT_DOCBOOK;
582 break;
583 case OPT_RST:
584 file_format = FORMAT_RST;
585 break;
586 case OPT_HELP:
587 usage();
588 return 0;
589 default:
590 case '?':
591 usage();
592 return 1;
593 }
594 }
595
596 argc -= optind;
597 argv += optind;
598
599 if (argc != 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 usage();
601 exit(1);
602 }
Jani Nikula568fb2d2016-05-12 16:15:39 +0300603
Jani Nikula064669b2016-05-12 16:15:43 +0300604 subcommand = argv[0];
605 filename = argv[1];
606
607 if (file_format == FORMAT_AUTO)
608 file_format = is_rst(filename) ? FORMAT_RST : FORMAT_DOCBOOK;
Jani Nikula568fb2d2016-05-12 16:15:39 +0300609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 /* Open file, exit on error */
Jani Nikula568fb2d2016-05-12 16:15:39 +0300611 infile = fopen(filename, "r");
Masahiro Yamadabb66fc62014-06-10 19:08:13 +0900612 if (infile == NULL) {
613 fprintf(stderr, "docproc: ");
Jani Nikula568fb2d2016-05-12 16:15:39 +0300614 perror(filename);
Masahiro Yamadabb66fc62014-06-10 19:08:13 +0900615 exit(2);
616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Jani Nikula568fb2d2016-05-12 16:15:39 +0300618 if (strcmp("doc", subcommand) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 /* Need to do this in two passes.
620 * First pass is used to collect all symbols exported
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700621 * in the various files;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 * Second pass generate the documentation.
Randy Dunlap6dd16f42007-09-04 21:23:22 -0700623 * This is required because some functions are declared
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 * and exported in different files :-((
625 */
626 /* Collect symbols */
627 defaultline = noaction;
628 internalfunctions = find_export_symbols;
629 externalfunctions = find_export_symbols;
630 symbolsonly = find_export_symbols;
631 singlefunctions = noaction2;
Johannes Berge662af42007-10-24 15:08:48 -0700632 docsection = noaction2;
Johannes Bergeda603f2010-09-11 15:55:22 -0700633 findall = find_all_symbols;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 parse_file(infile);
635
636 /* Rewind to start from beginning of file again */
637 fseek(infile, 0, SEEK_SET);
638 defaultline = printline;
639 internalfunctions = intfunc;
640 externalfunctions = extfunc;
641 symbolsonly = printline;
642 singlefunctions = singfunc;
Johannes Berge662af42007-10-24 15:08:48 -0700643 docsection = docsect;
Johannes Bergeda603f2010-09-11 15:55:22 -0700644 findall = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
646 parse_file(infile);
Johannes Bergeda603f2010-09-11 15:55:22 -0700647
648 for (i = 0; i < all_list_len; i++) {
649 if (!all_list[i])
650 continue;
651 fprintf(stderr, "Warning: didn't use docs for %s\n",
652 all_list[i]);
653 }
Jani Nikula568fb2d2016-05-12 16:15:39 +0300654 } else if (strcmp("depend", subcommand) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 /* Create first part of dependency chain
656 * file.tmpl */
Jani Nikula568fb2d2016-05-12 16:15:39 +0300657 printf("%s\t", filename);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 defaultline = noaction;
659 internalfunctions = adddep;
660 externalfunctions = adddep;
661 symbolsonly = adddep;
662 singlefunctions = adddep2;
Johannes Berge662af42007-10-24 15:08:48 -0700663 docsection = adddep2;
Johannes Bergeda603f2010-09-11 15:55:22 -0700664 findall = adddep;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 parse_file(infile);
666 printf("\n");
Jesper Juhlf0f3ca82011-06-15 11:53:13 +0200667 } else {
Jani Nikula568fb2d2016-05-12 16:15:39 +0300668 fprintf(stderr, "Unknown option: %s\n", subcommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 exit(1);
670 }
671 fclose(infile);
672 fflush(stdout);
673 return exitstatus;
674}