|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)lint.c 1.14 (Berkeley) 12/11/87";
3: #endif lint
4:
5: # include "pass1.h"
6:
7: # include "lmanifest.h"
8:
9: # include <ctype.h>
10:
11: # define VAL 0
12: # define EFF 1
13:
14: /* these are appropriate for the -p flag */
15: int SZCHAR = 8;
16: int SZINT = 16;
17: int SZFLOAT = 32;
18: int SZDOUBLE = 64;
19: int SZLONG = 32;
20: int SZSHORT = 16;
21: int SZPOINT = 16;
22: int ALCHAR = 8;
23: int ALINT = 16;
24: int ALFLOAT = 32;
25: int ALDOUBLE = 64;
26: int ALLONG = 32;
27: int ALSHORT = 16;
28: int ALPOINT = 16;
29: int ALSTRUCT = 16;
30:
31: int nflag = 0; /* avoid gripes about printf et al. */
32: int vflag = 1; /* tell about unused argments */
33: int xflag = 0; /* tell about unused externals */
34: int argflag = 0; /* used to turn off complaints about arguments */
35: int libflag = 0; /* used to generate library descriptions */
36: int vaflag = -1; /* signal functions with a variable number of args */
37: int aflag = 0; /* used to check precision of assignments */
38: int zflag = 0; /* no 'structure never defined' error */
39: int Cflag = 0; /* filter out certain output, for generating libraries */
40: char *libname = 0; /* name of the library we're generating */
41:
42: /* flags for the "outdef" function */
43: # define USUAL (-101)
44: # define DECTY (-102)
45: # define NOFILE (-103)
46: # define SVLINE (-104)
47:
48: # define LNAMES 250
49:
50: struct lnm {
51: short lid, flgs;
52: } lnames[LNAMES], *lnp;
53:
54: contx( p, down, pl, pr ) register NODE *p; register *pl, *pr; {
55:
56: *pl = *pr = VAL;
57: switch( p->in.op ){
58:
59: case ANDAND:
60: case OROR:
61: case QUEST:
62: *pr = down;
63: break;
64:
65: case SCONV:
66: case PCONV:
67: case COLON:
68: *pr = *pl = down;
69: break;
70:
71: case COMOP:
72: *pl = EFF;
73: *pr = down;
74:
75: case FORCE:
76: case INIT:
77: case UNARY CALL:
78: case STCALL:
79: case UNARY STCALL:
80: case CALL:
81: case UNARY FORTCALL:
82: case FORTCALL:
83: case CBRANCH:
84: break;
85:
86: default:
87: if( asgop(p->in.op) ) break;
88: if( p->in.op == UNARY MUL && ( p->in.type == STRTY || p->in.type == UNIONTY || p->in.type == UNDEF) ) {
89: /* struct x f( ); main( ) { (void) f( ); }
90: * the the cast call appears as U* UNDEF
91: */
92: break; /* the compiler does this... */
93: }
94: if( down == EFF && hflag ) werror( "null effect" );
95:
96: }
97: }
98:
99: ecode( p ) NODE *p; {
100: /* compile code for p */
101:
102: fwalk( p, contx, EFF );
103: lnp = lnames;
104: lprt( p, EFF, 0 );
105: strforget();
106: }
107:
108: ejobcode( flag ){
109: /* called after processing each job */
110: /* flag is nonzero if errors were detected */
111: register k;
112: register struct symtab *p;
113:
114: for( p=stab; p< &stab[SYMTSZ]; ++p ){
115:
116: if( p->stype != TNULL ) {
117:
118: if( p->stype == STRTY || p->stype == UNIONTY ){
119: if( !zflag && dimtab[p->sizoff+1] < 0 ){
120: /* never defined */
121: #ifndef FLEXNAMES
122: if( hflag ) werror( "struct/union %.8s never defined", p->sname );
123: #else
124: if( hflag ) werror( "struct/union %s never defined", p->sname );
125: #endif
126: }
127: }
128:
129: switch( p->sclass ){
130:
131: case STATIC:
132: if( p->suse > 0 ){
133: k = lineno;
134: lineno = p->suse;
135: #ifndef FLEXNAMES
136: uerror( "static variable %.8s unused",
137: #else
138: uerror( "static variable %s unused",
139: #endif
140: p->sname );
141: lineno = k;
142: break;
143: }
144: /* no statics in libraries */
145: if( Cflag ) break;
146:
147: case EXTERN:
148: case USTATIC:
149: /* with the xflag, worry about externs not used */
150: /* the filename may be wrong here... */
151: if( xflag && p->suse >= 0 && !libflag ){
152: outdef( p, LDX, NOFILE );
153: }
154:
155: case EXTDEF:
156: if( p->suse < 0 ){ /* used */
157: outdef( p, LUM, SVLINE );
158: }
159: break;
160: }
161:
162: }
163:
164: }
165: exit( 0 );
166: }
167:
168: astype( t, i ) ATYPE *t; {
169: TWORD tt;
170: int j, k=0, l=0;
171:
172: if( (tt=BTYPE(t->aty))==STRTY || tt==UNIONTY ){
173: if( i<0 || i>= DIMTABSZ-3 ){
174: werror( "lint's little mind is blown" );
175: }
176: else {
177: j = dimtab[i+3];
178: if( j<0 || j>SYMTSZ ){
179: k = dimtab[i];
180: l = X_NONAME | stab[j].suse;
181: }
182: else {
183: if( stab[j].suse <= 0 ) {
184: #ifndef FLEXNAMES
185: werror( "no line number for %.8s",
186: #else
187: werror( "no line number for %s",
188: #endif
189: stab[j].sname );
190: }
191: else {
192: k = dimtab[i];
193: #ifdef FLEXNAMES
194: l = hashstr(stab[j].sname);
195: #else
196: l = hashstr(stab[j].sname, LCHNM);
197: #endif
198: }
199: }
200: }
201:
202: t->extra = k;
203: t->extra1 = l;
204: return( 1 );
205: }
206: else return( 0 );
207: }
208:
209: bfcode( a, n ) int a[]; {
210: /* code for the beginning of a function; a is an array of
211: indices in stab for the arguments; n is the number */
212: /* this must also set retlab */
213: register i;
214: register struct symtab *cfp;
215: static ATYPE t;
216:
217: strforget();
218: retlab = 1;
219:
220: cfp = &stab[curftn];
221:
222: /* if creating library, don't do static functions */
223: if( Cflag && cfp->sclass == STATIC ) return;
224:
225: /* if variable number of arguments, only print the ones which will be checked */
226: if( vaflag >= 0 ){
227: if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
228: else n = vaflag;
229: }
230: fsave( ftitle );
231: if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?~n:n );
232: else outdef( cfp, libflag?LIB:LDI, vaflag>=0?~n:n );
233: vaflag = -1;
234:
235: /* output the arguments */
236: if( n ){
237: for( i=0; i<n; ++i ) {
238: t.aty = stab[a[i]].stype;
239: t.extra = 0;
240: t.extra1 = 0;
241: if( !astype( &t, stab[a[i]].sizoff ) ) {
242: switch( t.aty ){
243:
244: case ULONG:
245: break;
246:
247: case CHAR:
248: case SHORT:
249: t.aty = INT;
250: break;
251:
252: case UCHAR:
253: case USHORT:
254: case UNSIGNED:
255: t.aty = UNSIGNED;
256: break;
257:
258: }
259: }
260: fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
261: }
262: }
263: }
264:
265: ctargs( p ) NODE *p; {
266: /* count arguments; p points to at least one */
267: /* the arguemnts are a tower of commas to the left */
268: register c;
269: c = 1; /* count the rhs */
270: while( p->in.op == CM ){
271: ++c;
272: p = p->in.left;
273: }
274: return( c );
275: }
276:
277: lpta( p ) NODE *p; {
278: static ATYPE t;
279:
280: if( p->in.op == CM ){
281: lpta( p->in.left );
282: p = p->in.right;
283: }
284:
285: t.aty = p->in.type;
286: t.extra = (p->in.op==ICON);
287: t.extra1 = 0;
288:
289: if( !astype( &t, p->fn.csiz ) ) {
290: switch( t.aty ){
291:
292: case CHAR:
293: case SHORT:
294: t.aty = INT;
295: case LONG:
296: case ULONG:
297: case INT:
298: case UNSIGNED:
299: break;
300:
301: case UCHAR:
302: case USHORT:
303: t.aty = UNSIGNED;
304: break;
305:
306: case FLOAT:
307: t.aty = DOUBLE;
308: t.extra = 0;
309: break;
310:
311: default:
312: t.extra = 0;
313: break;
314: }
315: }
316: fwrite( (char *)&t, sizeof(ATYPE), 1, stdout );
317: }
318:
319: # define VALSET 1
320: # define VALUSED 2
321: # define VALASGOP 4
322: # define VALADDR 8
323:
324: lprt( p, down, uses ) register NODE *p; {
325: register struct symtab *q;
326: register id;
327: register acount;
328: register down1, down2;
329: register use1, use2;
330: register struct lnm *np1, *np2;
331:
332: /* first, set variables which are set... */
333:
334: use1 = use2 = VALUSED;
335: if( p->in.op == ASSIGN ) use1 = VALSET;
336: else if( p->in.op == UNARY AND ) use1 = VALADDR;
337: else if( asgop( p->in.op ) ){ /* =ops */
338: use1 = VALUSED|VALSET;
339: if( down == EFF ) use1 |= VALASGOP;
340: }
341:
342:
343: /* print the lines for lint */
344:
345: down2 = down1 = VAL;
346: acount = 0;
347:
348: switch( p->in.op ){
349:
350: case EQ:
351: case NE:
352: case GT:
353: case GE:
354: case LT:
355: case LE:
356: if( p->in.left->in.type == CHAR && p->in.right->in.op==ICON && p->in.right->tn.lval < 0 ){
357: werror( "nonportable character comparison" );
358: }
359: if( (p->in.op==EQ || p->in.op==NE ) && ISUNSIGNED(p->in.left->in.type) && p->in.right->in.op == ICON ){
360: if( p->in.right->tn.lval < 0 && p->in.right->tn.rval == NONAME && !ISUNSIGNED(p->in.right->in.type) ){
361: werror( "comparison of unsigned with negative constant" );
362: }
363: }
364: break;
365:
366: case UGE:
367: case ULT:
368: if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->tn.rval == NONAME ){
369: werror( "unsigned comparison with 0?" );
370: break;
371: }
372: case UGT:
373: case ULE:
374: 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 ){
375: werror( "degenerate unsigned comparison" );
376: }
377: break;
378:
379: case COMOP:
380: down1 = EFF;
381:
382: case ANDAND:
383: case OROR:
384: case QUEST:
385: down2 = down;
386: /* go recursively left, then right */
387: np1 = lnp;
388: lprt( p->in.left, down1, use1 );
389: np2 = lnp;
390: lprt( p->in.right, down2, use2 );
391: lmerge( np1, np2, 0 );
392: return;
393:
394: case SCONV:
395: case PCONV:
396: case COLON:
397: down1 = down2 = down;
398: break;
399:
400: case CALL:
401: case STCALL:
402: case FORTCALL:
403: acount = ctargs( p->in.right );
404: case UNARY CALL:
405: case UNARY STCALL:
406: case UNARY FORTCALL:
407: if( p->in.left->in.op == ICON && (id=p->in.left->tn.rval) != NONAME ){ /* used to be &name */
408: struct symtab *sp = &stab[id];
409: int lty;
410:
411: fsave( ftitle );
412: if (!nflag)
413: doform(p, sp, acount);
414: /*
415: * if we're generating a library -C then
416: * we don't want to output references to functions
417: */
418: if( Cflag ) break;
419: /* if a function used in an effects context is
420: * cast to type void then consider its value
421: * to have been disposed of properly
422: * thus a call of type undef in an effects
423: * context is construed to be used in a value
424: * context
425: */
426: if ((down == EFF) && (p->in.type != UNDEF)) {
427: lty = LUE;
428: } else if (down == EFF) {
429: lty = LUV | LUE;
430: } else {
431: lty = LUV;
432: }
433: outdef( sp, lty, acount );
434: if( acount ) {
435: lpta( p->in.right );
436: }
437: }
438: break;
439:
440: case ICON:
441: /* look for &name case */
442: if( (id = p->tn.rval) >= 0 && id != NONAME ){
443: q = &stab[id];
444: q->sflags |= (SREF|SSET);
445: q->suse = -lineno;
446: }
447: return;
448:
449: case NAME:
450: if( (id = p->tn.rval) >= 0 && id != NONAME ){
451: q = &stab[id];
452: if( (uses&VALUSED) && !(q->sflags&SSET) ){
453: if( q->sclass == AUTO || q->sclass == REGISTER ){
454: if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY && q->stype!=UNIONTY ){
455: #ifndef FLEXNAMES
456: werror( "%.8s may be used before set", q->sname );
457: #else
458: werror( "%s may be used before set", q->sname );
459: #endif
460: q->sflags |= SSET;
461: }
462: }
463: }
464: if( uses & VALASGOP ) break; /* not a real use */
465: if( uses & VALSET ) q->sflags |= SSET;
466: if( uses & VALUSED ) q->sflags |= SREF;
467: if( uses & VALADDR ) q->sflags |= (SREF|SSET);
468: if( p->tn.lval == 0 ){
469: lnp->lid = id;
470: lnp->flgs = (uses&VALADDR)?0:((uses&VALSET)?VALSET:VALUSED);
471: if( ++lnp >= &lnames[LNAMES] ) --lnp;
472: }
473: }
474: return;
475:
476: }
477:
478: /* recurse, going down the right side first if we can */
479:
480: switch( optype(p->in.op) ){
481:
482: case BITYPE:
483: np1 = lnp;
484: lprt( p->in.right, down2, use2 );
485: case UTYPE:
486: np2 = lnp;
487: lprt( p->in.left, down1, use1 );
488: }
489:
490: if( optype(p->in.op) == BITYPE ){
491: if( p->in.op == ASSIGN && p->in.left->in.op == NAME ){ /* special case for a = .. a .. */
492: lmerge( np1, np2, 0 );
493: }
494: else lmerge( np1, np2, p->in.op != COLON );
495: /* look for assignments to fields, and complain */
496: if( p->in.op == ASSIGN && p->in.left->in.op == FLD && p->in.right->in.op == ICON ) fldcon( p );
497: }
498:
499: }
500:
501: lmerge( np1, np2, flag ) struct lnm *np1, *np2; {
502: /* np1 and np2 point to lists of lnm members, for the two sides
503: * of a binary operator
504: * flag is 1 if commutation is possible, 0 otherwise
505: * lmerge returns a merged list, starting at np1, resetting lnp
506: * it also complains, if appropriate, about side effects
507: */
508:
509: register struct lnm *npx, *npy;
510:
511: for( npx = np2; npx < lnp; ++npx ){
512:
513: /* is it already there? */
514: for( npy = np1; npy < np2; ++npy ){
515: if( npx->lid == npy->lid ){ /* yes */
516: if( npx->flgs == 0 || npx->flgs == (VALSET|VALUSED) )
517: ; /* do nothing */
518: else if( (npx->flgs|npy->flgs)== (VALSET|VALUSED) ||
519: (npx->flgs&npy->flgs&VALSET) ){
520: #ifndef FLEXNAMES
521: if( flag ) werror( "%.8s evaluation order undefined", stab[npy->lid].sname );
522: #else
523: if( flag ) werror( "%s evaluation order undefined", stab[npy->lid].sname );
524: #endif
525: }
526: if( npy->flgs == 0 ) npx->flgs = 0;
527: else npy->flgs |= npx->flgs;
528: goto foundit;
529: }
530: }
531:
532: /* not there: update entry */
533: np2->lid = npx->lid;
534: np2->flgs = npx->flgs;
535: ++np2;
536:
537: foundit: ;
538: }
539:
540: /* all finished: merged list is at np1 */
541: lnp = np2;
542: }
543:
544: efcode(){
545: /* code for the end of a function */
546: register struct symtab *cfp;
547:
548: cfp = &stab[curftn];
549: if( retstat & RETVAL && !(Cflag && cfp->sclass==STATIC) )
550: outdef( cfp, LRV, DECTY );
551: if( !vflag ){
552: vflag = argflag;
553: argflag = 0;
554: }
555: if( retstat == RETVAL+NRETVAL )
556: #ifndef FLEXNAMES
557: werror( "function %.8s has return(e); and return;", cfp->sname);
558: #else
559: werror( "function %s has return(e); and return;", cfp->sname);
560: #endif
561: }
562:
563: aocode(p) struct symtab *p; {
564: /* called when automatic p removed from stab */
565: register struct symtab *cfs;
566: cfs = &stab[curftn];
567: if(p->suse>0 && !(p->sflags&(SMOS|STAG)) ){
568: if( p->sclass == PARAM ){
569: #ifndef FLEXNAMES
570: if( vflag ) werror( "argument %.8s unused in function %.8s",
571: #else
572: if( vflag ) werror( "argument %s unused in function %s",
573: #endif
574: p->sname,
575: cfs->sname );
576: }
577: else {
578: #ifndef FLEXNAMES
579: if( p->sclass != TYPEDEF ) werror( "%.8s unused in function %.8s",
580: #else
581: if( p->sclass != TYPEDEF ) werror( "%s unused in function %s",
582: #endif
583: p->sname, cfs->sname );
584: }
585: }
586:
587: if( p->suse < 0 && (p->sflags & (SSET|SREF|SMOS)) == SSET &&
588: !ISARY(p->stype) && !ISFTN(p->stype) ){
589:
590: #ifndef FLEXNAMES
591: werror( "%.8s set but not used in function %.8s", p->sname, cfs->sname );
592: #else
593: werror( "%s set but not used in function %s", p->sname, cfs->sname );
594: #endif
595: }
596:
597: if( p->stype == STRTY || p->stype == UNIONTY || p->stype == ENUMTY ){
598: if( !zflag && dimtab[p->sizoff+1] < 0 )
599: #ifndef FLEXNAMES
600: werror( "structure %.8s never defined", p->sname );
601: #else
602: werror( "structure %s never defined", p->sname );
603: #endif
604: }
605:
606: }
607:
608: defnam( p ) register struct symtab *p; {
609: /* define the current location as the name p->sname */
610:
611: if( p->sclass == STATIC && (p->slevel>1 || Cflag) ) return;
612:
613: if( !ISFTN( p->stype ) )
614: if( p->sclass == STATIC ) outdef( p, LST, USUAL );
615: else outdef( p, libflag?LIB:LDI, USUAL );
616: }
617:
618: zecode( n ){
619: /* n integer words of zeros */
620: OFFSZ temp;
621: temp = n;
622: inoff += temp*SZINT;
623: ;
624: }
625:
626: andable( p ) NODE *p; { /* p is a NAME node; can it accept & ? */
627: register r;
628:
629: if( p->in.op != NAME ) cerror( "andable error" );
630:
631: if( (r = p->tn.rval) < 0 ) return(1); /* labels are andable */
632:
633: if( stab[r].sclass == AUTO || stab[r].sclass == PARAM ) return(0);
634: #ifndef FLEXNAMES
635: if( stab[r].sclass == REGISTER ) uerror( "can't take & of %.8s", stab[r].sname );
636: #else
637: if( stab[r].sclass == REGISTER ) uerror( "can't take & of %s", stab[r].sname );
638: #endif
639: return(1);
640: }
641:
642: NODE *
643: clocal(p) NODE *p; {
644:
645: /* this is called to do local transformations on
646: an expression tree preparitory to its being
647: written out in intermediate code.
648: */
649:
650: /* the major essential job is rewriting the
651: automatic variables and arguments in terms of
652: REG and OREG nodes */
653: /* conversion ops which are not necessary are also clobbered here */
654: /* in addition, any special features (such as rewriting
655: exclusive or) are easily handled here as well */
656:
657: register o;
658: register unsigned t, tl;
659: int s;
660:
661: switch( o = p->in.op ){
662: case NAME:
663: {
664: extern int didstr, subscr;
665: extern NODE * strnodes[];
666:
667: if (didstr) {
668: didstr = 0;
669: strnodes[subscr] = p;
670: }
671: }
672: break;
673:
674: case SCONV:
675: case PCONV:
676: if( p->in.left->in.type==ENUMTY ){
677: p->in.left = pconvert( p->in.left );
678: }
679: /* assume conversion takes place; type is inherited */
680: t = p->in.type;
681: tl = p->in.left->in.type;
682: if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG&&t!=UNDEF) ){
683: werror( "long assignment may lose accuracy" );
684: }
685: if( aflag>=2 && (tl!=LONG&&tl!=ULONG) && (t==LONG||t==ULONG) && p->in.left->in.op != ICON ){
686: werror( "assignment to long may sign-extend incorrectly" );
687: }
688: if( ISPTR(tl) && ISPTR(t) ){
689: tl = DECREF(tl);
690: t = DECREF(t);
691: switch( ISFTN(t) + ISFTN(tl) ){
692:
693: case 0: /* neither is a function pointer */
694: if( talign(t,p->fn.csiz) > talign(tl,p->in.left->fn.csiz) ){
695: if( hflag||pflag ) werror( "possible pointer alignment problem" );
696: }
697: break;
698:
699: case 1:
700: werror( "questionable conversion of function pointer" );
701:
702: case 2:
703: ;
704: }
705: }
706: p->in.left->in.type = p->in.type;
707: p->in.left->fn.cdim = p->fn.cdim;
708: p->in.left->fn.csiz = p->fn.csiz;
709: p->in.op = FREE;
710: return( p->in.left );
711:
712: case PVCONV:
713: case PMCONV:
714: if( p->in.right->in.op != ICON ) cerror( "bad conversion");
715: p->in.op = FREE;
716: return( buildtree( o==PMCONV?MUL:DIV, p->in.left, p->in.right ) );
717:
718: case RS:
719: case LS:
720: case ASG RS:
721: case ASG LS:
722: if( p->in.right->in.op != ICON )
723: break;
724: s = p->in.right->tn.lval;
725: if( s < 0 )
726: werror( "negative shift" );
727: else
728: if( s >= dimtab[ p->fn.csiz ] )
729: werror( "shift greater than size of object" );
730: break;
731:
732: }
733:
734: return(p);
735: }
736:
737: NODE *
738: offcon( off, t, d, s ) OFFSZ off; TWORD t;{ /* make a structure offset node */
739: register NODE *p;
740: p = bcon(0);
741: p->tn.lval = off/SZCHAR;
742: return(p);
743: }
744:
745: noinit(){
746: /* storage class for such as "int a;" */
747: return( pflag ? EXTDEF : EXTERN );
748: }
749:
750:
751: cinit( p, sz ) NODE *p; { /* initialize p into size sz */
752: register int id;
753:
754: inoff += sz;
755: if( p->in.op == INIT ){
756: if( p->in.left->in.op == ICON ) return;
757: if( p->in.left->in.op == NAME && p->in.left->in.type == MOE ) return;
758: }
759: uerror( "illegal initialization" );
760: }
761:
762: char *
763: exname( p ) char *p; {
764: /* make a name look like an external name in the local machine */
765: static char aa[8];
766: register int i;
767:
768: if( !pflag ) return(p);
769: for( i=0; i<6; ++i ){
770: if( isupper(*p ) ) aa[i] = tolower( *p );
771: else aa[i] = *p;
772: if( *p ) ++p;
773: }
774: aa[6] = '\0';
775: return( aa );
776: }
777:
778: char *
779: strip(s) char *s; {
780: #ifndef FLEXNAMES
781: static char x[LFNM+1];
782: #else
783: static char x[BUFSIZ];
784: #endif
785: register char *p;
786: static int stripping = 0;
787:
788: if (stripping)
789: return(s);
790: stripping++;
791: for( p=x; *s; ++s ){
792: if( *s != '"' ){
793: #ifndef FLEXNAMES
794: /* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */
795: if( p >= &x[LFNM] )
796: #else
797: if( p >= &x[BUFSIZ] )
798: #endif
799: cerror( "filename too long" );
800: *p++ = *s;
801: }
802: }
803: stripping = 0;
804: *p = '\0';
805: #ifndef FLEXNAMES
806: return( x );
807: #else
808: return( hash(x) );
809: #endif
810: }
811:
812: fsave( s ) char *s; {
813: static union rec fsname;
814: s = strip( s );
815: #ifndef FLEXNAMES
816: if( strncmp( s, fsname.f.fn, LFNM ) )
817: #else
818: if (fsname.f.fn == NULL || strcmp(s, fsname.f.fn))
819: #endif
820: {
821: /* new one */
822: #ifndef FLEXNAMES
823: strncpy( fsname.f.fn, s, LFNM );
824: #else
825: fsname.f.fn = s;
826: #endif
827: fsname.f.decflag = LFN;
828: fwrite( (char *)&fsname, sizeof(fsname), 1, stdout );
829: #ifdef FLEXNAMES
830: /* if generating a library, prefix with the library name */
831: /* only do this for flexnames */
832: if( libname ){
833: fwrite( libname, strlen(libname), 1, stdout );
834: putchar( ':' );
835: }
836: fwrite( fsname.f.fn, strlen(fsname.f.fn)+1, 1, stdout );
837: #endif
838: }
839: }
840:
841: where(f){ /* print true location of error */
842: if( f == 'u' && nerrors > 1 )
843: --nerrors; /* don't get "too many errors" */
844: fprintf( stderr, "%s(%d): ", strip(ftitle), lineno);
845: }
846:
847: /* a number of dummy routines, unneeded by lint */
848:
849: branch(n){;}
850: defalign(n){;}
851: deflab(n){;}
852:
853: extern char * strchr();
854:
855: #define SBUFSIZE 16
856: #define SCLICK 80
857:
858: #ifndef size_t
859: #define size_t unsigned
860: #endif /* !size_t */
861:
862: static char * strings[SBUFSIZE];
863: static NODE * strnodes[SBUFSIZE];
864: static int didstr;
865: static int subscr;
866: static int strapped;
867:
868: bycode(t, i)
869: {
870: extern char * calloc();
871: extern char * realloc();
872:
873: if (nflag || strapped)
874: return;
875: if (i == 0)
876: if (subscr < (SBUFSIZE - 1))
877: ++subscr;
878: if (subscr >= SBUFSIZE)
879: return;
880: didstr = 1;
881: if ((i % SCLICK) == 0) {
882: strings[subscr] = (strings[subscr] == NULL) ?
883: calloc((size_t) (SCLICK + 1), 1) :
884: realloc(strings[subscr], (size_t) (i + SCLICK + 1));
885: if (strings[subscr] == NULL) {
886: strapped = 1;
887: return;
888: }
889: }
890: strings[subscr][i] = t;
891: }
892:
893: strforget()
894: {
895: didstr = subscr = 0;
896: }
897:
898: static char *
899: typestr(t)
900: {
901: switch (t) {
902: case CHAR: return "char";
903: case UCHAR: return "unsigned char";
904: case SHORT: return "short";
905: case USHORT: return "unsigned short";
906: case INT: return "int";
907: case UNSIGNED: return "unsigned";
908: case ENUMTY: return "enum";
909: case LONG: return "long";
910: case ULONG: return "unsigned long";
911: case FLOAT: return "float";
912: case DOUBLE: return "double";
913: case STRTY: return "struct";
914: case UNIONTY: return "union";
915: case PTR|CHAR: return "char *";
916: case PTR|UCHAR: return "unsigned char *";
917: case PTR|SHORT: return "short *";
918: case PTR|USHORT: return "unsigned short *";
919: case PTR|INT: return "int *";
920: case PTR|UNSIGNED: return "unsigned *";
921: case PTR|ENUMTY: return "enum *";
922: case PTR|LONG: return "long *";
923: case PTR|ULONG: return "unsigned long *";
924: case PTR|FLOAT: return "float *";
925: case PTR|DOUBLE: return "double *";
926: case PTR|STRTY: return "struct *";
927: case PTR|UNIONTY: return "union *";
928: default: return ISPTR(t) ?
929: "pointer" : "non-scalar";
930: }
931: }
932:
933: NODE *
934: ntharg(p, n, acount)
935: NODE * p;
936: register int n;
937: register int acount;
938: {
939: if (n > acount)
940: return NULL;
941: p = p->in.right;
942: while (n != acount) {
943: p = p->in.left;
944: --acount;
945: }
946: return (n == 1) ? p : p->in.right;
947: }
948:
949: struct entry {
950: /* If argument to print/scan is of type... */ int argtype;
951: /* ...and this length character is used... */ char lchar;
952: /* ...and one of these is control char... */ char * cchars;
953: /* ...then use this format with werror... */ char * werror;
954: /* ...(where NULL means it's hunky dory)... */
955: };
956:
957: /*
958: ** Portable printf.
959: ** H&S says "%o" takes an unsigned argument;
960: ** X3J11 says "%o" takes an int argument;
961: ** we'll allow either here.
962: */
963:
964: static struct entry pprintf[] = {
965: CHAR, '\0', "c", NULL, /* this is deliberate */
966: INT, '\0', "cdoxX", NULL,
967: UNSIGNED, '\0', "uoxX", NULL,
968: CHAR, '\0', "cdoxX", NULL,
969: UCHAR, '\0', "udoxX", NULL, /* yes, d is okay */
970: SHORT, '\0', "cdoxX", NULL,
971: USHORT, '\0', "uoxX", NULL,
972: ENUMTY, '\0', "duoxX", NULL,
973: LONG, 'l', "doxX", NULL,
974: ULONG, 'l', "uoxX", NULL,
975: FLOAT, '\0', "eEfgG", NULL,
976: DOUBLE, '\0', "eEfgG", NULL,
977: PTR|CHAR, '\0', "s", NULL,
978: UNDEF, '\0', "", NULL
979: };
980:
981: /*
982: ** Berkeley printf.
983: ** It allows %D, %O, and %U, which we deprecate.
984: ** Since
985: ** sizeof (char *) == sizeof (int) &&
986: ** sizeof (int) == sizeof (long) &&
987: ** sizeof (char *) == sizeof (int *)
988: ** you can be lax--and we tolerate *some* laxness.
989: ** g/lax/p to find lax table entries and code.
990: */
991:
992: static char uppercase[] = "deprecated upper-case control character (%c)";
993: #define lax NULL
994:
995: static struct entry bprintf[] = {
996: CHAR, '\0', "c", NULL, /* this is deliberate */
997: INT, '\0', "cdoxX", NULL,
998: INT, '\0', "DO", uppercase,
999: UNSIGNED, '\0', "uoxX", NULL,
1000: UNSIGNED, '\0', "UO", uppercase,
1001: CHAR, '\0', "cdoxX", NULL,
1002: CHAR, '\0', "DO", uppercase,
1003: UCHAR, '\0', "duoxX", NULL, /* yes, d is okay */
1004: UCHAR, '\0', "DUO", uppercase,
1005: SHORT, '\0', "cdoxX", NULL,
1006: SHORT, '\0', "DO", uppercase,
1007: USHORT, '\0', "duoxX", NULL, /* d okay on BSD */
1008: USHORT, '\0', "DUO", uppercase,
1009: ENUMTY, '\0', "duoxX", NULL,
1010: ENUMTY, '\0', "DUO", uppercase,
1011: LONG, '\0', "doxX", lax,
1012: LONG, '\0', "DO", uppercase,
1013: LONG, 'l', "doxX", NULL,
1014: INT, 'l', "doxX", lax,
1015: ULONG, '\0', "uoxX", lax,
1016: ULONG, '\0', "UO", uppercase,
1017: ULONG, 'l', "uoxX", NULL,
1018: UNSIGNED, 'l', "uoxX", lax,
1019: FLOAT, '\0', "eEfgG", NULL,
1020: DOUBLE, '\0', "eEfgG", NULL,
1021: PTR|CHAR, '\0', "s", NULL,
1022: UNDEF, '\0', NULL, NULL,
1023: };
1024:
1025: /*
1026: ** Portable scanf. 'l' and 'h' are universally ignored preceding 'c' and 's',
1027: ** and 'h' is universally ignored preceding 'e' and 'f',
1028: ** but you won't find such cruft here.
1029: */
1030:
1031: static struct entry pscanf[] = {
1032: INT, '\0', "dox", NULL,
1033: UNSIGNED, '\0', "uox", NULL,
1034: CHAR, '\0', "cs[", NULL,
1035: SHORT, 'h', "dox", NULL,
1036: USHORT, 'h', "uox", NULL,
1037: LONG, 'l', "dox", NULL,
1038: ULONG, 'l', "uox", NULL,
1039: FLOAT, '\0', "ef", NULL, /* BSD doesn't handle g */
1040: DOUBLE, 'l', "ef", NULL,
1041: UNDEF, '\0', NULL, NULL,
1042: };
1043:
1044: /*
1045: ** Berkeley scanf. An upper case letter equals an l plus the lower case char,
1046: ** but this is deprecated.
1047: ** Even though sizeof (int) == sizeof (long), we'll be picky here.
1048: */
1049:
1050: static struct entry bscanf[] = {
1051: INT, '\0', "dox", NULL,
1052: UNSIGNED, '\0', "uox", NULL,
1053: CHAR, '\0', "cs[", NULL,
1054: SHORT, 'h', "dox", NULL,
1055: USHORT, 'h', "uox", NULL,
1056: LONG, '\0', "dox", lax,
1057: LONG, '\0', "DOX", uppercase,
1058: LONG, 'l', "dox", NULL,
1059: ULONG, '\0', "uox", lax,
1060: ULONG, '\0', "UOX", uppercase,
1061: ULONG, 'l', "uox", NULL,
1062: FLOAT, '\0', "ef", NULL,
1063: DOUBLE, '\0', "EF", uppercase,
1064: DOUBLE, 'l', "ef", NULL,
1065: UNDEF, '\0', NULL, NULL,
1066: };
1067:
1068: static struct item {
1069: char * name; /* such as "printf" */
1070: int isscan; /* scanf/printf */
1071: int fmtarg; /* number of format argument */
1072: struct entry * ptable; /* portable checking table */
1073: struct entry * btable; /* berkeley checking table */
1074: } items[] = {
1075: "printf", 0, 1, pprintf, bprintf,
1076: "fprintf", 0, 2, pprintf, bprintf,
1077: "sprintf", 0, 2, pprintf, bprintf,
1078: "scanf", 1, 1, pscanf, bscanf,
1079: "fscanf", 1, 2, pscanf, bscanf,
1080: "sscanf", 1, 2, pscanf, bscanf,
1081: NULL, -1, -1, NULL, NULL
1082: };
1083:
1084: static char pwf[] = "possible wild format";
1085: static char pfacm[] = "possible format/argument count mismatch";
1086:
1087: static struct entry *
1088: findlc(ep, lchar, cchar)
1089: register struct entry * ep;
1090: register int lchar;
1091: register int cchar;
1092: {
1093: for ( ; ep->argtype != UNDEF; ++ep)
1094: if (ep->lchar == lchar && strchr(ep->cchars, cchar) != 0)
1095: return ep;
1096: return NULL;
1097: }
1098:
1099: static char *
1100: subform(p, sp, acount)
1101: register NODE * p;
1102: register struct symtab * sp;
1103: {
1104: register int i, j, isscan;
1105: register NODE * tp;
1106: register char * cp;
1107: register struct entry * basep;
1108: register struct entry * ep;
1109: register struct item * ip;
1110: register int lchar;
1111: register int cchar;
1112: register int t;
1113: register int suppressed;
1114: static char errbuf[132];
1115:
1116: if (nflag || strapped)
1117: return NULL;
1118: cp = sp->sname;
1119: for (ip = items; ; ++ip)
1120: if (ip->name == NULL)
1121: return NULL; /* not a print/scan function */
1122: else if (strcmp(ip->name, sp->sname) == 0)
1123: break;
1124: isscan = ip->isscan;
1125: i = ip->fmtarg;
1126: if (i > acount)
1127: return NULL; /* handled in pass 2 */
1128: tp = ntharg(p, i, acount);
1129: if (tp->in.type != (PTR|CHAR))
1130: return NULL; /* handled in pass 2 */
1131: if (tp->in.op != ICON || tp->tn.lval != 0)
1132: return NULL; /* can't check it */
1133: for (j = 1; j <= subscr; ++j)
1134: if (tp == strnodes[j])
1135: break;
1136: if (j > subscr)
1137: return NULL; /* oh well. . . */
1138: cp = strings[j];
1139: /*
1140: ** cp now points to format string.
1141: */
1142: /*
1143: ** For now, ALWAYS use "portable" table, rather than doing this:
1144: ** basep = pflag ? ip->ptable : ip->btable;
1145: */
1146: basep = ip->ptable;
1147: for ( ; ; ) {
1148: if (*cp == '\0')
1149: return (i == acount) ? NULL : pfacm;
1150: if (*cp++ != '%')
1151: continue;
1152: if (*cp == '\0')
1153: return "wild trailing %% in format";
1154: if (*cp == '%') {
1155: ++cp;
1156: continue;
1157: }
1158: if (isscan) {
1159: suppressed = *cp == '*';
1160: if (suppressed)
1161: ++cp;
1162: while (isdigit(*cp))
1163: ++cp;
1164: if (!suppressed && ++i <= acount) {
1165: t = ntharg(p, i, acount)->in.type;
1166: if (!ISPTR(t)) {
1167: (void) sprintf(errbuf,
1168: "%s argument is type (%s) rather than pointer (arg %d)",
1169: ip->name, typestr(t), i);
1170: return errbuf;
1171: }
1172: t = DECREF(t);
1173: }
1174: } else {
1175: int nspace, ndash, nplus, nhash;
1176:
1177: suppressed = 0;
1178: nspace = ndash = nplus = nhash = 0;
1179: for ( ; ; ) {
1180: if (*cp == ' ')
1181: ++nspace;
1182: else if (*cp == '+')
1183: ++nplus;
1184: else if (*cp == '-')
1185: ++ndash;
1186: else if (*cp == '#')
1187: ++nhash;
1188: else break;
1189: ++cp;
1190: }
1191: if (nspace > 1 || ndash > 1 || nplus > 1 || nhash > 1)
1192: return "wild repeated flag character in format";
1193: if (*cp == '*') {
1194: ++cp;
1195: if (++i > acount)
1196: break;
1197: t = ntharg(p, i, acount)->in.type;
1198: /*
1199: ** Width other than INT or UNSIGNED is suspect.
1200: */
1201: if (t != INT && t != UNSIGNED) {
1202: (void) sprintf(errbuf,
1203: "field width argument is type (%s) rather than (int) (arg %d)",
1204: typestr(t), i);
1205: return errbuf;
1206: }
1207: } else while (isdigit(*cp))
1208: ++cp;
1209: if (*cp == '.') {
1210: ++cp;
1211: if (*cp == '*') {
1212: ++cp;
1213: if (++i > acount)
1214: return pfacm;
1215: t = ntharg(p, i, acount)->in.type;
1216: if (t != INT && t != UNSIGNED) {
1217: (void) sprintf(errbuf,
1218: "precision argument is type (%s) rather than (int) (arg %d)",
1219: typestr(t), i);
1220: return errbuf;
1221: }
1222: } else while (isdigit(*cp))
1223: ++cp;
1224: }
1225: if (++i <= acount)
1226: t = ntharg(p, i, acount)->in.type;
1227: }
1228: if (*cp == 'h' || *cp == 'l')
1229: lchar = *cp++;
1230: else lchar = '\0';
1231: if ((cchar = *cp++) == '\0')
1232: return pwf;
1233: if (i > acount)
1234: return (findlc(basep, lchar, cchar) == NULL) ?
1235: pwf : pfacm;
1236: if (!isscan && !pflag && ISPTR(t) &&
1237: strchr("douxX", cchar) != 0)
1238: continue; /* lax--printf("%d", (int *)) */
1239: if (suppressed) {
1240: if (findlc(basep, lchar, cchar) == NULL)
1241: return pwf;
1242: } else for (ep = basep; ; ++ep) {
1243: if (ep->argtype == UNDEF) { /* end of table */
1244: ep = findlc(basep, lchar, cchar);
1245: if (ep == NULL)
1246: return pwf;
1247: (void) sprintf(errbuf, "%s: (%s) format, (%s) arg (arg %d)",
1248: ip->name,
1249: typestr(ep->argtype),
1250: typestr(isscan ? (t | PTR) : t), i);
1251: return errbuf;
1252: }
1253: if (ep->argtype == t && ep->lchar == lchar &&
1254: strchr(ep->cchars, cchar) != 0)
1255: if (ep->werror == 0)
1256: break;
1257: else {
1258: werror(ep->werror, cchar);
1259: return NULL;
1260: }
1261: }
1262: if (cchar != '[')
1263: continue;
1264: do {
1265: if (*cp == '\0')
1266: return "possible unmatched '[' in format";
1267: } while (*cp++ != ']');
1268: }
1269: /*NOTREACHED*/
1270: }
1271:
1272: doform(p, sp, acount)
1273: NODE * p;
1274: struct symtab * sp;
1275: {
1276: char * cp;
1277:
1278: if ((cp = subform(p, sp, acount)) != NULL)
1279: werror(cp);
1280: }
1281:
1282: cisreg(t) TWORD t; {return(1);} /* everyting is a register variable! */
1283:
1284: fldty(p) struct symtab *p; {
1285: ; /* all types are OK here... */
1286: }
1287:
1288: fldal(t) unsigned t; { /* field alignment... */
1289: if( t == ENUMTY ) return( ALCHAR ); /* this should be thought through better... */
1290: if( ISPTR(t) ){ /* really for the benefit of honeywell (and someday IBM) */
1291: if( pflag ) uerror( "nonportable field type" );
1292: }
1293: else uerror( "illegal field type" );
1294: return(ALINT);
1295: }
1296:
1297: main(argc, argv)
1298: int argc;
1299: char **argv;
1300: {
1301: extern char *optarg;
1302: extern int optind;
1303: int ch;
1304:
1305: while ((ch = getopt(argc,argv,"C:D:I:U:LX:Pabchnpuvxz")) != EOF)
1306: switch((char)ch) {
1307: case 'C':
1308: Cflag = 1;
1309: libname = optarg;
1310: continue;
1311: case 'D': /* #define */
1312: case 'I': /* include path */
1313: case 'U': /* #undef */
1314: case 'X': /* debugging, done in first pass */
1315: case 'P': /* debugging, done in second pass */
1316: break;
1317: case 'L':
1318: libflag = 1;
1319: /*FALLTHROUGH*/
1320: case 'v': /* unused arguments in functions */
1321: vflag = 0;
1322: break;
1323: case 'a': /* long to int assignment */
1324: ++aflag;
1325: break;
1326: case 'b': /* unreached break statements */
1327: brkflag = 1;
1328: break;
1329: case 'c': /* questionable casts */
1330: cflag = 1;
1331: break;
1332: case 'h': /* heuristics */
1333: hflag = 1;
1334: break;
1335: case 'n': /* standard library check */
1336: nflag = 1;
1337: break;
1338: case 'p': /* IBM & GCOS portability */
1339: pflag = 1;
1340: break;
1341: case 'u': /* 2nd pass: undefined or unused */
1342: break;
1343: case 'x': /* unused externs */
1344: xflag = 1;
1345: break;
1346: case 'z': /* use of undefined structures */
1347: zflag = 1;
1348: break;
1349: case '?':
1350: default:
1351: fputs("usage: lint [-C lib] [-D def] [-I include] [-U undef] [-Labchnpuvx] file ...\n",stderr);
1352: exit(1);
1353: }
1354:
1355: if (!pflag) { /* set sizes to sizes of target machine */
1356: # ifdef gcos
1357: SZCHAR = ALCHAR = 9;
1358: # else
1359: SZCHAR = ALCHAR = 8;
1360: # endif
1361: SZINT = ALINT = sizeof(int)*SZCHAR;
1362: SZFLOAT = ALFLOAT = sizeof(float)*SZCHAR;
1363: SZDOUBLE = ALDOUBLE = sizeof(double)*SZCHAR;
1364: SZLONG = ALLONG = sizeof(long)*SZCHAR;
1365: SZSHORT = ALSHORT = sizeof(short)*SZCHAR;
1366: SZPOINT = ALPOINT = sizeof(int *)*SZCHAR;
1367: ALSTRUCT = ALINT;
1368: /* now, fix some things up for various machines (I wish we had "alignof") */
1369:
1370: # ifdef pdp11
1371: ALLONG = ALDOUBLE = ALFLOAT = ALINT;
1372: # endif
1373: # ifdef ibm
1374: ALSTRUCT = ALCHAR;
1375: # endif
1376: }
1377: return(mainp1(argc,argv));
1378: }
1379:
1380: ctype( type ) unsigned type; { /* are there any funny types? */
1381: return( type );
1382: }
1383:
1384: commdec( i ){
1385: /* put out a common declaration */
1386: if( stab[i].sclass == STATIC ) outdef( &stab[i], LST, USUAL );
1387: else outdef( &stab[i], libflag?LIB:LDC, USUAL );
1388: }
1389:
1390: isitfloat ( s ) char *s; {
1391: /* s is a character string;
1392: if floating point is implemented, set dcon to the value of s */
1393: /* lint version
1394: */
1395: dcon = atof( s );
1396: return( DCON );
1397: }
1398:
1399: fldcon( p ) register NODE *p; {
1400: /* p is an assignment of a constant to a field */
1401: /* check to see if the assignment is going to overflow, or otherwise cause trouble */
1402: register s;
1403: CONSZ v;
1404:
1405: if( !hflag & !pflag ) return;
1406:
1407: s = UPKFSZ(p->in.left->tn.rval);
1408: v = p->in.right->tn.lval;
1409:
1410: switch( p->in.left->in.type ){
1411:
1412: case CHAR:
1413: case INT:
1414: case SHORT:
1415: case LONG:
1416: case ENUMTY:
1417: if( v>=0 && (v>>(s-1))==0 ) return;
1418: werror( "precision lost in assignment to (possibly sign-extended) field" );
1419: default:
1420: return;
1421:
1422: case UNSIGNED:
1423: case UCHAR:
1424: case USHORT:
1425: case ULONG:
1426: if( v<0 || (v>>s)!=0 ) werror( "precision lost in field assignment" );
1427:
1428: return;
1429: }
1430:
1431: }
1432:
1433: outdef( p, lty, mode ) struct symtab *p; {
1434: /* output a definition for the second pass */
1435: /* if mode is > USUAL, it is the number of args */
1436: char *fname;
1437: TWORD t;
1438: int line;
1439: static union rec rc;
1440:
1441: if( mode == NOFILE ){
1442: fname = "???";
1443: line = p->suse;
1444: }
1445: else if( mode == SVLINE ){
1446: fname = ftitle;
1447: line = -p->suse;
1448: }
1449: else {
1450: fname = ftitle;
1451: line = lineno;
1452: }
1453: fsave( fname );
1454: #ifndef FLEXNAMES
1455: strncpy( rc.l.name, exname(p->sname), LCHNM );
1456: #endif
1457: rc.l.decflag = lty;
1458: t = p->stype;
1459: if( mode == DECTY ) t = DECREF(t);
1460: rc.l.type.aty = t;
1461: rc.l.type.extra = 0;
1462: rc.l.type.extra1 = 0;
1463: astype( &rc.l.type, p->sizoff );
1464: rc.l.nargs = (mode>USUAL) ? mode : 0;
1465: rc.l.fline = line;
1466: fwrite( (char *)&rc, sizeof(rc), 1, stdout );
1467: #ifdef FLEXNAMES
1468: rc.l.name = exname(p->sname);
1469: fwrite( rc.l.name, strlen(rc.l.name)+1, 1, stdout );
1470: #endif
1471: }
1472: int proflg;
1473: int gdebug;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.