Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.bin / xlint / lint1 / emit1.c
1 /*      $NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo Exp $    */
2
3 /*
4  * Copyright (c) 1994, 1995 Jochen Pohl
5  * All Rights Reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Jochen Pohl for
18  *      The NetBSD Project.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * $NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo Exp $
34  */
35
36 #include <ctype.h>
37
38 #include "lint1.h"
39
40 static  void    outtt __P((sym_t *, sym_t *));
41 static  void    outfstrg __P((strg_t *));
42
43 /*
44  * Write type into the output buffer.
45  * The type is written as a sequence of substrings, each of which describes a
46  * node of type type_t
47  * a node is coded as follows:
48  *      char                    C
49  *      signed char             s C
50  *      unsigned char           u C
51  *      short                   S
52  *      unsigned short          u S
53  *      int                     I
54  *      unsigned int            u I
55  *      long                    L
56  *      unsigned long           u L
57  *      long long               Q
58  *      unsigned long long      u Q
59  *      float                   s D
60  *      double                  D
61  *      long double             l D
62  *      void                    V
63  *      *                       P
64  *      [n]                     A n
65  *      ()                      F
66  *      (void)                  F 0
67  *      (n arguments)           F n arg1 arg2 ... argn
68  *      (n arguments, ...)      F n arg1 arg2 ... argn-1 E
69  *      (a, b, c, ...)          f n arg1 arg2 ...
70  *      enum tag                e T tag_or_typename
71  *      struct tag              s T tag_or_typename
72  *      union tag               u T tag_or_typename
73  *
74  *      tag_or_typename         0                       no tag or type name
75  *                              1 n tag                 Tag
76  *                              2 n typename            only type name
77  *
78  * spaces are only for better readability
79  * additionaly it is possible to prepend the characters 'c' (for const)
80  * and 'v' (for volatile)
81  */
82 void
83 outtype(tp)
84         type_t  *tp;
85 {
86         int     t, s, na;
87         sym_t   *arg;
88         tspec_t ts;
89
90         while (tp != NULL) {
91                 if ((ts = tp->t_tspec) == INT && tp->t_isenum)
92                         ts = ENUM;
93                 switch (ts) {
94                 case CHAR:      t = 'C';        s = '\0';       break;
95                 case SCHAR:     t = 'C';        s = 's';        break;
96                 case UCHAR:     t = 'C';        s = 'u';        break;
97                 case SHORT:     t = 'S';        s = '\0';       break;
98                 case USHORT:    t = 'S';        s = 'u';        break;
99                 case INT:       t = 'I';        s = '\0';       break;
100                 case UINT:      t = 'I';        s = 'u';        break;
101                 case LONG:      t = 'L';        s = '\0';       break;
102                 case ULONG:     t = 'L';        s = 'u';        break;
103                 case QUAD:      t = 'Q';        s = '\0';       break;
104                 case UQUAD:     t = 'Q';        s = 'u';        break;
105                 case FLOAT:     t = 'D';        s = 's';        break;
106                 case DOUBLE:    t = 'D';        s = '\0';       break;
107                 case LDOUBLE:   t = 'D';        s = 'l';        break;
108                 case VOID:      t = 'V';        s = '\0';       break;
109                 case PTR:       t = 'P';        s = '\0';       break;
110                 case ARRAY:     t = 'A';        s = '\0';       break;
111                 case FUNC:      t = 'F';        s = '\0';       break;
112                 case ENUM:      t = 'T';        s = 'e';        break;
113                 case STRUCT:    t = 'T';        s = 's';        break;
114                 case UNION:     t = 'T';        s = 'u';        break;
115                 default:
116                         lerror("outtyp() 1");
117                 }
118                 if (tp->t_const)
119                         outchar('c');
120                 if (tp->t_volatile)
121                         outchar('v');
122                 if (s != '\0')
123                         outchar(s);
124                 outchar(t);
125                 if (ts == ARRAY) {
126                         outint(tp->t_dim);
127                 } else if (ts == ENUM) {
128                         outtt(tp->t_enum->etag, tp->t_enum->etdef);
129                 } else if (ts == STRUCT || ts == UNION) {
130                         outtt(tp->t_str->stag, tp->t_str->stdef);
131                 } else if (ts == FUNC && tp->t_proto) {
132                         na = 0;
133                         for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
134                                         na++;
135                         if (tp->t_vararg)
136                                 na++;
137                         outint(na);
138                         for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
139                                 outtype(arg->s_type);
140                         if (tp->t_vararg)
141                                 outchar('E');
142                 }
143                 tp = tp->t_subt;
144         }
145 }
146
147 /*
148  * type to string
149  * used for debugging output
150  *
151  * it uses its own output buffer for conversion
152  */
153 const char *
154 ttos(tp)
155         type_t  *tp;
156 {
157         static  ob_t    tob;
158         ob_t    tmp;
159
160         if (tob.o_buf == NULL) {
161                 tob.o_len = 64;
162                 tob.o_buf = tob.o_nxt = xmalloc(tob.o_len);
163                 tob.o_end = tob.o_buf + tob.o_len;
164         }
165
166         tmp = ob;
167         ob = tob;
168         ob.o_nxt = ob.o_buf;
169         outtype(tp);
170         outchar('\0');
171         tob = ob;
172         ob = tmp;
173
174         return (tob.o_buf);
175 }
176
177 /*
178  * write the name of a tag or typename
179  *
180  * if the tag is named, the name of the
181  * tag is written, otherwise, if a typename exists which
182  * refers to this tag, this typename is written
183  */
184 static void
185 outtt(tag, tdef)
186         sym_t   *tag, *tdef;
187 {
188         if (tag->s_name != unnamed) {
189                 outint(1);
190                 outname(tag->s_name);
191         } else if (tdef != NULL) {
192                 outint(2);
193                 outname(tdef->s_name);
194         } else {
195                 outint(0);
196         }
197 }
198
199 /*
200  * write information about an global declared/defined symbol
201  * with storage class extern
202  *
203  * informations about function definitions are written in outfdef(),
204  * not here
205  */
206 void
207 outsym(sym, sc, def)
208         sym_t   *sym;
209         scl_t   sc;
210         def_t   def;
211 {
212         /*
213          * Static function declarations must also be written to the output
214          * file. Compatibility of function declarations (for both static
215          * and extern functions) must be checked in lint2. Lint1 can't do
216          * this, especially not, if functions are declared at block level
217          * before their first declaration at level 0.
218          */
219         if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
220                 return;
221
222         /* reset buffer */
223         outclr();
224
225         /*
226          * line number of .c source, 'd' for declaration, Id of current
227          * source (.c or .h), and line in current source.
228          */
229         outint(csrc_pos.p_line);
230         outchar('d');
231         outint(getfnid(sym->s_dpos.p_file));
232         outchar('.');
233         outint(sym->s_dpos.p_line);
234
235         /* flags */
236
237         switch (def) {
238         case DEF:
239                 /* defined */
240                 outchar('d');
241                 break;
242         case TDEF:
243                 /* tentative defined */
244                 outchar('t');
245                 break;
246         case DECL:
247                 /* declared */
248                 outchar('e');
249                 break;
250         default:
251                 lerror("outsym() 2");
252         }
253         if (llibflg && def != DECL) {
254                 /*
255                  * mark it as used so we get no warnings from lint2 about
256                  * unused symbols in libraries.
257                  */
258                 outchar('u');
259         }
260
261         if (sc == STATIC)
262                 outchar('s');
263
264         /* name of the symbol */
265         outname(sym->s_name);
266
267         /* type of the symbol */
268         outtype(sym->s_type);
269 }
270
271 /*
272  * write information about function definition
273  *
274  * this is also done for static functions so we are able to check if
275  * they are called with proper argument types
276  */
277 void
278 outfdef(fsym, posp, rval, osdef, args)
279         sym_t   *fsym, *args;
280         pos_t   *posp;
281         int     rval, osdef;
282 {
283         int     narg;
284         sym_t   *arg;
285
286         /* reset the buffer */
287         outclr();
288
289         /*
290          * line number of .c source, 'd' for declaration, Id of current
291          * source (.c or .h), and line in current source
292          *
293          * we are already at the end of the function. If we are in the
294          * .c source, posp->p_line is correct, otherwise csrc_pos.p_line
295          * (for functions defined in header files).
296          */
297         if (posp->p_file == csrc_pos.p_file) {
298                 outint(posp->p_line);
299         } else {
300                 outint(csrc_pos.p_line);
301         }
302         outchar('d');
303         outint(getfnid(posp->p_file));
304         outchar('.');
305         outint(posp->p_line);
306
307         /* flags */
308
309         /* both SCANFLIKE and PRINTFLIKE imply VARARGS */
310         if (prflstrg != -1) {
311                 nvararg = prflstrg;
312         } else if (scflstrg != -1) {
313                 nvararg = scflstrg;
314         }
315
316         if (nvararg != -1) {
317                 outchar('v');
318                 outint(nvararg);
319         }
320         if (scflstrg != -1) {
321                 outchar('S');
322                 outint(scflstrg);
323         }
324         if (prflstrg != -1) {
325                 outchar('P');
326                 outint(prflstrg);
327         }
328         nvararg = prflstrg = scflstrg = -1;
329
330         outchar('d');
331
332         if (rval)
333                 /* has return value */
334                 outchar('r');
335
336         if (llibflg)
337                 /*
338                  * mark it as used so lint2 does not complain about
339                  * unused symbols in libraries
340                  */
341                 outchar('u');
342
343         if (osdef)
344                 /* old style function definition */
345                 outchar('o');
346
347         if (fsym->s_scl == STATIC)
348                 outchar('s');
349
350         /* name of function */
351         outname(fsym->s_name);
352
353         /* argument types and return value */
354         if (osdef) {
355                 narg = 0;
356                 for (arg = args; arg != NULL; arg = arg->s_nxt)
357                         narg++;
358                 outchar('f');
359                 outint(narg);
360                 for (arg = args; arg != NULL; arg = arg->s_nxt)
361                         outtype(arg->s_type);
362                 outtype(fsym->s_type->t_subt);
363         } else {
364                 outtype(fsym->s_type);
365         }
366 }
367
368 /*
369  * write out all information necessary for lint2 to check function
370  * calls
371  *
372  * rvused is set if the return value is used (asigned to a variable)
373  * rvdisc is set if the return value is not used and not ignored
374  * (casted to void)
375  */
376 void
377 outcall(tn, rvused, rvdisc)
378         tnode_t *tn;
379         int     rvused, rvdisc;
380 {
381         tnode_t *args, *arg;
382         int     narg, n, i;
383         quad_t  q;
384         tspec_t t;
385
386         /* reset buffer */
387         outclr();
388
389         /*
390          * line number of .c source, 'c' for function call, Id of current
391          * source (.c or .h), and line in current source
392          */
393         outint(csrc_pos.p_line);
394         outchar('c');
395         outint(getfnid(curr_pos.p_file));
396         outchar('.');
397         outint(curr_pos.p_line);
398
399         /*
400          * flags; 'u' and 'i' must be last to make sure a letter
401          * is between the numeric argument of a flag and the name of
402          * the function
403          */
404         narg = 0;
405         args = tn->tn_right;
406         for (arg = args; arg != NULL; arg = arg->tn_right)
407                 narg++;
408         /* informations about arguments */
409         for (n = 1; n <= narg; n++) {
410                 /* the last argument is the top one in the tree */
411                 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
412                 arg = arg->tn_left;
413                 if (arg->tn_op == CON) {
414                         if (isityp(t = arg->tn_type->t_tspec)) {
415                                 /*
416                                  * XXX it would probably be better to
417                                  * explizitly test the sign
418                                  */
419                                 if ((q = arg->tn_val->v_quad) == 0) {
420                                         /* zero constant */
421                                         outchar('z');
422                                 } else if (msb(q, t, 0) == 0) {
423                                         /* positive if casted to signed */
424                                         outchar('p');
425                                 } else {
426                                         /* negative if casted to signed */
427                                         outchar('n');
428                                 }
429                                 outint(n);
430                         }
431                 } else if (arg->tn_op == AMPER &&
432                            arg->tn_left->tn_op == STRING &&
433                            arg->tn_left->tn_strg->st_tspec == CHAR) {
434                         /* constant string, write all format specifiers */
435                         outchar('s');
436                         outint(n);
437                         outfstrg(arg->tn_left->tn_strg);
438                 }
439
440         }
441         /* return value discarded/used/ignored */
442         outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i'));
443
444         /* name of the called function */
445         outname(tn->tn_left->tn_left->tn_sym->s_name);
446
447         /* types of arguments */
448         outchar('f');
449         outint(narg);
450         for (n = 1; n <= narg; n++) {
451                 /* the last argument is the top one in the tree */
452                 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
453                 outtype(arg->tn_left->tn_type);
454         }
455         /* expected type of return value */
456         outtype(tn->tn_type);
457 }
458
459 /*
460  * extracts potential format specifiers for printf() and scanf() and
461  * writes them, enclosed in "" and qouted if necessary, to the output buffer
462  */
463 static void
464 outfstrg(strg)
465         strg_t  *strg;
466 {
467         int     c, oc, first;
468         u_char  *cp;
469
470         if (strg->st_tspec != CHAR)
471                 lerror("outfstrg() 1");
472
473         cp = strg->st_cp;
474
475         outchar('"');
476
477         c = *cp++;
478
479         while (c != '\0') {
480
481                 if (c != '%') {
482                         c = *cp++;
483                         continue;
484                 }
485
486                 outqchar('%');
487                 c = *cp++;
488
489                 /* flags for printf and scanf and *-fieldwidth for printf */
490                 while (c != '\0' && (c == '-' || c == '+' || c == ' ' ||
491                                      c == '#' || c == '0' || c == '*')) {
492                         outqchar(c);
493                         c = *cp++;
494                 }
495
496                 /* numeric field width */
497                 while (c != '\0' && isdigit(c)) {
498                         outqchar(c);
499                         c = *cp++;
500                 }
501
502                 /* precision for printf */
503                 if (c == '.') {
504                         outqchar(c);
505                         if ((c = *cp++) == '*') {
506                                 outqchar(c);
507                                 c = *cp++;
508                         } else {
509                                 while (c != '\0' && isdigit(c)) {
510                                         outqchar(c);
511                                         c = *cp++;
512                                 }
513                         }
514                 }
515
516                 /* h, l, L and q flags fpr printf and scanf */
517                 if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
518                         outqchar(c);
519                         c = *cp++;
520                 }
521
522                 /*
523                  * The last character. It is always written so we can detect
524                  * invalid format specifiers.
525                  */
526                 if (c != '\0') {
527                         outqchar(c);
528                         oc = c;
529                         c = *cp++;
530                         /*
531                          * handle [ for scanf. [-] means that a minus sign
532                          * was found at an undefined position.
533                          */
534                         if (oc == '[') {
535                                 if (c == '^')
536                                         c = *cp++;
537                                 if (c == ']')
538                                         c = *cp++;
539                                 first = 1;
540                                 while (c != '\0' && c != ']') {
541                                         if (c == '-') {
542                                                 if (!first && *cp != ']')
543                                                         outqchar(c);
544                                         }
545                                         first = 0;
546                                         c = *cp++;
547                                 }
548                                 if (c == ']') {
549                                         outqchar(c);
550                                         c = *cp++;
551                                 }
552                         }
553                 }
554
555         }
556
557         outchar('"');
558 }
559
560 /*
561  * writes a record if sym was used
562  */
563 void
564 outusg(sym)
565         sym_t   *sym;
566 {
567         /* reset buffer */
568         outclr();
569
570         /*
571          * line number of .c source, 'u' for used, Id of current
572          * source (.c or .h), and line in current source
573          */
574         outint(csrc_pos.p_line);
575         outchar('u');
576         outint(getfnid(curr_pos.p_file));
577         outchar('.');
578         outint(curr_pos.p_line);
579
580         /* necessary to delimit both numbers */
581         outchar('x');
582
583         /* Den Namen des Symbols ausgeben */
584         outname(sym->s_name);
585 }