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