diff options
Diffstat (limited to 'scripts/docproc.c')
| -rw-r--r-- | scripts/docproc.c | 681 | 
1 files changed, 0 insertions, 681 deletions
diff --git a/scripts/docproc.c b/scripts/docproc.c deleted file mode 100644 index 0a12593b9041..000000000000 --- a/scripts/docproc.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - *	docproc is a simple preprocessor for the template files - *      used as placeholders for the kernel internal documentation. - *	docproc is used for documentation-frontend and - *      dependency-generator. - *	The two usages have in common that they require - *	some knowledge of the .tmpl syntax, therefore they - *	are kept together. - * - *	documentation-frontend - *		Scans the template file and call kernel-doc for - *		all occurrences of ![EIF]file - *		Beforehand each referenced file is scanned for - *		any symbols that are exported via these macros: - *			EXPORT_SYMBOL(), EXPORT_SYMBOL_GPL(), & - *			EXPORT_SYMBOL_GPL_FUTURE() - *		This is used to create proper -function and - *		-nofunction arguments in calls to kernel-doc. - *		Usage: docproc doc file.tmpl - * - *	dependency-generator: - *		Scans the template file and list all files - *		referenced in a format recognized by make. - *		Usage:	docproc depend file.tmpl - *		Writes dependency information to stdout - *		in the following format: - *		file.tmpl src.c	src2.c - *		The filenames are obtained from the following constructs: - *		!Efilename - *		!Ifilename - *		!Dfilename - *		!Ffilename - *		!Pfilename - * - */ - -#define _GNU_SOURCE -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <unistd.h> -#include <limits.h> -#include <errno.h> -#include <getopt.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <time.h> - -/* exitstatus is used to keep track of any failing calls to kernel-doc, - * but execution continues. */ -int exitstatus = 0; - -typedef void DFL(char *); -DFL *defaultline; - -typedef void FILEONLY(char * file); -FILEONLY *internalfunctions; -FILEONLY *externalfunctions; -FILEONLY *symbolsonly; -FILEONLY *findall; - -typedef void FILELINE(char * file, char * line); -FILELINE * singlefunctions; -FILELINE * entity_system; -FILELINE * docsection; - -#define MAXLINESZ     2048 -#define MAXFILES      250 -#define KERNELDOCPATH "scripts/" -#define KERNELDOC     "kernel-doc" -#define DOCBOOK       "-docbook" -#define RST           "-rst" -#define LIST          "-list" -#define FUNCTION      "-function" -#define NOFUNCTION    "-nofunction" -#define NODOCSECTIONS "-no-doc-sections" -#define SHOWNOTFOUND  "-show-not-found" - -enum file_format { -	FORMAT_AUTO, -	FORMAT_DOCBOOK, -	FORMAT_RST, -}; - -static enum file_format file_format = FORMAT_AUTO; - -#define KERNELDOC_FORMAT	(file_format == FORMAT_RST ? RST : DOCBOOK) - -static char *srctree, *kernsrctree; - -static char **all_list = NULL; -static int all_list_len = 0; - -static void consume_symbol(const char *sym) -{ -	int i; - -	for (i = 0; i < all_list_len; i++) { -		if (!all_list[i]) -			continue; -		if (strcmp(sym, all_list[i])) -			continue; -		all_list[i] = NULL; -		break; -	} -} - -static void usage (void) -{ -	fprintf(stderr, "Usage: docproc [{--docbook|--rst}] {doc|depend} file\n"); -	fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n"); -	fprintf(stderr, "doc: frontend when generating kernel documentation\n"); -	fprintf(stderr, "depend: generate list of files referenced within file\n"); -	fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n"); -	fprintf(stderr, "                     KBUILD_SRC: absolute path to kernel source tree.\n"); -} - -/* - * Execute kernel-doc with parameters given in svec - */ -static void exec_kernel_doc(char **svec) -{ -	pid_t pid; -	int ret; -	char real_filename[PATH_MAX + 1]; -	/* Make sure output generated so far are flushed */ -	fflush(stdout); -	switch (pid=fork()) { -		case -1: -			perror("fork"); -			exit(1); -		case  0: -			memset(real_filename, 0, sizeof(real_filename)); -			strncat(real_filename, kernsrctree, PATH_MAX); -			strncat(real_filename, "/" KERNELDOCPATH KERNELDOC, -					PATH_MAX - strlen(real_filename)); -			execvp(real_filename, svec); -			fprintf(stderr, "exec "); -			perror(real_filename); -			exit(1); -		default: -			waitpid(pid, &ret ,0); -	} -	if (WIFEXITED(ret)) -		exitstatus |= WEXITSTATUS(ret); -	else -		exitstatus = 0xff; -} - -/* Types used to create list of all exported symbols in a number of files */ -struct symbols -{ -	char *name; -}; - -struct symfile -{ -	char *filename; -	struct symbols *symbollist; -	int symbolcnt; -}; - -struct symfile symfilelist[MAXFILES]; -int symfilecnt = 0; - -static void add_new_symbol(struct symfile *sym, char * symname) -{ -	sym->symbollist = -	  realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *)); -	sym->symbollist[sym->symbolcnt++].name = strdup(symname); -} - -/* Add a filename to the list */ -static struct symfile * add_new_file(char * filename) -{ -	symfilelist[symfilecnt++].filename = strdup(filename); -	return &symfilelist[symfilecnt - 1]; -} - -/* Check if file already are present in the list */ -static struct symfile * filename_exist(char * filename) -{ -	int i; -	for (i=0; i < symfilecnt; i++) -		if (strcmp(symfilelist[i].filename, filename) == 0) -			return &symfilelist[i]; -	return NULL; -} - -/* - * List all files referenced within the template file. - * Files are separated by tabs. - */ -static void adddep(char * file)		   { printf("\t%s", file); } -static void adddep2(char * file, char * line)     { line = line; adddep(file); } -static void noaction(char * line)		   { line = line; } -static void noaction2(char * file, char * line)   { file = file; line = line; } - -/* Echo the line without further action */ -static void printline(char * line)               { printf("%s", line); } - -/* - * Find all symbols in filename that are exported with EXPORT_SYMBOL & - * EXPORT_SYMBOL_GPL (& EXPORT_SYMBOL_GPL_FUTURE implicitly). - * All symbols located are stored in symfilelist. - */ -static void find_export_symbols(char * filename) -{ -	FILE * fp; -	struct symfile *sym; -	char line[MAXLINESZ]; -	if (filename_exist(filename) == NULL) { -		char real_filename[PATH_MAX + 1]; -		memset(real_filename, 0, sizeof(real_filename)); -		strncat(real_filename, srctree, PATH_MAX); -		strncat(real_filename, "/", PATH_MAX - strlen(real_filename)); -		strncat(real_filename, filename, -				PATH_MAX - strlen(real_filename)); -		sym = add_new_file(filename); -		fp = fopen(real_filename, "r"); -		if (fp == NULL)	{ -			fprintf(stderr, "docproc: "); -			perror(real_filename); -			exit(1); -		} -		while (fgets(line, MAXLINESZ, fp)) { -			char *p; -			char *e; -			if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) || -			    ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) { -				/* Skip EXPORT_SYMBOL{_GPL} */ -				while (isalnum(*p) || *p == '_') -					p++; -				/* Remove parentheses & additional whitespace */ -				while (isspace(*p)) -					p++; -				if (*p != '(') -					continue; /* Syntax error? */ -				else -					p++; -				while (isspace(*p)) -					p++; -				e = p; -				while (isalnum(*e) || *e == '_') -					e++; -				*e = '\0'; -				add_new_symbol(sym, p); -			} -		} -		fclose(fp); -	} -} - -/* - * Document all external or internal functions in a file. - * Call kernel-doc with following parameters: - * kernel-doc [-docbook|-rst] -nofunction function_name1 filename - * Function names are obtained from all the src files - * by find_export_symbols. - * intfunc uses -nofunction - * extfunc uses -function - */ -static void docfunctions(char * filename, char * type) -{ -	int i,j; -	int symcnt = 0; -	int idx = 0; -	char **vec; - -	for (i=0; i <= symfilecnt; i++) -		symcnt += symfilelist[i].symbolcnt; -	vec = malloc((2 + 2 * symcnt + 3) * sizeof(char *)); -	if (vec == NULL) { -		perror("docproc: "); -		exit(1); -	} -	vec[idx++] = KERNELDOC; -	vec[idx++] = KERNELDOC_FORMAT; -	vec[idx++] = NODOCSECTIONS; -	for (i=0; i < symfilecnt; i++) { -		struct symfile * sym = &symfilelist[i]; -		for (j=0; j < sym->symbolcnt; j++) { -			vec[idx++]     = type; -			consume_symbol(sym->symbollist[j].name); -			vec[idx++] = sym->symbollist[j].name; -		} -	} -	vec[idx++]     = filename; -	vec[idx] = NULL; -	if (file_format == FORMAT_RST) -		printf(".. %s\n", filename); -	else -		printf("<!-- %s -->\n", filename); -	exec_kernel_doc(vec); -	fflush(stdout); -	free(vec); -} -static void intfunc(char * filename) {	docfunctions(filename, NOFUNCTION); } -static void extfunc(char * filename) { docfunctions(filename, FUNCTION);   } - -/* - * Document specific function(s) in a file. - * Call kernel-doc with the following parameters: - * kernel-doc -docbook -function function1 [-function function2] - */ -static void singfunc(char * filename, char * line) -{ -	char *vec[200]; /* Enough for specific functions */ -	int i, idx = 0; -	int startofsym = 1; -	vec[idx++] = KERNELDOC; -	vec[idx++] = KERNELDOC_FORMAT; -	vec[idx++] = SHOWNOTFOUND; - -	/* Split line up in individual parameters preceded by FUNCTION */ -	for (i=0; line[i]; i++) { -		if (isspace(line[i])) { -			line[i] = '\0'; -			startofsym = 1; -			continue; -		} -		if (startofsym) { -			startofsym = 0; -			vec[idx++] = FUNCTION; -			vec[idx++] = &line[i]; -		} -	} -	for (i = 0; i < idx; i++) { -		if (strcmp(vec[i], FUNCTION)) -			continue; -		consume_symbol(vec[i + 1]); -	} -	vec[idx++] = filename; -	vec[idx] = NULL; -	exec_kernel_doc(vec); -} - -/* - * Insert specific documentation section from a file. - * Call kernel-doc with the following parameters: - * kernel-doc -docbook -function "doc section" filename - */ -static void docsect(char *filename, char *line) -{ -	/* kerneldoc -docbook -show-not-found -function "section" file NULL */ -	char *vec[7]; -	char *s; - -	for (s = line; *s; s++) -		if (*s == '\n') -			*s = '\0'; - -	if (asprintf(&s, "DOC: %s", line) < 0) { -		perror("asprintf"); -		exit(1); -	} -	consume_symbol(s); -	free(s); - -	vec[0] = KERNELDOC; -	vec[1] = KERNELDOC_FORMAT; -	vec[2] = SHOWNOTFOUND; -	vec[3] = FUNCTION; -	vec[4] = line; -	vec[5] = filename; -	vec[6] = NULL; -	exec_kernel_doc(vec); -} - -static void find_all_symbols(char *filename) -{ -	char *vec[4]; /* kerneldoc -list file NULL */ -	pid_t pid; -	int ret, i, count, start; -	char real_filename[PATH_MAX + 1]; -	int pipefd[2]; -	char *data, *str; -	size_t data_len = 0; - -	vec[0] = KERNELDOC; -	vec[1] = LIST; -	vec[2] = filename; -	vec[3] = NULL; - -	if (pipe(pipefd)) { -		perror("pipe"); -		exit(1); -	} - -	switch (pid=fork()) { -		case -1: -			perror("fork"); -			exit(1); -		case  0: -			close(pipefd[0]); -			dup2(pipefd[1], 1); -			memset(real_filename, 0, sizeof(real_filename)); -			strncat(real_filename, kernsrctree, PATH_MAX); -			strncat(real_filename, "/" KERNELDOCPATH KERNELDOC, -					PATH_MAX - strlen(real_filename)); -			execvp(real_filename, vec); -			fprintf(stderr, "exec "); -			perror(real_filename); -			exit(1); -		default: -			close(pipefd[1]); -			data = malloc(4096); -			do { -				while ((ret = read(pipefd[0], -						   data + data_len, -						   4096)) > 0) { -					data_len += ret; -					data = realloc(data, data_len + 4096); -				} -			} while (ret == -EAGAIN); -			if (ret != 0) { -				perror("read"); -				exit(1); -			} -			waitpid(pid, &ret ,0); -	} -	if (WIFEXITED(ret)) -		exitstatus |= WEXITSTATUS(ret); -	else -		exitstatus = 0xff; - -	count = 0; -	/* poor man's strtok, but with counting */ -	for (i = 0; i < data_len; i++) { -		if (data[i] == '\n') { -			count++; -			data[i] = '\0'; -		} -	} -	start = all_list_len; -	all_list_len += count; -	all_list = realloc(all_list, sizeof(char *) * all_list_len); -	str = data; -	for (i = 0; i < data_len && start != all_list_len; i++) { -		if (data[i] == '\0') { -			all_list[start] = str; -			str = data + i + 1; -			start++; -		} -	} -} - -/* - * Terminate s at first space, if any. If there was a space, return pointer to - * the character after that. Otherwise, return pointer to the terminating NUL. - */ -static char *chomp(char *s) -{ -	while (*s && !isspace(*s)) -		s++; - -	if (*s) -		*s++ = '\0'; - -	return s; -} - -/* Return pointer to directive content, or NULL if not a directive. */ -static char *is_directive(char *line) -{ -	if (file_format == FORMAT_DOCBOOK && line[0] == '!') -		return line + 1; -	else if (file_format == FORMAT_RST && !strncmp(line, ".. !", 4)) -		return line + 4; - -	return NULL; -} - -/* - * Parse file, calling action specific functions for: - * 1) Lines containing !E - * 2) Lines containing !I - * 3) Lines containing !D - * 4) Lines containing !F - * 5) Lines containing !P - * 6) Lines containing !C - * 7) Default lines - lines not matching the above - */ -static void parse_file(FILE *infile) -{ -	char line[MAXLINESZ]; -	char *p, *s; -	while (fgets(line, MAXLINESZ, infile)) { -		p = is_directive(line); -		if (!p) { -			defaultline(line); -			continue; -		} - -		switch (*p++) { -		case 'E': -			chomp(p); -			externalfunctions(p); -			break; -		case 'I': -			chomp(p); -			internalfunctions(p); -			break; -		case 'D': -			chomp(p); -			symbolsonly(p); -			break; -		case 'F': -			/* filename */ -			s = chomp(p); -			/* function names */ -			while (isspace(*s)) -				s++; -			singlefunctions(p, s); -			break; -		case 'P': -			/* filename */ -			s = chomp(p); -			/* DOC: section name */ -			while (isspace(*s)) -				s++; -			docsection(p, s); -			break; -		case 'C': -			chomp(p); -			if (findall) -				findall(p); -			break; -		default: -			defaultline(line); -		} -	} -	fflush(stdout); -} - -/* - * Is this a RestructuredText template?  Answer the question by seeing if its - * name ends in ".rst". - */ -static int is_rst(const char *file) -{ -	char *dot = strrchr(file, '.'); - -	return dot && !strcmp(dot + 1, "rst"); -} - -enum opts { -	OPT_DOCBOOK, -	OPT_RST, -	OPT_HELP, -}; - -int main(int argc, char *argv[]) -{ -	const char *subcommand, *filename; -	FILE * infile; -	int i; - -	srctree = getenv("SRCTREE"); -	if (!srctree) -		srctree = getcwd(NULL, 0); -	kernsrctree = getenv("KBUILD_SRC"); -	if (!kernsrctree || !*kernsrctree) -		kernsrctree = srctree; - -	for (;;) { -		int c; -		struct option opts[] = { -			{ "docbook",	no_argument, NULL, OPT_DOCBOOK }, -			{ "rst",	no_argument, NULL, OPT_RST }, -			{ "help",	no_argument, NULL, OPT_HELP }, -			{} -		}; - -		c = getopt_long_only(argc, argv, "", opts, NULL); -		if (c == -1) -			break; - -		switch (c) { -		case OPT_DOCBOOK: -			file_format = FORMAT_DOCBOOK; -			break; -		case OPT_RST: -			file_format = FORMAT_RST; -			break; -		case OPT_HELP: -			usage(); -			return 0; -		default: -		case '?': -			usage(); -			return 1; -		} -	} - -	argc -= optind; -	argv += optind; - -	if (argc != 2) { -		usage(); -		exit(1); -	} - -	subcommand = argv[0]; -	filename = argv[1]; - -	if (file_format == FORMAT_AUTO) -		file_format = is_rst(filename) ? FORMAT_RST : FORMAT_DOCBOOK; - -	/* Open file, exit on error */ -	infile = fopen(filename, "r"); -	if (infile == NULL) { -		fprintf(stderr, "docproc: "); -		perror(filename); -		exit(2); -	} - -	if (strcmp("doc", subcommand) == 0) { -		if (file_format == FORMAT_RST) { -			time_t t = time(NULL); -			printf(".. generated from %s by docproc %s\n", -			       filename, ctime(&t)); -		} - -		/* Need to do this in two passes. -		 * First pass is used to collect all symbols exported -		 * in the various files; -		 * Second pass generate the documentation. -		 * This is required because some functions are declared -		 * and exported in different files :-(( -		 */ -		/* Collect symbols */ -		defaultline       = noaction; -		internalfunctions = find_export_symbols; -		externalfunctions = find_export_symbols; -		symbolsonly       = find_export_symbols; -		singlefunctions   = noaction2; -		docsection        = noaction2; -		findall           = find_all_symbols; -		parse_file(infile); - -		/* Rewind to start from beginning of file again */ -		fseek(infile, 0, SEEK_SET); -		defaultline       = printline; -		internalfunctions = intfunc; -		externalfunctions = extfunc; -		symbolsonly       = printline; -		singlefunctions   = singfunc; -		docsection        = docsect; -		findall           = NULL; - -		parse_file(infile); - -		for (i = 0; i < all_list_len; i++) { -			if (!all_list[i]) -				continue; -			fprintf(stderr, "Warning: didn't use docs for %s\n", -				all_list[i]); -		} -	} else if (strcmp("depend", subcommand) == 0) { -		/* Create first part of dependency chain -		 * file.tmpl */ -		printf("%s\t", filename); -		defaultline       = noaction; -		internalfunctions = adddep; -		externalfunctions = adddep; -		symbolsonly       = adddep; -		singlefunctions   = adddep2; -		docsection        = adddep2; -		findall           = adddep; -		parse_file(infile); -		printf("\n"); -	} else { -		fprintf(stderr, "Unknown option: %s\n", subcommand); -		exit(1); -	} -	fclose(infile); -	fflush(stdout); -	return exitstatus; -}  |