BSD 4_3_Tahoe release
[unix-history] / usr / src / usr.bin / lint / lint.c
CommitLineData
13d26355 1#ifndef lint
ca67e7b4 2static char sccsid[] = "@(#)lint.c 1.14 (Berkeley) 12/11/87";
13d26355
RH
3#endif lint
4
7184b3eb 5# include "pass1.h"
13d26355 6
7184b3eb 7# include "lmanifest.h"
13d26355
RH
8
9# include <ctype.h>
10
11# define VAL 0
12# define EFF 1
13
14/* these are appropriate for the -p flag */
15int SZCHAR = 8;
16int SZINT = 16;
17int SZFLOAT = 32;
18int SZDOUBLE = 64;
19int SZLONG = 32;
20int SZSHORT = 16;
21int SZPOINT = 16;
22int ALCHAR = 8;
23int ALINT = 16;
24int ALFLOAT = 32;
25int ALDOUBLE = 64;
26int ALLONG = 32;
27int ALSHORT = 16;
28int ALPOINT = 16;
29int ALSTRUCT = 16;
30
476534cd
KB
31int nflag = 0; /* avoid gripes about printf et al. */
32int vflag = 1; /* tell about unused argments */
33int xflag = 0; /* tell about unused externals */
34int argflag = 0; /* used to turn off complaints about arguments */
35int libflag = 0; /* used to generate library descriptions */
36int vaflag = -1; /* signal functions with a variable number of args */
37int aflag = 0; /* used to check precision of assignments */
38int zflag = 0; /* no 'structure never defined' error */
39int Cflag = 0; /* filter out certain output, for generating libraries */
40char *libname = 0; /* name of the library we're generating */
41
42 /* flags for the "outdef" function */
13d26355
RH
43# define USUAL (-101)
44# define DECTY (-102)
45# define NOFILE (-103)
46# define SVLINE (-104)
47
48# define LNAMES 250
49
50struct lnm {
51 short lid, flgs;
52 } lnames[LNAMES], *lnp;
53
54contx( 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
99ecode( p ) NODE *p; {
100 /* compile code for p */
101
102 fwalk( p, contx, EFF );
103 lnp = lnames;
104 lprt( p, EFF, 0 );
476534cd 105 strforget();
13d26355
RH
106 }
107
108ejobcode( 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 ){
bbc65794
EW
119 if( !zflag && dimtab[p->sizoff+1] < 0 ){
120 /* never defined */
13d26355
RH
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 }
d44c5e20
PN
144 /* no statics in libraries */
145 if( Cflag ) break;
13d26355
RH
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
168astype( t, i ) ATYPE *t; {
169 TWORD tt;
bbc65794 170 int j, k=0, l=0;
13d26355
RH
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 ){
bbc65794
EW
179 k = dimtab[i];
180 l = X_NONAME | stab[j].suse;
13d26355
RH
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 }
bbc65794
EW
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 }
13d26355
RH
199 }
200 }
201
202 t->extra = k;
bbc65794 203 t->extra1 = l;
13d26355
RH
204 return( 1 );
205 }
206 else return( 0 );
207 }
208
209bfcode( 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
476534cd 217 strforget();
13d26355 218 retlab = 1;
d44c5e20 219
13d26355
RH
220 cfp = &stab[curftn];
221
d44c5e20
PN
222 /* if creating library, don't do static functions */
223 if( Cflag && cfp->sclass == STATIC ) return;
224
13d26355 225 /* if variable number of arguments, only print the ones which will be checked */
6b3507db 226 if( vaflag >= 0 ){
13d26355
RH
227 if( n < vaflag ) werror( "declare the VARARGS arguments you want checked!" );
228 else n = vaflag;
229 }
230 fsave( ftitle );
6b3507db
DS
231 if( cfp->sclass == STATIC ) outdef( cfp, LST, vaflag>=0?~n:n );
232 else outdef( cfp, libflag?LIB:LDI, vaflag>=0?~n:n );
13d26355
RH
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;
bbc65794 240 t.extra1 = 0;
13d26355
RH
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
265ctargs( 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
277lpta( 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);
bbc65794 287 t.extra1 = 0;
13d26355 288
7184b3eb 289 if( !astype( &t, p->fn.csiz ) ) {
13d26355
RH
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
324lprt( 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;
d44c5e20
PN
410
411 fsave( ftitle );
d105ff1f 412 if (!nflag)
476534cd 413 doform(p, sp, acount);
d44c5e20
PN
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;
13d26355
RH
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 }
d44c5e20 433 outdef( sp, lty, acount );
13d26355
RH
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 ){
bbc65794 454 if( !ISARY(q->stype ) && !ISFTN(q->stype) && q->stype!=STRTY && q->stype!=UNIONTY ){
13d26355
RH
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
501lmerge( 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
544efcode(){
545 /* code for the end of a function */
546 register struct symtab *cfp;
547
548 cfp = &stab[curftn];
d44c5e20
PN
549 if( retstat & RETVAL && !(Cflag && cfp->sclass==STATIC) )
550 outdef( cfp, LRV, DECTY );
13d26355
RH
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
563aocode(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 ){
bbc65794 598 if( !zflag && dimtab[p->sizoff+1] < 0 )
13d26355 599#ifndef FLEXNAMES
bbc65794 600 werror( "structure %.8s never defined", p->sname );
13d26355 601#else
bbc65794 602 werror( "structure %s never defined", p->sname );
13d26355
RH
603#endif
604 }
605
606 }
607
608defnam( p ) register struct symtab *p; {
609 /* define the current location as the name p->sname */
610
d44c5e20 611 if( p->sclass == STATIC && (p->slevel>1 || Cflag) ) return;
13d26355 612
bbc65794
EW
613 if( !ISFTN( p->stype ) )
614 if( p->sclass == STATIC ) outdef( p, LST, USUAL );
615 else outdef( p, libflag?LIB:LDI, USUAL );
13d26355
RH
616 }
617
618zecode( n ){
619 /* n integer words of zeros */
620 OFFSZ temp;
621 temp = n;
622 inoff += temp*SZINT;
623 ;
624 }
625
626andable( 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
642NODE *
643clocal(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;
a72909f3 659 int s;
13d26355
RH
660
661 switch( o = p->in.op ){
476534cd
KB
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;
13d26355
RH
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;
c1881ef2 682 if( aflag && (tl==LONG||tl==ULONG) && (t!=LONG&&t!=ULONG&&t!=UNDEF) ){
13d26355
RH
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
a72909f3
DS
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
13d26355
RH
732 }
733
734 return(p);
735 }
736
737NODE *
738offcon( 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
745noinit(){
746 /* storage class for such as "int a;" */
747 return( pflag ? EXTDEF : EXTERN );
748 }
749
750
751cinit( p, sz ) NODE *p; { /* initialize p into size sz */
6b3507db
DS
752 register int id;
753
13d26355
RH
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
762char *
763exname( 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
778char *
779strip(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;
cd93e144 786 static int stripping = 0;
13d26355 787
cd93e144
RH
788 if (stripping)
789 return(s);
790 stripping++;
13d26355 791 for( p=x; *s; ++s ){
cd93e144 792 if( *s != '"' ){
13d26355
RH
793#ifndef FLEXNAMES
794/* PATCHED by ROBERT HENRY on 8Jul80 to fix 14 character file name bug */
795 if( p >= &x[LFNM] )
d44c5e20
PN
796#else
797 if( p >= &x[BUFSIZ] )
13d26355 798#endif
d44c5e20 799 cerror( "filename too long" );
13d26355
RH
800 *p++ = *s;
801 }
802 }
cd93e144 803 stripping = 0;
13d26355
RH
804 *p = '\0';
805#ifndef FLEXNAMES
806 return( x );
807#else
808 return( hash(x) );
809#endif
810 }
811
812fsave( s ) char *s; {
813 static union rec fsname;
814 s = strip( s );
815#ifndef FLEXNAMES
7e84ad26 816 if( strncmp( s, fsname.f.fn, LFNM ) )
13d26355 817#else
7e84ad26 818 if (fsname.f.fn == NULL || strcmp(s, fsname.f.fn))
13d26355 819#endif
7e84ad26 820 {
13d26355
RH
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
d44c5e20
PN
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 }
13d26355
RH
836 fwrite( fsname.f.fn, strlen(fsname.f.fn)+1, 1, stdout );
837#endif
838 }
839 }
840
841where(f){ /* print true location of error */
cd93e144
RH
842 if( f == 'u' && nerrors > 1 )
843 --nerrors; /* don't get "too many errors" */
844 fprintf( stderr, "%s(%d): ", strip(ftitle), lineno);
13d26355
RH
845 }
846
847 /* a number of dummy routines, unneeded by lint */
848
849branch(n){;}
850defalign(n){;}
851deflab(n){;}
476534cd
KB
852
853extern 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
862static char * strings[SBUFSIZE];
863static NODE * strnodes[SBUFSIZE];
864static int didstr;
865static int subscr;
866static int strapped;
867
868bycode(t, i)
869{
870 extern char * calloc();
871 extern char * realloc();
872
d105ff1f 873 if (nflag || strapped)
476534cd
KB
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
893strforget()
894{
895 didstr = subscr = 0;
896}
897
898static char *
899typestr(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
933NODE *
934ntharg(p, n, acount)
935NODE * p;
936register int n;
937register 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
949struct 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
964static 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
992static char uppercase[] = "deprecated upper-case control character (%c)";
993#define lax NULL
994
995static 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
1031static 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
1050static 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
1068static 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
1084static char pwf[] = "possible wild format";
1085static char pfacm[] = "possible format/argument count mismatch";
1086
1087static struct entry *
1088findlc(ep, lchar, cchar)
1089register struct entry * ep;
1090register int lchar;
1091register 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
1099static char *
1100subform(p, sp, acount)
1101register NODE * p;
1102register 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
d105ff1f 1116 if (nflag || strapped)
476534cd
KB
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 */
d105ff1f
KB
1142 /*
1143 ** For now, ALWAYS use "portable" table, rather than doing this:
1144 ** basep = pflag ? ip->ptable : ip->btable;
1145 */
1146 basep = ip->ptable;
476534cd
KB
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
1272doform(p, sp, acount)
1273NODE * p;
1274struct symtab * sp;
1275{
1276 char * cp;
1277
1278 if ((cp = subform(p, sp, acount)) != NULL)
1279 werror(cp);
1280}
1281
13d26355
RH
1282cisreg(t) TWORD t; {return(1);} /* everyting is a register variable! */
1283
1284fldty(p) struct symtab *p; {
1285 ; /* all types are OK here... */
1286 }
1287
1288fldal(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
476534cd
KB
1297main(argc, argv)
1298 int argc;
1299 char **argv;
1300{
1301 extern char *optarg;
1302 extern int optind;
1303 int ch;
13d26355 1304
6b3507db 1305 while ((ch = getopt(argc,argv,"C:D:I:U:LX:Pabchnpuvxz")) != EOF)
476534cd
KB
1306 switch((char)ch) {
1307 case 'C':
1308 Cflag = 1;
1309 libname = optarg;
d44c5e20 1310 continue;
476534cd
KB
1311 case 'D': /* #define */
1312 case 'I': /* include path */
1313 case 'U': /* #undef */
6b3507db 1314 case 'X': /* debugging, done in first pass */
476534cd 1315 case 'P': /* debugging, done in second pass */
d44c5e20 1316 break;
d44c5e20
PN
1317 case 'L':
1318 libflag = 1;
476534cd
KB
1319 /*FALLTHROUGH*/
1320 case 'v': /* unused arguments in functions */
d44c5e20 1321 vflag = 0;
476534cd
KB
1322 break;
1323 case 'a': /* long to int assignment */
d44c5e20 1324 ++aflag;
476534cd
KB
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 */
bbc65794 1347 zflag = 1;
476534cd
KB
1348 break;
1349 case '?':
d44c5e20 1350 default:
476534cd
KB
1351 fputs("usage: lint [-C lib] [-D def] [-I include] [-U undef] [-Labchnpuvx] file ...\n",stderr);
1352 exit(1);
1353 }
13d26355 1354
476534cd 1355 if (!pflag) { /* set sizes to sizes of target machine */
13d26355
RH
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;
476534cd 1372# endif
13d26355
RH
1373# ifdef ibm
1374 ALSTRUCT = ALCHAR;
476534cd 1375# endif
13d26355 1376 }
476534cd
KB
1377 return(mainp1(argc,argv));
1378}
13d26355
RH
1379
1380ctype( type ) unsigned type; { /* are there any funny types? */
1381 return( type );
1382 }
1383
1384commdec( i ){
1385 /* put out a common declaration */
bbc65794
EW
1386 if( stab[i].sclass == STATIC ) outdef( &stab[i], LST, USUAL );
1387 else outdef( &stab[i], libflag?LIB:LDC, USUAL );
13d26355
RH
1388 }
1389
1390isitfloat ( 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 );
dfa87255 1396 return( DCON );
13d26355
RH
1397 }
1398
1399fldcon( 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
1433outdef( 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;
bbc65794 1462 rc.l.type.extra1 = 0;
13d26355
RH
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 }
1472int proflg;
1473int gdebug;