⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mref.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* mref - MINIX cross referencer	Author: Andy Tanenbaum *//* Mref is intended for producing listings and cross reference maps of * MINIX.  The default is to produce three outputs: * *	on stdout:	numbered listing of all the files given as args *	on symbol.out:	list of all "global" symbols and their definition line *	on xref.out:	cross reference map of all references to global symbols * * For this program, a global symbol is one that is defined as PUBLIC, PRIVATE, * EXTERN, #define, or SYMBOL.  The latter is provided to allow users to force * symbols x, y, and z to "global" status but simply making up a file with * *	SYMBOL x *	SYMBOL y *	SYMBOL z * * The numbering is consecutive across files, i.e., the second file begins * where the first one left off, except that each file begins at the top of * a new page, and the line number is rounded upward to the next page. * The three types of output can each be suppressed, using the -l, -d, and -x * flags, respectively.  Line numbering between procedures may be optionally * suppressed with -s, as in the MINIX book.  Page length and numbering can be * user controlled with flags. * * Normally output is designed for a dumb line printer, but the -t flag causes * the output to be enhanced with macros and font control so it can be fed to * troff (or nroff).  If troff form, the symbol table is printed in three * columns, the first page being shorter to allow for the chapter opening. * * Flags: *	-#	Number of lines to print per page, default = 50 *	-d	Don't produce definition file (symbol table) *	-l	Don't produce listing *	-m	Multiple reference on one line only are cited once *	-p n	Set initial page number to n *	-t	Generate troff macro call before each page *	-s	Suppress line numbering between procedures *	-x	Don't produce the cross reference map * * Examples: *	mref -60 *.c		# print 60 lines per page (default is 50) *	mref -t -p 50 *.c	# first page is 50; generate .Ep and .Op macros *	mref -l -d *.h *.c	# no listing or symbols, just cross ref map */#include <sys/types.h>#include <ctype.h>#include <fcntl.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/wait.h>#include <stdio.h>#define LINE_SIZE     512#define PHYS_PAGE      66	/* physical page length */#define DEF_LEN        50	/* default # lines/page */#define SYM_SIZE       13	/* symbols are truncated to this size */#define HDR_SIZE        5	/* number of lines in the default header */#define NSYMS        2000	/* size of the symbol table */#define NTOKENS       100	/* maximum number of tokens per line */#define MAX_VALUES    100	/* maximum times a name can be declared */#define MAX_PER_LINE    9	/* number of cross refs to print per line */#define NCOLS           3	/* number of columns for troffed symbol.out */#define SYM_FILE "symbol.out"	/* place to write the symbol table */#define XREF_FILE "xref.out"	/* place to write cross ref map */#define TMP_FILE  "xref.tmp"	/* temporary xref file for gathering refs */#define SORTED_FILE "xref.sort"	/* temporary xref file for sorting */#define DEF             1	/* this line contains #define */#define EXT             2	/* this line contains EXTERN  */#define PRIV            3	/* this line contains PRIVATE */#define PUB             4	/* this line contains PUBLIC  */#define SYM             5	/* this line contains SYMBOL  */int listing = 1;		/* 1 = output listing;		0: don't */int xref = 1;			/* 1 = output cross ref map;	0: don't */int definitions = 1;		/* 1 = output definitions;	0: don't */int sflag = 0;			/* 1 = number all lines;	0: most  */int tflag = 0;			/* 1 = troff output;		0: flat  */int mflag = 0;			/* 1 = max one ref/line		0: many  */int page_len = DEF_LEN;		/* # lines to print per page */int phys_page = PHYS_PAGE;	/* total page size: top hdr+text+bottom hdr */int cur_line;			/* current line number */int cur_page = 1;		/* current page number */int nsymbols;			/* number of symbols in symbol table */int ntokens;			/* number of tokens in the token[] array */int suppressing;		/* don't print numbers between procedures */int hunting;			/* set when hunting for end of declaration */int comment;			/* set when scanning a comment */int xcount;			/* number of references so far to this sym */int prev_ref;			/* previous reference printed */int stride;			/* length of first symbol table page */int stride2;			/* length of second symbol table page */char *prog_name;		/* argv[0] */char line_buf[LINE_SIZE];	/* buffer for 1 line */char b[LINE_SIZE];		/* processed line goes here */char *token[NTOKENS];		/* array of pointers to tokens *//* Symbol table.  If a symbol is defined multiple times, it will get as many * entries in the symbol table as there are definitions. */struct symtab {  char sym_name[SYM_SIZE + 1];	/* symbol, followed by at least one '\0' */  char sym_type;		/* PUB, PRIV, EXT, SYM, or DEF */  int sym_val;			/* line number on which symbol occurs */} symtab[NSYMS];char *ppmap[] = {"", "#define", "EXTERN ", "PRIVATE", "PUBLIC ", "SYMBOL "};char *ppmap2[] = {"", "#def", "EXTN", "PRIV", "PUBL", "SYMB"};char spaces[] = "                ";char *xref_text[] = {  ".nf\n",  ".tr _\\(ru\n",  ".ta 1.25i 2iR 2.45iR 2.9iR 3.35iR 3.8iR 4.25iR 4.7iR 5.15iR 5.6iR 6.05iR\n",  (char *) 0};char *list_text[] = {  ".po .5i\n",  ".lg 0\n",  ".nf\n",  ".ec `\n",  ".ps 10\n",  ".vs 12p\n",  "`f(lb\n",  ".nr T `w'0'\n",  ".ta 8u*`nTu 16u*`nTu 24u*`nTu 32u*`nTu 40u*`nTu 48u*`nTu 56u*`nTu 64u*`nTu 72u*`nTu 80u*`nTu\n",  ".de Op \n",  ".bp ``$1\n",  ".sp 0.5i\n",  ".tl '``fR``s10MINIX SOURCE CODE``s0'``s11File: ``$2``s0``fP'``fB``s12``n%%``s0``fP'\n",  ".sp 1\n",  "``f(lb\n",  "..\n",  ".de Ep \n",  ".bp ``$1\n",  ".sp 0.5i\n",  ".tl '``fB``s12``n%%``s0``fP``fR'``s11File: ``$2'``s0``s10MINIX SOURCE CODE``s0``fP'\n",  ".sp 1\n",  "``f(lb\n",  "..\n",  (char *) 0};char *sym_text[] = {  ".nf\n",  ".tr _\\(ru\n",  ".ta 1.6iR 2.0i 3.6iR 4.0i 5.6iR\n",  (char *) 0};FILE *sym;			/* for symbol table file */FILE *xr;			/* for cross reference file */FILE *tmp;			/* for collecting cross references */FILE *sortf;			/* for sorting cross refernces */_PROTOTYPE(int main, (int argc, char **argv));_PROTOTYPE(int eat_flag, (char *argv [], int i));_PROTOTYPE(void make_files, (void));_PROTOTYPE(void process, (char *file));_PROTOTYPE(void list, (char *file));_PROTOTYPE(void get_sym, (void));_PROTOTYPE(void fill_page, (void));_PROTOTYPE(void eject, (void));_PROTOTYPE(void new_page, (char *file));_PROTOTYPE(void squash, (void));_PROTOTYPE(void strip, (char *string, char *s, int n));_PROTOTYPE(char *backup, (char *q));_PROTOTYPE(void enter_sym, (char *p, int value, int type));_PROTOTYPE(int find_slot, (char *p));_PROTOTYPE(int lookup, (char *p));_PROTOTYPE(unsigned int hash, (char *p));_PROTOTYPE(void print_sym, (void));_PROTOTYPE(int compact, (void));_PROTOTYPE(void swap, (struct symtab *ap, struct symtab *bp));_PROTOTYPE(void sort, (int n));_PROTOTYPE(void gen_xref, (char *file));_PROTOTYPE(char *skip_comment, (char *p));_PROTOTYPE(void collect_xref, (void));_PROTOTYPE(int new_name, (char *cur, int used, char *pname, int values []));_PROTOTYPE(void sort_xref, (void));_PROTOTYPE(void output_macros, (FILE *f, char *text []));_PROTOTYPE(void sym_macros, (void));_PROTOTYPE(void xref_macros, (void));_PROTOTYPE(void panic, (char *s));_PROTOTYPE(void usage, (void));int main(argc, argv)int argc;char *argv[];{  int i, j;  char *p;  prog_name = argv[0];  /* Process the command line. */  if (argc < 2) usage();  for (i = 1; i < argc; i++) {	p = argv[i];	if (*p != '-') break;	p++;	i += eat_flag(argv, i);  }  stride = page_len / 2;	/* allow for chapter opening */  stride2 = page_len;  /* Create the output files. */  make_files();  /* Read all the files. Make the listing and extract the symbols. */  for (j = i; j < argc; j++) process(argv[j]);  if (xref) {	/* Read all the files again and generate the cross	 * refererence data. */	cur_line = 0;	for (j = i; j < argc; j++) gen_xref(argv[j]);	/* Go get the cross reference data and print it. */	collect_xref();  }  /* Print the symbol table. */  if (definitions) print_sym();  return(0);}int eat_flag(argv, i)char *argv[];			/* argument array */int i;				/* process argv[i] */{  char *p;  int r = 0;  p = argv[i];  p++;  if (*p >= '0' && *p <= '9') {	page_len = atoi(p);	/* e.g. numb -60 file */	return(r);  }  while (1) {	/* Flag may be something like -dls. */	switch (*p) {	    case 'd':	definitions = 0;	break;	    case 'l':	listing = 0;	break;	    case 'x':	xref = 0;	break;	    case 'm':	mflag = 1;	break;	    case 's':	sflag = 1;	break;	    case 't':	tflag = 1;	break;	    case 'p':		cur_page = atoi(argv[i + 1]);		i++;		r = 1;		break;	    default:	usage();	}	p++;	if (*p == 0) return(r);  }}void make_files(){/* Create output files. */  int fd;  if (tflag && listing) output_macros(stdout, list_text);  if (definitions) {	if ((fd = creat(SYM_FILE, 0666)) < 0) {		fprintf(stderr, "%s: cannot create %s\n", prog_name, SYM_FILE);		exit(2);	}	close(fd);	sym = fopen(SYM_FILE, "w");	if (sym == NULL) {		fprintf(stderr, 		       "%s: cannot open %s for output\n", prog_name, SYM_FILE);		exit(2);	}	if (tflag) output_macros(sym, sym_text);  }  if (xref) {	if ((fd = creat(XREF_FILE, 0666)) < 0) {		fprintf(stderr,"%s: cannot create %s\n", prog_name, XREF_FILE);		exit(2);	}	close(fd);	xr = fopen(XREF_FILE, "w");	if (xr == NULL) {		fprintf(stderr,		      "%s: cannot open %s for output\n", prog_name, XREF_FILE);		exit(2);	}	if (tflag) output_macros(xr, xref_text);	if ((fd = creat(TMP_FILE, 0666)) < 0) {		fprintf(stderr, "%s: cannot create %s\n", prog_name, TMP_FILE);		exit(2);	}	close(fd);	tmp = fopen(TMP_FILE, "w");	if (tmp == NULL) {		fprintf(stderr,		       "%s: cannot open %s for output\n", prog_name, TMP_FILE);		exit(2);	}  }}void process(file)char *file;{/* Process one file. */  FILE *f;  if ((f = fopen(file, "r")) == NULL) {	fprintf(stderr, "%s: cannot open %s\n", prog_name, file);	exit(1);  }  while (1) {	if (fgets(line_buf, LINE_SIZE, f) == NULL) {		/* End of file hit. */		fclose(f);		if (listing && cur_line % page_len != 0) {			fill_page();	/* fill out the e.g. 50 lines */			eject();/* space to top of next sheet */		}		return;	}	if (listing)		list(file);	else		cur_line++;	if (definitions || xref) get_sym();  }}void list(file)char *file;{/* We are printing a listing. */  if (cur_line % page_len == 0) new_page(file);  if (suppressing == 1 && strlen(line_buf) == 1)	printf("\n");  else	printf("%5d   %s", cur_line, line_buf);  cur_line++;  if (cur_line % page_len == 0) eject();  if (strlen(line_buf) > 1) suppressing = 0;  if (strcmp(line_buf, "}\n") == 0 && sflag) suppressing = 1;}void get_sym(){/* Look for lines starting with PRIVATE, PUBLIC, EXTERN, SYMBOL or #define and * make a symbol table entry for them.  Life is slightly complicated by * constructions like: * * 1000 PRIVATE struct foobar { * 1001   int i; * 1002   char c; * 1003 } name[MAX]; * * in which the symbol 'name' is triggered on line 1000, but its value is 1003. */  int type;  register char c;  char *p, *q;  /* If we are hunting for the end of a declaration, the rules are   * different. */  if (hunting) {	q = line_buf;	while (*q == ' ' || *q == '\t') q++;	if (*q != '}') return;	q++;	while (*q == ' ' || *q == '\t') q++;	p = q;	while (isalnum(*p) || *p == '_') p++;	*p = 0;	enter_sym(q, cur_line - 1, hunting);	hunting = 0;	return;  }  /* For efficiency, make a quick check to see if this line is interesting. */  c = line_buf[0];  if (c != 'P' && c != 'E' && c != 'S' && c != '#') return;  squash();			/* squeeze out white space */  /* Real check to see if this line is interesting. */  type = 0;  if (strncmp(b, "#define", (size_t)7) == 0) type = DEF;  if (strncmp(b, "PRIVATE", (size_t)7) == 0) type = PRIV;  if (strncmp(b, "PUBLIC", (size_t)6) == 0) type = PUB;  if (strncmp(b, "EXTERN", (size_t)6) == 0) type = EXT;  if (strncmp(b, "SYMBOL", (size_t)6) == 0) type = SYM;  if (type == 0) return;  /* Process #define */  if (type == DEF) {	q = &b[8];	while (*q != ' ') q++;	*q = 0;	enter_sym(&b[8], cur_line - 1, type);	return;  }  q = b + strlen(b) - 1;	/* q points to last character */  if (*q == '!' || *q == '+') {	*q = ' ';	while (*q == ' ') q--;  }  /* If last char is paren, }, or comma, this is a function call. */  if (*q == ')' || *q == ',' || *q == '}') {	/* It is a paren. */	q = b;	while (*q != '(') q++;	if (*(q + 1) == '*')		*q = ' ';	/* worry about: int (*foo[N])() */	strip(b, "(", 1);	strip(b, "[", 1);	q = b + strlen(b) - 1;	q = backup(q);	enter_sym(q, cur_line - 1, type);	return;  }  /* If last char is semicolon, '[', or letter, this is a declaration. */  if (*q == ';' || *q == ']' || *q == '_' || isalnum(*q)) {	/* It is a declaration. */	if (*q == ';') q--;	if (*q == ' ') q--;	*(q + 1) = 0;	if (*q == ']') strip(b, "[", 1);	/* e.g. PRIVATE int foo[N]; */	q = b + strlen(b) - 1;	q = backup(q);	enter_sym(q, cur_line - 1, type);	return;  }  /* If last char is curly bracket, this is the start of a struct array. */  if (*q == '{') {	hunting = type;		/* Start hunting for the '}' */	return;  }  panic("getsym got unknown line type");}void fill_page(){/* Fill out current page with line feeds. This routine is only called when * an end of file is encountered.  It fills out the current page to 50 * lines (or whatever).  For -t it does nothing. */  int k;  k = cur_line % page_len;  if (k > 0) k = page_len - k;  cur_line += k;  if (tflag == 0) while (k--)		printf("\n");}void eject(){/* Finish off the last 11 or so blank lines on a page (not for -t. */  int i;  if (tflag) return;  i = phys_page - page_len - HDR_SIZE;  while (i--) printf("\n");}void new_page(file)char *file;{/* Top of page processing. */  if (tflag) {	/* Generate a troff macro that does the heading (odd/even). */	if (cur_page & 1)		printf(".Op %d %s\n", cur_page, file);	/* odd page */	else		printf(".Ep %d %s\n", cur_page, file);	/* even page */  } else {	/* Standard header */	printf("\n\n\nPage: %d                         ", cur_page);	printf("File: %s\n\n", file);  }  cur_page++;}void squash(){/* Copy line_buf to b, squeezing out white space, comments, and initializers. */  register char *p, *q;  char c;  p = line_buf;  q = b;  c = *p;  *q++ = *p++;			/* copy first character */  if (c == '#') {	while (*p == ' ' || *p == '\t') p++;	/* skip spaces after '#' */  }  while (*p != '\0') {	if (*p == '\n' || *p == '=') break;	if (*p == '/' && *(p + 1) == '*') break;	if (*p == ' ' || *p == '\t') {		while (*p == ' ' || *p == '\t') p++;		*q++ = ' ';	/* copy one space */	} else {		*q++ = *p++;	}  }  if (*(q - 1) == ' ') q--;  *q = 0;}void strip(string, s, n)char *string;char *s;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -