211 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | |
|  * See the copyright notice in the ACK home directory, in the file "Copyright".
 | |
|  */
 | |
| /* $Header$ */
 | |
| /*	Lint-specific comment handling	*/
 | |
| 
 | |
| #include	<ctype.h>
 | |
| 
 | |
| #include	"lint.h"
 | |
| 
 | |
| #ifdef	LINT
 | |
| 
 | |
| #include	<alloc.h>
 | |
| #include	"interface.h"
 | |
| #include	"arith.h"
 | |
| #include	"l_state.h"
 | |
| #include	"l_comment.h"
 | |
| 
 | |
| extern char loptions[];
 | |
| 
 | |
| /*	Since the lexical analyser does a one-token look-ahead, pseudo-
 | |
| 	comments are read too soon.  This is remedied by first storing them
 | |
| 	in static variables and then moving them to the real variables
 | |
| 	one token later.
 | |
| */
 | |
| 
 | |
| PRIVATE int notreached;
 | |
| PRIVATE int varargsN = -1;
 | |
| PRIVATE int argsused;
 | |
| PRIVATE int formatN;
 | |
| PRIVATE int formatVAR;
 | |
| PRIVATE char *format;
 | |
| PRIVATE char *prev_format;
 | |
| 
 | |
| PRIVATE make_format();
 | |
| 
 | |
| int LINTLIB;				/* file is lint library */
 | |
| int s_NOTREACHED;			/* statement not reached */
 | |
| int f_VARARGSn;				/* function with variable # of args */
 | |
| int f_ARGSUSED;				/* function does not use all args */
 | |
| int f_FORMATn;				/* argument f_FORMATn is f_FORMAT */
 | |
| char *f_FORMAT;
 | |
| int f_FORMATvar;			/* but the formal argument may be
 | |
| 					   absent because of varargs.h */
 | |
| 
 | |
| lint_init_comment()
 | |
| {
 | |
| 	LINTLIB = loptions['L'];
 | |
| }
 | |
| 
 | |
| lint_comment_ahead()
 | |
| {
 | |
| 	s_NOTREACHED = notreached;
 | |
| 	notreached = 0;
 | |
| }
 | |
| 
 | |
| lint_comment_function()
 | |
| {
 | |
| 	f_ARGSUSED = argsused | loptions['v'];
 | |
| 	argsused = 0;
 | |
| 
 | |
| 	f_VARARGSn = varargsN;
 | |
| 	varargsN = -1;
 | |
| 
 | |
| 	f_FORMATn = formatN;
 | |
| 	formatN = 0;
 | |
| 	f_FORMAT = format;
 | |
| 	if (format)
 | |
| 		prev_format = format;
 | |
| 	format = 0;
 | |
| 
 | |
| 	f_FORMATvar = formatVAR;
 | |
| 	formatVAR = 0;
 | |
| }
 | |
| 
 | |
| PRIVATE char buf[1000];
 | |
| PRIVATE char *bufpos;			/* next free position in buf */
 | |
| 
 | |
| lint_start_comment()
 | |
| {
 | |
| 	bufpos = &buf[0];
 | |
| }
 | |
| 
 | |
| lint_comment_char(c)
 | |
| 	int c;
 | |
| {
 | |
| /* This function is called with every character between /_* and *_/ */
 | |
| 	if (bufpos - &buf[0] < sizeof(buf)-1)
 | |
| 		*bufpos++ = (char)c;
 | |
| }
 | |
| 
 | |
| lint_end_comment()
 | |
