1*753d2d2eSraf /*
2*753d2d2eSraf  * CDDL HEADER START
3*753d2d2eSraf  *
4*753d2d2eSraf  * The contents of this file are subject to the terms of the
5*753d2d2eSraf  * Common Development and Distribution License, Version 1.0 only
6*753d2d2eSraf  * (the "License").  You may not use this file except in compliance
7*753d2d2eSraf  * with the License.
8*753d2d2eSraf  *
9*753d2d2eSraf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*753d2d2eSraf  * or http://www.opensolaris.org/os/licensing.
11*753d2d2eSraf  * See the License for the specific language governing permissions
12*753d2d2eSraf  * and limitations under the License.
13*753d2d2eSraf  *
14*753d2d2eSraf  * When distributing Covered Code, include this CDDL HEADER in each
15*753d2d2eSraf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*753d2d2eSraf  * If applicable, add the following below this CDDL HEADER, with the
17*753d2d2eSraf  * fields enclosed by brackets "[]" replaced with your own identifying
18*753d2d2eSraf  * information: Portions Copyright [yyyy] [name of copyright owner]
19*753d2d2eSraf  *
20*753d2d2eSraf  * CDDL HEADER END
21*753d2d2eSraf  */
22*753d2d2eSraf /*
23*753d2d2eSraf  * Copyright (c) 1997-1999 by Sun Microsystems, Inc.
24*753d2d2eSraf  * All rights reserved.
25*753d2d2eSraf  */
26*753d2d2eSraf 
27*753d2d2eSraf #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*753d2d2eSraf 
29*753d2d2eSraf #include <stdlib.h>
30*753d2d2eSraf #include <stdio.h>
31*753d2d2eSraf #include <string.h>
32*753d2d2eSraf #include <limits.h>
33*753d2d2eSraf #include "parser.h"
34*753d2d2eSraf #include "trace.h"
35*753d2d2eSraf #include "util.h"
36*753d2d2eSraf #include "db.h"
37*753d2d2eSraf #include "symtab.h"
38*753d2d2eSraf #include "io.h"
39*753d2d2eSraf #include "printfuncs.h"
40*753d2d2eSraf #include "errlog.h"
41*753d2d2eSraf 
42*753d2d2eSraf static int	 prepare_printf_part(ENTRY *, char *, char *, int);
43*753d2d2eSraf static char	 *space_to_uscore(char const *);
44*753d2d2eSraf 
45*753d2d2eSraf static char	arglist[_POSIX_ARG_MAX];
46*753d2d2eSraf 
47*753d2d2eSraf /*
48*753d2d2eSraf  * generate_printf -- make the cleanest possible printf for the
49*753d2d2eSraf  *	parameters, in a relatively terse apptrace/dbx-like format,
50*753d2d2eSraf  *	ending in ") = ", or ) if its a void function we're doing.
51*753d2d2eSraf  */
52*753d2d2eSraf void
53*753d2d2eSraf generate_printf(ENTRY *f)
54*753d2d2eSraf {
55*753d2d2eSraf 	ENTRY	*e;
56*753d2d2eSraf 	char	*p, *name;
57*753d2d2eSraf 	int	l, n;
58*753d2d2eSraf 
59*753d2d2eSraf 	errlog(BEGIN, "generate_printf");
60*753d2d2eSraf 	(void) fprintf(Bodyfp, "    fprintf(ABISTREAM, \"");
61*753d2d2eSraf 	p = &arglist[0];
62*753d2d2eSraf 	l = (int)sizeof (arglist);
63*753d2d2eSraf 	*p = NULL;
64*753d2d2eSraf 	for (e = symtab_get_first_arg(); e != NULL; e = symtab_get_next_arg()) {
65*753d2d2eSraf 		errlog(TRACING, "arglist = '%s'", arglist);
66*753d2d2eSraf 
67*753d2d2eSraf 		if (is_void(e)) {
68*753d2d2eSraf 			/* This placeholder means there are no real args. */
69*753d2d2eSraf 			break;
70*753d2d2eSraf 		}
71*753d2d2eSraf 		/* Insert punctuation. */
72*753d2d2eSraf 		if (p != &arglist[0]) {
73*753d2d2eSraf 			(void) fprintf(Bodyfp, ", ");
74*753d2d2eSraf 		}
75*753d2d2eSraf 		if (*(name =  name_of(e)) == NULL) {
76*753d2d2eSraf 			/* It's a varargs indicator instead */
77*753d2d2eSraf 			(void) fprintf(Bodyfp, "...");
78*753d2d2eSraf 		} else {
79*753d2d2eSraf 			(void) fprintf(Bodyfp, "%s = ", name);
80*753d2d2eSraf 			n = prepare_printf_part(e, name, p, l);
81*753d2d2eSraf 			l -= n;
82*753d2d2eSraf 			p += n;
83*753d2d2eSraf 			*(p+1) = NULL;
84*753d2d2eSraf 		}
85*753d2d2eSraf 	}
86*753d2d2eSraf 
87*753d2d2eSraf 	if (is_void(f) || symtab_get_nonreturn() == YES) {
88*753d2d2eSraf 		/* It is a function returning void, or a function */
89*753d2d2eSraf 		/* which doesn't return. Close off args. */
90*753d2d2eSraf 		(void) fprintf(Bodyfp, ")\"");
91*753d2d2eSraf 	} else {
92*753d2d2eSraf 		/* Make some more printf for the return type. */
93*753d2d2eSraf 		(void) fprintf(Bodyfp, ") = ");
94*753d2d2eSraf 		(void) prepare_printf_part(f, "_return", p, l);
95*753d2d2eSraf 		(void) fprintf(Bodyfp, "\"");
96*753d2d2eSraf 
97*753d2d2eSraf 	}
98*753d2d2eSraf 	(void) fprintf(Bodyfp, "%s);\n", arglist);
99*753d2d2eSraf 	errlog(END, "}");
100*753d2d2eSraf }
101*753d2d2eSraf 
102*753d2d2eSraf 
103*753d2d2eSraf /*
104*753d2d2eSraf  * prepare_printf_part -- do one element of a printf/argument string,
105*753d2d2eSraf  *	for printing non-verbose parameter lists
106*753d2d2eSraf  */
107*753d2d2eSraf static int
108*753d2d2eSraf prepare_printf_part(ENTRY *e, char *name, char *place, int size)
109*753d2d2eSraf {
110*753d2d2eSraf 	char	*bt;
111*753d2d2eSraf 	int	li;
112*753d2d2eSraf 
113*753d2d2eSraf 	errlog(BEGIN, "prepare_printf_part() {");
114*753d2d2eSraf 	errlog(TRACING, "name = '%s'", name);
115*753d2d2eSraf 
116*753d2d2eSraf 	bt = basetype_of(e);
117*753d2d2eSraf 	li = levels_of(e);
118*753d2d2eSraf 
119*753d2d2eSraf 	if (li == 1 && (strcmp(bt, "char") == 0)) {
120*753d2d2eSraf 		/* It's a string, print the beginning of it. */
121*753d2d2eSraf 		(void) fputs("\\\"%.*s\\\"", Bodyfp);
122*753d2d2eSraf 		size = snprintf(place, size,
123*753d2d2eSraf 		    /*CSTYLED*/
124*753d2d2eSraf 		    ",\n\tabi_strpsz, (%s) ? %s : nilstr",
125*753d2d2eSraf 		    name, name);
126*753d2d2eSraf 	} else {
127*753d2d2eSraf 		/* Just print a hex value */
128*753d2d2eSraf 		(void) fprintf(Bodyfp, "%s", "0x%p");
129*753d2d2eSraf 		size = snprintf(place, size, ", \n\t%s", name);
130*753d2d2eSraf 	}
131*753d2d2eSraf 
132*753d2d2eSraf 	errlog(TRACING, "place='%s'\n", place);
133*753d2d2eSraf 	errlog(END, "}");
134*753d2d2eSraf 	return (size);
135*753d2d2eSraf 
136*753d2d2eSraf }
137*753d2d2eSraf 
138*753d2d2eSraf 
139*753d2d2eSraf /*
140*753d2d2eSraf  * generate_printfunc_calls -- generate print commands for primitive types
141*753d2d2eSraf  *	and calls to print functions for composite types, cleanly.
142*753d2d2eSraf  *	Needs to know about base types of primitives, difference
143*753d2d2eSraf  *	between primitives and composite types: TBD.
144*753d2d2eSraf  */
145*753d2d2eSraf void
146*753d2d2eSraf generate_printfunc_calls(ENTRY *f)
147*753d2d2eSraf {
148*753d2d2eSraf 	ENTRY	*e;
149*753d2d2eSraf 	char	*name;
150*753d2d2eSraf 	char	*pf_str_name;
151*753d2d2eSraf 	int	li;
152*753d2d2eSraf 	char	*format;
153*753d2d2eSraf 
154*753d2d2eSraf 	errlog(BEGIN, "generate_printfunc_calls() {");
155*753d2d2eSraf 	for (e = symtab_get_first_arg(); e != NULL; e = symtab_get_next_arg()) {
156*753d2d2eSraf 		if (is_void(e)) {
157*753d2d2eSraf 			break;
158*753d2d2eSraf 		}
159*753d2d2eSraf 		if (*(name = name_of(e)) == NULL) {
160*753d2d2eSraf 			(void) fprintf(Bodyfp, "        fputs(\"  ...\\n\", "
161*753d2d2eSraf 				"ABISTREAM);\n");
162*753d2d2eSraf 		}
163*753d2d2eSraf 		errlog(TRACING, "name = '%s'\n", name);
164*753d2d2eSraf 		(void) fprintf(Bodyfp,
165*753d2d2eSraf 		    "        fprintf(ABISTREAM, \"  %s = \");\n",
166*753d2d2eSraf 		    name);
167*753d2d2eSraf 
168*753d2d2eSraf 		pf_str_name = space_to_uscore(basetype_of(e));
169*753d2d2eSraf 
170*753d2d2eSraf 		/*
171*753d2d2eSraf 		 * If we're dealing with a scalar (non-pointer) then
172*753d2d2eSraf 		 * we need to call the printer with a &
173*753d2d2eSraf 		 */
174*753d2d2eSraf 		li = levels_of(e);
175*753d2d2eSraf 		if (li)
176*753d2d2eSraf 			format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
177*753d2d2eSraf 			    "(void const *)%s);\n";
178*753d2d2eSraf 		else
179*753d2d2eSraf 			format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
180*753d2d2eSraf 			    "(void const *)&%s);\n";
181*753d2d2eSraf 
182*753d2d2eSraf 		(void) fprintf(Bodyfp, format, pf_str_name, li, name);
183*753d2d2eSraf 
184*753d2d2eSraf 		free(pf_str_name);
185*753d2d2eSraf 	}
186*753d2d2eSraf 
187*753d2d2eSraf 	if (is_void(f)) {
188*753d2d2eSraf 		/*EMPTY*/;
189*753d2d2eSraf 	} else {
190*753d2d2eSraf 		pf_str_name = space_to_uscore(basetype_of(f));
191*753d2d2eSraf 
192*753d2d2eSraf 		li = levels_of(f);
193*753d2d2eSraf 		if (li)
194*753d2d2eSraf 			format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
195*753d2d2eSraf 			    "(void const *)_return);\n";
196*753d2d2eSraf 		else
197*753d2d2eSraf 			format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
198*753d2d2eSraf 			    "(void const *)&_return);\n";
199*753d2d2eSraf 
200*753d2d2eSraf 		(void) fputs("        fputs(retstr, ABISTREAM);\n", Bodyfp);
201*753d2d2eSraf 		(void) fprintf(Bodyfp, format, pf_str_name, li);
202*753d2d2eSraf 
203*753d2d2eSraf 		free(pf_str_name);
204*753d2d2eSraf 	}
205*753d2d2eSraf 
206*753d2d2eSraf 	errlog(END, "}");
207*753d2d2eSraf }
208*753d2d2eSraf 
209*753d2d2eSraf 
210*753d2d2eSraf /*
211*753d2d2eSraf  * Print Function Pointers -- definition, declaration and initialization.
212*753d2d2eSraf  *	Use is above...
213*753d2d2eSraf  */
214*753d2d2eSraf 
215*753d2d2eSraf /*
216*753d2d2eSraf  * generate_print_definitions -- generate variable definitions and
217*753d2d2eSraf  *	initialize them to NULL.
218*753d2d2eSraf  *      These will be set non-null by a lazy evaluation in the
219*753d2d2eSraf  *	main.c file if and only if the print function will be used.
220*753d2d2eSraf  *	All print functions which can be called must be defined.
221*753d2d2eSraf  */
222*753d2d2eSraf void
223*753d2d2eSraf generate_print_definitions(FILE *fp)
224*753d2d2eSraf {
225*753d2d2eSraf 	char	*print_type,
226*753d2d2eSraf 		*c_type,
227*753d2d2eSraf 		*pf_str_name;
228*753d2d2eSraf 
229*753d2d2eSraf 	errlog(BEGIN, "generate_print_definitions() {");
230*753d2d2eSraf 	for (print_type = db_get_first_print_type();
231*753d2d2eSraf 		print_type != NULL;
232*753d2d2eSraf 			print_type = db_get_next_print_type()) {
233*753d2d2eSraf 		c_type = strchr(print_type, ','); /* Safe by construction. */
234*753d2d2eSraf 		*c_type++ = NULL;
235*753d2d2eSraf 		errlog(TRACING,  "print_type=%s\n", print_type);
236*753d2d2eSraf 
237*753d2d2eSraf 		pf_str_name = space_to_uscore(print_type);
238*753d2d2eSraf 
239*753d2d2eSraf 		(void) fprintf(fp,
240*753d2d2eSraf 		    "char const *pf_%s_str = \"%s\";\n",
241*753d2d2eSraf 		    pf_str_name, print_type);
242*753d2d2eSraf 
243*753d2d2eSraf 		free(pf_str_name);
244*753d2d2eSraf 
245*753d2d2eSraf 		*--c_type = ',';
246*753d2d2eSraf 	}
247*753d2d2eSraf 
248*753d2d2eSraf 	errlog(END, "}");
249*753d2d2eSraf }
250*753d2d2eSraf 
251*753d2d2eSraf /*
252*753d2d2eSraf  * generate_print_declarations -- generate variable declarations
253*753d2d2eSraf  *	for the strings that'll be used as arguments to the type
254*753d2d2eSraf  *	printing function.
255*753d2d2eSraf  */
256*753d2d2eSraf void
257*753d2d2eSraf generate_print_declarations(FILE *fp)
258*753d2d2eSraf {
259*753d2d2eSraf 	char	*print_type,
260*753d2d2eSraf 		*c_type,
261*753d2d2eSraf 		*pf_str_name;
262*753d2d2eSraf 
263*753d2d2eSraf 	errlog(BEGIN, "generate_print_declarations() {");
264*753d2d2eSraf 	for (print_type = symtab_get_first_print_type();
265*753d2d2eSraf 	    print_type != NULL;
266*753d2d2eSraf 	    print_type = symtab_get_next_print_type()) {
267*753d2d2eSraf 
268*753d2d2eSraf 		errlog(TRACING,  "print_type, c_type=%s\n", print_type);
269*753d2d2eSraf 
270*753d2d2eSraf 		c_type = strchr(print_type, ','); /* Safe by construction. */
271*753d2d2eSraf 		*c_type++ = NULL;
272*753d2d2eSraf 
273*753d2d2eSraf 		pf_str_name = space_to_uscore(print_type);
274*753d2d2eSraf 
275*753d2d2eSraf 		(void) fprintf(fp, "extern char const *pf_%s_str;\n",
276*753d2d2eSraf 		    pf_str_name);
277*753d2d2eSraf 
278*753d2d2eSraf 		free(pf_str_name);
279*753d2d2eSraf 
280*753d2d2eSraf 		*--c_type = ',';
281*753d2d2eSraf 	}
282*753d2d2eSraf 
283*753d2d2eSraf 	errlog(END, "}");
284*753d2d2eSraf }
285*753d2d2eSraf 
286*753d2d2eSraf /*
287*753d2d2eSraf  * is_void -- see if a type is void.
288*753d2d2eSraf  */
289*753d2d2eSraf int
290*753d2d2eSraf is_void(ENTRY *e)
291*753d2d2eSraf {
292*753d2d2eSraf 	if ((e != NULL) &&
293*753d2d2eSraf 	    levels_of(e) == 0 && (strcmp(basetype_of(e), "void") == 0))
294*753d2d2eSraf 		return (1);
295*753d2d2eSraf 	else
296*753d2d2eSraf 		return (0);
297*753d2d2eSraf }
298*753d2d2eSraf 
299*753d2d2eSraf static char *
300*753d2d2eSraf space_to_uscore(char const *str)
301*753d2d2eSraf {
302*753d2d2eSraf 	char *strp, *p;
303*753d2d2eSraf 
304*753d2d2eSraf 	strp = strdup(str);
305*753d2d2eSraf 
306*753d2d2eSraf 	assert(strp != NULL, "strdup failed");
307*753d2d2eSraf 
308*753d2d2eSraf 	for (p = strp; *p != '\0'; p++)
309*753d2d2eSraf 		if (*p == ' ')
310*753d2d2eSraf 			*p = '_';
311*753d2d2eSraf 
312*753d2d2eSraf 	return (strp);
313*753d2d2eSraf }
314