xref: /csrg-svn/old/pcc/lint/lpass1/lint.c (revision 32980)
17988Srrh #ifndef lint
2*32980Sdonn static char sccsid[] = "@(#)lint.c	1.14	(Berkeley)	12/11/87";
37988Srrh #endif lint
47988Srrh 
518598Sralph # include "pass1.h"
67988Srrh 
718598Sralph # include "lmanifest.h"
87988Srrh 
97988Srrh # include <ctype.h>
107988Srrh 
117988Srrh # define VAL 0
127988Srrh # define EFF 1
137988Srrh 
147988Srrh /* these are appropriate for the -p flag */
157988Srrh int  SZCHAR = 8;
167988Srrh int  SZINT = 16;
177988Srrh int  SZFLOAT = 32;
187988Srrh int  SZDOUBLE = 64;
197988Srrh int  SZLONG = 32;
207988Srrh int  SZSHORT = 16;
217988Srrh int SZPOINT = 16;
227988Srrh int ALCHAR = 8;
237988Srrh int ALINT = 16;
247988Srrh int ALFLOAT = 32;
257988Srrh int ALDOUBLE = 64;
267988Srrh int ALLONG = 32;
277988Srrh int ALSHORT = 16;
287988Srrh int ALPOINT = 16;
297988Srrh int ALSTRUCT = 16;
307988Srrh 
3130819Sbostic int nflag = 0;		/* avoid gripes about printf et al. */
3230819Sbostic int vflag = 1;		/* tell about unused argments */
3330819Sbostic int xflag = 0;		/* tell about unused externals */
3430819Sbostic int argflag = 0;	/* used to turn off complaints about arguments */
3530819Sbostic int libflag = 0;	/* used to generate library descriptions */
3630819Sbostic int vaflag = -1;	/* signal functions with a variable number of args */
3730819Sbostic int aflag = 0;		/* used to check precision of assignments */
3830819Sbostic int zflag = 0;		/* no 'structure never defined' error */
3930819Sbostic int Cflag = 0;	/* filter out certain output, for generating libraries */
4030819Sbostic char *libname = 0;	/* name of the library we're generating */
417988Srrh 
4230819Sbostic 			/* flags for the "outdef" function */
437988Srrh # define USUAL (-101)
447988Srrh # define DECTY (-102)
457988Srrh # define NOFILE (-103)
467988Srrh # define SVLINE (-104)
477988Srrh 
487988Srrh # define LNAMES 250
497988Srrh 
507988Srrh struct lnm {
517988Srrh 	short lid, flgs;
527988Srrh 	}  lnames[LNAMES], *lnp;
537988Srrh 
contx(p,down,pl,pr)547988Srrh contx( p, down, pl, pr ) register NODE *p; register *pl, *pr; {
557988Srrh 
567988Srrh 	*pl = *pr = VAL;
577988Srrh 	switch( p->in.op ){
587988Srrh 
597988Srrh 	case ANDAND:
607988Srrh 	case OROR:
617988Srrh 	case QUEST:
627988Srrh 		*pr = down;
637988Srrh 		break;
647988Srrh 
657988Srrh 	case SCONV:
667988Srrh 	case PCONV:
677988Srrh 	case COLON:
687988Srrh 		*pr = *pl = down;
697988Srrh 		break;
707988Srrh 
717988Srrh 	case COMOP:
727988Srrh 		*pl = EFF;
737988Srrh 		*pr = down;
747988Srrh 
757988Srrh 	case FORCE:
767988Srrh 	case INIT:
777988Srrh 	case UNARY CALL:
787988Srrh 	case STCALL:
797988Srrh 	case UNARY STCALL:
807988Srrh 	case CALL:
817988Srrh 	case UNARY FORTCALL:
827988Srrh 	case FORTCALL:
837988Srrh 	case CBRANCH:
847988Srrh 		break;
857988Srrh 
867988Srrh 	default:
877988Srrh 		if( asgop(p->in.op) ) break;
887988Srrh 		if( p->in.op == UNARY MUL && ( p->in.type == STRTY || p->in.type == UNIONTY || p->in.type == UNDEF) ) {
897988Srrh 		/* struct x f( );  main( ) {  (void) f( ); }
907988Srrh 		 * the the cast call appears as U* UNDEF
917988Srrh 		 */
927988Srrh 			break;  /* the compiler does this... */
937988Srrh 			}
947988Srrh 		if( down == EFF && hflag ) werror( "null effect" );
957988Srrh 
967988Srrh 		}
977988Srrh 	}
987988Srrh 
ecode(p)997988Srrh ecode( p ) NODE *p; {
1007988Srrh 	/* compile code for p */
1017988Srrh 
1027988Srrh 	fwalk( p, contx, EFF );
1037988Srrh 	lnp = lnames;
1047988Srrh 	lprt( p, EFF, 0 );
10530819Sbostic 	strforget();
1067988Srrh 	}
1077988Srrh 
ejobcode(flag)1087988Srrh ejobcode( flag ){
1097988Srrh 	/* called after processing each job */
1107988Srrh 	/* flag is nonzero if errors were detected */
1117988Srrh 	register k;
1127988Srrh 	register struct symtab *p;
1137988Srrh 
1147988Srrh 	for( p=stab; p< &stab[SYMTSZ]; ++p ){
1157988Srrh 
1167988Srrh 		if( p->stype != TNULL ) {
1177988Srrh 
1187988Srrh 			if( p->stype == STRTY || p->stype == UNIONTY ){
11911761Sedward 				if( !zflag && dimtab[p->sizoff+1] < 0 ){
12011761Sedward 					/* never defined */
1217988Srrh #ifndef FLEXNAMES
1227988Srrh 					if( hflag ) werror( "struct/union %.8s never defined", p->sname );
1237988Srrh #else
1247988Srrh 					if( hflag ) werror( "struct/union %s never defined", p->sname );
1257988Srrh #endif
1267988Srrh 					}
1277988Srrh 				}
1287988Srrh 
1297988Srrh 			switch( p->sclass ){
1307988Srrh 
1317988Srrh 			case STATIC:
1327988Srrh 				if( p->suse > 0 ){
1337988Srrh 					k = lineno;
1347988Srrh 					lineno = p->suse;
1357988Srrh #ifndef FLEXNAMES
1367988Srrh 					uerror( "static variable %.8s unused",
1377988Srrh #else
1387988Srrh 					uerror( "static variable %s unused",
1397988Srrh #endif
1407988Srrh 						p->sname );
1417988Srrh 					lineno = k;
1427988Srrh 					break;
1437988Srrh 					}
14411403Snicklin 				/* no statics in libraries */
14511403Snicklin 				if( Cflag ) break;
1467988Srrh 
1477988Srrh 			case EXTERN:
1487988Srrh 			case USTATIC:
1497988Srrh 				/* with the xflag, worry about externs not used */
1507988Srrh 				/* the filename may be wrong here... */
1517988Srrh 				if( xflag && p->suse >= 0 && !libflag ){
1527988Srrh 					outdef( p, LDX, NOFILE );
1537988Srrh 					}
1547988Srrh 
1557988Srrh 			case EXTDEF:
1567988Srrh 				if( p->suse < 0 ){  /* used */
1577988Srrh 					outdef( p, LUM, SVLINE );
1587988Srrh 					}
1597988Srrh 				break;
1607988Srrh 				}
1617988Srrh 
1627988Srrh 			}
1637988Srrh 
1647988Srrh 		}
1657988Srrh 	exit( 0 );
1667988Srrh 	}
1677988Srrh 
astype(t,i)1687988Srrh astype( t, i ) ATYPE *t; {
1697988Srrh 	TWORD tt;
17011761Sedward 	int j, k=0, l=0;
1717988Srrh 
1727988Srrh 	if( (tt=BTYPE(t->aty))==STRTY || tt==UNIONTY ){
1737988Srrh 		if( i<0 || i>= DIMTABSZ-3 ){
1747988Srrh 			werror( "lint's little mind is blown" );
1757988Srrh 			}
1767988Srrh 		else {
1777988Srrh 			j = dimtab[i+3];
1787988Srrh 			if( j<0 || j>SYMTSZ ){
17911761Sedward 				k = dimtab[i];
18011761Sedward 				l = X_NONAME | stab[j].suse;
1817988Srrh 				}
1827988Srrh 			else {
1837988Srrh 				if( stab[j].suse <= 0 ) {
1847988Srrh #ifndef FLEXNAMES
1857988Srrh 					werror( "no line number for %.8s",
1867988Srrh #else
1877988Srrh 					werror( "no line number for %s",
1887988Srrh #endif
1897988Srrh 						stab[j].sname );
1907988Srrh 					}
19111761Sedward 				else {
19211761Sedward 					k = dimtab[i];
19311761Sedward #ifdef FLEXNAMES
19411761Sedward 					l = hashstr(stab[j].sname);
19511761Sedward #else
19611761Sedward 					l = hashstr(stab[j].sname, LCHNM);
19711761Sedward #endif
19811761Sedward 					}
1997988Srrh 				}
2007988Srrh 			}
2017988Srrh 
2027988Srrh 		t->extra = k;
20311761Sedward 		t->extra1 = l;
2047988Srrh 		return( 1 );
2057988Srrh 		}
2067988Srrh 	else return( 0 );
2077988Srrh 	}
2087988Srrh 
bfcode(a,n)2097988Srrh bfcode( a, n ) int a[]; {
2107988Srrh 	/* code for the beginning of a function; a is an array of
2117988Srrh 		indices in stab for the arguments; n is the number */
2127988Srrh 	/* this must also set retlab */
2137988Srrh 	register i;
2147988Srrh 	register struct symtab *cfp;
2157988Srrh 	static ATYPE t;
2167988Srrh 
21730819Sbostic 	strforget();
2187988Srrh 	retlab = 1;
21911403Snicklin 
2207988Srrh 	cfp = &stab[curftn];
2217988Srrh 
22211403Snicklin 	/* if creating library, don't do static functions */
22311403Snicklin 	if( Cflag && cfp->sclass == STATIC ) return;
22411403Snicklin 
2257988Srrh 	/* if variable number of arguments, only print the ones which will be checked */
22632979Sdonn 	if( vaflag >= 0 ){
2277988Srrh 		if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
2287988Srrh 		else n = vaflag;
2297988Srrh 		}
2307988Srrh 	fsave( ftitle );
23132979Sdonn 	if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?~n:n );
23232979Sdonn 	else outdef( cfp, libflag?LIB:LDI, vaflag>=0?~n:n );
2337988Srrh 	vaflag = -1;
2347988Srrh 
2357988Srrh 	/* output the arguments */
2367988Srrh 	if( n ){
2377988Srrh 		for( i=0; i<n; ++i ) {
2387988Srrh 			t.aty = stab[a[i]].stype;
2397988Srrh 			t.extra = 0;
24011761Sedward 			t.extra1 = 0;
2417988Srrh 			if( !astype( &t, stab[a[i]].sizoff ) ) {
2427988Srrh 				switch( t.aty ){
2437988Srrh 
2447988Srrh 				case ULONG:
2457988Srrh 					break;
2467988Srrh 
2477988Srrh 				case CHAR:
2487988Srrh 				case SHORT:
2497988Srrh 					t.aty = INT;
2507988Srrh 					break;
2517988Srrh 
2527988Srrh 				case UCHAR:
2537988Srrh 				case USHORT:
2547988Srrh 				case UNSIGNED:
2557988Srrh 					t.aty = UNSIGNED;
2567988Srrh 					break;
2577988Srrh 
2587988Srrh 					}
2597988Srrh 				}
2607988Srrh 			fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
2617988Srrh 			}
2627988Srrh 		}
2637988Srrh 	}
2647988Srrh 
ctargs(p)2657988Srrh ctargs( p ) NODE *p; {
2667988Srrh 	/* count arguments; p points to at least one */
2677988Srrh 	/* the arguemnts are a tower of commas to the left */
2687988Srrh 	register c;
2697988Srrh 	c = 1; /* count the rhs */
2707988Srrh 	while( p->in.op == CM ){
2717988Srrh 		++c;
2727988Srrh 		p = p->in.left;
2737988Srrh 		}
2747988Srrh 	return( c );
2757988Srrh 	}
2767988Srrh 
lpta(p)2777988Srrh lpta( p ) NODE *p; {
2787988Srrh 	static ATYPE t;
2797988Srrh 
2807988Srrh 	if( p->in.op == CM ){
2817988Srrh 		lpta( p->in.left );
2827988Srrh 		p = p->in.right;
2837988Srrh 		}
2847988Srrh 
2857988Srrh 	t.aty = p->in.type;
2867988Srrh 	t.extra = (p->in.op==ICON);
28711761Sedward 	t.extra1 = 0;
2887988Srrh 
28918598Sralph 	if( !astype( &t, p->fn.csiz ) ) {
2907988Srrh 		switch( t.aty ){
2917988Srrh 
2927988Srrh 			case CHAR:
2937988Srrh 			case SHORT:
2947988Srrh 				t.aty = INT;
2957988Srrh 			case LONG:
2967988Srrh 			case ULONG:
2977988Srrh 			case INT:
2987988Srrh 			case UNSIGNED:
2997988Srrh 				break;
3007988Srrh 
3017988Srrh 			case UCHAR:
3027988Srrh 			case USHORT:
3037988Srrh 				t.aty = UNSIGNED;
3047988Srrh 				break;
3057988Srrh 
3067988Srrh 			case FLOAT:
3077988Srrh 				t.aty = DOUBLE;
3087988Srrh 				t.extra = 0;
3097988Srrh 				break;
3107988Srrh 
3117988Srrh 			default:
3127988Srrh 				t.extra = 0;
3137988Srrh 				break;
3147988Srrh 			}
3157988Srrh 		}
3167988Srrh 	fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
3177988Srrh 	}
3187988Srrh 
3197988Srrh # define VALSET 1
3207988Srrh # define VALUSED 2
3217988Srrh # define VALASGOP 4
3227988Srrh # define VALADDR 8
3237988Srrh 
lprt(p,down,uses)3247988Srrh lprt( p, down, uses ) register NODE *p; {
3257988Srrh 	register struct symtab *q;
3267988Srrh 	register id;
3277988Srrh 	register acount;
3287988Srrh 	register down1, down2;
3297988Srrh 	register use1, use2;
3307988Srrh 	register struct lnm *np1, *np2;
3317988Srrh 
3327988Srrh 	/* first, set variables which are set... */
3337988Srrh 
3347988Srrh 	use1 = use2 = VALUSED;
3357988Srrh 	if( p->in.op == ASSIGN ) use1 = VALSET;
3367988Srrh 	else if( p->in.op == UNARY AND ) use1 = VALADDR;
3377988Srrh 	else if( asgop( p->in.op ) ){ /* =ops */
3387988Srrh 		use1 = VALUSED|VALSET;
3397988Srrh 		if( down == EFF ) use1 |= VALASGOP;
3407988Srrh 		}
3417988Srrh 
3427988Srrh 
3437988Srrh 	/* print the lines for lint */
3447988Srrh 
3457988Srrh 	down2 = down1 = VAL;
3467988Srrh 	acount = 0;
3477988Srrh 
3487988Srrh 	switch( p->in.op ){
3497988Srrh 
3507988Srrh 	case EQ:
3517988Srrh 	case NE:
3527988Srrh 	case GT:
3537988Srrh 	case GE:
3547988Srrh 	case LT:
3557988Srrh 	case LE:
3567988Srrh 		if( p->in.left->in.type == CHAR && p->in.right->in.op==ICON && p->in.right->tn.lval < 0 ){
3577988Srrh 			werror( "nonportable character comparison" );
3587988Srrh 			}
3597988Srrh 		if( (p->in.op==EQ || p->in.op==NE ) && ISUNSIGNED(p->in.left->in.type) && p->in.right->in.op == ICON ){
3607988Srrh 			if( p->in.right->tn.lval < 0 && p->in.right->tn.rval == NONAME && !ISUNSIGNED(p->in.right->in.type) ){
3617988Srrh 				werror( "comparison of unsigned with negative constant" );
3627988Srrh 				}
3637988Srrh 			}
3647988Srrh 		break;
3657988Srrh 
3667988Srrh 	case UGE:
3677988Srrh 	case ULT:
3687988Srrh 		if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->tn.rval == NONAME ){
3697988Srrh 			werror( "unsigned comparison with 0?" );
3707988Srrh 			break;
3717988Srrh 			}
3727988Srrh 	case UGT:
3737988Srrh 	case ULE:
3747988Srrh 		if( p->in.right->in.op == ICON && p->in.right->tn.lval <= 0 && !ISUNSIGNED(p->in.right->in.type) && p->in.right->tn.rval == NONAME ){
3757988Srrh 			werror( "degenerate unsigned comparison" );
3767988Srrh 			}
3777988Srrh 		break;
3787988Srrh 
3797988Srrh 	case COMOP:
3807988Srrh 		down1 = EFF;
3817988Srrh 
3827988Srrh 	case ANDAND:
3837988Srrh 	case OROR:
3847988Srrh 	case QUEST:
3857988Srrh 		down2 = down;
3867988Srrh 		/* go recursively left, then right  */
3877988Srrh 		np1 = lnp;
3887988Srrh 		lprt( p->in.left, down1, use1 );
3897988Srrh 		np2 = lnp;
3907988Srrh 		lprt( p->in.right, down2, use2 );
3917988Srrh 		lmerge( np1, np2, 0 );
3927988Srrh 		return;
3937988Srrh 
3947988Srrh 	case SCONV:
3957988Srrh 	case PCONV:
3967988Srrh 	case COLON:
3977988Srrh 		down1 = down2 = down;
3987988Srrh 		break;
3997988Srrh 
4007988Srrh 	case CALL:
4017988Srrh 	case STCALL:
4027988Srrh 	case FORTCALL:
4037988Srrh 		acount = ctargs( p->in.right );
4047988Srrh 	case UNARY CALL:
4057988Srrh 	case UNARY STCALL:
4067988Srrh 	case UNARY FORTCALL:
4077988Srrh 		if( p->in.left->in.op == ICON && (id=p->in.left->tn.rval) != NONAME ){ /* used to be &name */
4087988Srrh 			struct symtab *sp = &stab[id];
4097988Srrh 			int lty;
41011403Snicklin 
41111403Snicklin 			fsave( ftitle );
41230905Sbostic 			if (!nflag)
41330819Sbostic 				doform(p, sp, acount);
41411403Snicklin 			/*
41511403Snicklin 			 * if we're generating a library -C then
41611403Snicklin 			 * we don't want to output references to functions
41711403Snicklin 			 */
41811403Snicklin 			if( Cflag ) break;
4197988Srrh 			/*  if a function used in an effects context is
4207988Srrh 			 *  cast to type  void  then consider its value
4217988Srrh 			 *  to have been disposed of properly
4227988Srrh 			 *  thus a call of type  undef  in an effects
4237988Srrh 			 *  context is construed to be used in a value
4247988Srrh 			 *  context
4257988Srrh 			 */
4267988Srrh 			if ((down == EFF) && (p->in.type != UNDEF)) {
4277988Srrh 				lty = LUE;
4287988Srrh 			} else if (down == EFF) {
4297988Srrh 				lty = LUV | LUE;
4307988Srrh 			} else {
4317988Srrh 				lty = LUV;
4327988Srrh 			}
43311403Snicklin 			outdef( sp, lty, acount );
4347988Srrh 			if( acount ) {
4357988Srrh 				lpta( p->in.right );
4367988Srrh 				}
4377988Srrh 			}
4387988Srrh 		break;
4397988Srrh 
4407988Srrh 	case ICON:
4417988Srrh 		/* look for &name case */
4427988Srrh 		if( (id = p->tn.rval) >= 0 && id != NONAME ){
4437988Srrh 			q = &stab[id];
4447988Srrh 			q->sflags |= (SREF|SSET);
4457988Srrh 			q->suse = -lineno;
4467988Srrh 			}
4477988Srrh 		return;
4487988Srrh 
4497988Srrh 	case NAME:
4507988Srrh 		if( (id = p->tn.rval) >= 0 && id != NONAME ){
4517988Srrh 			q = &stab[id];
4527988Srrh 			if( (uses&VALUSED) && !(q->sflags&SSET) ){
4537988Srrh 				if( q->sclass == AUTO || q->sclass == REGISTER ){
45411761Sedward 					if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY && q->stype!=UNIONTY ){
4557988Srrh #ifndef FLEXNAMES
4567988Srrh 						werror( "%.8s may be used before set", q->sname );
4577988Srrh #else
4587988Srrh 						werror( "%s may be used before set", q->sname );
4597988Srrh #endif
4607988Srrh 						q->sflags |= SSET;
4617988Srrh 						}
4627988Srrh 					}
4637988Srrh 				}
4647988Srrh 			if( uses & VALASGOP ) break;  /* not a real use */
4657988Srrh 			if( uses & VALSET ) q->sflags |= SSET;
4667988Srrh 			if( uses & VALUSED ) q->sflags |= SREF;
4677988Srrh 			if( uses & VALADDR ) q->sflags |= (SREF|SSET);
4687988Srrh 			if( p->tn.lval == 0 ){
4697988Srrh 				lnp->lid = id;
4707988Srrh 				lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED);
4717988Srrh 				if( ++lnp >= &lnames[LNAMES] ) --lnp;
4727988Srrh 				}
4737988Srrh 			}
4747988Srrh 		return;
4757988Srrh 
4767988Srrh 		}
4777988Srrh 
4787988Srrh 	/* recurse, going down the right side first if we can */
4797988Srrh 
4807988Srrh 	switch( optype(p->in.op) ){
4817988Srrh 
4827988Srrh 	case BITYPE:
4837988Srrh 		np1 = lnp;
4847988Srrh 		lprt( p->in.right, down2, use2 );
4857988Srrh 	case UTYPE:
4867988Srrh 		np2 = lnp;
4877988Srrh 		lprt( p->in.left, down1, use1 );
4887988Srrh 		}
4897988Srrh 
4907988Srrh 	if( optype(p->in.op) == BITYPE ){
4917988Srrh 		if( p->in.op == ASSIGN && p->in.left->in.op == NAME ){ /* special case for a =  .. a .. */
4927988Srrh 			lmerge( np1, np2, 0 );
4937988Srrh 			}
4947988Srrh 		else lmerge( np1, np2, p->in.op != COLON );
4957988Srrh 		/* look for assignments to fields, and complain */
4967988Srrh 		if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.op == ICON ) fldcon( p );
4977988Srrh 		}
4987988Srrh 
4997988Srrh 	}
5007988Srrh 
5017988Srrh lmerge( np1, np2, flag ) struct lnm *np1, *np2; {
5027988Srrh 	/* np1 and np2 point to lists of lnm members, for the two sides
5037988Srrh 	 * of a binary operator
5047988Srrh 	 * flag is 1 if commutation is possible, 0 otherwise
5057988Srrh 	 * lmerge returns a merged list, starting at np1, resetting lnp
5067988Srrh 	 * it also complains, if appropriate, about side effects
5077988Srrh 	 */
5087988Srrh 
5097988Srrh 	register struct lnm *npx, *npy;
5107988Srrh 
5117988Srrh 	for( npx = np2; npx < lnp; ++npx ){
5127988Srrh 
5137988Srrh 		/* is it already there? */
5147988Srrh 		for( npy = np1; npy < np2; ++npy ){
5157988Srrh 			if( npx->lid == npy->lid ){ /* yes */
5167988Srrh 				if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) )
5177988Srrh 					;  /* do nothing */
5187988Srrh 				else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) ||
5197988Srrh 					(npx->flgs&npy->flgs&VALSET) ){
5207988Srrh #ifndef FLEXNAMES
5217988Srrh 					if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname );
5227988Srrh #else
5237988Srrh 					if( flag ) werror( "%s evaluation order undefined", stab[npy->lid].sname );
5247988Srrh #endif
5257988Srrh 					}
5267988Srrh 				if( npy->flgs == 0 ) npx->flgs = 0;
5277988Srrh 				else npy->flgs |= npx->flgs;
5287988Srrh 				goto foundit;
5297988Srrh 				}
5307988Srrh 			}
5317988Srrh 
5327988Srrh 		/* not there: update entry */
5337988Srrh 		np2->lid = npx->lid;
5347988Srrh 		np2->flgs = npx->flgs;
5357988Srrh 		++np2;
5367988Srrh 
5377988Srrh 		foundit: ;
5387988Srrh 		}
5397988Srrh 
5407988Srrh 	/* all finished: merged list is at np1 */
5417988Srrh 	lnp = np2;
5427988Srrh 	}
5437988Srrh 
efcode()5447988Srrh efcode(){
5457988Srrh 	/* code for the end of a function */
5467988Srrh 	register struct symtab *cfp;
5477988Srrh 
5487988Srrh 	cfp = &stab[curftn];
54911403Snicklin 	if( retstat & RETVAL && !(Cflag && cfp->sclass==STATIC) )
55011403Snicklin 		outdef( cfp, LRV, DECTY );
5517988Srrh 	if( !vflag ){
5527988Srrh 		vflag = argflag;
5537988Srrh 		argflag = 0;
5547988Srrh 		}
5557988Srrh 	if( retstat == RETVAL+NRETVAL )
5567988Srrh #ifndef FLEXNAMES
5577988Srrh 		werror( "function %.8s has return(e); and return;", cfp->sname);
5587988Srrh #else
5597988Srrh 		werror( "function %s has return(e); and return;", cfp->sname);
5607988Srrh #endif
5617988Srrh 	}
5627988Srrh 
5637988Srrh aocode(p) struct symtab *p; {
5647988Srrh 	/* called when automatic p removed from stab */
5657988Srrh 	register struct symtab *cfs;
5667988Srrh 	cfs = &stab[curftn];
5677988Srrh 	if(p->suse>0 && !(p->sflags&(SMOS|STAG)) ){
5687988Srrh 		if( p->sclass == PARAM ){
5697988Srrh #ifndef FLEXNAMES
5707988Srrh 			if( vflag ) werror( "argument %.8s unused in function %.8s",
5717988Srrh #else
5727988Srrh 			if( vflag ) werror( "argument %s unused in function %s",
5737988Srrh #endif
5747988Srrh 				p->sname,
5757988Srrh 				cfs->sname );
5767988Srrh 			}
5777988Srrh 		else {
5787988Srrh #ifndef FLEXNAMES
5797988Srrh 			if( p->sclass != TYPEDEF ) werror( "%.8s unused in function %.8s",
5807988Srrh #else
5817988Srrh 			if( p->sclass != TYPEDEF ) werror( "%s unused in function %s",
5827988Srrh #endif
5837988Srrh 				p->sname, cfs->sname );
5847988Srrh 			}
5857988Srrh 		}
5867988Srrh 
5877988Srrh 	if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET &&
5887988Srrh 		!ISARY(p->stype) && !ISFTN(p->stype) ){
5897988Srrh 
5907988Srrh #ifndef FLEXNAMES
5917988Srrh 		werror( "%.8s set but not used in function %.8s", p->sname, cfs->sname );
5927988Srrh #else
5937988Srrh 		werror( "%s set but not used in function %s", p->sname, cfs->sname );
5947988Srrh #endif
5957988Srrh 		}
5967988Srrh 
5977988Srrh 	if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){
59811761Sedward 		if( !zflag && dimtab[p->sizoff+1] < 0 )
5997988Srrh #ifndef FLEXNAMES
60011761Sedward 			werror( "structure %.8s never defined", p->sname );
6017988Srrh #else
60211761Sedward 			werror( "structure %s never defined", p->sname );
6037988Srrh #endif
6047988Srrh 		}
6057988Srrh 
6067988Srrh 	}
6077988Srrh 
defnam(p)6087988Srrh defnam( p ) register struct symtab *p; {
6097988Srrh 	/* define the current location as the name p->sname */
6107988Srrh 
61111403Snicklin 	if( p->sclass == STATIC && (p->slevel>1 || Cflag) ) return;
6127988Srrh 
61311761Sedward 	if( !ISFTN( p->stype ) )
61411761Sedward 		if( p->sclass == STATIC ) outdef( p, LST, USUAL );
61511761Sedward 		else outdef( p, libflag?LIB:LDI, USUAL );
6167988Srrh 	}
6177988Srrh 
zecode(n)6187988Srrh zecode( n ){
6197988Srrh 	/* n integer words of zeros */
6207988Srrh 	OFFSZ temp;
6217988Srrh 	temp = n;
6227988Srrh 	inoff += temp*SZINT;
6237988Srrh 	;
6247988Srrh 	}
6257988Srrh 
andable(p)6267988Srrh andable( p ) NODE *p; {  /* p is a NAME node; can it accept & ? */
6277988Srrh 	register r;
6287988Srrh 
6297988Srrh 	if( p->in.op != NAME ) cerror( "andable error" );
6307988Srrh 
6317988Srrh 	if( (r = p->tn.rval) < 0 ) return(1);  /* labels are andable */
6327988Srrh 
6337988Srrh 	if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0);
6347988Srrh #ifndef FLEXNAMES
6357988Srrh 	if( stab[r].sclass == REGISTER ) uerror( "can't take & of %.8s", stab[r].sname );
6367988Srrh #else
6377988Srrh 	if( stab[r].sclass == REGISTER ) uerror( "can't take & of %s", stab[r].sname );
6387988Srrh #endif
6397988Srrh 	return(1);
6407988Srrh 	}
6417988Srrh 
6427988Srrh NODE *
clocal(p)6437988Srrh clocal(p) NODE *p; {
6447988Srrh 
6457988Srrh 	/* this is called to do local transformations on
6467988Srrh 	   an expression tree preparitory to its being
6477988Srrh 	   written out in intermediate code.
6487988Srrh 	*/
6497988Srrh 
6507988Srrh 	/* the major essential job is rewriting the
6517988Srrh 	   automatic variables and arguments in terms of
6527988Srrh 	   REG and OREG nodes */
6537988Srrh 	/* conversion ops which are not necessary are also clobbered here */
6547988Srrh 	/* in addition, any special features (such as rewriting
6557988Srrh 	   exclusive or) are easily handled here as well */
6567988Srrh 
6577988Srrh 	register o;
6587988Srrh 	register unsigned t, tl;
65925757Sdonn 	int s;
6607988Srrh 
6617988Srrh 	switch( o = p->in.op ){
66230819Sbostic 	case NAME:
66330819Sbostic 		{
66430819Sbostic 			extern int	didstr, subscr;
66530819Sbostic 			extern NODE *	strnodes[];
6667988Srrh 
66730819Sbostic 			if (didstr) {
66830819Sbostic 				didstr = 0;
66930819Sbostic 				strnodes[subscr] = p;
67030819Sbostic 			}
67130819Sbostic 		}
67230819Sbostic 		break;
67330819Sbostic 
6747988Srrh 	case SCONV:
6757988Srrh 	case PCONV:
6767988Srrh 		if( p->in.left->in.type==ENUMTY ){
6777988Srrh 			p->in.left = pconvert( p->in.left );
6787988Srrh 			}
6797988Srrh 		/* assume conversion takes place; type is inherited */
6807988Srrh 		t = p->in.type;
6817988Srrh 		tl = p->in.left->in.type;
68226403Sdonn 		if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG&&t!=UNDEF) ){
6837988Srrh 			werror( "long assignment may lose accuracy" );
6847988Srrh 			}
6857988Srrh 		if( aflag>=2 && (tl!=LONG&&tl!=ULONG) && (t==LONG||t==ULONG) && p->in.left->in.op != ICON ){
6867988Srrh 			werror( "assignment to long may sign-extend incorrectly" );
6877988Srrh 			}
6887988Srrh 		if( ISPTR(tl) && ISPTR(t) ){
6897988Srrh 			tl = DECREF(tl);
6907988Srrh 			t = DECREF(t);
6917988Srrh 			switch( ISFTN(t) + ISFTN(tl) ){
6927988Srrh 
6937988Srrh 			case 0:  /* neither is a function pointer */
6947988Srrh 				if( talign(t,p->fn.csiz) > talign(tl,p->in.left->fn.csiz) ){
6957988Srrh 					if( hflag||pflag ) werror( "possible pointer alignment problem" );
6967988Srrh 					}
6977988Srrh 				break;
6987988Srrh 
6997988Srrh 			case 1:
7007988Srrh 				werror( "questionable conversion of function pointer" );
7017988Srrh 
7027988Srrh 			case 2:
7037988Srrh 				;
7047988Srrh 				}
7057988Srrh 			}
7067988Srrh 		p->in.left->in.type = p->in.type;
7077988Srrh 		p->in.left->fn.cdim = p->fn.cdim;
7087988Srrh 		p->in.left->fn.csiz = p->fn.csiz;
7097988Srrh 		p->in.op = FREE;
7107988Srrh 		return( p->in.left );
7117988Srrh 
7127988Srrh 	case PVCONV:
7137988Srrh 	case PMCONV:
7147988Srrh 		if( p->in.right->in.op != ICON ) cerror( "bad conversion");
7157988Srrh 		p->in.op = FREE;
7167988Srrh 		return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) );
7177988Srrh 
71825757Sdonn 	case RS:
71925757Sdonn 	case LS:
72025757Sdonn 	case ASG RS:
72125757Sdonn 	case ASG LS:
72225757Sdonn 		if( p->in.right->in.op != ICON )
72325757Sdonn 			break;
72425757Sdonn 		s = p->in.right->tn.lval;
72525757Sdonn 		if( s < 0 )
72625757Sdonn 			werror( "negative shift" );
72725757Sdonn 		else
72825757Sdonn 		if( s >= dimtab[ p->fn.csiz ] )
72925757Sdonn 			werror( "shift greater than size of object" );
73025757Sdonn 		break;
73125757Sdonn 
7327988Srrh 		}
7337988Srrh 
7347988Srrh 	return(p);
7357988Srrh 	}
7367988Srrh 
7377988Srrh NODE *
offcon(off,t,d,s)7387988Srrh offcon( off, t, d, s ) OFFSZ off; TWORD t;{  /* make a structure offset node */
7397988Srrh 	register NODE *p;
7407988Srrh 	p = bcon(0);
7417988Srrh 	p->tn.lval = off/SZCHAR;
7427988Srrh 	return(p);
7437988Srrh 	}
7447988Srrh 
noinit()7457988Srrh noinit(){
7467988Srrh 	/* storage class for such as "int a;" */
7477988Srrh 	return( pflag ? EXTDEF : EXTERN );
7487988Srrh 	}
7497988Srrh 
7507988Srrh 
cinit(p,sz)7517988Srrh cinit( p, sz ) NODE *p; { /* initialize p into size sz */
75232979Sdonn 	register int id;
75332979Sdonn 
7547988Srrh 	inoff += sz;
7557988Srrh 	if( p->in.op == INIT ){
7567988Srrh 		if( p->in.left->in.op == ICON ) return;
7577988Srrh 		if( p->in.left->in.op == NAME && p->in.left->in.type == MOE ) return;
7587988Srrh 		}
7597988Srrh 	uerror( "illegal initialization" );
7607988Srrh 	}
7617988Srrh 
7627988Srrh char *
exname(p)7637988Srrh exname( p ) char *p; {
7647988Srrh 	/* make a name look like an external name in the local machine */
7657988Srrh 	static char aa[8];
7667988Srrh 	register int i;
7677988Srrh 
7687988Srrh 	if( !pflag ) return(p);
7697988Srrh 	for( i=0; i<6; ++i ){
7707988Srrh 		if( isupper(*p ) ) aa[i] = tolower( *p );
7717988Srrh 		else aa[i] = *p;
7727988Srrh 		if( *p ) ++p;
7737988Srrh 		}
7747988Srrh 	aa[6] = '\0';
7757988Srrh 	return( aa );
7767988Srrh 	}
7777988Srrh 
7787988Srrh char *
strip(s)7797988Srrh strip(s) char *s; {
7807988Srrh #ifndef FLEXNAMES
7817988Srrh 	static char x[LFNM+1];
7827988Srrh #else
7837988Srrh 	static char x[BUFSIZ];
7847988Srrh #endif
7857988Srrh 	register char *p;
7867996Srrh 	static	int	stripping = 0;
7877988Srrh 
7887996Srrh 	if (stripping)
7897996Srrh 		return(s);
7907996Srrh 	stripping++;
7917988Srrh 	for( p=x; *s; ++s ){
7927996Srrh 		if( *s != '"' ){
7937988Srrh #ifndef FLEXNAMES
7947988Srrh /* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */
7957988Srrh 			if( p >= &x[LFNM] )
79611403Snicklin #else
79711403Snicklin 			if( p >= &x[BUFSIZ] )
79811403Snicklin #endif
7997988Srrh 				cerror( "filename too long" );
8007988Srrh 			*p++ = *s;
8017988Srrh 		}
8027988Srrh 	}
8037996Srrh 	stripping = 0;
8047988Srrh 	*p = '\0';
8057988Srrh #ifndef FLEXNAMES
8067988Srrh 	return( x );
8077988Srrh #else
8087988Srrh 	return( hash(x) );
8097988Srrh #endif
8107988Srrh 	}
8117988Srrh 
fsave(s)8127988Srrh fsave( s ) char *s; {
8137988Srrh 	static union rec fsname;
8147988Srrh 	s = strip( s );
8157988Srrh #ifndef FLEXNAMES
81626916Sdonn 	if( strncmp( s, fsname.f.fn, LFNM ) )
8177988Srrh #else
81826916Sdonn 	if (fsname.f.fn == NULL || strcmp(s, fsname.f.fn))
8197988Srrh #endif
82026916Sdonn 		{
8217988Srrh 		/* new one */
8227988Srrh #ifndef FLEXNAMES
8237988Srrh 		strncpy( fsname.f.fn, s, LFNM );
8247988Srrh #else
8257988Srrh 		fsname.f.fn = s;
8267988Srrh #endif
8277988Srrh 		fsname.f.decflag = LFN;
8287988Srrh 		fwrite( (char *)&fsname, sizeof(fsname), 1, stdout );
8297988Srrh #ifdef FLEXNAMES
83011403Snicklin 		/* if generating a library, prefix with the library name */
83111403Snicklin 		/* only do this for flexnames */
83211403Snicklin 		if( libname ){
83311403Snicklin 			fwrite( libname, strlen(libname), 1, stdout );
83411403Snicklin 			putchar( ':' );
83511403Snicklin 			}
8367988Srrh 		fwrite( fsname.f.fn, strlen(fsname.f.fn)+1, 1, stdout );
8377988Srrh #endif
8387988Srrh 		}
8397988Srrh 	}
8407988Srrh 
where(f)8417988Srrh where(f){ /* print true location of error */
8427996Srrh 	if( f == 'u' && nerrors > 1 )
8437996Srrh 		--nerrors; /* don't get "too many errors" */
8447996Srrh 	fprintf( stderr, "%s(%d): ", strip(ftitle), lineno);
8457988Srrh 	}
8467988Srrh 
8477988Srrh 	/* a number of dummy routines, unneeded by lint */
8487988Srrh 
branch(n)8497988Srrh branch(n){;}
defalign(n)8507988Srrh defalign(n){;}
deflab(n)8517988Srrh deflab(n){;}
8527988Srrh 
85330819Sbostic extern char *	strchr();
8547988Srrh 
85530819Sbostic #define SBUFSIZE	16
85630819Sbostic #define SCLICK		80
85730819Sbostic 
85830819Sbostic #ifndef size_t
85930819Sbostic #define size_t	unsigned
86030819Sbostic #endif /* !size_t */
86130819Sbostic 
86230819Sbostic static char *	strings[SBUFSIZE];
86330819Sbostic static NODE *	strnodes[SBUFSIZE];
86430819Sbostic static int	didstr;
86530819Sbostic static int	subscr;
86630819Sbostic static int	strapped;
86730819Sbostic 
bycode(t,i)86830819Sbostic bycode(t, i)
86930819Sbostic {
87030819Sbostic 	extern char *	calloc();
87130819Sbostic 	extern char *	realloc();
87230819Sbostic 
87330905Sbostic 	if (nflag || strapped)
87430819Sbostic 		return;
87530819Sbostic 	if (i == 0)
87630819Sbostic 		if (subscr < (SBUFSIZE - 1))
87730819Sbostic 			++subscr;
87830819Sbostic 	if (subscr >= SBUFSIZE)
87930819Sbostic 		return;
88030819Sbostic 	didstr = 1;
88130819Sbostic 	if ((i % SCLICK) == 0) {
88230819Sbostic 		strings[subscr] = (strings[subscr] == NULL) ?
88330819Sbostic 			calloc((size_t) (SCLICK + 1), 1) :
88430819Sbostic 			realloc(strings[subscr], (size_t) (i + SCLICK + 1));
88530819Sbostic 		if (strings[subscr] == NULL) {
88630819Sbostic 			strapped = 1;
88730819Sbostic 			return;
8887988Srrh 		}
8897988Srrh 	}
89030819Sbostic 	strings[subscr][i] = t;
89130819Sbostic }
8927988Srrh 
strforget()89330819Sbostic strforget()
89430819Sbostic {
89530819Sbostic 	didstr = subscr = 0;
89630819Sbostic }
8977988Srrh 
89830819Sbostic static char *
typestr(t)89930819Sbostic typestr(t)
90030819Sbostic {
90130819Sbostic 	switch (t) {
90230819Sbostic 		case CHAR:		return "char";
90330819Sbostic 		case UCHAR:		return "unsigned char";
90430819Sbostic 		case SHORT:		return "short";
90530819Sbostic 		case USHORT:		return "unsigned short";
90630819Sbostic 		case INT:		return "int";
90730819Sbostic 		case UNSIGNED:		return "unsigned";
90830819Sbostic 		case ENUMTY:		return "enum";
90930819Sbostic 		case LONG:		return "long";
91030819Sbostic 		case ULONG:		return "unsigned long";
91130819Sbostic 		case FLOAT:		return "float";
91230819Sbostic 		case DOUBLE:		return "double";
91330819Sbostic 		case STRTY:		return "struct";
91430819Sbostic 		case UNIONTY:		return "union";
91530819Sbostic 		case PTR|CHAR:		return "char *";
91630819Sbostic 		case PTR|UCHAR:		return "unsigned char *";
91730819Sbostic 		case PTR|SHORT:		return "short *";
91830819Sbostic 		case PTR|USHORT:	return "unsigned short *";
91930819Sbostic 		case PTR|INT:		return "int *";
92030819Sbostic 		case PTR|UNSIGNED:	return "unsigned *";
92130819Sbostic 		case PTR|ENUMTY:	return "enum *";
92230819Sbostic 		case PTR|LONG:		return "long *";
92330819Sbostic 		case PTR|ULONG:		return "unsigned long *";
92430819Sbostic 		case PTR|FLOAT:		return "float *";
92530819Sbostic 		case PTR|DOUBLE:	return "double *";
92630819Sbostic 		case PTR|STRTY:		return "struct *";
92730819Sbostic 		case PTR|UNIONTY:	return "union *";
92830819Sbostic 		default:		return ISPTR(t) ?
92930819Sbostic 						"pointer" : "non-scalar";
93030819Sbostic 	}
93130819Sbostic }
9327988Srrh 
93330819Sbostic NODE *
ntharg(p,n,acount)93430819Sbostic ntharg(p, n, acount)
93530819Sbostic NODE *		p;
93630819Sbostic register int	n;
93730819Sbostic register int	acount;
93830819Sbostic {
93930819Sbostic 	if (n > acount)
94030819Sbostic 		return NULL;
94130819Sbostic 	p = p->in.right;
94230819Sbostic 	while (n != acount) {
94330819Sbostic 		p = p->in.left;
94430819Sbostic 		--acount;
94530819Sbostic 	}
94630819Sbostic 	return (n == 1) ? p : p->in.right;
94730819Sbostic }
9487988Srrh 
94930819Sbostic struct entry {
95030819Sbostic 	/* If argument to print/scan is of type... */	int	argtype;
95130819Sbostic 	/* ...and this length character is used... */	char	lchar;
95230819Sbostic 	/* ...and one of these is control char... */	char *	cchars;
95330819Sbostic 	/* ...then use this format with werror... */	char *	werror;
95430819Sbostic 	/* ...(where NULL means it's hunky dory)... */
95530819Sbostic };
9567988Srrh 
95730819Sbostic /*
95830819Sbostic ** Portable printf.
95930819Sbostic ** H&S says "%o" takes an unsigned argument;
96030819Sbostic ** X3J11 says "%o" takes an int argument;
96130819Sbostic ** we'll allow either here.
96230819Sbostic */
9637988Srrh 
96430819Sbostic static struct entry pprintf[] = {
96530819Sbostic 	CHAR,		'\0',	"c",		NULL, /* this is deliberate */
96630819Sbostic 	INT,		'\0',	"cdoxX",	NULL,
96730819Sbostic 	UNSIGNED,	'\0',	"uoxX",		NULL,
96830819Sbostic 	CHAR,		'\0',	"cdoxX",	NULL,
96930819Sbostic 	UCHAR,		'\0',	"udoxX",	NULL, /* yes, d is okay */
97030819Sbostic 	SHORT,		'\0',	"cdoxX",	NULL,
97130819Sbostic 	USHORT,		'\0',	"uoxX",		NULL,
97230819Sbostic 	ENUMTY,		'\0',	"duoxX",	NULL,
97330819Sbostic 	LONG,		'l',	"doxX",		NULL,
97430819Sbostic 	ULONG,		'l',	"uoxX",		NULL,
97530819Sbostic 	FLOAT,		'\0',	"eEfgG",	NULL,
97630819Sbostic 	DOUBLE,		'\0',	"eEfgG",	NULL,
97730819Sbostic 	PTR|CHAR,	'\0',	"s",		NULL,
97830819Sbostic 	UNDEF,		'\0',	"",		NULL
97930819Sbostic };
9807988Srrh 
98130819Sbostic /*
98230819Sbostic ** Berkeley printf.
98330819Sbostic ** It allows %D, %O, and %U, which we deprecate.
98430819Sbostic ** Since
98530819Sbostic **	sizeof (char *) == sizeof (int) &&
98630819Sbostic **	sizeof (int) == sizeof (long) &&
98730819Sbostic **	sizeof (char *) == sizeof (int *)
98830819Sbostic ** you can be lax--and we tolerate *some* laxness.
98930819Sbostic ** g/lax/p to find lax table entries and code.
99030819Sbostic */
9917988Srrh 
99230819Sbostic static char	uppercase[] = "deprecated upper-case control character (%c)";
99330819Sbostic #define lax	NULL
9947988Srrh 
99530819Sbostic static struct entry bprintf[] = {
99630819Sbostic 	CHAR,		'\0',	"c",		NULL,	/* this is deliberate */
99730819Sbostic 	INT,		'\0',	"cdoxX",	NULL,
99830819Sbostic 	INT,		'\0',	"DO",		uppercase,
99930819Sbostic 	UNSIGNED,	'\0',	"uoxX",		NULL,
100030819Sbostic 	UNSIGNED,	'\0',	"UO",		uppercase,
100130819Sbostic 	CHAR,		'\0',	"cdoxX",	NULL,
100230819Sbostic 	CHAR,		'\0',	"DO",		uppercase,
100330819Sbostic 	UCHAR,		'\0',	"duoxX",	NULL,	/* yes, d is okay */
100430819Sbostic 	UCHAR,		'\0',	"DUO",		uppercase,
100530819Sbostic 	SHORT,		'\0',	"cdoxX",	NULL,
100630819Sbostic 	SHORT,		'\0',	"DO",		uppercase,
100730819Sbostic 	USHORT,		'\0',	"duoxX",	NULL,	/* d okay on BSD */
100830819Sbostic 	USHORT,		'\0',	"DUO",		uppercase,
100930819Sbostic 	ENUMTY,		'\0',	"duoxX",	NULL,
101030819Sbostic 	ENUMTY,		'\0',	"DUO",		uppercase,
101130819Sbostic 	LONG,		'\0',	"doxX",		lax,
101230819Sbostic 	LONG,		'\0',	"DO",		uppercase,
101330819Sbostic 	LONG,		'l',	"doxX",		NULL,
101430819Sbostic 	INT,		'l',	"doxX",		lax,
101530819Sbostic 	ULONG,		'\0',	"uoxX",		lax,
101630819Sbostic 	ULONG,		'\0',	"UO",		uppercase,
101730819Sbostic 	ULONG,		'l',	"uoxX",		NULL,
101830819Sbostic 	UNSIGNED,	'l',	"uoxX",		lax,
101930819Sbostic 	FLOAT,		'\0',	"eEfgG",	NULL,
102030819Sbostic 	DOUBLE,		'\0',	"eEfgG",	NULL,
102130819Sbostic 	PTR|CHAR,	'\0',	"s",		NULL,
102230819Sbostic 	UNDEF,		'\0',	NULL,		NULL,
102330819Sbostic };
10247988Srrh 
102530819Sbostic /*
102630819Sbostic ** Portable scanf.  'l' and 'h' are universally ignored preceding 'c' and 's',
102730819Sbostic ** and 'h' is universally ignored preceding 'e' and 'f',
102830819Sbostic ** but you won't find such cruft here.
102930819Sbostic */
10307988Srrh 
103130819Sbostic static struct entry pscanf[] = {
103230819Sbostic 	INT,		'\0',	"dox",	NULL,
103330819Sbostic 	UNSIGNED,	'\0',	"uox",	NULL,
103430819Sbostic 	CHAR,		'\0',	"cs[",	NULL,
103530819Sbostic 	SHORT,		'h',	"dox",	NULL,
103630819Sbostic 	USHORT,		'h',	"uox",	NULL,
103730819Sbostic 	LONG,		'l',	"dox",	NULL,
103830819Sbostic 	ULONG,		'l',	"uox",	NULL,
103930819Sbostic 	FLOAT,		'\0',	"ef",	NULL,	/* BSD doesn't handle g */
104030819Sbostic 	DOUBLE,		'l',	"ef",	NULL,
104130819Sbostic 	UNDEF,		'\0',	NULL,	NULL,
104230819Sbostic };
10437988Srrh 
104430819Sbostic /*
104530819Sbostic ** Berkeley scanf.  An upper case letter equals an l plus the lower case char,
104630819Sbostic ** but this is deprecated.
104730819Sbostic ** Even though sizeof (int) == sizeof (long), we'll be picky here.
104830819Sbostic */
10497988Srrh 
105030819Sbostic static struct entry bscanf[] = {
105130819Sbostic 	INT,		'\0',	"dox",	NULL,
105230819Sbostic 	UNSIGNED,	'\0',	"uox",	NULL,
105330819Sbostic 	CHAR,		'\0',	"cs[",	NULL,
105430819Sbostic 	SHORT,		'h',	"dox",	NULL,
105530819Sbostic 	USHORT,		'h',	"uox",	NULL,
105630819Sbostic 	LONG,		'\0',	"dox",	lax,
105730819Sbostic 	LONG,		'\0',	"DOX",	uppercase,
105830819Sbostic 	LONG,		'l',	"dox",	NULL,
105930819Sbostic 	ULONG,		'\0',	"uox",	lax,
106030819Sbostic 	ULONG,		'\0',	"UOX",	uppercase,
106130819Sbostic 	ULONG,		'l',	"uox",	NULL,
106230819Sbostic 	FLOAT,		'\0',	"ef",	NULL,
106330819Sbostic 	DOUBLE,		'\0',	"EF",	uppercase,
106430819Sbostic 	DOUBLE,		'l',	"ef",	NULL,
106530819Sbostic 	UNDEF,		'\0',	NULL,	NULL,
106630819Sbostic };
10677988Srrh 
106830819Sbostic static struct item {
106930819Sbostic 	char *		name;		/* such as "printf" */
107030819Sbostic 	int		isscan;		/* scanf/printf */
107130819Sbostic 	int		fmtarg;		/* number of format argument */
107230819Sbostic 	struct entry *	ptable;		/* portable checking table */
107330819Sbostic 	struct entry *	btable;		/* berkeley checking table */
107430819Sbostic } items[] = {
107530819Sbostic 	"printf",	0,	1,	pprintf,	bprintf,
107630819Sbostic 	"fprintf",	0,	2,	pprintf,	bprintf,
107730819Sbostic 	"sprintf",	0,	2,	pprintf,	bprintf,
107830819Sbostic 	"scanf",	1,	1,	pscanf,		bscanf,
107930819Sbostic 	"fscanf",	1,	2,	pscanf,		bscanf,
108030819Sbostic 	"sscanf",	1,	2,	pscanf,		bscanf,
108130819Sbostic 	NULL,		-1,	-1,	NULL,		NULL
108230819Sbostic };
10837988Srrh 
108430819Sbostic static char	pwf[]	= "possible wild format";
108530819Sbostic static char	pfacm[]	= "possible format/argument count mismatch";
108611761Sedward 
108730819Sbostic static struct entry *
findlc(ep,lchar,cchar)108830819Sbostic findlc(ep, lchar, cchar)
108930819Sbostic register struct entry *	ep;
109030819Sbostic register int		lchar;
109130819Sbostic register int		cchar;
109230819Sbostic {
109330819Sbostic 	for ( ; ep->argtype != UNDEF; ++ep)
109430819Sbostic 		if (ep->lchar == lchar && strchr(ep->cchars, cchar) != 0)
109530819Sbostic 			return ep;
109630819Sbostic 	return NULL;
109730819Sbostic }
10987988Srrh 
109930819Sbostic static char *
subform(p,sp,acount)110030819Sbostic subform(p, sp, acount)
110130819Sbostic register NODE *			p;
110230819Sbostic register struct symtab *	sp;
110330819Sbostic {
110430819Sbostic 	register int		i, j, isscan;
110530819Sbostic 	register NODE *		tp;
110630819Sbostic 	register char *		cp;
110730819Sbostic 	register struct entry *	basep;
110830819Sbostic 	register struct entry *	ep;
110930819Sbostic 	register struct item *	ip;
111030819Sbostic 	register int		lchar;
111130819Sbostic 	register int		cchar;
111230819Sbostic 	register int		t;
111330819Sbostic 	register int		suppressed;
111430819Sbostic 	static char		errbuf[132];
111511761Sedward 
111630905Sbostic 	if (nflag || strapped)
111730819Sbostic 		return NULL;
111830819Sbostic 	cp = sp->sname;
111930819Sbostic 	for (ip = items; ; ++ip)
112030819Sbostic 		if (ip->name == NULL)
112130819Sbostic 			return NULL;	/* not a print/scan function */
112230819Sbostic 		else if (strcmp(ip->name, sp->sname) == 0)
112330819Sbostic 			break;
112430819Sbostic 	isscan = ip->isscan;
112530819Sbostic 	i = ip->fmtarg;
112630819Sbostic 	if (i > acount)
112730819Sbostic 		return NULL;	/* handled in pass 2 */
112830819Sbostic 	tp = ntharg(p, i, acount);
112930819Sbostic 	if (tp->in.type != (PTR|CHAR))
113030819Sbostic 		return NULL;	/* handled in pass 2 */
113130819Sbostic 	if (tp->in.op != ICON || tp->tn.lval != 0)
113230819Sbostic 		return NULL;	/* can't check it */
113330819Sbostic 	for (j = 1; j <= subscr; ++j)
113430819Sbostic 		if (tp == strnodes[j])
113530819Sbostic 			break;
113630819Sbostic 	if (j > subscr)
113730819Sbostic 		return NULL;	/* oh well. . . */
113830819Sbostic 	cp = strings[j];
113930819Sbostic 	/*
114030819Sbostic 	** cp now points to format string.
114130819Sbostic 	*/
114230905Sbostic 	/*
114330905Sbostic 	** For now, ALWAYS use "portable" table, rather than doing this:
114430905Sbostic 	**	basep = pflag ? ip->ptable : ip->btable;
114530905Sbostic 	*/
114630905Sbostic 	basep = ip->ptable;
114730819Sbostic 	for ( ; ; ) {
114830819Sbostic 		if (*cp == '\0')
114930819Sbostic 			return (i == acount) ? NULL : pfacm;
115030819Sbostic 		if (*cp++ != '%')
115130819Sbostic 			continue;
115230819Sbostic 		if (*cp == '\0')
115330819Sbostic 			return "wild trailing %% in format";
115430819Sbostic 		if (*cp == '%') {
115530819Sbostic 			++cp;
115630819Sbostic 			continue;
115730819Sbostic 		}
115830819Sbostic 		if (isscan) {
115930819Sbostic 			suppressed = *cp == '*';
116030819Sbostic 			if (suppressed)
116130819Sbostic 				++cp;
116230819Sbostic 			while (isdigit(*cp))
116330819Sbostic 				++cp;
116430819Sbostic 			if (!suppressed && ++i <= acount) {
116530819Sbostic 				t = ntharg(p, i, acount)->in.type;
116630819Sbostic 				if (!ISPTR(t)) {
116730819Sbostic (void) sprintf(errbuf,
116830819Sbostic 	"%s argument is type (%s) rather than pointer (arg %d)",
116930819Sbostic 	ip->name, typestr(t), i);
117030819Sbostic 					return errbuf;
117130819Sbostic 				}
117230819Sbostic 				t = DECREF(t);
117330819Sbostic 			}
117430819Sbostic 		} else {
117530819Sbostic 			int	nspace, ndash, nplus, nhash;
117630819Sbostic 
117730819Sbostic 			suppressed = 0;
117830819Sbostic 			nspace = ndash = nplus = nhash = 0;
117930819Sbostic 			for ( ; ; ) {
118030819Sbostic 				if (*cp == ' ')
118130819Sbostic 					++nspace;
118230819Sbostic 				else if (*cp == '+')
118330819Sbostic 					++nplus;
118430819Sbostic 				else if (*cp == '-')
118530819Sbostic 					++ndash;
118630819Sbostic 				else if (*cp == '#')
118730819Sbostic 					++nhash;
118830819Sbostic 				else	break;
118930819Sbostic 				++cp;
119030819Sbostic 			}
119130819Sbostic 			if (nspace > 1 || ndash > 1 || nplus > 1 || nhash > 1)
119230819Sbostic 				return "wild repeated flag character in format";
119330819Sbostic 			if (*cp == '*') {
119430819Sbostic 				++cp;
119530819Sbostic 				if (++i > acount)
119630819Sbostic 					break;
119730819Sbostic 				t = ntharg(p, i, acount)->in.type;
119830819Sbostic 				/*
119930819Sbostic 				** Width other than INT or UNSIGNED is suspect.
120030819Sbostic 				*/
120130819Sbostic 				if (t != INT && t != UNSIGNED) {
120230819Sbostic (void) sprintf(errbuf,
120330819Sbostic 	"field width argument is type (%s) rather than (int) (arg %d)",
120430819Sbostic 	typestr(t), i);
120530819Sbostic 					return errbuf;
120630819Sbostic 				}
120730819Sbostic 			} else while (isdigit(*cp))
120830819Sbostic 				++cp;
120930819Sbostic 			if (*cp == '.') {
121030819Sbostic 				++cp;
121130819Sbostic 				if (*cp == '*') {
121230819Sbostic 					++cp;
121330819Sbostic 					if (++i > acount)
121430819Sbostic 						return pfacm;
121530819Sbostic 					t = ntharg(p, i, acount)->in.type;
121630819Sbostic 					if (t != INT && t != UNSIGNED) {
121730819Sbostic (void) sprintf(errbuf,
121830819Sbostic 	"precision argument is type (%s) rather than (int) (arg %d)",
121930819Sbostic 	typestr(t), i);
122030819Sbostic 						return errbuf;
122130819Sbostic 					}
122230819Sbostic 				} else while (isdigit(*cp))
122330819Sbostic 					++cp;
122430819Sbostic 			}
122530819Sbostic 			if (++i <= acount)
122630819Sbostic 				t = ntharg(p, i, acount)->in.type;
122730819Sbostic 		}
122830819Sbostic 		if (*cp == 'h' || *cp == 'l')
122930819Sbostic 			lchar = *cp++;
123030819Sbostic 		else	lchar = '\0';
123130819Sbostic 		if ((cchar = *cp++) == '\0')
123230819Sbostic 			return pwf;
123330819Sbostic 		if (i > acount)
123430819Sbostic 			return (findlc(basep, lchar, cchar) == NULL) ?
123530819Sbostic 				pwf : pfacm;
123630819Sbostic 		if (!isscan && !pflag && ISPTR(t) &&
123730819Sbostic 			strchr("douxX", cchar) != 0)
123830819Sbostic 				continue;	/* lax--printf("%d", (int *)) */
123930819Sbostic 		if (suppressed) {
124030819Sbostic 			if (findlc(basep, lchar, cchar) == NULL)
124130819Sbostic 				return pwf;
124230819Sbostic 		} else for (ep = basep; ; ++ep) {
124330819Sbostic 			if (ep->argtype == UNDEF) {	/* end of table */
124430819Sbostic 				ep = findlc(basep, lchar, cchar);
124530819Sbostic 				if (ep == NULL)
124630819Sbostic 					return pwf;
124730819Sbostic (void) sprintf(errbuf, "%s: (%s) format, (%s) arg (arg %d)",
124830819Sbostic 					ip->name,
124930819Sbostic 					typestr(ep->argtype),
125030819Sbostic 					typestr(isscan ? (t | PTR) : t), i);
125130819Sbostic 				return errbuf;
125230819Sbostic 			}
125330819Sbostic 			if (ep->argtype == t && ep->lchar == lchar &&
125430819Sbostic 				strchr(ep->cchars, cchar) != 0)
125530819Sbostic 					if (ep->werror == 0)
125630819Sbostic 						break;
125730819Sbostic 					else {
125830819Sbostic 						werror(ep->werror, cchar);
125930819Sbostic 						return NULL;
126030819Sbostic 					}
126130819Sbostic 		}
126230819Sbostic 		if (cchar != '[')
126330819Sbostic 			continue;
126430819Sbostic 		do {
126530819Sbostic 			if (*cp == '\0')
126630819Sbostic 				return "possible unmatched '[' in format";
126730819Sbostic 		} while (*cp++ != ']');
126830819Sbostic 	}
126930819Sbostic 	/*NOTREACHED*/
127030819Sbostic }
127130819Sbostic 
doform(p,sp,acount)127230819Sbostic doform(p, sp, acount)
127330819Sbostic NODE *		p;
127430819Sbostic struct symtab *	sp;
127530819Sbostic {
127630819Sbostic 	char *	cp;
127730819Sbostic 
127830819Sbostic 	if ((cp = subform(p, sp, acount)) != NULL)
127930819Sbostic 		werror(cp);
128030819Sbostic }
128130819Sbostic 
cisreg(t)128230819Sbostic cisreg(t) TWORD t; {return(1);}  /* everyting is a register variable! */
128330819Sbostic 
128430819Sbostic fldty(p) struct symtab *p; {
128530819Sbostic 	; /* all types are OK here... */
128630819Sbostic 	}
128730819Sbostic 
fldal(t)128830819Sbostic fldal(t) unsigned t; { /* field alignment... */
128930819Sbostic 	if( t == ENUMTY ) return( ALCHAR );  /* this should be thought through better... */
129030819Sbostic 	if( ISPTR(t) ){ /* really for the benefit of honeywell (and someday IBM) */
129130819Sbostic 		if( pflag ) uerror( "nonportable field type" );
129230819Sbostic 		}
129330819Sbostic 	else uerror( "illegal field type" );
129430819Sbostic 	return(ALINT);
129530819Sbostic 	}
129630819Sbostic 
main(argc,argv)129730819Sbostic main(argc, argv)
129830819Sbostic 	int	argc;
129930819Sbostic 	char	**argv;
130030819Sbostic {
130130819Sbostic 	extern char	*optarg;
130230819Sbostic 	extern int	optind;
130330819Sbostic 	int	ch;
130430819Sbostic 
130532979Sdonn 	while ((ch = getopt(argc,argv,"C:D:I:U:LX:Pabchnpuvxz")) != EOF)
130630819Sbostic 		switch((char)ch) {
130711403Snicklin 			case 'C':
130811403Snicklin 				Cflag = 1;
130930819Sbostic 				libname = optarg;
131011403Snicklin 				continue;
131130819Sbostic 			case 'D':	/* #define */
131230819Sbostic 			case 'I':	/* include path */
131330819Sbostic 			case 'U':	/* #undef */
131432979Sdonn 			case 'X':	/* debugging, done in first pass */
131530819Sbostic 			case 'P':	/* debugging, done in second pass */
131630819Sbostic 				break;
131730819Sbostic 			case 'L':
131830819Sbostic 				libflag = 1;
131930819Sbostic 				/*FALLTHROUGH*/
132030819Sbostic 			case 'v':	/* unused arguments in functions */
132130819Sbostic 				vflag = 0;
132230819Sbostic 				break;
132330819Sbostic 			case 'a':	/* long to int assignment */
132430819Sbostic 				++aflag;
132530819Sbostic 				break;
132630819Sbostic 			case 'b':	/* unreached break statements */
132730819Sbostic 				brkflag = 1;
132830819Sbostic 				break;
132930819Sbostic 			case 'c':	/* questionable casts */
133030819Sbostic 				cflag = 1;
133130819Sbostic 				break;
133230819Sbostic 			case 'h':	/* heuristics */
133330819Sbostic 				hflag = 1;
133430819Sbostic 				break;
133530819Sbostic 			case 'n':	/* standard library check */
133630819Sbostic 				nflag = 1;
133730819Sbostic 				break;
133830819Sbostic 			case 'p':	/* IBM & GCOS portability */
133930819Sbostic 				pflag = 1;
134030819Sbostic 				break;
134130819Sbostic 			case 'u':	/* 2nd pass: undefined or unused */
134230819Sbostic 				break;
134330819Sbostic 			case 'x':	/* unused externs */
134430819Sbostic 				xflag = 1;
134530819Sbostic 				break;
134630819Sbostic 			case 'z':	/* use of undefined structures */
134730819Sbostic 				zflag = 1;
134830819Sbostic 				break;
134930819Sbostic 			case '?':
135011403Snicklin 			default:
135130819Sbostic 				fputs("usage: lint [-C lib] [-D def] [-I include] [-U undef] [-Labchnpuvx] file ...\n",stderr);
135230819Sbostic 				exit(1);
135330819Sbostic 		}
135411403Snicklin 
135530819Sbostic 	if (!pflag) {		/* set sizes to sizes of target machine */
13567988Srrh # ifdef gcos
13577988Srrh 		SZCHAR = ALCHAR = 9;
13587988Srrh # else
13597988Srrh 		SZCHAR = ALCHAR = 8;
13607988Srrh # endif
13617988Srrh 		SZINT = ALINT = sizeof(int)*SZCHAR;
13627988Srrh 		SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR;
13637988Srrh 		SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR;
13647988Srrh 		SZLONG = ALLONG = sizeof(long)*SZCHAR;
13657988Srrh 		SZSHORT = ALSHORT = sizeof(short)*SZCHAR;
13667988Srrh 		SZPOINT = ALPOINT = sizeof(int *)*SZCHAR;
13677988Srrh 		ALSTRUCT = ALINT;
13687988Srrh 		/* now, fix some things up for various machines (I wish we had "alignof") */
13697988Srrh 
13707988Srrh # ifdef pdp11
13717988Srrh 		ALLONG = ALDOUBLE = ALFLOAT = ALINT;
137230819Sbostic # endif
13737988Srrh # ifdef ibm
13747988Srrh 		ALSTRUCT = ALCHAR;
137530819Sbostic # endif
13767988Srrh 	}
137730819Sbostic 	return(mainp1(argc,argv));
137830819Sbostic }
13797988Srrh 
ctype(type)13807988Srrh ctype( type ) unsigned type; { /* are there any funny types? */
13817988Srrh 	return( type );
13827988Srrh 	}
13837988Srrh 
commdec(i)13847988Srrh commdec( i ){
13857988Srrh 	/* put out a common declaration */
138611761Sedward 	if( stab[i].sclass == STATIC ) outdef( &stab[i], LST, USUAL );
138711761Sedward 	else outdef( &stab[i], libflag?LIB:LDC, USUAL );
13887988Srrh 	}
13897988Srrh 
isitfloat(s)13907988Srrh isitfloat ( s ) char *s; {
13917988Srrh 	/* s is a character string;
13927988Srrh 	   if floating point is implemented, set dcon to the value of s */
13937988Srrh 	/* lint version
13947988Srrh 	*/
13957988Srrh 	dcon = atof( s );
139625304Sbloom 	return( DCON );
13977988Srrh 	}
13987988Srrh 
fldcon(p)13997988Srrh fldcon( p ) register NODE *p; {
14007988Srrh 	/* p is an assignment of a constant to a field */
14017988Srrh 	/* check to see if the assignment is going to overflow, or otherwise cause trouble */
14027988Srrh 	register s;
14037988Srrh 	CONSZ v;
14047988Srrh 
14057988Srrh 	if( !hflag & !pflag ) return;
14067988Srrh 
14077988Srrh 	s = UPKFSZ(p->in.left->tn.rval);
14087988Srrh 	v = p->in.right->tn.lval;
14097988Srrh 
14107988Srrh 	switch( p->in.left->in.type ){
14117988Srrh 
14127988Srrh 	case CHAR:
14137988Srrh 	case INT:
14147988Srrh 	case SHORT:
14157988Srrh 	case LONG:
14167988Srrh 	case ENUMTY:
14177988Srrh 		if( v>=0 && (v>>(s-1))==0 ) return;
14187988Srrh 		werror( "precision lost in assignment to (possibly sign-extended) field" );
14197988Srrh 	default:
14207988Srrh 		return;
14217988Srrh 
14227988Srrh 	case UNSIGNED:
14237988Srrh 	case UCHAR:
14247988Srrh 	case USHORT:
14257988Srrh 	case ULONG:
14267988Srrh 		if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" );
14277988Srrh 
14287988Srrh 		return;
14297988Srrh 		}
14307988Srrh 
14317988Srrh 	}
14327988Srrh 
14337988Srrh outdef( p, lty, mode ) struct symtab *p; {
14347988Srrh 	/* output a definition for the second pass */
14357988Srrh 	/* if mode is > USUAL, it is the number of args */
14367988Srrh 	char *fname;
14377988Srrh 	TWORD t;
14387988Srrh 	int line;
14397988Srrh 	static union rec rc;
14407988Srrh 
14417988Srrh 	if( mode == NOFILE ){
14427988Srrh 		fname = "???";
14437988Srrh 		line = p->suse;
14447988Srrh 		}
14457988Srrh 	else if( mode == SVLINE ){
14467988Srrh 		fname = ftitle;
14477988Srrh 		line = -p->suse;
14487988Srrh 		}
14497988Srrh 	else {
14507988Srrh 		fname = ftitle;
14517988Srrh 		line = lineno;
14527988Srrh 		}
14537988Srrh 	fsave( fname );
14547988Srrh #ifndef FLEXNAMES
14557988Srrh 	strncpy( rc.l.name, exname(p->sname), LCHNM );
14567988Srrh #endif
14577988Srrh 	rc.l.decflag = lty;
14587988Srrh 	t = p->stype;
14597988Srrh 	if( mode == DECTY ) t = DECREF(t);
14607988Srrh 	rc.l.type.aty = t;
14617988Srrh 	rc.l.type.extra = 0;
146211761Sedward 	rc.l.type.extra1 = 0;
14637988Srrh 	astype( &rc.l.type, p->sizoff );
14647988Srrh 	rc.l.nargs = (mode>USUAL) ? mode : 0;
14657988Srrh 	rc.l.fline = line;
14667988Srrh 	fwrite( (char *)&rc, sizeof(rc), 1, stdout );
14677988Srrh #ifdef FLEXNAMES
14687988Srrh 	rc.l.name = exname(p->sname);
14697988Srrh 	fwrite( rc.l.name, strlen(rc.l.name)+1, 1, stdout );
14707988Srrh #endif
14717988Srrh 	}
14727988Srrh int proflg;
14737988Srrh int gdebug;
1474