| {
 | |
| 	*bufpos++ = '\0';
 | |
| 	bufpos = &buf[0];
 | |
| 
 | |
| 	/* skip initial blanks */
 | |
| 	while (*bufpos && isspace(*bufpos)) {
 | |
| 		bufpos++;
 | |
| 	}
 | |
| 
 | |
| 	/* now test for one of the pseudo-comments */
 | |
| 	if (strncmp(bufpos, "NOTREACHED", 10) == 0) {
 | |
| 		notreached = 1;
 | |
| 	}
 | |
| 	else
 | |
| 	if (strncmp(bufpos, "ARGSUSED", 8) == 0) {
 | |
| 		argsused = 1;
 | |
| 	}
 | |
| 	else
 | |
| 	if (strncmp(bufpos, "LINTLIBRARY", 11) == 0) {
 | |
| 		LINTLIB = 1;
 | |
| 	}
 | |
| 	else
 | |
| 	if (strncmp(bufpos, "VARARGS", 7) == 0) {
 | |
| 		bufpos += 7;
 | |
| 		varargsN = isdigit(*bufpos) ? atoi(bufpos) : 0;
 | |
| 	}
 | |
| 	else
 | |
| 	if (strncmp(bufpos, "FORMAT", 6) == 0 && isdigit(bufpos[6])) {
 | |
| 		register int argn;
 | |
| 
 | |
| 		bufpos += 6;
 | |
| 		argn = *bufpos++ - '0';
 | |
| 		varargsN = argn + 1;
 | |
| 		if (*bufpos == 'v') {
 | |
| 			/* something like FORMAT3v */
 | |
| 			formatVAR = 1;
 | |
| 			bufpos++;
 | |
| 		}
 | |
| 		make_format(argn, bufpos);
 | |
| 		
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*	We use a small FSA to skip layout inside formats, but to preserve
 | |
| 	a space between letters and digits.
 | |
| */
 | |
| 
 | |
| #define	NONE		0
 | |
| #define	LETGIT		1
 | |
| #define	LETGITSPACE	2
 | |
| 
 | |
| PRIVATE
 | |
| make_format(argn, oldf)
 | |
| 	int argn;
 | |
| 	char *oldf;
 | |
| {
 | |
| 	register char *newf;
 | |
| 	register int last_stat;
 | |
| 
 | |
| 	while (*oldf && *oldf != '$') {
 | |
| 		oldf++;
 | |
| 	}
 | |
| 	if (!*oldf) {
 | |
| 		/* no format given, repeat previous format */
 | |
| 		if (!prev_format) {
 | |
| 			warning("format missing and no previous format");
 | |
| 		}
 | |
| 		formatN = argn;
 | |
| 		format = prev_format;
 | |
| 		return;
 | |
| 	}
 | |
| 	if (*oldf++ != '$') {
 | |
| 		warning("no format in FORMAT pseudo-comment");
 | |
| 		format = 0;
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* there is a new format to be composed */
 | |
| 	newf = Malloc(strlen(oldf));
 | |
| 		/* certainly enough and probably not overly too much */
 | |
| 	formatN = argn;
 | |
| 	format = newf;
 | |
| 
 | |
| 	last_stat = NONE;
 | |
| 	while (*oldf && *oldf != '$') {
 | |
| 		register char ch = *oldf++;
 | |
| 
 | |
| 		if (isspace(ch)) {
 | |
| 			if (last_stat == LETGIT)
 | |
| 				last_stat = LETGITSPACE;
 | |
| 		}
 | |
| 		else
 | |
| 		if (isalnum(ch)) {
 | |
| 			switch (last_stat) {
 | |
| 			case NONE:
 | |
| 				last_stat = LETGIT;
 | |
| 				break;
 | |
| 			case LETGITSPACE:
 | |
| 				*newf++ = ' ';
 | |
| 				last_stat = LETGIT;
 | |
| 				break;
 | |
| 			}
 | |
| 			*newf++ = ch;
 | |
| 		}
 | |
| 		else {
 | |
| 			last_stat = NONE;
 | |
| 			*newf++ = ch;
 | |
| 		}
 | |
| 	}
 | |
| 	if (*oldf != '$') {
 | |
| 		warning("no end of format in FORMAT pseudo-comment");
 | |
| 		format = 0;
 | |
| 		return;
 | |
| 	}
 | |
| 	*newf++ = '\0';
 | |
| }
 | |
| 
 | |
| #endif	LINT
 |