17988Srrh #ifndef lint 2*30905Sbostic static char sccsid[] = "@(#)lint.c 1.12 (Berkeley) 04/13/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 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 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 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 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 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 */ 2267988Srrh if( vaflag > 0 ){ 2277988Srrh if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" ); 2287988Srrh else n = vaflag; 2297988Srrh } 2307988Srrh fsave( ftitle ); 23111761Sedward if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?-n:n ); 23211761Sedward 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 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 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 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 ); 412*30905Sbostic 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); 468*30905Sbostic if (uses & (VALSET | VALADDR)) 469*30905Sbostic q->suse = -lineno; 4707988Srrh if( p->tn.lval == 0 ){ 4717988Srrh lnp->lid = id; 4727988Srrh lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED); 4737988Srrh if( ++lnp >= &lnames[LNAMES] ) --lnp; 4747988Srrh } 4757988Srrh } 4767988Srrh return; 4777988Srrh 4787988Srrh } 4797988Srrh 4807988Srrh /* recurse, going down the right side first if we can */ 4817988Srrh 4827988Srrh switch( optype(p->in.op) ){ 4837988Srrh 4847988Srrh case BITYPE: 4857988Srrh np1 = lnp; 4867988Srrh lprt( p->in.right, down2, use2 ); 4877988Srrh case UTYPE: 4887988Srrh np2 = lnp; 4897988Srrh lprt( p->in.left, down1, use1 ); 4907988Srrh } 4917988Srrh 4927988Srrh if( optype(p->in.op) == BITYPE ){ 4937988Srrh if( p->in.op == ASSIGN && p->in.left->in.op == NAME ){ /* special case for a = .. a .. */ 4947988Srrh lmerge( np1, np2, 0 ); 4957988Srrh } 4967988Srrh else lmerge( np1, np2, p->in.op != COLON ); 4977988Srrh /* look for assignments to fields, and complain */ 4987988Srrh if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.op == ICON ) fldcon( p ); 4997988Srrh } 5007988Srrh 5017988Srrh } 5027988Srrh 5037988Srrh lmerge( np1, np2, flag ) struct lnm *np1, *np2; { 5047988Srrh /* np1 and np2 point to lists of lnm members, for the two sides 5057988Srrh * of a binary operator 5067988Srrh * flag is 1 if commutation is possible, 0 otherwise 5077988Srrh * lmerge returns a merged list, starting at np1, resetting lnp 5087988Srrh * it also complains, if appropriate, about side effects 5097988Srrh */ 5107988Srrh 5117988Srrh register struct lnm *npx, *npy; 5127988Srrh 5137988Srrh for( npx = np2; npx < lnp; ++npx ){ 5147988Srrh 5157988Srrh /* is it already there? */ 5167988Srrh for( npy = np1; npy < np2; ++npy ){ 5177988Srrh if( npx->lid == npy->lid ){ /* yes */ 5187988Srrh if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) ) 5197988Srrh ; /* do nothing */ 5207988Srrh else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) || 5217988Srrh (npx->flgs&npy->flgs&VALSET) ){ 5227988Srrh #ifndef FLEXNAMES 5237988Srrh if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname ); 5247988Srrh #else 5257988Srrh if( flag ) werror( "%s evaluation order undefined", stab[npy->lid].sname ); 5267988Srrh #endif 5277988Srrh } 5287988Srrh if( npy->flgs == 0 ) npx->flgs = 0; 5297988Srrh else npy->flgs |= npx->flgs; 5307988Srrh goto foundit; 5317988Srrh } 5327988Srrh } 5337988Srrh 5347988Srrh /* not there: update entry */ 5357988Srrh np2->lid = npx->lid; 5367988Srrh np2->flgs = npx->flgs; 5377988Srrh ++np2; 5387988Srrh 5397988Srrh foundit: ; 5407988Srrh } 5417988Srrh 5427988Srrh /* all finished: merged list is at np1 */ 5437988Srrh lnp = np2; 5447988Srrh } 5457988Srrh 5467988Srrh efcode(){ 5477988Srrh /* code for the end of a function */ 5487988Srrh register struct symtab *cfp; 5497988Srrh 5507988Srrh cfp = &stab[curftn]; 55111403Snicklin if( retstat & RETVAL && !(Cflag && cfp->sclass==STATIC) ) 55211403Snicklin outdef( cfp, LRV, DECTY ); 5537988Srrh if( !vflag ){ 5547988Srrh vflag = argflag; 5557988Srrh argflag = 0; 5567988Srrh } 5577988Srrh if( retstat == RETVAL+NRETVAL ) 5587988Srrh #ifndef FLEXNAMES 5597988Srrh werror( "function %.8s has return(e); and return;", cfp->sname); 5607988Srrh #else 5617988Srrh werror( "function %s has return(e); and return;", cfp->sname); 5627988Srrh #endif 5637988Srrh } 5647988Srrh 5657988Srrh aocode(p) struct symtab *p; { 5667988Srrh /* called when automatic p removed from stab */ 5677988Srrh register struct symtab *cfs; 5687988Srrh cfs = &stab[curftn]; 5697988Srrh if(p->suse>0 && !(p->sflags&(SMOS|STAG)) ){ 5707988Srrh if( p->sclass == PARAM ){ 5717988Srrh #ifndef FLEXNAMES 5727988Srrh if( vflag ) werror( "argument %.8s unused in function %.8s", 5737988Srrh #else 5747988Srrh if( vflag ) werror( "argument %s unused in function %s", 5757988Srrh #endif 5767988Srrh p->sname, 5777988Srrh cfs->sname ); 5787988Srrh } 5797988Srrh else { 5807988Srrh #ifndef FLEXNAMES 5817988Srrh if( p->sclass != TYPEDEF ) werror( "%.8s unused in function %.8s", 5827988Srrh #else 5837988Srrh if( p->sclass != TYPEDEF ) werror( "%s unused in function %s", 5847988Srrh #endif 5857988Srrh p->sname, cfs->sname ); 5867988Srrh } 5877988Srrh } 5887988Srrh 5897988Srrh if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET && 5907988Srrh !ISARY(p->stype) && !ISFTN(p->stype) ){ 5917988Srrh 5927988Srrh #ifndef FLEXNAMES 5937988Srrh werror( "%.8s set but not used in function %.8s", p->sname, cfs->sname ); 5947988Srrh #else 5957988Srrh werror( "%s set but not used in function %s", p->sname, cfs->sname ); 5967988Srrh #endif 5977988Srrh } 5987988Srrh 5997988Srrh if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){ 60011761Sedward if( !zflag && dimtab[p->sizoff+1] < 0 ) 6017988Srrh #ifndef FLEXNAMES 60211761Sedward werror( "structure %.8s never defined", p->sname ); 6037988Srrh #else 60411761Sedward werror( "structure %s never defined", p->sname ); 6057988Srrh #endif 6067988Srrh } 6077988Srrh 6087988Srrh } 6097988Srrh 6107988Srrh defnam( p ) register struct symtab *p; { 6117988Srrh /* define the current location as the name p->sname */ 6127988Srrh 61311403Snicklin if( p->sclass == STATIC && (p->slevel>1 || Cflag) ) return; 6147988Srrh 61511761Sedward if( !ISFTN( p->stype ) ) 61611761Sedward if( p->sclass == STATIC ) outdef( p, LST, USUAL ); 61711761Sedward else outdef( p, libflag?LIB:LDI, USUAL ); 6187988Srrh } 6197988Srrh 6207988Srrh zecode( n ){ 6217988Srrh /* n integer words of zeros */ 6227988Srrh OFFSZ temp; 6237988Srrh temp = n; 6247988Srrh inoff += temp*SZINT; 6257988Srrh ; 6267988Srrh } 6277988Srrh 6287988Srrh andable( p ) NODE *p; { /* p is a NAME node; can it accept & ? */ 6297988Srrh register r; 6307988Srrh 6317988Srrh if( p->in.op != NAME ) cerror( "andable error" ); 6327988Srrh 6337988Srrh if( (r = p->tn.rval) < 0 ) return(1); /* labels are andable */ 6347988Srrh 6357988Srrh if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0); 6367988Srrh #ifndef FLEXNAMES 6377988Srrh if( stab[r].sclass == REGISTER ) uerror( "can't take & of %.8s", stab[r].sname ); 6387988Srrh #else 6397988Srrh if( stab[r].sclass == REGISTER ) uerror( "can't take & of %s", stab[r].sname ); 6407988Srrh #endif 6417988Srrh return(1); 6427988Srrh } 6437988Srrh 6447988Srrh NODE * 6457988Srrh clocal(p) NODE *p; { 6467988Srrh 6477988Srrh /* this is called to do local transformations on 6487988Srrh an expression tree preparitory to its being 6497988Srrh written out in intermediate code. 6507988Srrh */ 6517988Srrh 6527988Srrh /* the major essential job is rewriting the 6537988Srrh automatic variables and arguments in terms of 6547988Srrh REG and OREG nodes */ 6557988Srrh /* conversion ops which are not necessary are also clobbered here */ 6567988Srrh /* in addition, any special features (such as rewriting 6577988Srrh exclusive or) are easily handled here as well */ 6587988Srrh 6597988Srrh register o; 6607988Srrh register unsigned t, tl; 66125757Sdonn int s; 6627988Srrh 6637988Srrh switch( o = p->in.op ){ 66430819Sbostic case NAME: 66530819Sbostic { 66630819Sbostic extern int didstr, subscr; 66730819Sbostic extern NODE * strnodes[]; 6687988Srrh 66930819Sbostic if (didstr) { 67030819Sbostic didstr = 0; 67130819Sbostic strnodes[subscr] = p; 67230819Sbostic } 67330819Sbostic } 67430819Sbostic break; 67530819Sbostic 6767988Srrh case SCONV: 6777988Srrh case PCONV: 6787988Srrh if( p->in.left->in.type==ENUMTY ){ 6797988Srrh p->in.left = pconvert( p->in.left ); 6807988Srrh } 6817988Srrh /* assume conversion takes place; type is inherited */ 6827988Srrh t = p->in.type; 6837988Srrh tl = p->in.left->in.type; 68426403Sdonn if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG&&t!=UNDEF) ){ 6857988Srrh werror( "long assignment may lose accuracy" ); 6867988Srrh } 6877988Srrh if( aflag>=2 && (tl!=LONG&&tl!=ULONG) && (t==LONG||t==ULONG) && p->in.left->in.op != ICON ){ 6887988Srrh werror( "assignment to long may sign-extend incorrectly" ); 6897988Srrh } 6907988Srrh if( ISPTR(tl) && ISPTR(t) ){ 6917988Srrh tl = DECREF(tl); 6927988Srrh t = DECREF(t); 6937988Srrh switch( ISFTN(t) + ISFTN(tl) ){ 6947988Srrh 6957988Srrh case 0: /* neither is a function pointer */ 6967988Srrh if( talign(t,p->fn.csiz) > talign(tl,p->in.left->fn.csiz) ){ 6977988Srrh if( hflag||pflag ) werror( "possible pointer alignment problem" ); 6987988Srrh } 6997988Srrh break; 7007988Srrh 7017988Srrh case 1: 7027988Srrh werror( "questionable conversion of function pointer" ); 7037988Srrh 7047988Srrh case 2: 7057988Srrh ; 7067988Srrh } 7077988Srrh } 7087988Srrh p->in.left->in.type = p->in.type; 7097988Srrh p->in.left->fn.cdim = p->fn.cdim; 7107988Srrh p->in.left->fn.csiz = p->fn.csiz; 7117988Srrh p->in.op = FREE; 7127988Srrh return( p->in.left ); 7137988Srrh 7147988Srrh case PVCONV: 7157988Srrh case PMCONV: 7167988Srrh if( p->in.right->in.op != ICON ) cerror( "bad conversion"); 7177988Srrh p->in.op = FREE; 7187988Srrh return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) ); 7197988Srrh 72025757Sdonn case RS: 72125757Sdonn case LS: 72225757Sdonn case ASG RS: 72325757Sdonn case ASG LS: 72425757Sdonn if( p->in.right->in.op != ICON ) 72525757Sdonn break; 72625757Sdonn s = p->in.right->tn.lval; 72725757Sdonn if( s < 0 ) 72825757Sdonn werror( "negative shift" ); 72925757Sdonn else 73025757Sdonn if( s >= dimtab[ p->fn.csiz ] ) 73125757Sdonn werror( "shift greater than size of object" ); 73225757Sdonn break; 73325757Sdonn 7347988Srrh } 7357988Srrh 7367988Srrh return(p); 7377988Srrh } 7387988Srrh 7397988Srrh NODE * 7407988Srrh offcon( off, t, d, s ) OFFSZ off; TWORD t;{ /* make a structure offset node */ 7417988Srrh register NODE *p; 7427988Srrh p = bcon(0); 7437988Srrh p->tn.lval = off/SZCHAR; 7447988Srrh return(p); 7457988Srrh } 7467988Srrh 7477988Srrh noinit(){ 7487988Srrh /* storage class for such as "int a;" */ 7497988Srrh return( pflag ? EXTDEF : EXTERN ); 7507988Srrh } 7517988Srrh 7527988Srrh 7537988Srrh cinit( p, sz ) NODE *p; { /* initialize p into size sz */ 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 * 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 * 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 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 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 8497988Srrh branch(n){;} 8507988Srrh defalign(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 86830819Sbostic bycode(t, i) 86930819Sbostic { 87030819Sbostic extern char * calloc(); 87130819Sbostic extern char * realloc(); 87230819Sbostic 873*30905Sbostic 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 89330819Sbostic strforget() 89430819Sbostic { 89530819Sbostic didstr = subscr = 0; 89630819Sbostic } 8977988Srrh 89830819Sbostic static char * 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 * 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 * 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 * 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 1116*30905Sbostic 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 */ 1142*30905Sbostic /* 1143*30905Sbostic ** For now, ALWAYS use "portable" table, rather than doing this: 1144*30905Sbostic ** basep = pflag ? ip->ptable : ip->btable; 1145*30905Sbostic */ 1146*30905Sbostic 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 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 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 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 129730819Sbostic main(argc, argv) 129830819Sbostic int argc; 129930819Sbostic char **argv; 130030819Sbostic { 130130819Sbostic extern char *optarg; 130230819Sbostic extern int optind; 130330819Sbostic int ch; 130430819Sbostic 130530819Sbostic while ((ch = getopt(argc,argv,"C:D:I:U:LPabchnpuvxz")) != 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 */ 131430819Sbostic case 'P': /* debugging, done in second pass */ 131530819Sbostic break; 131630819Sbostic case 'L': 131730819Sbostic libflag = 1; 131830819Sbostic /*FALLTHROUGH*/ 131930819Sbostic case 'v': /* unused arguments in functions */ 132030819Sbostic vflag = 0; 132130819Sbostic break; 132230819Sbostic case 'a': /* long to int assignment */ 132330819Sbostic ++aflag; 132430819Sbostic break; 132530819Sbostic case 'b': /* unreached break statements */ 132630819Sbostic brkflag = 1; 132730819Sbostic break; 132830819Sbostic case 'c': /* questionable casts */ 132930819Sbostic cflag = 1; 133030819Sbostic break; 133130819Sbostic case 'h': /* heuristics */ 133230819Sbostic hflag = 1; 133330819Sbostic break; 133430819Sbostic case 'n': /* standard library check */ 133530819Sbostic nflag = 1; 133630819Sbostic break; 133730819Sbostic case 'p': /* IBM & GCOS portability */ 133830819Sbostic pflag = 1; 133930819Sbostic break; 134030819Sbostic case 'u': /* 2nd pass: undefined or unused */ 134130819Sbostic break; 134230819Sbostic case 'x': /* unused externs */ 134330819Sbostic xflag = 1; 134430819Sbostic break; 134530819Sbostic case 'z': /* use of undefined structures */ 134630819Sbostic zflag = 1; 134730819Sbostic break; 134830819Sbostic case '?': 134911403Snicklin default: 135030819Sbostic fputs("usage: lint [-C lib] [-D def] [-I include] [-U undef] [-Labchnpuvx] file ...\n",stderr); 135130819Sbostic exit(1); 135230819Sbostic } 135311403Snicklin 135430819Sbostic if (!pflag) { /* set sizes to sizes of target machine */ 13557988Srrh # ifdef gcos 13567988Srrh SZCHAR = ALCHAR = 9; 13577988Srrh # else 13587988Srrh SZCHAR = ALCHAR = 8; 13597988Srrh # endif 13607988Srrh SZINT = ALINT = sizeof(int)*SZCHAR; 13617988Srrh SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR; 13627988Srrh SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR; 13637988Srrh SZLONG = ALLONG = sizeof(long)*SZCHAR; 13647988Srrh SZSHORT = ALSHORT = sizeof(short)*SZCHAR; 13657988Srrh SZPOINT = ALPOINT = sizeof(int *)*SZCHAR; 13667988Srrh ALSTRUCT = ALINT; 13677988Srrh /* now, fix some things up for various machines (I wish we had "alignof") */ 13687988Srrh 13697988Srrh # ifdef pdp11 13707988Srrh ALLONG = ALDOUBLE = ALFLOAT = ALINT; 137130819Sbostic # endif 13727988Srrh # ifdef ibm 13737988Srrh ALSTRUCT = ALCHAR; 137430819Sbostic # endif 13757988Srrh } 137630819Sbostic return(mainp1(argc,argv)); 137730819Sbostic } 13787988Srrh 13797988Srrh ctype( type ) unsigned type; { /* are there any funny types? */ 13807988Srrh return( type ); 13817988Srrh } 13827988Srrh 13837988Srrh commdec( i ){ 13847988Srrh /* put out a common declaration */ 138511761Sedward if( stab[i].sclass == STATIC ) outdef( &stab[i], LST, USUAL ); 138611761Sedward else outdef( &stab[i], libflag?LIB:LDC, USUAL ); 13877988Srrh } 13887988Srrh 13897988Srrh isitfloat ( s ) char *s; { 13907988Srrh /* s is a character string; 13917988Srrh if floating point is implemented, set dcon to the value of s */ 13927988Srrh /* lint version 13937988Srrh */ 13947988Srrh dcon = atof( s ); 139525304Sbloom return( DCON ); 13967988Srrh } 13977988Srrh 13987988Srrh fldcon( p ) register NODE *p; { 13997988Srrh /* p is an assignment of a constant to a field */ 14007988Srrh /* check to see if the assignment is going to overflow, or otherwise cause trouble */ 14017988Srrh register s; 14027988Srrh CONSZ v; 14037988Srrh 14047988Srrh if( !hflag & !pflag ) return; 14057988Srrh 14067988Srrh s = UPKFSZ(p->in.left->tn.rval); 14077988Srrh v = p->in.right->tn.lval; 14087988Srrh 14097988Srrh switch( p->in.left->in.type ){ 14107988Srrh 14117988Srrh case CHAR: 14127988Srrh case INT: 14137988Srrh case SHORT: 14147988Srrh case LONG: 14157988Srrh case ENUMTY: 14167988Srrh if( v>=0 && (v>>(s-1))==0 ) return; 14177988Srrh werror( "precision lost in assignment to (possibly sign-extended) field" ); 14187988Srrh default: 14197988Srrh return; 14207988Srrh 14217988Srrh case UNSIGNED: 14227988Srrh case UCHAR: 14237988Srrh case USHORT: 14247988Srrh case ULONG: 14257988Srrh if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" ); 14267988Srrh 14277988Srrh return; 14287988Srrh } 14297988Srrh 14307988Srrh } 14317988Srrh 14327988Srrh outdef( p, lty, mode ) struct symtab *p; { 14337988Srrh /* output a definition for the second pass */ 14347988Srrh /* if mode is > USUAL, it is the number of args */ 14357988Srrh char *fname; 14367988Srrh TWORD t; 14377988Srrh int line; 14387988Srrh static union rec rc; 14397988Srrh 14407988Srrh if( mode == NOFILE ){ 14417988Srrh fname = "???"; 14427988Srrh line = p->suse; 14437988Srrh } 14447988Srrh else if( mode == SVLINE ){ 14457988Srrh fname = ftitle; 14467988Srrh line = -p->suse; 14477988Srrh } 14487988Srrh else { 14497988Srrh fname = ftitle; 14507988Srrh line = lineno; 14517988Srrh } 14527988Srrh fsave( fname ); 14537988Srrh #ifndef FLEXNAMES 14547988Srrh strncpy( rc.l.name, exname(p->sname), LCHNM ); 14557988Srrh #endif 14567988Srrh rc.l.decflag = lty; 14577988Srrh t = p->stype; 14587988Srrh if( mode == DECTY ) t = DECREF(t); 14597988Srrh rc.l.type.aty = t; 14607988Srrh rc.l.type.extra = 0; 146111761Sedward rc.l.type.extra1 = 0; 14627988Srrh astype( &rc.l.type, p->sizoff ); 14637988Srrh rc.l.nargs = (mode>USUAL) ? mode : 0; 14647988Srrh rc.l.fline = line; 14657988Srrh fwrite( (char *)&rc, sizeof(rc), 1, stdout ); 14667988Srrh #ifdef FLEXNAMES 14677988Srrh rc.l.name = exname(p->sname); 14687988Srrh fwrite( rc.l.name, strlen(rc.l.name)+1, 1, stdout ); 14697988Srrh #endif 14707988Srrh } 14717988Srrh int proflg; 14727988Srrh int gdebug; 1473