Bell 32V release
[unix-history] / usr / src / cmd / lint / lpass2.c
CommitLineData
8f3f849b
TL
1# include "lmanifest"
2# include "manifest"
3
4# define USED 01
5# define VUSED 02
6# define EUSED 04
7# define RVAL 010
8# define VARARGS 0100
9
10typedef struct { TWORD aty; int extra; } atype;
11
12struct line {
13 char name[8];
14 int decflag;
15 atype type;
16 int nargs;
17 atype atyp[50];
18 int fline;
19 char file[100];
20 }
21
22 l1,
23 l2,
24 *pd, /* pointer to line having definition */
25 *pc, /* pointer to current line read */
26 *p3; /* used for swapping pc and pd */
27
28int uses = USED;
29int hflag = 0;
30int pflag = 0;
31int xflag = 0;
32int uflag = 1;
33
34
35main( argc, argv ) char *argv[]; {
36
37 register char *p;
38
39 /* first argument is - options */
40
41 if( argc>=2 && argv[1][0] == '-' ){
42 for( p=argv[1]; *p; ++p ){
43 switch( *p ){
44
45 case 'h':
46 hflag = 1;
47 break;
48
49 case 'p':
50 pflag = 1;
51 break;
52
53 case 'x':
54 xflag = 1;
55 break;
56
57 case 'u':
58 uflag = 0;
59 break;
60
61 }
62 }
63 }
64
65
66
67 pd = &l1;
68 pc = &l2;
69 pd->name[0] = '\0' ;
70 pd->fline = 0;
71 pd->file[0] = '\0';
72 pd->decflag = LDI;
73
74 /* main loop: read a line;
75 if same as last line, check compatibility
76 if not same as last line, becomes df.
77 */
78
79 for(;;){
80 lread();
81 if( steq(pc->name, pd->name) ) chkcompat();
82 else {
83 lastone();
84 setuse();
85 p3=pc;
86 pc = pd;
87 pd = p3;
88 }
89 }
90
91 }
92
93lread(){ /* read a line into pc */
94
95 register i, n;
96
97 getnam( pc->name );
98
99 pc->decflag = rdin10();
100 rdinty( &pc->type );
101 n = pc->nargs = rdin10();
102 if( n<0 ) n = -n;
103
104 for( i=0; i<n; ++i ){
105 rdinty( &pc->atyp[i] );
106 }
107
108 getnam( pc->file );
109 pc->fline = rdin10();
110
111 while( getchar() != '\n' ) ; /* VOID */
112 }
113
114rdin10(){
115 register val, c, s;
116
117 val = 0;
118 s = 1;
119
120 while( (c=getchar()) != '\t' ){
121 if( c <= 0 ) error( "unexpected EOF" );
122 else if( c == '-' ) {
123 s = -1;
124 continue;
125 }
126 else if( c<'0' || c>'9' ) {
127 error("rotten digit: %o\n", c );
128 }
129 val = val*10 + c - '0';
130 }
131 return( val*s );
132 }
133
134rdinty( p ) atype *p; {
135 register val, c, s;
136
137 val = 0;
138 s = 1;
139
140 while( (c=getchar()) != '\t' && c!= '<' ){
141 if( c <= 0 ) error( "unexpected EOF" );
142 else if( c == '-' ) {
143 s = -1;
144 continue;
145 }
146 else if( c<'0' || c>'7' ) {
147 error("rotten digit: %o\n", c );
148 }
149 val = (val<<3) + c - '0';
150 }
151 p->aty = val*s;
152 if( c == '<' ) p->extra = rdin10();
153 else p->extra = 0;
154 }
155
156getnam(p) char *p; {
157 register c;
158 while( (c=getchar()) != '\t' ){
159 if( c == '\n' ) error( "rotten name\n" );
160 if( c <= 0 ) cleanup();
161 *p++ = c;
162 }
163 *p = '\0';
164 }
165
166/* VARARGS */
167error( s, a ) char *s; {
168
169 fprintf( stderr, "pass 2 error: " );
170 fprintf( stderr, s, a );
171 fprintf( stderr, "\n" );
172 exit(1);
173 }
174
175steq(p,q) char *p,*q; { /* check that the p and q names are the same */
176
177
178 while( *p == *q ){
179 if( *p == 0 ) return(1);
180 ++p;
181 ++q;
182 }
183
184 return(0);
185 }
186
187chkcompat(){
188 /* are the types, etc. in pc and pd compatible */
189 register int i;
190
191 setuse();
192
193 /* argument check */
194
195 if( pd->decflag & (LDI|LIB|LUV|LUE) ){
196 if( pc->decflag & (LUV|LIB|LUE) ){
197 if( pd->nargs != pc->nargs ){
198 if( !(uses&VARARGS) ){
199 printf( "%.7s: variable # of args.", pd->name );
200 viceversa();
201 }
202 if( pc->nargs > pd->nargs ) pc->nargs = pd->nargs;
203 if( !(pd->decflag & (LDI|LIB) ) ) {
204 pd->nargs = pc->nargs;
205 uses |= VARARGS;
206 }
207 }
208 for( i=0; i<pc->nargs; ++i ){
209 if( chktype(&pd->atyp[i], &pc->atyp[i]) ){
210 printf( "%.7s, arg. %d used inconsistently",
211 pd->name, i+1 );
212 viceversa();
213 }
214 }
215 }
216 }
217
218 if( (pd->decflag&(LDI|LIB|LUV)) && pc->decflag==LUV ){
219 if( chktype( &pc->type, &pd->type ) ){
220 printf( "%.7s value used inconsistently", pd->name );
221 viceversa();
222 }
223 }
224
225 /* check for multiple declaration */
226
227 if( (pd->decflag&LDI) && (pc->decflag&(LDI|LIB)) ){
228 printf( "%.7s multiply declared", pd->name );
229 viceversa();
230 }
231
232 /* do a bit of checking of definitions and uses... */
233
234 if( (pd->decflag & (LDI|LIB|LDX|LDC)) && (pc->decflag & (LDX|LDC)) && pd->type.aty != pc->type.aty ){
235 printf( "%.7s value declared inconsistently", pd->name );
236 viceversa();
237 }
238
239 /* better not call functions which are declared to be structure or union returning */
240
241 if( (pd->decflag & (LDI|LIB|LDX|LDC)) && (pc->decflag & LUE) && pd->type.aty != pc->type.aty ){
242 /* only matters if the function returns union or structure */
243 TWORD ty;
244 ty = pd->type.aty;
245 if( ISFTN(ty) && ((ty = DECREF(ty))==STRTY || ty==UNIONTY ) ){
246 printf( "%.7s function value type must be declared before use", pd->name );
247 viceversa();
248 }
249 }
250
251 if( pflag && pd->decflag==LDX && pc->decflag == LUM && !ISFTN(pd->type.aty) ){
252 /* make the external declaration go away */
253 /* in effect, it was used without being defined */
254
255 /* swap pc and pd */
256 p3 = pc;
257 pc = pd;
258 pd = p3;
259 }
260
261 }
262
263viceversa(){
264 /* print out file comparison */
265 printf( " %s(%d) :: %s(%d)\n", pd->file, pd->fline, pc->file, pc->fline );
266 }
267
268 /* messages for defintion/use */
269char *
270mess[2][2] = {
271 "",
272 "%.7s used( %s(%d) ), but not defined\n",
273 "%.7s defined( %s(%d) ), but never used\n",
274 "%.7s declared( %s(%d) ), but never used or defined\n"
275 };
276
277lastone(){
278
279 /* called when pc and pd are at last different */
280 register nu, nd;
281
282 nu = nd = 0;
283
284 if( !(uses&USED) && pd->decflag != LIB ) {
285 if( !steq(pd->name,"main") )
286 nu = 1;
287 }
288
289 if( !ISFTN(pd->type.aty) ){
290 switch( pd->decflag ){
291
292 case LIB:
293 nu = nd = 0; /* don't complain about uses on libraries */
294 break;
295 case LDX:
296 if( !xflag ) break;
297 case LUV:
298 case LUE:
299 case LUM:
300 nd = 1;
301 }
302 }
303
304 if( uflag && ( nu || nd ) ) printf( mess[nu][nd], pd->name, pd->file, pd->fline );
305
306 if( (uses&(RVAL+EUSED)) == (RVAL+EUSED) ){
307 printf( "%.7s returns value which is %s ignored\n", pd->name,
308 uses&VUSED ? "sometimes" : "always" );
309 }
310
311 if( (uses&(RVAL+VUSED)) == (VUSED) && (pd->decflag&(LDI|LIB)) ){
312 printf( "%.7s value is used, but none returned\n", pd->name );
313 }
314
315 /* clean up pc, in preparation for the next thing */
316
317 uses = 0;
318 if( pc->nargs < 0 ){
319 pc->nargs = -pc->nargs;
320 uses = VARARGS;
321 }
322
323 }
324
325cleanup(){ /* call lastone and die gracefully */
326 lastone();
327 exit(0);
328 }
329
330setuse(){ /* check new type to ensure that it is used */
331
332 switch( pc->decflag ){
333
334 case LRV:
335 uses |= RVAL;
336 return;
337 case LUV:
338 uses |= VUSED+USED;
339 return;
340 case LUE:
341 uses |= EUSED+USED;
342 return;
343 case LUM:
344 uses |= USED;
345 return;
346
347 }
348 }
349
350chktype( pt1, pt2 ) register atype *pt1, *pt2; {
351
352 /* check the two type words to see if they are compatible */
353 /* for the moment, enums are turned into ints, and should be checked as such */
354 if( pt1->aty == ENUMTY ) pt1->aty = INT;
355 if( pt2->aty == ENUMTY ) pt2->aty = INT;
356
357 if( pt2->extra ){ /* constant passed in */
358 if( pt1->aty == UNSIGNED && pt2->aty == INT ) return( 0 );
359 else if( pt1->aty == ULONG && pt2->aty == LONG ) return( 0 );
360 }
361 else if( pt1->extra ){ /* for symmetry */
362 if( pt2->aty == UNSIGNED && pt1->aty == INT ) return( 0 );
363 else if( pt2->aty == ULONG && pt1->aty == LONG ) return( 0 );
364 }
365
366 return( pt1->aty != pt2->aty );
367 }