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