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