Synchronise with NetBSD: ANSIfy.
[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.5 2004/07/07 12:13:26 asmodai 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(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(type_t *tp)
155 {
156         static  ob_t    tob;
157         ob_t    tmp;
158
159         if (tob.o_buf == NULL) {
160                 tob.o_len = 64;
161                 tob.o_buf = tob.o_nxt = xmalloc(tob.o_len);
162                 tob.o_end = tob.o_buf + tob.o_len;
163         }
164
165         tmp = ob;
166         ob = tob;
167         ob.o_nxt = ob.o_buf;
168         outtype(tp);
169         outchar('\0');
170         tob = ob;
171         ob = tmp;
172
173         return (tob.o_buf);
174 }
175
176 /*
177  * write the name of a tag or typename
178  *
179  * if the tag is named, the name of the
180  * tag is written, otherwise, if a typename exists which
181  * refers to this tag, this typename is written
182  */
183 static void
184 outtt(sym_t *tag, sym_t *tdef)
185 {
186         if (tag->s_name != unnamed) {
187                 outint(1);
188                 outname(tag->s_name);
189         } else if (tdef != NULL) {
190                 outint(2);
191                 outname(tdef->s_name);
192         } else {
193                 outint(0);
194         }
195 }
196
197 /*
198  * write information about an global declared/defined symbol
199  * with storage class extern
200  *
201  * informations about function definitions are written in outfdef(),
202  * not here
203  */
204 void
205 outsym(sym_t *sym, scl_t sc, def_t def)
206 {
207         /*
208          * Static function declarations must also be written to the output
209          * file. Compatibility of function declarations (for both static
210          * and extern functions) must be checked in lint2. Lint1 can't do
211          * this, especially not, if functions are declared at block level
212          * before their first declaration at level 0.
213          */
214         if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
215                 return;
216
217         /* reset buffer */
218         outclr();
219
220         /*
221          * line number of .c source, 'd' for declaration, Id of current
222          * source (.c or .h), and line in current source.
223          */
224         outint(csrc_pos.p_line);
225         outchar('d');
226         outint(getfnid(sym->s_dpos.p_file));
227         outchar('.');
228         outint(sym->s_dpos.p_line);
229
230         /* flags */
231
232         switch (def) {
233         case DEF:
234                 /* defined */
235                 outchar('d');
236                 break;
237         case TDEF:
238                 /* tentative defined */
239                 outchar('t');
240                 break;
241         case DECL:
242                 /* declared */
243                 outchar('e');
244                 break;
245         default:
246                 lerror("outsym() 2");
247         }
248         if (llibflg && def != DECL) {
249                 /*
250                  * mark it as used so we get no warnings from lint2 about
251                  * unused symbols in libraries.
252                  */
253                 outchar('u');
254         }
255
256         if (sc == STATIC)
257                 outchar('s');
258
259         /* name of the symbol */
260         outname(sym->s_name);
261
262         /* type of the symbol */
263         outtype(sym->s_type);
264 }
265
266 /*
267  * write information about function definition
268  *
269  * this is also done for static functions so we are able to check if
270  * they are called with proper argument types
271  */
272 void
273 outfdef(sym_t *fsym, pos_t *posp, int rval, int osdef, sym_t *args)
274 {
275         int     narg;
276         sym_t   *arg;
277
278         /* reset the buffer */
279         outclr();
280
281         /*
282          * line number of .c source, 'd' for declaration, Id of current
283          * source (.c or .h), and line in current source
284          *
285          * we are already at the end of the function. If we are in the
286          * .c source, posp->p_line is correct, otherwise csrc_pos.p_line
287          * (for functions defined in header files).
288          */
289         if (posp->p_file == csrc_pos.p_file) {
290                 outint(posp->p_line);
291         } else {
292                 outint(csrc_pos.p_line);
293         }
294         outchar('d');
295         outint(getfnid(posp->p_file));
296         outchar('.');
297         outint(posp->p_line);
298
299         /* flags */
300
301         /* both SCANFLIKE and PRINTFLIKE imply VARARGS */
302         if (prflstrg != -1) {
303                 nvararg = prflstrg;
304         } else if (scflstrg != -1) {
305                 nvararg = scflstrg;
306         }
307
308         if (nvararg != -1) {
309                 outchar('v');
310                 outint(nvararg);
311         }
312         if (scflstrg != -1) {
313                 outchar('S');
314                 outint(scflstrg);
315         }
316         if (prflstrg != -1) {
317                 outchar('P');
318                 outint(prflstrg);
319         }
320         nvararg = prflstrg = scflstrg = -1;
321
322         outchar('d');
323
324         if (rval)
325                 /* has return value */
326                 outchar('r');
327
328         if (llibflg)
329                 /*
330                  * mark it as used so lint2 does not complain about
331                  * unused symbols in libraries
332                  */
333                 outchar('u');
334
335         if (osdef)
336                 /* old style function definition */
337                 outchar('o');
338
339         if (fsym->s_scl == STATIC)
340                 outchar('s');
341
342         /* name of function */
343         outname(fsym->s_name);
344
345         /* argument types and return value */
346         if (osdef) {
347                 narg = 0;
348                 for (arg = args; arg != NULL; arg = arg->s_nxt)
349                         narg++;
350                 outchar('f');
351                 outint(narg);
352                 for (arg = args; arg != NULL; arg = arg->s_nxt)
353                         outtype(arg->s_type);
354                 outtype(fsym->s_type->t_subt);
355         } else {
356                 outtype(fsym->s_type);
357         }
358 }
359
360 /*
361  * write out all information necessary for lint2 to check function
362  * calls
363  *
364  * rvused is set if the return value is used (asigned to a variable)
365  * rvdisc is set if the return value is not used and not ignored
366  * (casted to void)
367  */
368 void
369 outcall(tnode_t *tn, int rvused, int rvdisc)
370 {
371         tnode_t *args, *arg;
372         int     narg, n, i;
373         quad_t  q;
374         tspec_t t;
375
376         /* reset buffer */
377         outclr();
378
379         /*
380          * line number of .c source, 'c' for function call, Id of current
381          * source (.c or .h), and line in current source
382          */
383         outint(csrc_pos.p_line);
384         outchar('c');
385         outint(getfnid(curr_pos.p_file));
386         outchar('.');
387         outint(curr_pos.p_line);
388
389         /*
390          * flags; 'u' and 'i' must be last to make sure a letter
391          * is between the numeric argument of a flag and the name of
392          * the function
393          */
394         narg = 0;
395         args = tn->tn_right;
396         for (arg = args; arg != NULL; arg = arg->tn_right)
397                 narg++;
398         /* informations about arguments */
399         for (n = 1; n <= narg; n++) {
400                 /* the last argument is the top one in the tree */
401                 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
402                 arg = arg->tn_left;
403                 if (arg->tn_op == CON) {
404                         if (isityp(t = arg->tn_type->t_tspec)) {
405                                 /*
406                                  * XXX it would probably be better to
407                                  * explizitly test the sign
408                                  */
409                                 if ((q = arg->tn_val->v_quad) == 0) {
410                                         /* zero constant */
411                                         outchar('z');
412                                 } else if (msb(q, t, 0) == 0) {
413                                         /* positive if casted to signed */
414                                         outchar('p');
415                                 } else {
416                                         /* negative if casted to signed */
417                                         outchar('n');
418                                 }
419                                 outint(n);
420                         }
421                 } else if (arg->tn_op == AMPER &&
422                            arg->tn_left->tn_op == STRING &&
423                            arg->tn_left->tn_strg->st_tspec == CHAR) {
424                         /* constant string, write all format specifiers */
425                         outchar('s');
426                         outint(n);
427                         outfstrg(arg->tn_left->tn_strg);
428                 }
429
430         }
431         /* return value discarded/used/ignored */
432         outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i'));
433
434         /* name of the called function */
435         outname(tn->tn_left->tn_left->tn_sym->s_name);
436
437         /* types of arguments */
438         outchar('f');
439         outint(narg);
440         for (n = 1; n <= narg; n++) {
441                 /* the last argument is the top one in the tree */
442                 for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
443                 outtype(arg->tn_left->tn_type);
444         }
445         /* expected type of return value */
446         outtype(tn->tn_type);
447 }
448
449 /*
450  * extracts potential format specifiers for printf() and scanf() and
451  * writes them, enclosed in "" and qouted if necessary, to the output buffer
452  */
453 static void
454 outfstrg(strg_t *strg)
455 {
456         int     c, oc, first;
457         u_char  *cp;
458
459         if (strg->st_tspec != CHAR)
460                 lerror("outfstrg() 1");
461
462         cp = strg->st_cp;
463
464         outchar('"');
465
466         c = *cp++;
467
468         while (c != '\0') {
469
470                 if (c != '%') {
471                         c = *cp++;
472                         continue;
473                 }
474
475                 outqchar('%');
476                 c = *cp++;
477
478                 /* flags for printf and scanf and *-fieldwidth for printf */
479                 while (c != '\0' && (c == '-' || c == '+' || c == ' ' ||
480                                      c == '#' || c == '0' || c == '*')) {
481                         outqchar(c);
482                         c = *cp++;
483                 }
484
485                 /* numeric field width */
486                 while (c != '\0' && isdigit(c)) {
487                         outqchar(c);
488                         c = *cp++;
489                 }
490
491                 /* precision for printf */
492                 if (c == '.') {
493                         outqchar(c);
494                         if ((c = *cp++) == '*') {
495                                 outqchar(c);
496                                 c = *cp++;
497                         } else {
498                                 while (c != '\0' && isdigit(c)) {
499                                         outqchar(c);
500                                         c = *cp++;
501                                 }
502                         }
503                 }
504
505                 /* h, l, L and q flags fpr printf and scanf */
506                 if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
507                         outqchar(c);
508                         c = *cp++;
509                 }
510
511                 /*
512                  * The last character. It is always written so we can detect
513                  * invalid format specifiers.
514                  */
515                 if (c != '\0') {
516                         outqchar(c);
517                         oc = c;
518                         c = *cp++;
519                         /*
520                          * handle [ for scanf. [-] means that a minus sign
521                          * was found at an undefined position.
522                          */
523                         if (oc == '[') {
524                                 if (c == '^')
525                                         c = *cp++;
526                                 if (c == ']')
527                                         c = *cp++;
528                                 first = 1;
529                                 while (c != '\0' && c != ']') {
530                                         if (c == '-') {
531                                                 if (!first && *cp != ']')
532                                                         outqchar(c);
533                                         }
534                                         first = 0;
535                                         c = *cp++;
536                                 }
537                                 if (c == ']') {
538                                         outqchar(c);
539                                         c = *cp++;
540                                 }
541                         }
542                 }
543
544         }
545
546         outchar('"');
547 }
548
549 /*
550  * writes a record if sym was used
551  */
552 void
553 outusg(sym_t *sym)
554 {
555         /* reset buffer */
556         outclr();
557
558         /*
559          * line number of .c source, 'u' for used, Id of current
560          * source (.c or .h), and line in current source
561          */
562         outint(csrc_pos.p_line);
563         outchar('u');
564         outint(getfnid(curr_pos.p_file));
565         outchar('.');
566         outint(curr_pos.p_line);
567
568         /* necessary to delimit both numbers */
569         outchar('x');
570
571         /* Den Namen des Symbols ausgeben */
572         outname(sym->s_name);
573 }