emit1.c revision 1.85 1 1.85 rillig /* $NetBSD: emit1.c,v 1.85 2024/02/03 19:25:16 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.72 rillig * 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.85 rillig __RCSID("$NetBSD: emit1.c,v 1.85 2024/02/03 19:25:16 rillig Exp $");
42 1.1 cgd #endif
43 1.1 cgd
44 1.85 rillig #include <stdlib.h>
45 1.85 rillig
46 1.1 cgd #include "lint1.h"
47 1.1 cgd
48 1.81 rillig static void outtt(sym_t *, sym_t *);
49 1.83 rillig static void outfstrg(const char *);
50 1.1 cgd
51 1.1 cgd /*
52 1.75 rillig * Write type into the output file, encoded as follows:
53 1.75 rillig * const c
54 1.75 rillig * volatile v
55 1.15 yamt * _Bool B
56 1.18 christos * _Complex float s X
57 1.21 rillig * _Complex double X
58 1.21 rillig * _Complex long double l X
59 1.1 cgd * char C
60 1.1 cgd * signed char s C
61 1.1 cgd * unsigned char u C
62 1.1 cgd * short S
63 1.1 cgd * unsigned short u S
64 1.1 cgd * int I
65 1.1 cgd * unsigned int u I
66 1.1 cgd * long L
67 1.1 cgd * unsigned long u L
68 1.1 cgd * long long Q
69 1.1 cgd * unsigned long long u Q
70 1.1 cgd * float s D
71 1.1 cgd * double D
72 1.1 cgd * long double l D
73 1.1 cgd * void V
74 1.1 cgd * * P
75 1.1 cgd * [n] A n
76 1.1 cgd * () F
77 1.1 cgd * (void) F 0
78 1.44 rillig * (n parameters) F n arg1 arg2 ... argn
79 1.65 rillig * (n parameters, ...) F n arg1 arg2 ... argn E
80 1.1 cgd * enum tag e T tag_or_typename
81 1.1 cgd * struct tag s T tag_or_typename
82 1.1 cgd * union tag u T tag_or_typename
83 1.1 cgd *
84 1.44 rillig * tag_or_typename 0 (obsolete) no tag or type name
85 1.44 rillig * 1 n tag tagged type
86 1.65 rillig * 2 n typename only typedef name
87 1.44 rillig * 3 line.file.uniq anonymous types
88 1.1 cgd */
89 1.1 cgd void
90 1.36 rillig outtype(const type_t *tp)
91 1.1 cgd {
92 1.53 rillig /* Available letters: ------GH--K-MNO--R--U-W-YZ */
93 1.53 rillig #ifdef INT128_SIZE
94 1.70 rillig static const char tt[NTSPEC] = "???BCCCSSIILLQQJJDDD?XXXVTTTPAF";
95 1.70 rillig static const char ss[NTSPEC] = "??? su u u u u us l?s l sue ";
96 1.53 rillig #else
97 1.70 rillig static const char tt[NTSPEC] = "???BCCCSSIILLQQDDD?XXXVTTTPAF";
98 1.70 rillig static const char ss[NTSPEC] = "??? su u u u us l?s l sue ";
99 1.53 rillig #endif
100 1.67 rillig int na;
101 1.67 rillig tspec_t ts;
102 1.1 cgd
103 1.1 cgd while (tp != NULL) {
104 1.42 rillig if ((ts = tp->t_tspec) == INT && tp->t_is_enum)
105 1.1 cgd ts = ENUM;
106 1.58 rillig lint_assert(tt[ts] != '?' && ss[ts] != '?');
107 1.1 cgd if (tp->t_const)
108 1.1 cgd outchar('c');
109 1.1 cgd if (tp->t_volatile)
110 1.1 cgd outchar('v');
111 1.58 rillig if (ss[ts] != ' ')
112 1.58 rillig outchar(ss[ts]);
113 1.58 rillig outchar(tt[ts]);
114 1.58 rillig
115 1.1 cgd if (ts == ARRAY) {
116 1.1 cgd outint(tp->t_dim);
117 1.1 cgd } else if (ts == ENUM) {
118 1.41 rillig outtt(tp->t_enum->en_tag, tp->t_enum->en_first_typedef);
119 1.63 rillig } else if (is_struct_or_union(ts)) {
120 1.66 rillig outtt(tp->t_sou->sou_tag, tp->t_sou->sou_first_typedef);
121 1.1 cgd } else if (ts == FUNC && tp->t_proto) {
122 1.1 cgd na = 0;
123 1.73 rillig for (const sym_t *param = tp->t_params;
124 1.79 rillig param != NULL; param = param->s_next)
125 1.45 rillig na++;
126 1.1 cgd if (tp->t_vararg)
127 1.1 cgd na++;
128 1.1 cgd outint(na);
129 1.73 rillig for (const sym_t *param = tp->t_params;
130 1.79 rillig param != NULL; param = param->s_next)
131 1.73 rillig outtype(param->s_type);
132 1.1 cgd if (tp->t_vararg)
133 1.1 cgd outchar('E');
134 1.1 cgd }
135 1.1 cgd tp = tp->t_subt;
136 1.1 cgd }
137 1.1 cgd }
138 1.1 cgd
139 1.1 cgd /*
140 1.1 cgd * write the name of a tag or typename
141 1.1 cgd *
142 1.44 rillig * if the tag is named, the name of the tag is written,
143 1.44 rillig * otherwise, if a typename exists which refers to this tag,
144 1.44 rillig * this typename is written
145 1.1 cgd */
146 1.1 cgd static void
147 1.10 lukem outtt(sym_t *tag, sym_t *tdef)
148 1.1 cgd {
149 1.5 cgd
150 1.44 rillig /* 0 is no longer used. */
151 1.44 rillig
152 1.1 cgd if (tag->s_name != unnamed) {
153 1.1 cgd outint(1);
154 1.1 cgd outname(tag->s_name);
155 1.1 cgd } else if (tdef != NULL) {
156 1.1 cgd outint(2);
157 1.1 cgd outname(tdef->s_name);
158 1.1 cgd } else {
159 1.5 cgd outint(3);
160 1.29 rillig outint(tag->s_def_pos.p_line);
161 1.5 cgd outchar('.');
162 1.43 rillig outint(get_filename_id(tag->s_def_pos.p_file));
163 1.5 cgd outchar('.');
164 1.29 rillig outint(tag->s_def_pos.p_uniq);
165 1.1 cgd }
166 1.1 cgd }
167 1.1 cgd
168 1.1 cgd /*
169 1.23 rillig * write information about a globally declared/defined symbol
170 1.3 jpo * with storage class extern
171 1.1 cgd *
172 1.23 rillig * information about function definitions are written in outfdef(),
173 1.1 cgd * not here
174 1.1 cgd */
175 1.1 cgd void
176 1.36 rillig outsym(const sym_t *sym, scl_t sc, def_t def)
177 1.1 cgd {
178 1.10 lukem
179 1.1 cgd /*
180 1.1 cgd * Static function declarations must also be written to the output
181 1.80 rillig * file. Compatibility of function declarations (for both static and
182 1.80 rillig * extern functions) must be checked in lint2. Lint1 can't do this,
183 1.80 rillig * especially not if functions are declared at block level before their
184 1.80 rillig * first declaration at level 0.
185 1.1 cgd */
186 1.1 cgd if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
187 1.1 cgd return;
188 1.60 rillig if (ch_isdigit(sym->s_name[0])) /* 00000000_tmp */
189 1.60 rillig return;
190 1.1 cgd
191 1.1 cgd outint(csrc_pos.p_line);
192 1.68 rillig outchar('d'); /* declaration */
193 1.43 rillig outint(get_filename_id(sym->s_def_pos.p_file));
194 1.1 cgd outchar('.');
195 1.29 rillig outint(sym->s_def_pos.p_line);
196 1.1 cgd
197 1.1 cgd /* flags */
198 1.1 cgd
199 1.48 rillig if (def == DEF)
200 1.48 rillig outchar('d'); /* defined */
201 1.48 rillig else if (def == TDEF)
202 1.48 rillig outchar('t'); /* tentative defined */
203 1.48 rillig else {
204 1.48 rillig lint_assert(def == DECL);
205 1.48 rillig outchar('e'); /* declared */
206 1.1 cgd }
207 1.48 rillig
208 1.3 jpo if (llibflg && def != DECL) {
209 1.1 cgd /*
210 1.80 rillig * mark it as used so lint2 does not complain about unused
211 1.80 rillig * symbols in libraries
212 1.1 cgd */
213 1.1 cgd outchar('u');
214 1.1 cgd }
215 1.1 cgd
216 1.1 cgd if (sc == STATIC)
217 1.1 cgd outchar('s');
218 1.1 cgd
219 1.1 cgd outname(sym->s_name);
220 1.1 cgd
221 1.37 rillig if (sym->s_rename != NULL) {
222 1.6 cgd outchar('r');
223 1.6 cgd outname(sym->s_rename);
224 1.6 cgd }
225 1.6 cgd
226 1.1 cgd outtype(sym->s_type);
227 1.74 rillig outchar('\n');
228 1.1 cgd }
229 1.1 cgd
230 1.1 cgd /*
231 1.68 rillig * Write information about a function definition. This is also done for static
232 1.68 rillig * functions, to later check if they are called with proper argument types.
233 1.1 cgd */
234 1.1 cgd void
235 1.37 rillig outfdef(const sym_t *fsym, const pos_t *posp, bool rval, bool osdef,
236 1.36 rillig const sym_t *args)
237 1.1 cgd {
238 1.36 rillig int narg;
239 1.1 cgd
240 1.1 cgd if (posp->p_file == csrc_pos.p_file) {
241 1.1 cgd outint(posp->p_line);
242 1.1 cgd } else {
243 1.1 cgd outint(csrc_pos.p_line);
244 1.1 cgd }
245 1.68 rillig outchar('d'); /* declaration */
246 1.43 rillig outint(get_filename_id(posp->p_file));
247 1.1 cgd outchar('.');
248 1.1 cgd outint(posp->p_line);
249 1.1 cgd
250 1.1 cgd /* both SCANFLIKE and PRINTFLIKE imply VARARGS */
251 1.33 rillig if (printflike_argnum != -1) {
252 1.33 rillig nvararg = printflike_argnum;
253 1.33 rillig } else if (scanflike_argnum != -1) {
254 1.33 rillig nvararg = scanflike_argnum;
255 1.1 cgd }
256 1.1 cgd
257 1.1 cgd if (nvararg != -1) {
258 1.1 cgd outchar('v');
259 1.1 cgd outint(nvararg);
260 1.1 cgd }
261 1.33 rillig if (scanflike_argnum != -1) {
262 1.1 cgd outchar('S');
263 1.33 rillig outint(scanflike_argnum);
264 1.1 cgd }
265 1.33 rillig if (printflike_argnum != -1) {
266 1.1 cgd outchar('P');
267 1.33 rillig outint(printflike_argnum);
268 1.1 cgd }
269 1.33 rillig nvararg = printflike_argnum = scanflike_argnum = -1;
270 1.1 cgd
271 1.1 cgd outchar('d');
272 1.1 cgd
273 1.1 cgd if (rval)
274 1.48 rillig outchar('r'); /* has return value */
275 1.1 cgd
276 1.1 cgd if (llibflg)
277 1.1 cgd /*
278 1.80 rillig * mark it as used so lint2 does not complain about unused
279 1.80 rillig * symbols in libraries
280 1.1 cgd */
281 1.1 cgd outchar('u');
282 1.1 cgd
283 1.1 cgd if (osdef)
284 1.64 rillig outchar('o'); /* old-style function definition */
285 1.1 cgd
286 1.20 christos if (fsym->s_inline)
287 1.20 christos outchar('i');
288 1.20 christos
289 1.1 cgd if (fsym->s_scl == STATIC)
290 1.1 cgd outchar('s');
291 1.1 cgd
292 1.1 cgd outname(fsym->s_name);
293 1.6 cgd
294 1.37 rillig if (fsym->s_rename != NULL) {
295 1.6 cgd outchar('r');
296 1.6 cgd outname(fsym->s_rename);
297 1.6 cgd }
298 1.1 cgd
299 1.73 rillig /* parameter types and return value */
300 1.1 cgd if (osdef) {
301 1.1 cgd narg = 0;
302 1.84 rillig for (const sym_t *arg = args; arg != NULL; arg = arg->s_next)
303 1.1 cgd narg++;
304 1.1 cgd outchar('f');
305 1.1 cgd outint(narg);
306 1.84 rillig for (const sym_t *arg = args; arg != NULL; arg = arg->s_next)
307 1.1 cgd outtype(arg->s_type);
308 1.4 jpo outtype(fsym->s_type->t_subt);
309 1.1 cgd } else {
310 1.4 jpo outtype(fsym->s_type);
311 1.1 cgd }
312 1.74 rillig outchar('\n');
313 1.1 cgd }
314 1.1 cgd
315 1.1 cgd /*
316 1.1 cgd * write out all information necessary for lint2 to check function
317 1.1 cgd * calls
318 1.1 cgd *
319 1.59 rillig * retval_used is set if the return value is used (assigned to a variable)
320 1.59 rillig * retval_discarded is set if the return value is neither used nor ignored
321 1.59 rillig * (that is, cast to void)
322 1.1 cgd */
323 1.1 cgd void
324 1.59 rillig outcall(const tnode_t *tn, bool retval_used, bool retval_discarded)
325 1.1 cgd {
326 1.67 rillig tnode_t *args, *arg;
327 1.84 rillig int narg, i;
328 1.1 cgd
329 1.1 cgd outint(csrc_pos.p_line);
330 1.68 rillig outchar('c'); /* function call */
331 1.43 rillig outint(get_filename_id(curr_pos.p_file));
332 1.1 cgd outchar('.');
333 1.1 cgd outint(curr_pos.p_line);
334 1.1 cgd
335 1.1 cgd /*
336 1.80 rillig * flags; 'u' and 'i' must be last to make sure a letter is between the
337 1.80 rillig * numeric argument of a flag and the name of the function
338 1.1 cgd */
339 1.1 cgd narg = 0;
340 1.77 rillig args = tn_ck_right(tn);
341 1.77 rillig for (arg = args; arg != NULL; arg = tn_ck_right(arg))
342 1.1 cgd narg++;
343 1.25 rillig /* information about arguments */
344 1.84 rillig for (int n = 1; n <= narg; n++) {
345 1.1 cgd /* the last argument is the top one in the tree */
346 1.10 lukem for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
347 1.10 lukem continue;
348 1.1 cgd arg = arg->tn_left;
349 1.1 cgd if (arg->tn_op == CON) {
350 1.84 rillig tspec_t t = arg->tn_type->t_tspec;
351 1.84 rillig if (is_integer(t)) {
352 1.1 cgd /*
353 1.1 cgd * XXX it would probably be better to
354 1.16 perry * explicitly test the sign
355 1.1 cgd */
356 1.71 rillig int64_t si = arg->tn_val.u.integer;
357 1.71 rillig if (si == 0) {
358 1.1 cgd /* zero constant */
359 1.1 cgd outchar('z');
360 1.71 rillig } else if (!msb(si, t)) {
361 1.49 rillig /* positive if cast to signed */
362 1.1 cgd outchar('p');
363 1.1 cgd } else {
364 1.49 rillig /* negative if cast to signed */
365 1.1 cgd outchar('n');
366 1.1 cgd }
367 1.1 cgd outint(n);
368 1.1 cgd }
369 1.39 rillig } else if (arg->tn_op == ADDR &&
370 1.79 rillig arg->tn_left->tn_op == STRING &&
371 1.83 rillig arg->tn_left->tn_string->data != NULL) {
372 1.85 rillig buffer buf;
373 1.85 rillig buf_init(&buf);
374 1.85 rillig quoted_iterator it = { .start = 0 };
375 1.85 rillig while (quoted_next(arg->tn_left->tn_string, &it))
376 1.85 rillig buf_add_char(&buf, (char)it.value);
377 1.85 rillig
378 1.85 rillig /* string literal, write all format specifiers */
379 1.1 cgd outchar('s');
380 1.1 cgd outint(n);
381 1.85 rillig outfstrg(buf.data);
382 1.85 rillig free(buf.data);
383 1.1 cgd }
384 1.1 cgd }
385 1.75 rillig outchar((char)(retval_discarded ? 'd' : retval_used ? 'u' : 'i'));
386 1.1 cgd
387 1.1 cgd /* name of the called function */
388 1.77 rillig outname(tn_ck_left(tn->tn_left)->tn_sym->s_name);
389 1.1 cgd
390 1.1 cgd /* types of arguments */
391 1.1 cgd outchar('f');
392 1.1 cgd outint(narg);
393 1.84 rillig for (int n = 1; n <= narg; n++) {
394 1.1 cgd /* the last argument is the top one in the tree */
395 1.10 lukem for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
396 1.10 lukem continue;
397 1.1 cgd outtype(arg->tn_left->tn_type);
398 1.1 cgd }
399 1.1 cgd /* expected type of return value */
400 1.1 cgd outtype(tn->tn_type);
401 1.74 rillig outchar('\n');
402 1.1 cgd }
403 1.1 cgd
404 1.76 rillig /* write a character to the output file, quoted if necessary */
405 1.56 rillig static void
406 1.56 rillig outqchar(char c)
407 1.56 rillig {
408 1.56 rillig
409 1.56 rillig if (ch_isprint(c) && c != '\\' && c != '"' && c != '\'') {
410 1.56 rillig outchar(c);
411 1.56 rillig return;
412 1.56 rillig }
413 1.56 rillig
414 1.56 rillig outchar('\\');
415 1.56 rillig switch (c) {
416 1.56 rillig case '\\':
417 1.56 rillig outchar('\\');
418 1.56 rillig break;
419 1.56 rillig case '"':
420 1.56 rillig outchar('"');
421 1.56 rillig break;
422 1.56 rillig case '\'':
423 1.56 rillig outchar('\'');
424 1.56 rillig break;
425 1.56 rillig case '\b':
426 1.56 rillig outchar('b');
427 1.56 rillig break;
428 1.56 rillig case '\t':
429 1.56 rillig outchar('t');
430 1.56 rillig break;
431 1.56 rillig case '\n':
432 1.56 rillig outchar('n');
433 1.56 rillig break;
434 1.56 rillig case '\f':
435 1.56 rillig outchar('f');
436 1.56 rillig break;
437 1.56 rillig case '\r':
438 1.56 rillig outchar('r');
439 1.56 rillig break;
440 1.56 rillig case '\v':
441 1.56 rillig outchar('v');
442 1.56 rillig break;
443 1.56 rillig case '\a':
444 1.56 rillig outchar('a');
445 1.56 rillig break;
446 1.56 rillig default:
447 1.56 rillig outchar((char)((((unsigned char)c >> 6) & 07) + '0'));
448 1.56 rillig outchar((char)((((unsigned char)c >> 3) & 07) + '0'));
449 1.56 rillig outchar((char)((c & 07) + '0'));
450 1.56 rillig break;
451 1.56 rillig }
452 1.56 rillig }
453 1.56 rillig
454 1.1 cgd /*
455 1.1 cgd * extracts potential format specifiers for printf() and scanf() and
456 1.76 rillig * writes them, enclosed in "" and quoted if necessary, to the output file
457 1.1 cgd */
458 1.1 cgd static void
459 1.83 rillig outfstrg(const char *cp)
460 1.1 cgd {
461 1.1 cgd
462 1.1 cgd outchar('"');
463 1.1 cgd
464 1.82 rillig char c = *cp++;
465 1.1 cgd while (c != '\0') {
466 1.1 cgd
467 1.1 cgd if (c != '%') {
468 1.1 cgd c = *cp++;
469 1.1 cgd continue;
470 1.1 cgd }
471 1.1 cgd
472 1.57 rillig outchar('%');
473 1.1 cgd c = *cp++;
474 1.1 cgd
475 1.1 cgd /* flags for printf and scanf and *-fieldwidth for printf */
476 1.57 rillig while (c == '-' || c == '+' || c == ' ' ||
477 1.79 rillig c == '#' || c == '0' || c == '*') {
478 1.57 rillig outchar(c);
479 1.1 cgd c = *cp++;
480 1.1 cgd }
481 1.1 cgd
482 1.1 cgd /* numeric field width */
483 1.57 rillig while (ch_isdigit(c)) {
484 1.57 rillig outchar(c);
485 1.1 cgd c = *cp++;
486 1.1 cgd }
487 1.1 cgd
488 1.1 cgd /* precision for printf */
489 1.1 cgd if (c == '.') {
490 1.57 rillig outchar(c);
491 1.57 rillig c = *cp++;
492 1.57 rillig if (c == '*') {
493 1.57 rillig outchar(c);
494 1.1 cgd c = *cp++;
495 1.1 cgd } else {
496 1.57 rillig while (ch_isdigit(c)) {
497 1.57 rillig outchar(c);
498 1.1 cgd c = *cp++;
499 1.1 cgd }
500 1.1 cgd }
501 1.1 cgd }
502 1.1 cgd
503 1.57 rillig /* h, l, L and q flags for printf and scanf */
504 1.1 cgd if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
505 1.57 rillig outchar(c);
506 1.1 cgd c = *cp++;
507 1.1 cgd }
508 1.1 cgd
509 1.1 cgd /*
510 1.57 rillig * The last character. It is always written, so we can detect
511 1.1 cgd * invalid format specifiers.
512 1.1 cgd */
513 1.1 cgd if (c != '\0') {
514 1.1 cgd outqchar(c);
515 1.82 rillig char oc = c;
516 1.1 cgd c = *cp++;
517 1.1 cgd /*
518 1.80 rillig * handle [ for scanf. [-] means that a minus sign was
519 1.80 rillig * found at an undefined position.
520 1.1 cgd */
521 1.1 cgd if (oc == '[') {
522 1.1 cgd if (c == '^')
523 1.1 cgd c = *cp++;
524 1.1 cgd if (c == ']')
525 1.1 cgd c = *cp++;
526 1.82 rillig bool first = true;
527 1.1 cgd while (c != '\0' && c != ']') {
528 1.1 cgd if (c == '-') {
529 1.1 cgd if (!first && *cp != ']')
530 1.57 rillig outchar(c);
531 1.1 cgd }
532 1.37 rillig first = false;
533 1.1 cgd c = *cp++;
534 1.1 cgd }
535 1.1 cgd if (c == ']') {
536 1.57 rillig outchar(c);
537 1.1 cgd c = *cp++;
538 1.1 cgd }
539 1.1 cgd }
540 1.1 cgd }
541 1.1 cgd }
542 1.1 cgd
543 1.1 cgd outchar('"');
544 1.1 cgd }
545 1.1 cgd
546 1.76 rillig /* writes a record if sym was used */
547 1.1 cgd void
548 1.36 rillig outusg(const sym_t *sym)
549 1.1 cgd {
550 1.68 rillig if (ch_isdigit(sym->s_name[0])) /* 00000000_tmp, from mktempsym */
551 1.60 rillig return;
552 1.60 rillig
553 1.1 cgd outint(csrc_pos.p_line);
554 1.68 rillig outchar('u'); /* used */
555 1.43 rillig outint(get_filename_id(curr_pos.p_file));
556 1.1 cgd outchar('.');
557 1.1 cgd outint(curr_pos.p_line);
558 1.75 rillig outchar('x'); /* separate the two numbers */
559 1.1 cgd outname(sym->s_name);
560 1.74 rillig outchar('\n');
561 1.1 cgd }
562