1281168Spfg/* $NetBSD: emit1.c,v 1.14 2004/06/20 22:20:16 jmc Exp $ */
212099Sjoerg
312099Sjoerg/*
491586Smarkm * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
512099Sjoerg * Copyright (c) 1994, 1995 Jochen Pohl
612099Sjoerg * All Rights Reserved.
712099Sjoerg *
812099Sjoerg * Redistribution and use in source and binary forms, with or without
912099Sjoerg * modification, are permitted provided that the following conditions
1012099Sjoerg * are met:
1112099Sjoerg * 1. Redistributions of source code must retain the above copyright
1212099Sjoerg *    notice, this list of conditions and the following disclaimer.
1312099Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1412099Sjoerg *    notice, this list of conditions and the following disclaimer in the
1512099Sjoerg *    documentation and/or other materials provided with the distribution.
1612099Sjoerg * 3. All advertising materials mentioning features or use of this software
1712099Sjoerg *    must display the following acknowledgement:
1812099Sjoerg *      This product includes software developed by Jochen Pohl for
1912099Sjoerg *	The NetBSD Project.
2012099Sjoerg * 4. The name of the author may not be used to endorse or promote products
2112099Sjoerg *    derived from this software without specific prior written permission.
2212099Sjoerg *
2312099Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2412099Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2512099Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2612099Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2712099Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2812099Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2912099Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3012099Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3112099Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3212099Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3312099Sjoerg */
3412099Sjoerg
3591586Smarkm#include <sys/cdefs.h>
3691586Smarkm#if defined(__RCSID) && !defined(lint)
37281168Spfg__RCSID("$NetBSD: emit1.c,v 1.14 2004/06/20 22:20:16 jmc Exp $");
3812099Sjoerg#endif
39108470Sschweikh__FBSDID("$FreeBSD$");
4012099Sjoerg
4112099Sjoerg#include <ctype.h>
4212099Sjoerg
4312099Sjoerg#include "lint1.h"
4412099Sjoerg
4591586Smarkmstatic	void	outtt(sym_t *, sym_t *);
4691586Smarkmstatic	void	outfstrg(strg_t *);
4712099Sjoerg
4812099Sjoerg/*
4912099Sjoerg * Write type into the output buffer.
5012099Sjoerg * The type is written as a sequence of substrings, each of which describes a
5112099Sjoerg * node of type type_t
5212099Sjoerg * a node is coded as follows:
5312099Sjoerg *	char			C
5412099Sjoerg *	signed char		s C
5512099Sjoerg *	unsigned char		u C
5612099Sjoerg *	short			S
5712099Sjoerg *	unsigned short		u S
5812099Sjoerg *	int			I
5912099Sjoerg *	unsigned int		u I
6012099Sjoerg *	long			L
6112099Sjoerg *	unsigned long		u L
6212099Sjoerg *	long long		Q
6312099Sjoerg *	unsigned long long	u Q
6412099Sjoerg *	float			s D
6512099Sjoerg *	double			D
6612099Sjoerg *	long double		l D
6712099Sjoerg *	void			V
6812099Sjoerg *	*			P
6912099Sjoerg *	[n]			A n
7012099Sjoerg *	()			F
7112099Sjoerg *	(void)			F 0
7212099Sjoerg *	(n arguments)		F n arg1 arg2 ... argn
7312099Sjoerg *	(n arguments, ...)	F n arg1 arg2 ... argn-1 E
7412099Sjoerg *	(a, b, c, ...)		f n arg1 arg2 ...
7512099Sjoerg *	enum tag		e T tag_or_typename
7612099Sjoerg *	struct tag		s T tag_or_typename
7712099Sjoerg *	union tag		u T tag_or_typename
7812099Sjoerg *
7912099Sjoerg *	tag_or_typename		0			no tag or type name
8012099Sjoerg *				1 n tag			Tag
8112099Sjoerg *				2 n typename		only type name
8212099Sjoerg *
8312099Sjoerg * spaces are only for better readability
84228992Suqs * additionally it is possible to prepend the characters 'c' (for const)
8512099Sjoerg * and 'v' (for volatile)
8612099Sjoerg */
8712099Sjoergvoid
8891586Smarkmouttype(type_t *tp)
8912099Sjoerg{
9012099Sjoerg	int	t, s, na;
9112099Sjoerg	sym_t	*arg;
9212099Sjoerg	tspec_t	ts;
9312099Sjoerg
9412099Sjoerg	while (tp != NULL) {
9512099Sjoerg		if ((ts = tp->t_tspec) == INT && tp->t_isenum)
9612099Sjoerg			ts = ENUM;
9712099Sjoerg		switch (ts) {
9812099Sjoerg		case CHAR:	t = 'C';	s = '\0';	break;
9912099Sjoerg		case SCHAR:	t = 'C';	s = 's';	break;
10012099Sjoerg		case UCHAR:	t = 'C';	s = 'u';	break;
10112099Sjoerg		case SHORT:	t = 'S';	s = '\0';	break;
10212099Sjoerg		case USHORT:	t = 'S';	s = 'u';	break;
10312099Sjoerg		case INT:	t = 'I';	s = '\0';	break;
10412099Sjoerg		case UINT:	t = 'I';	s = 'u';	break;
10512099Sjoerg		case LONG:	t = 'L';	s = '\0';	break;
10612099Sjoerg		case ULONG:	t = 'L';	s = 'u';	break;
10712099Sjoerg		case QUAD:	t = 'Q';	s = '\0';	break;
10812099Sjoerg		case UQUAD:	t = 'Q';	s = 'u';	break;
10912099Sjoerg		case FLOAT:	t = 'D';	s = 's';	break;
11012099Sjoerg		case DOUBLE:	t = 'D';	s = '\0';	break;
11112099Sjoerg		case LDOUBLE:	t = 'D';	s = 'l';	break;
11212099Sjoerg		case VOID:	t = 'V';	s = '\0';	break;
11312099Sjoerg		case PTR:	t = 'P';	s = '\0';	break;
11412099Sjoerg		case ARRAY:	t = 'A';	s = '\0';	break;
11512099Sjoerg		case FUNC:	t = 'F';	s = '\0';	break;
11612099Sjoerg		case ENUM:	t = 'T';	s = 'e';	break;
11712099Sjoerg		case STRUCT:	t = 'T';	s = 's';	break;
11812099Sjoerg		case UNION:	t = 'T';	s = 'u';	break;
11912099Sjoerg		default:
120281168Spfg			LERROR("outtyp()");
12112099Sjoerg		}
12212099Sjoerg		if (tp->t_const)
12312099Sjoerg			outchar('c');
12412099Sjoerg		if (tp->t_volatile)
12512099Sjoerg			outchar('v');
12612099Sjoerg		if (s != '\0')
12712099Sjoerg			outchar(s);
12812099Sjoerg		outchar(t);
12912099Sjoerg		if (ts == ARRAY) {
13012099Sjoerg			outint(tp->t_dim);
13112099Sjoerg		} else if (ts == ENUM) {
13212099Sjoerg			outtt(tp->t_enum->etag, tp->t_enum->etdef);
13312099Sjoerg		} else if (ts == STRUCT || ts == UNION) {
13412099Sjoerg			outtt(tp->t_str->stag, tp->t_str->stdef);
13512099Sjoerg		} else if (ts == FUNC && tp->t_proto) {
13612099Sjoerg			na = 0;
13712099Sjoerg			for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
13812099Sjoerg					na++;
13912099Sjoerg			if (tp->t_vararg)
14012099Sjoerg				na++;
14112099Sjoerg			outint(na);
14212099Sjoerg			for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
14312099Sjoerg				outtype(arg->s_type);
14412099Sjoerg			if (tp->t_vararg)
14512099Sjoerg				outchar('E');
14612099Sjoerg		}
14712099Sjoerg		tp = tp->t_subt;
14812099Sjoerg	}
14912099Sjoerg}
15012099Sjoerg
15112099Sjoerg/*
15212099Sjoerg * type to string
15312099Sjoerg * used for debugging output
15412099Sjoerg *
15512099Sjoerg * it uses its own output buffer for conversion
15612099Sjoerg */
15712099Sjoergconst char *
15891586Smarkmttos(type_t *tp)
15912099Sjoerg{
16012099Sjoerg	static	ob_t	tob;
16112099Sjoerg	ob_t	tmp;
16212099Sjoerg
16312099Sjoerg	if (tob.o_buf == NULL) {
16412099Sjoerg		tob.o_len = 64;
16512099Sjoerg		tob.o_buf = tob.o_nxt = xmalloc(tob.o_len);
16612099Sjoerg		tob.o_end = tob.o_buf + tob.o_len;
16712099Sjoerg	}
16812099Sjoerg
16912099Sjoerg	tmp = ob;
17012099Sjoerg	ob = tob;
17112099Sjoerg	ob.o_nxt = ob.o_buf;
17212099Sjoerg	outtype(tp);
17312099Sjoerg	outchar('\0');
17412099Sjoerg	tob = ob;
17512099Sjoerg	ob = tmp;
17612099Sjoerg
17712099Sjoerg	return (tob.o_buf);
17812099Sjoerg}
17912099Sjoerg
18012099Sjoerg/*
18112099Sjoerg * write the name of a tag or typename
18212099Sjoerg *
18312099Sjoerg * if the tag is named, the name of the
18412099Sjoerg * tag is written, otherwise, if a typename exists which
18512099Sjoerg * refers to this tag, this typename is written
18612099Sjoerg */
18712099Sjoergstatic void
18891586Smarkmouttt(sym_t *tag, sym_t *tdef)
18912099Sjoerg{
19091586Smarkm
19191586Smarkm	/*
19291586Smarkm	 * 0 is no longer used.
19391586Smarkm	 */
19412099Sjoerg	if (tag->s_name != unnamed) {
19512099Sjoerg		outint(1);
19612099Sjoerg		outname(tag->s_name);
19712099Sjoerg	} else if (tdef != NULL) {
19812099Sjoerg		outint(2);
19912099Sjoerg		outname(tdef->s_name);
20012099Sjoerg	} else {
20191586Smarkm		outint(3);
20291586Smarkm		outint(tag->s_dpos.p_line);
20391586Smarkm		outchar('.');
20491586Smarkm		outint(getfnid(tag->s_dpos.p_file));
20591586Smarkm		outchar('.');
20691586Smarkm		outint(tag->s_dpos.p_uniq);
20712099Sjoerg	}
20812099Sjoerg}
20912099Sjoerg
21012099Sjoerg/*
211108470Sschweikh * write information about a global declared/defined symbol
21212099Sjoerg * with storage class extern
21312099Sjoerg *
21412099Sjoerg * informations about function definitions are written in outfdef(),
21512099Sjoerg * not here
21612099Sjoerg */
21712099Sjoergvoid
21891586Smarkmoutsym(sym_t *sym, scl_t sc, def_t def)
21912099Sjoerg{
22091586Smarkm
22112099Sjoerg	/*
22212099Sjoerg	 * Static function declarations must also be written to the output
22312099Sjoerg	 * file. Compatibility of function declarations (for both static
22412099Sjoerg	 * and extern functions) must be checked in lint2. Lint1 can't do
22512099Sjoerg	 * this, especially not, if functions are declared at block level
22612099Sjoerg	 * before their first declaration at level 0.
22712099Sjoerg	 */
22812099Sjoerg	if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
22912099Sjoerg		return;
23012099Sjoerg
23112099Sjoerg	/* reset buffer */
23212099Sjoerg	outclr();
23312099Sjoerg
23412099Sjoerg	/*
23512099Sjoerg	 * line number of .c source, 'd' for declaration, Id of current
23612099Sjoerg	 * source (.c or .h), and line in current source.
23712099Sjoerg	 */
23812099Sjoerg	outint(csrc_pos.p_line);
23912099Sjoerg	outchar('d');
24012099Sjoerg	outint(getfnid(sym->s_dpos.p_file));
24112099Sjoerg	outchar('.');
24212099Sjoerg	outint(sym->s_dpos.p_line);
24312099Sjoerg
24412099Sjoerg	/* flags */
24512099Sjoerg
24612099Sjoerg	switch (def) {
24712099Sjoerg	case DEF:
24812099Sjoerg		/* defined */
24912099Sjoerg		outchar('d');
25012099Sjoerg		break;
25112099Sjoerg	case TDEF:
25212099Sjoerg		/* tentative defined */
25312099Sjoerg		outchar('t');
25412099Sjoerg		break;
25512099Sjoerg	case DECL:
25612099Sjoerg		/* declared */
25712099Sjoerg		outchar('e');
25812099Sjoerg		break;
25912099Sjoerg	default:
260281168Spfg		LERROR("outsym()");
26112099Sjoerg	}
26212099Sjoerg	if (llibflg && def != DECL) {
26312099Sjoerg		/*
26412099Sjoerg		 * mark it as used so we get no warnings from lint2 about
26512099Sjoerg		 * unused symbols in libraries.
26612099Sjoerg		 */
26712099Sjoerg		outchar('u');
26812099Sjoerg	}
26912099Sjoerg
27012099Sjoerg	if (sc == STATIC)
27112099Sjoerg		outchar('s');
27212099Sjoerg
27312099Sjoerg	/* name of the symbol */
27412099Sjoerg	outname(sym->s_name);
27512099Sjoerg
27691586Smarkm	/* renamed name of symbol, if necessary */
27791586Smarkm	if (sym->s_rename) {
27891586Smarkm		outchar('r');
27991586Smarkm		outname(sym->s_rename);
28091586Smarkm	}
28191586Smarkm
28212099Sjoerg	/* type of the symbol */
28312099Sjoerg	outtype(sym->s_type);
28412099Sjoerg}
28512099Sjoerg
28612099Sjoerg/*
28712099Sjoerg * write information about function definition
28812099Sjoerg *
28912099Sjoerg * this is also done for static functions so we are able to check if
29012099Sjoerg * they are called with proper argument types
29112099Sjoerg */
29212099Sjoergvoid
29391586Smarkmoutfdef(sym_t *fsym, pos_t *posp, int rval, int osdef, sym_t *args)
29412099Sjoerg{
29512099Sjoerg	int	narg;
29612099Sjoerg	sym_t	*arg;
29712099Sjoerg
29812099Sjoerg	/* reset the buffer */
29912099Sjoerg	outclr();
30012099Sjoerg
30112099Sjoerg	/*
30212099Sjoerg	 * line number of .c source, 'd' for declaration, Id of current
30312099Sjoerg	 * source (.c or .h), and line in current source
30412099Sjoerg	 *
30512099Sjoerg	 * we are already at the end of the function. If we are in the
30612099Sjoerg	 * .c source, posp->p_line is correct, otherwise csrc_pos.p_line
30712099Sjoerg	 * (for functions defined in header files).
30812099Sjoerg	 */
30912099Sjoerg	if (posp->p_file == csrc_pos.p_file) {
31012099Sjoerg		outint(posp->p_line);
31112099Sjoerg	} else {
31212099Sjoerg		outint(csrc_pos.p_line);
31312099Sjoerg	}
31412099Sjoerg	outchar('d');
31512099Sjoerg	outint(getfnid(posp->p_file));
31612099Sjoerg	outchar('.');
31712099Sjoerg	outint(posp->p_line);
31812099Sjoerg
31912099Sjoerg	/* flags */
32012099Sjoerg
32112099Sjoerg	/* both SCANFLIKE and PRINTFLIKE imply VARARGS */
32212099Sjoerg	if (prflstrg != -1) {
32312099Sjoerg		nvararg = prflstrg;
32412099Sjoerg	} else if (scflstrg != -1) {
32512099Sjoerg		nvararg = scflstrg;
32612099Sjoerg	}
32712099Sjoerg
32812099Sjoerg	if (nvararg != -1) {
32912099Sjoerg		outchar('v');
33012099Sjoerg		outint(nvararg);
33112099Sjoerg	}
33212099Sjoerg	if (scflstrg != -1) {
33312099Sjoerg		outchar('S');
33412099Sjoerg		outint(scflstrg);
33512099Sjoerg	}
33612099Sjoerg	if (prflstrg != -1) {
33712099Sjoerg		outchar('P');
33812099Sjoerg		outint(prflstrg);
33912099Sjoerg	}
34012099Sjoerg	nvararg = prflstrg = scflstrg = -1;
34112099Sjoerg
34212099Sjoerg	outchar('d');
34312099Sjoerg
34412099Sjoerg	if (rval)
34512099Sjoerg		/* has return value */
34612099Sjoerg		outchar('r');
34712099Sjoerg
34812099Sjoerg	if (llibflg)
34912099Sjoerg		/*
35012099Sjoerg		 * mark it as used so lint2 does not complain about
35112099Sjoerg		 * unused symbols in libraries
35212099Sjoerg		 */
35312099Sjoerg		outchar('u');
35412099Sjoerg
35512099Sjoerg	if (osdef)
35612099Sjoerg		/* old style function definition */
35712099Sjoerg		outchar('o');
35812099Sjoerg
35912099Sjoerg	if (fsym->s_scl == STATIC)
36012099Sjoerg		outchar('s');
36112099Sjoerg
36212099Sjoerg	/* name of function */
36312099Sjoerg	outname(fsym->s_name);
36412099Sjoerg
36591586Smarkm	/* renamed name of function, if necessary */
36691586Smarkm	if (fsym->s_rename) {
36791586Smarkm		outchar('r');
36891586Smarkm		outname(fsym->s_rename);
36991586Smarkm	}
37091586Smarkm
37112099Sjoerg	/* argument types and return value */
37212099Sjoerg	if (osdef) {
37312099Sjoerg		narg = 0;
37412099Sjoerg		for (arg = args; arg != NULL; arg = arg->s_nxt)
37512099Sjoerg			narg++;
37612099Sjoerg		outchar('f');
37712099Sjoerg		outint(narg);
37812099Sjoerg		for (arg = args; arg != NULL; arg = arg->s_nxt)
37912099Sjoerg			outtype(arg->s_type);
38012099Sjoerg		outtype(fsym->s_type->t_subt);
38112099Sjoerg	} else {
38212099Sjoerg		outtype(fsym->s_type);
38312099Sjoerg	}
38412099Sjoerg}
38512099Sjoerg
38612099Sjoerg/*
38712099Sjoerg * write out all information necessary for lint2 to check function
38812099Sjoerg * calls
38912099Sjoerg *
39012099Sjoerg * rvused is set if the return value is used (asigned to a variable)
39112099Sjoerg * rvdisc is set if the return value is not used and not ignored
39212099Sjoerg * (casted to void)
39312099Sjoerg */
39412099Sjoergvoid
39591586Smarkmoutcall(tnode_t *tn, int rvused, int rvdisc)
39612099Sjoerg{
39712099Sjoerg	tnode_t	*args, *arg;
39812099Sjoerg	int	narg, n, i;
39991586Smarkm	int64_t	q;
40012099Sjoerg	tspec_t	t;
40112099Sjoerg
40212099Sjoerg	/* reset buffer */
40312099Sjoerg	outclr();
40412099Sjoerg
40512099Sjoerg	/*
40612099Sjoerg	 * line number of .c source, 'c' for function call, Id of current
40712099Sjoerg	 * source (.c or .h), and line in current source
40812099Sjoerg	 */
40912099Sjoerg	outint(csrc_pos.p_line);
41012099Sjoerg	outchar('c');
41112099Sjoerg	outint(getfnid(curr_pos.p_file));
41212099Sjoerg	outchar('.');
41312099Sjoerg	outint(curr_pos.p_line);
41412099Sjoerg
41512099Sjoerg	/*
41612099Sjoerg	 * flags; 'u' and 'i' must be last to make sure a letter
41712099Sjoerg	 * is between the numeric argument of a flag and the name of
41812099Sjoerg	 * the function
41912099Sjoerg	 */
42012099Sjoerg	narg = 0;
42112099Sjoerg	args = tn->tn_right;
42212099Sjoerg	for (arg = args; arg != NULL; arg = arg->tn_right)
42312099Sjoerg		narg++;
42412099Sjoerg	/* informations about arguments */
42512099Sjoerg	for (n = 1; n <= narg; n++) {
42612099Sjoerg		/* the last argument is the top one in the tree */
42791586Smarkm		for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
42891586Smarkm			continue;
42912099Sjoerg		arg = arg->tn_left;
43012099Sjoerg		if (arg->tn_op == CON) {
43112099Sjoerg			if (isityp(t = arg->tn_type->t_tspec)) {
43212099Sjoerg				/*
43312099Sjoerg				 * XXX it would probably be better to
43412099Sjoerg				 * explizitly test the sign
43512099Sjoerg				 */
43612099Sjoerg				if ((q = arg->tn_val->v_quad) == 0) {
43712099Sjoerg					/* zero constant */
43812099Sjoerg					outchar('z');
43912099Sjoerg				} else if (msb(q, t, 0) == 0) {
44012099Sjoerg					/* positive if casted to signed */
44112099Sjoerg					outchar('p');
44212099Sjoerg				} else {
44312099Sjoerg					/* negative if casted to signed */
44412099Sjoerg					outchar('n');
44512099Sjoerg				}
44612099Sjoerg				outint(n);
44712099Sjoerg			}
44812099Sjoerg		} else if (arg->tn_op == AMPER &&
44912099Sjoerg			   arg->tn_left->tn_op == STRING &&
45012099Sjoerg			   arg->tn_left->tn_strg->st_tspec == CHAR) {
45112099Sjoerg			/* constant string, write all format specifiers */
45212099Sjoerg			outchar('s');
45312099Sjoerg			outint(n);
45412099Sjoerg			outfstrg(arg->tn_left->tn_strg);
45512099Sjoerg		}
45612099Sjoerg
45712099Sjoerg	}
45812099Sjoerg	/* return value discarded/used/ignored */
45912099Sjoerg	outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i'));
46012099Sjoerg
46112099Sjoerg	/* name of the called function */
46212099Sjoerg	outname(tn->tn_left->tn_left->tn_sym->s_name);
46312099Sjoerg
46412099Sjoerg	/* types of arguments */
46512099Sjoerg	outchar('f');
46612099Sjoerg	outint(narg);
46712099Sjoerg	for (n = 1; n <= narg; n++) {
46812099Sjoerg		/* the last argument is the top one in the tree */
46991586Smarkm		for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
47091586Smarkm			continue;
47112099Sjoerg		outtype(arg->tn_left->tn_type);
47212099Sjoerg	}
47312099Sjoerg	/* expected type of return value */
47412099Sjoerg	outtype(tn->tn_type);
47512099Sjoerg}
47612099Sjoerg
47712099Sjoerg/*
47812099Sjoerg * extracts potential format specifiers for printf() and scanf() and
47912099Sjoerg * writes them, enclosed in "" and qouted if necessary, to the output buffer
48012099Sjoerg */
48112099Sjoergstatic void
48291586Smarkmoutfstrg(strg_t *strg)
48312099Sjoerg{
48412099Sjoerg	int	c, oc, first;
48512099Sjoerg	u_char	*cp;
48612099Sjoerg
48712099Sjoerg	if (strg->st_tspec != CHAR)
488281168Spfg		LERROR("outfstrg()");
48912099Sjoerg
49012099Sjoerg	cp = strg->st_cp;
49112099Sjoerg
49212099Sjoerg	outchar('"');
49312099Sjoerg
49412099Sjoerg	c = *cp++;
49512099Sjoerg
49612099Sjoerg	while (c != '\0') {
49712099Sjoerg
49812099Sjoerg		if (c != '%') {
49912099Sjoerg			c = *cp++;
50012099Sjoerg			continue;
50112099Sjoerg		}
50212099Sjoerg
50312099Sjoerg		outqchar('%');
50412099Sjoerg		c = *cp++;
50512099Sjoerg
50612099Sjoerg		/* flags for printf and scanf and *-fieldwidth for printf */
50712099Sjoerg		while (c != '\0' && (c == '-' || c == '+' || c == ' ' ||
50812099Sjoerg				     c == '#' || c == '0' || c == '*')) {
50912099Sjoerg			outqchar(c);
51012099Sjoerg			c = *cp++;
51112099Sjoerg		}
51212099Sjoerg
51312099Sjoerg		/* numeric field width */
51412099Sjoerg		while (c != '\0' && isdigit(c)) {
51512099Sjoerg			outqchar(c);
51612099Sjoerg			c = *cp++;
51712099Sjoerg		}
51812099Sjoerg
51912099Sjoerg		/* precision for printf */
52012099Sjoerg		if (c == '.') {
52112099Sjoerg			outqchar(c);
52212099Sjoerg			if ((c = *cp++) == '*') {
52312099Sjoerg				outqchar(c);
52412099Sjoerg				c = *cp++;
52512099Sjoerg			} else {
52612099Sjoerg				while (c != '\0' && isdigit(c)) {
52712099Sjoerg					outqchar(c);
52812099Sjoerg					c = *cp++;
52912099Sjoerg				}
53012099Sjoerg			}
53112099Sjoerg		}
53212099Sjoerg
53312099Sjoerg		/* h, l, L and q flags fpr printf and scanf */
53412099Sjoerg		if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
53512099Sjoerg			outqchar(c);
53612099Sjoerg			c = *cp++;
53712099Sjoerg		}
53812099Sjoerg
53912099Sjoerg		/*
54012099Sjoerg		 * The last character. It is always written so we can detect
54112099Sjoerg		 * invalid format specifiers.
54212099Sjoerg		 */
54312099Sjoerg		if (c != '\0') {
54412099Sjoerg			outqchar(c);
54512099Sjoerg			oc = c;
54612099Sjoerg			c = *cp++;
54712099Sjoerg			/*
54812099Sjoerg			 * handle [ for scanf. [-] means that a minus sign
54912099Sjoerg			 * was found at an undefined position.
55012099Sjoerg			 */
55112099Sjoerg			if (oc == '[') {
55212099Sjoerg				if (c == '^')
55312099Sjoerg					c = *cp++;
55412099Sjoerg				if (c == ']')
55512099Sjoerg					c = *cp++;
55612099Sjoerg				first = 1;
55712099Sjoerg				while (c != '\0' && c != ']') {
55812099Sjoerg					if (c == '-') {
55912099Sjoerg						if (!first && *cp != ']')
56012099Sjoerg							outqchar(c);
56112099Sjoerg					}
56212099Sjoerg					first = 0;
56312099Sjoerg					c = *cp++;
56412099Sjoerg				}
56512099Sjoerg				if (c == ']') {
56612099Sjoerg					outqchar(c);
56712099Sjoerg					c = *cp++;
56812099Sjoerg				}
56912099Sjoerg			}
57012099Sjoerg		}
57112099Sjoerg
57212099Sjoerg	}
57312099Sjoerg
57412099Sjoerg	outchar('"');
57512099Sjoerg}
57612099Sjoerg
57712099Sjoerg/*
57812099Sjoerg * writes a record if sym was used
57912099Sjoerg */
58012099Sjoergvoid
58191586Smarkmoutusg(sym_t *sym)
58212099Sjoerg{
58312099Sjoerg	/* reset buffer */
58412099Sjoerg	outclr();
58512099Sjoerg
58612099Sjoerg	/*
58712099Sjoerg	 * line number of .c source, 'u' for used, Id of current
58812099Sjoerg	 * source (.c or .h), and line in current source
58912099Sjoerg	 */
59012099Sjoerg	outint(csrc_pos.p_line);
59112099Sjoerg	outchar('u');
59212099Sjoerg	outint(getfnid(curr_pos.p_file));
59312099Sjoerg	outchar('.');
59412099Sjoerg	outint(curr_pos.p_line);
59512099Sjoerg
59612099Sjoerg	/* necessary to delimit both numbers */
59712099Sjoerg	outchar('x');
59812099Sjoerg
59912099Sjoerg	/* Den Namen des Symbols ausgeben */
60012099Sjoerg	outname(sym->s_name);
60112099Sjoerg}
602