Remove __P macros from src/usr.bin and src/usr.sbin.
[dragonfly.git] / usr.bin / xlint / lint1 / emit1.c
CommitLineData
984263bc
MD
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.
1de703da
MD
32 *
33 * $NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo Exp $
2d8a3be7 34 * $DragonFly: src/usr.bin/xlint/lint1/emit1.c,v 1.4 2003/11/03 19:31:34 eirikn Exp $
984263bc
MD
35 */
36
984263bc
MD
37#include <ctype.h>
38
39#include "lint1.h"
40
2d8a3be7
EN
41static void outtt(sym_t *, sym_t *);
42static void outfstrg(strg_t *);
984263bc
MD
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 */
83void
84outtype(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 */
154const char *
155ttos(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 */
185static void
186outtt(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 */
207void
208outsym(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 */
278void
279outfdef(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 */
377void
378outcall(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 */
464static void
465outfstrg(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 */
564void
565outusg(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}