17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate/*
307c478bdstevel@tonic-gate * Read in "high-level" adb script and emit C program.
317c478bdstevel@tonic-gate * The input may have specifications within {} which
327c478bdstevel@tonic-gate * we analyze and then emit C code to generate the
337c478bdstevel@tonic-gate * ultimate adb acript.
347c478bdstevel@tonic-gate * We are just a filter; no arguments are accepted.
357c478bdstevel@tonic-gate */
367c478bdstevel@tonic-gate
377c478bdstevel@tonic-gate#include <stdio.h>
387c478bdstevel@tonic-gate#include <stdlib.h>
397c478bdstevel@tonic-gate#include <string.h>
407c478bdstevel@tonic-gate
417c478bdstevel@tonic-gate#define	streq(s1, s2)	(strcmp(s1, s2) == 0)
427c478bdstevel@tonic-gate
437c478bdstevel@tonic-gate#define	LINELEN  	1024	/* max line length expected in input */
447c478bdstevel@tonic-gate#define	STRLEN		128	/* for shorter strings */
457c478bdstevel@tonic-gate#define	NARGS		5	/* number of emitted subroutine arguments */
467c478bdstevel@tonic-gate
477c478bdstevel@tonic-gate/*
487c478bdstevel@tonic-gate * Format specifier strings
497c478bdstevel@tonic-gate * which are recognized by adbgen when surrounded by {}
507c478bdstevel@tonic-gate */
517c478bdstevel@tonic-gate#define	FSTR_PTR	"POINTER"
527c478bdstevel@tonic-gate#define	FSTR_LONG_DEC	"LONGDEC"
537c478bdstevel@tonic-gate#define	FSTR_LONG_OCT	"LONGOCT"
547c478bdstevel@tonic-gate#define	FSTR_ULONG_DEC	"ULONGDEC"
557c478bdstevel@tonic-gate#define	FSTR_ULONG_HEX	"ULONGHEX"
567c478bdstevel@tonic-gate#define	FSTR_ULONG_OCT	"ULONGOCT"
577c478bdstevel@tonic-gate
587c478bdstevel@tonic-gate/*
597c478bdstevel@tonic-gate * Types of specifications in {}.
607c478bdstevel@tonic-gate */
617c478bdstevel@tonic-gate#define	PTR_HEX		0	/* emit hex pointer format char */
627c478bdstevel@tonic-gate#define	LONG_DEC	1	/* emit decimal long format char */
637c478bdstevel@tonic-gate#define	LONG_OCT	2	/* emit octal unsigned long format char */
647c478bdstevel@tonic-gate#define	ULONG_DEC	3	/* emit decimal unsigned long format char */
657c478bdstevel@tonic-gate#define	ULONG_HEX	4	/* emit hexadecimal long format char */
667c478bdstevel@tonic-gate#define	ULONG_OCT	5	/* emit octal unsigned long format char */
677c478bdstevel@tonic-gate
687c478bdstevel@tonic-gate#define	FMT_ENTRIES	6	/* number of adbgen format specifier strings */
697c478bdstevel@tonic-gate
707c478bdstevel@tonic-gate#define	PRINT   	6	/* print member name with format */
717c478bdstevel@tonic-gate#define	INDIRECT	7	/* fetch member value */
727c478bdstevel@tonic-gate#define	OFFSETOK	8	/* insist that the offset is ok */
737c478bdstevel@tonic-gate#define	SIZEOF		9	/* print sizeof struct */
747c478bdstevel@tonic-gate#define	END		10	/* get offset to end of struct */
757c478bdstevel@tonic-gate#define	OFFSET		11	/* just emit offset */
767c478bdstevel@tonic-gate#define	EXPR		12	/* arbitrary C expression */
777c478bdstevel@tonic-gate
787c478bdstevel@tonic-gate/*
797c478bdstevel@tonic-gate * Special return code from nextchar.
807c478bdstevel@tonic-gate */
817c478bdstevel@tonic-gate#define	CPP		-2	/* cpp line, restart parsing */
827c478bdstevel@tonic-gate
837c478bdstevel@tonic-gatetypedef struct adbgen_fmt {
847c478bdstevel@tonic-gate	char *f_str;
857c478bdstevel@tonic-gate	char f_char;
867c478bdstevel@tonic-gate} adbgen_fmt_t;
877c478bdstevel@tonic-gate
887c478bdstevel@tonic-gatechar struct_name[STRLEN];	/* struct name */
897c478bdstevel@tonic-gatechar member[STRLEN];		/* member name */
907c478bdstevel@tonic-gatechar format[STRLEN];		/* adb format spec */
917c478bdstevel@tonic-gatechar arg[NARGS][STRLEN];	/* arg list for called subroutine */
927c478bdstevel@tonic-gatechar *ptr_hex_fmt;		/* adb format character for pointer in hex */
937c478bdstevel@tonic-gatechar *long_dec_fmt;		/* adb format character for long in decimal */
947c478bdstevel@tonic-gatechar *ulong_dec_fmt;		/* adb format character for ulong in decimal */
957c478bdstevel@tonic-gatechar *ulong_hex_fmt;		/* adb format character for ulong in hex */
967c478bdstevel@tonic-gatechar *long_oct_fmt;		/* adb format character for long in octal */
977c478bdstevel@tonic-gatechar *ulong_oct_fmt;		/* adb format character for ulong in octal */
987c478bdstevel@tonic-gate
997c478bdstevel@tonic-gateint line_no = 1;		/* input line number - for error messages */
1007c478bdstevel@tonic-gateint specsize;			/* size of {} specification - 1 or 2 parts */
1017c478bdstevel@tonic-gateint state;			/* XXX 1 = gathering a printf */
1027c478bdstevel@tonic-gate				/* This is a kludge so we emit pending */
1037c478bdstevel@tonic-gate				/* printf's when we see a CPP line */
1047c478bdstevel@tonic-gate
1057c478bdstevel@tonic-gateadbgen_fmt_t adbgen_fmt_tbl [FMT_ENTRIES] = {
1067c478bdstevel@tonic-gate	{FSTR_PTR},
1077c478bdstevel@tonic-gate	{FSTR_LONG_DEC},
1087c478bdstevel@tonic-gate	{FSTR_LONG_OCT},
1097c478bdstevel@tonic-gate	{FSTR_ULONG_DEC},
1107c478bdstevel@tonic-gate	{FSTR_ULONG_HEX},
1117c478bdstevel@tonic-gate	{FSTR_ULONG_OCT}
1127c478bdstevel@tonic-gate};
1137c478bdstevel@tonic-gate
1147c478bdstevel@tonic-gatevoid emit_call(char *name, int nargs);
1157c478bdstevel@tonic-gatevoid emit_end(void);
1167c478bdstevel@tonic-gatevoid emit_expr(void);
1177c478bdstevel@tonic-gatevoid emit_indirect(void);
1187c478bdstevel@tonic-gatevoid emit_offset(void);
1197c478bdstevel@tonic-gatevoid emit_offsetok(void);
1207c478bdstevel@tonic-gatevoid emit_print(void);
1217c478bdstevel@tonic-gatevoid emit_printf(char *cp);
1227c478bdstevel@tonic-gatevoid emit_sizeof(void);
1237c478bdstevel@tonic-gatevoid generate(void);
1247c478bdstevel@tonic-gateint get_type(void);
1257c478bdstevel@tonic-gateint nextchar(char *cp);
1267c478bdstevel@tonic-gatevoid read_spec(void);
1277c478bdstevel@tonic-gatechar *start_printf(void);
1287c478bdstevel@tonic-gate
1297c478bdstevel@tonic-gateint
1307c478bdstevel@tonic-gatemain(int argc, char **argv)
1317c478bdstevel@tonic-gate{
1327c478bdstevel@tonic-gate	char *cp;
1337c478bdstevel@tonic-gate	int c;
1347c478bdstevel@tonic-gate	int warn_flag = 0;
1357c478bdstevel@tonic-gate	int is_lp64 = 0;
1367c478bdstevel@tonic-gate	char *usage = "adbgen1 [-w] [-m ilp32|lp64] < <macro file>\n";
1377c478bdstevel@tonic-gate
1387c478bdstevel@tonic-gate	while ((c = getopt(argc, argv, "m:w")) != EOF) {
1397c478bdstevel@tonic-gate		switch (c) {
1407c478bdstevel@tonic-gate		case 'm':
1417c478bdstevel@tonic-gate			if (streq(optarg, "ilp32"))
1427c478bdstevel@tonic-gate				is_lp64 = 0;
1437c478bdstevel@tonic-gate			else if (streq(optarg, "lp64"))
1447c478bdstevel@tonic-gate				is_lp64 = 1;
1457c478bdstevel@tonic-gate			else
1467c478bdstevel@tonic-gate				fprintf(stderr, usage);
1477c478bdstevel@tonic-gate			break;
1487c478bdstevel@tonic-gate		case 'w':
1497c478bdstevel@tonic-gate			warn_flag++;
1507c478bdstevel@tonic-gate			break;
1517c478bdstevel@tonic-gate		case '?':
1527c478bdstevel@tonic-gate			fprintf(stderr, usage);
1537c478bdstevel@tonic-gate			break;
1547c478bdstevel@tonic-gate		}
1557c478bdstevel@tonic-gate	}
1567c478bdstevel@tonic-gate	if (is_lp64) {
1577c478bdstevel@tonic-gate		adbgen_fmt_tbl[PTR_HEX].f_char = 'J';
1587c478bdstevel@tonic-gate		adbgen_fmt_tbl[LONG_DEC].f_char = 'e';
1597c478bdstevel@tonic-gate		adbgen_fmt_tbl[LONG_OCT].f_char = 'g';
1607c478bdstevel@tonic-gate		adbgen_fmt_tbl[ULONG_DEC].f_char = 'E';
1617c478bdstevel@tonic-gate		adbgen_fmt_tbl[ULONG_HEX].f_char = 'J';
1627c478bdstevel@tonic-gate		adbgen_fmt_tbl[ULONG_OCT].f_char = 'G';
1637c478bdstevel@tonic-gate	} else {
1647c478bdstevel@tonic-gate		adbgen_fmt_tbl[PTR_HEX].f_char = 'X';
1657c478bdstevel@tonic-gate		adbgen_fmt_tbl[LONG_DEC].f_char = 'D';
1667c478bdstevel@tonic-gate		adbgen_fmt_tbl[LONG_OCT].f_char = 'Q';
1677c478bdstevel@tonic-gate		adbgen_fmt_tbl[ULONG_DEC].f_char = 'U';
1687c478bdstevel@tonic-gate		adbgen_fmt_tbl[ULONG_HEX].f_char = 'X';
1697c478bdstevel@tonic-gate		adbgen_fmt_tbl[ULONG_OCT].f_char = 'O';
1707c478bdstevel@tonic-gate	}
1717c478bdstevel@tonic-gate
1727c478bdstevel@tonic-gate	/*
1737c478bdstevel@tonic-gate	 * Get structure name.
1747c478bdstevel@tonic-gate	 */
1757c478bdstevel@tonic-gate	cp = struct_name;
1767c478bdstevel@tonic-gate	while ((c = nextchar(NULL)) != '\n') {
1777c478bdstevel@tonic-gate		if (c == EOF) {
1787c478bdstevel@tonic-gate			fprintf(stderr, "Premature EOF\n");
1797c478bdstevel@tonic-gate			exit(1);
1807c478bdstevel@tonic-gate		}
1817c478bdstevel@tonic-gate		if (c == CPP)
1827c478bdstevel@tonic-gate			continue;
1837c478bdstevel@tonic-gate		*cp++ = (char)c;
1847c478bdstevel@tonic-gate	}
1857c478bdstevel@tonic-gate	*cp = '\0';
1867c478bdstevel@tonic-gate	/*
1877c478bdstevel@tonic-gate	 * Basically, the generated program is just an ongoing printf
1887c478bdstevel@tonic-gate	 * with breaks for {} format specifications.
1897c478bdstevel@tonic-gate	 */
1907c478bdstevel@tonic-gate	printf("\n");
1917c478bdstevel@tonic-gate	printf("#include <sys/types.h>\n");
1927c478bdstevel@tonic-gate	printf("#include <sys/inttypes.h>\n");
1937c478bdstevel@tonic-gate	printf("\n\n");
1947c478bdstevel@tonic-gate	printf("int do_fmt(char *acp);\n");
1957c478bdstevel@tonic-gate	printf("void format(char *name, size_t size, char *fmt);\n");
1967c478bdstevel@tonic-gate	printf("void indirect(off_t offset, size_t size, "
1977c478bdstevel@tonic-gate	    "char *base, char *member);\n");
1987c478bdstevel@tonic-gate	printf("void offset(off_t off);\n");
1997c478bdstevel@tonic-gate	printf("void offsetok(void);\n");
2007c478bdstevel@tonic-gate	printf("\n\n");
2017c478bdstevel@tonic-gate	printf("main(int argc, char *argv[])\n");
2027c478bdstevel@tonic-gate	printf("{\n");
2037c478bdstevel@tonic-gate	if (warn_flag) {
2047c478bdstevel@tonic-gate		printf("\textern int warnings;\n\n\twarnings = 0;\n");
2057c478bdstevel@tonic-gate	}
2067c478bdstevel@tonic-gate	cp = start_printf();
2077c478bdstevel@tonic-gate	while ((c = nextchar(cp)) != EOF) {
2087c478bdstevel@tonic-gate		switch (c) {
2097c478bdstevel@tonic-gate		case '"':
2107c478bdstevel@tonic-gate			*cp++ = '\\';	/* escape ' in string */
2117c478bdstevel@tonic-gate			*cp++ = '"';
2127c478bdstevel@tonic-gate			break;
2137c478bdstevel@tonic-gate		case '\n':
2147c478bdstevel@tonic-gate			*cp++ = '\\';	/* escape newline in string */
2157c478bdstevel@tonic-gate			*cp++ = 'n';
2167c478bdstevel@tonic-gate			break;
2177c478bdstevel@tonic-gate		case '{':
2187c478bdstevel@tonic-gate			emit_printf(cp);
2197c478bdstevel@tonic-gate			read_spec();
2207c478bdstevel@tonic-gate			generate();
2217c478bdstevel@tonic-gate			cp = start_printf();
2227c478bdstevel@tonic-gate			break;
2237c478bdstevel@tonic-gate		case CPP:
2247c478bdstevel@tonic-gate			/*
2257c478bdstevel@tonic-gate			 * Restart printf after cpp line.
2267c478bdstevel@tonic-gate			 */
2277c478bdstevel@tonic-gate			cp = start_printf();
2287c478bdstevel@tonic-gate			break;
2297c478bdstevel@tonic-gate		default:
2307c478bdstevel@tonic-gate			*cp++ = c;
2317c478bdstevel@tonic-gate			break;
2327c478bdstevel@tonic-gate		}
2337c478bdstevel@tonic-gate		if (cp - arg[1] >= STRLEN - 10) {
2347c478bdstevel@tonic-gate			emit_printf(cp);
2357c478bdstevel@tonic-gate			cp = start_printf();
2367c478bdstevel@tonic-gate		}
2377c478bdstevel@tonic-gate	}
2387c478bdstevel@tonic-gate	emit_printf(cp);
2397c478bdstevel@tonic-gate
2407c478bdstevel@tonic-gate	/* terminate program, checking for "error" mode */
2417c478bdstevel@tonic-gate	printf("\n\tif (argc > 1 && strcmp(argv[1], \"-e\") == 0) {\n");
2427c478bdstevel@tonic-gate	printf("\t\textern int warns;\n\n");
2437c478bdstevel@tonic-gate	printf("\t\tif (warns)\n");
2447c478bdstevel@tonic-gate	printf("\t\t\treturn (1);\n");
2457c478bdstevel@tonic-gate	printf("\t}\n");
2467c478bdstevel@tonic-gate	printf("\treturn (0);\n");
2477c478bdstevel@tonic-gate	printf("}\n");
2487c478bdstevel@tonic-gate
2497c478bdstevel@tonic-gate	return (0);
2507c478bdstevel@tonic-gate}
2517c478bdstevel@tonic-gate
2527c478bdstevel@tonic-gateint
2537c478bdstevel@tonic-gatenextchar(char *cp)
2547c478bdstevel@tonic-gate{
2557c478bdstevel@tonic-gate	int c;
2567c478bdstevel@tonic-gate	static int newline = 1;
2577c478bdstevel@tonic-gate
2587c478bdstevel@tonic-gate	c = getchar();
2597c478bdstevel@tonic-gate	/*
2607c478bdstevel@tonic-gate	 * Lines beginning with '#' and blank lines are passed right through.
2617c478bdstevel@tonic-gate	 */
2627c478bdstevel@tonic-gate	while (newline) {
2637c478bdstevel@tonic-gate		switch (c) {
2647c478bdstevel@tonic-gate		case '#':
2657c478bdstevel@tonic-gate			if (state)
2667c478bdstevel@tonic-gate				emit_printf(cp);
2677c478bdstevel@tonic-gate			do {
2687c478bdstevel@tonic-gate				putchar(c);
2697c478bdstevel@tonic-gate				c = getchar();
2707c478bdstevel@tonic-gate				if (c == EOF)
2717c478bdstevel@tonic-gate					return (c);
2727c478bdstevel@tonic-gate			} while (c != '\n');
2737c478bdstevel@tonic-gate			putchar(c);
2747c478bdstevel@tonic-gate			line_no++;
2757c478bdstevel@tonic-gate			return (CPP);
2767c478bdstevel@tonic-gate		case '\n':
2777c478bdstevel@tonic-gate			if (state)
2787c478bdstevel@tonic-gate				emit_printf(cp);
2797c478bdstevel@tonic-gate			putchar(c);
2807c478bdstevel@tonic-gate			c = getchar();
2817c478bdstevel@tonic-gate			line_no++;
2827c478bdstevel@tonic-gate			break;
2837c478bdstevel@tonic-gate		default:
2847c478bdstevel@tonic-gate			newline = 0;
2857c478bdstevel@tonic-gate			break;
2867c478bdstevel@tonic-gate		}
2877c478bdstevel@tonic-gate	}
2887c478bdstevel@tonic-gate	if (c == '\n') {
2897c478bdstevel@tonic-gate		newline++;
2907c478bdstevel@tonic-gate		line_no++;
2917c478bdstevel@tonic-gate	}
2927c478bdstevel@tonic-gate	return (c);
2937c478bdstevel@tonic-gate}
2947c478bdstevel@tonic-gate
2957c478bdstevel@tonic-gate/*
2967c478bdstevel@tonic-gate * Get started on printf of ongoing adb script.
2977c478bdstevel@tonic-gate */
2987c478bdstevel@tonic-gatechar *
2997c478bdstevel@tonic-gatestart_printf(void)
3007c478bdstevel@tonic-gate{
3017c478bdstevel@tonic-gate	char *cp;
3027c478bdstevel@tonic-gate
3037c478bdstevel@tonic-gate	strcpy(arg[0], "\"%s\"");
3047c478bdstevel@tonic-gate	cp = arg[1];
3057c478bdstevel@tonic-gate	*cp++ = '"';
3067c478bdstevel@tonic-gate	state = 1;			/* XXX */
3077c478bdstevel@tonic-gate	return (cp);
3087c478bdstevel@tonic-gate}
3097c478bdstevel@tonic-gate
3107c478bdstevel@tonic-gate/*
3117c478bdstevel@tonic-gate * Emit call to printf to print part of ongoing adb script.
3127c478bdstevel@tonic-gate */
3137c478bdstevel@tonic-gatevoid
3147c478bdstevel@tonic-gateemit_printf(cp)
3157c478bdstevel@tonic-gate	char *cp;
3167c478bdstevel@tonic-gate{
3177c478bdstevel@tonic-gate	*cp++ = '"';
3187c478bdstevel@tonic-gate	*cp = '\0';
3197c478bdstevel@tonic-gate	emit_call("printf", 2);
3207c478bdstevel@tonic-gate	state = 0;			/* XXX */
3217c478bdstevel@tonic-gate}
3227c478bdstevel@tonic-gate
3237c478bdstevel@tonic-gate/*
3247c478bdstevel@tonic-gate * Read {} specification.
3257c478bdstevel@tonic-gate * The first part (up to a comma) is put into "member".
3267c478bdstevel@tonic-gate * The second part, if present, is put into "format".
3277c478bdstevel@tonic-gate */
3287c478bdstevel@tonic-gatevoid
3297c478bdstevel@tonic-gateread_spec(void)
3307c478bdstevel@tonic-gate{
3317c478bdstevel@tonic-gate	char *cp;
3327c478bdstevel@tonic-gate	int c;
3337c478bdstevel@tonic-gate	int nesting;
3347c478bdstevel@tonic-gate
3357c478bdstevel@tonic-gate	cp = member;
3367c478bdstevel@tonic-gate	specsize = 1;
3377c478bdstevel@tonic-gate	nesting = 0;
3387c478bdstevel@tonic-gate	while ((c = nextchar(NULL)) != '}' || (c == '}' && nesting)) {
3397c478bdstevel@tonic-gate		switch (c) {
3407c478bdstevel@tonic-gate		case EOF:
3417c478bdstevel@tonic-gate			fprintf(stderr, "Unexpected EOF inside {}\n");
3427c478bdstevel@tonic-gate			exit(1);
3437c478bdstevel@tonic-gate		case '\n':
3447c478bdstevel@tonic-gate			fprintf(stderr, "Newline not allowed in {}, line %d\n",
3457c478bdstevel@tonic-gate				line_no);
3467c478bdstevel@tonic-gate			exit(1);
3477c478bdstevel@tonic-gate		case '#':
3487c478bdstevel@tonic-gate			fprintf(stderr, "# not allowed in {}, line %d\n",
3497c478bdstevel@tonic-gate				line_no);
3507c478bdstevel@tonic-gate			exit(1);
3517c478bdstevel@tonic-gate		case ',':
3527c478bdstevel@tonic-gate			if (specsize == 2) {
3537c478bdstevel@tonic-gate				fprintf(stderr, "Excessive commas in {}, ");
3547c478bdstevel@tonic-gate				fprintf(stderr, "line %d\n", line_no);
3557c478bdstevel@tonic-gate				exit(1);
3567c478bdstevel@tonic-gate			}
3577c478bdstevel@tonic-gate			specsize = 2;
3587c478bdstevel@tonic-gate			*cp = '\0';
3597c478bdstevel@tonic-gate			cp = format;
3607c478bdstevel@tonic-gate			break;
3617c478bdstevel@tonic-gate		case '{':
3627c478bdstevel@tonic-gate			/*
3637c478bdstevel@tonic-gate			 * Allow up to one set of nested {}'s for adbgen
3647c478bdstevel@tonic-gate			 * requests of the form {member, {format string}}
3657c478bdstevel@tonic-gate			 */
3667c478bdstevel@tonic-gate			if (!nesting) {
3677c478bdstevel@tonic-gate				nesting = 1;
3687c478bdstevel@tonic-gate				*cp++ = c;
3697c478bdstevel@tonic-gate			} else {
3707c478bdstevel@tonic-gate				fprintf(stderr, "Too many {'s, line %d\n",
3717c478bdstevel@tonic-gate					line_no);
3727c478bdstevel@tonic-gate				exit(1);
3737c478bdstevel@tonic-gate			}
3747c478bdstevel@tonic-gate			break;
3757c478bdstevel@tonic-gate		case '}':
3767c478bdstevel@tonic-gate			*cp++ = c;
3777c478bdstevel@tonic-gate			nesting = 0;
3787c478bdstevel@tonic-gate			break;
3797c478bdstevel@tonic-gate		default:
3807c478bdstevel@tonic-gate			*cp++ = c;
3817c478bdstevel@tonic-gate			break;
3827c478bdstevel@tonic-gate		}
3837c478bdstevel@tonic-gate	}
3847c478bdstevel@tonic-gate	*cp = '\0';
3857c478bdstevel@tonic-gate	if (cp == member) {
3867c478bdstevel@tonic-gate		specsize = 0;
3877c478bdstevel@tonic-gate	}
3887c478bdstevel@tonic-gate}
3897c478bdstevel@tonic-gate
3907c478bdstevel@tonic-gate/*
3917c478bdstevel@tonic-gate * Decide what type of input specification we have.
3927c478bdstevel@tonic-gate */
3937c478bdstevel@tonic-gateint
3947c478bdstevel@tonic-gateget_type(void)
3957c478bdstevel@tonic-gate{
3967c478bdstevel@tonic-gate	int i;
3977c478bdstevel@tonic-gate
3987c478bdstevel@tonic-gate	if (specsize == 1) {
3997c478bdstevel@tonic-gate		if (streq(member, "SIZEOF")) {
4007c478bdstevel@tonic-gate			return (SIZEOF);
4017c478bdstevel@tonic-gate		}
4027c478bdstevel@tonic-gate		if (streq(member, "OFFSETOK")) {
4037c478bdstevel@tonic-gate			return (OFFSETOK);
4047c478bdstevel@tonic-gate		}
4057c478bdstevel@tonic-gate		if (streq(member, "END")) {
4067c478bdstevel@tonic-gate			return (END);
4077c478bdstevel@tonic-gate		}
4087c478bdstevel@tonic-gate		for (i = 0; i < FMT_ENTRIES; i++)
4097c478bdstevel@tonic-gate			if (streq(member, adbgen_fmt_tbl[i].f_str))
4107c478bdstevel@tonic-gate				return (i);
4117c478bdstevel@tonic-gate		return (OFFSET);
4127c478bdstevel@tonic-gate	}
4137c478bdstevel@tonic-gate	if (specsize == 2) {
4147c478bdstevel@tonic-gate		if (member[0] == '*') {
4157c478bdstevel@tonic-gate			return (INDIRECT);
4167c478bdstevel@tonic-gate		}
4177c478bdstevel@tonic-gate		if (streq(member, "EXPR")) {
4187c478bdstevel@tonic-gate			return (EXPR);
4197c478bdstevel@tonic-gate		}
4207c478bdstevel@tonic-gate		return (PRINT);
4217c478bdstevel@tonic-gate	}
4227c478bdstevel@tonic-gate	fprintf(stderr, "Invalid specification, line %d\n", line_no);
4237c478bdstevel@tonic-gate	exit(1);
4247c478bdstevel@tonic-gate}
4257c478bdstevel@tonic-gate
4267c478bdstevel@tonic-gate/*
4277c478bdstevel@tonic-gate * Generate the appropriate output for an input specification.
4287c478bdstevel@tonic-gate */
4297c478bdstevel@tonic-gatevoid
4307c478bdstevel@tonic-gategenerate(void)
4317c478bdstevel@tonic-gate{
4327c478bdstevel@tonic-gate	char *cp;
4337c478bdstevel@tonic-gate	int type;
4347c478bdstevel@tonic-gate
4357c478bdstevel@tonic-gate	type = get_type();
4367c478bdstevel@tonic-gate
4377c478bdstevel@tonic-gate	switch (type) {
4387c478bdstevel@tonic-gate	case PTR_HEX:
4397c478bdstevel@tonic-gate	case LONG_DEC:
4407c478bdstevel@tonic-gate	case LONG_OCT:
4417c478bdstevel@tonic-gate	case ULONG_DEC:
4427c478bdstevel@tonic-gate	case ULONG_HEX:
4437c478bdstevel@tonic-gate	case ULONG_OCT:
4447c478bdstevel@tonic-gate		cp = start_printf();
4457c478bdstevel@tonic-gate		*cp++ = adbgen_fmt_tbl[type].f_char;
4467c478bdstevel@tonic-gate		emit_printf(cp);
4477c478bdstevel@tonic-gate		break;
4487c478bdstevel@tonic-gate	case PRINT:
4497c478bdstevel@tonic-gate		emit_print();
4507c478bdstevel@tonic-gate		break;
4517c478bdstevel@tonic-gate	case OFFSET:
4527c478bdstevel@tonic-gate		emit_offset();
4537c478bdstevel@tonic-gate		break;
4547c478bdstevel@tonic-gate	case INDIRECT:
4557c478bdstevel@tonic-gate		emit_indirect();
4567c478bdstevel@tonic-gate		break;
4577c478bdstevel@tonic-gate	case OFFSETOK:
4587c478bdstevel@tonic-gate		emit_offsetok();
4597c478bdstevel@tonic-gate		break;
4607c478bdstevel@tonic-gate	case SIZEOF:
4617c478bdstevel@tonic-gate		emit_sizeof();
4627c478bdstevel@tonic-gate		break;
4637c478bdstevel@tonic-gate	case EXPR:
4647c478bdstevel@tonic-gate		emit_expr();
4657c478bdstevel@tonic-gate		break;
4667c478bdstevel@tonic-gate	case END:
4677c478bdstevel@tonic-gate		emit_end();
4687c478bdstevel@tonic-gate		break;
4697c478bdstevel@tonic-gate	default:
4707c478bdstevel@tonic-gate		fprintf(stderr, "Internal error in generate\n");
4717c478bdstevel@tonic-gate		exit(1);
4727c478bdstevel@tonic-gate	}
4737c478bdstevel@tonic-gate}
4747c478bdstevel@tonic-gate
4757c478bdstevel@tonic-gate/*
4767c478bdstevel@tonic-gate * Emit calls to set the offset and print a member.
4777c478bdstevel@tonic-gate */
4787c478bdstevel@tonic-gatevoid
4797c478bdstevel@tonic-gateemit_print(void)
4807c478bdstevel@tonic-gate{
4817c478bdstevel@tonic-gate	char *cp;
4827c478bdstevel@tonic-gate	char fmt_request[STRLEN];
4837c478bdstevel@tonic-gate	int i;
4847c478bdstevel@tonic-gate	char number[STRLEN];
4857c478bdstevel@tonic-gate
4867c478bdstevel@tonic-gate	emit_offset();
4877c478bdstevel@tonic-gate	/*
4887c478bdstevel@tonic-gate	 * Emit call to "format" subroutine
4897c478bdstevel@tonic-gate	 */
4907c478bdstevel@tonic-gate	sprintf(arg[0], "\"%s\"", member);
4917c478bdstevel@tonic-gate	sprintf(arg[1], "sizeof ((struct %s *)0)->%s",
4927c478bdstevel@tonic-gate		struct_name, member);
4937c478bdstevel@tonic-gate
4947c478bdstevel@tonic-gate	/*
4957c478bdstevel@tonic-gate	 * Split the format string into <number><format character string>
4967c478bdstevel@tonic-gate	 * This is for format strings that contain format specifier requests
4977c478bdstevel@tonic-gate	 * like {POINTER_HEX}, {LONG_DEC}, etc. which need to be substituted
4987c478bdstevel@tonic-gate	 * with a format character instead.
4997c478bdstevel@tonic-gate	 */
5007c478bdstevel@tonic-gate	for (cp = format, i = 0; *cp >= '0' && *cp <= '9' && *cp != '\0';
5017c478bdstevel@tonic-gate	    cp++, i++)
5027c478bdstevel@tonic-gate		number[i] = *cp;
5037c478bdstevel@tonic-gate	number[i] = '\0';
5047c478bdstevel@tonic-gate
5057c478bdstevel@tonic-gate	for (i = 0; i < FMT_ENTRIES; i++) {
5067c478bdstevel@tonic-gate		(void) sprintf(fmt_request, "{%s}", adbgen_fmt_tbl[i].f_str);
5077c478bdstevel@tonic-gate		if (streq(cp, fmt_request)) {
5087c478bdstevel@tonic-gate			sprintf(arg[2], "\"%s%c\"",
5097c478bdstevel@tonic-gate				number, adbgen_fmt_tbl[i].f_char);
5107c478bdstevel@tonic-gate			break;
5117c478bdstevel@tonic-gate		}
5127c478bdstevel@tonic-gate	}
5137c478bdstevel@tonic-gate	if (i == FMT_ENTRIES)
5147c478bdstevel@tonic-gate		sprintf(arg[2], "\"%s\"", format);
5157c478bdstevel@tonic-gate
5167c478bdstevel@tonic-gate	emit_call("format", 3);
5177c478bdstevel@tonic-gate}
5187c478bdstevel@tonic-gate
5197c478bdstevel@tonic-gate/*
5207c478bdstevel@tonic-gate * Emit calls to set the offset and print a member.
5217c478bdstevel@tonic-gate */
5227c478bdstevel@tonic-gatevoid
5237c478bdstevel@tonic-gateemit_offset(void)
5247c478bdstevel@tonic-gate{
5257c478bdstevel@tonic-gate	/*
5267c478bdstevel@tonic-gate	 * Emit call to "offset" subroutine
5277c478bdstevel@tonic-gate	 */
5287c478bdstevel@tonic-gate	sprintf(arg[0], "(off_t) &(((struct %s *)0)->%s)",
5297c478bdstevel@tonic-gate		struct_name, member);
5307c478bdstevel@tonic-gate	emit_call("offset", 1);
5317c478bdstevel@tonic-gate}
5327c478bdstevel@tonic-gate
5337c478bdstevel@tonic-gate/*
5347c478bdstevel@tonic-gate * Emit call to indirect routine.
5357c478bdstevel@tonic-gate */
5367c478bdstevel@tonic-gatevoid
5377c478bdstevel@tonic-gateemit_indirect(void)
5387c478bdstevel@tonic-gate{
5397c478bdstevel@tonic-gate	sprintf(arg[0], "(off_t) &(((struct %s *)0)->%s)",
5407c478bdstevel@tonic-gate		struct_name, member+1);
5417c478bdstevel@tonic-gate	sprintf(arg[1], "sizeof ((struct %s *)0)->%s", struct_name, member+1);
5427c478bdstevel@tonic-gate	sprintf(arg[2], "\"%s\"", format);	/* adb register name */
5437c478bdstevel@tonic-gate	sprintf(arg[3], "\"%s\"", member);
5447c478bdstevel@tonic-gate	emit_call("indirect", 4);
5457c478bdstevel@tonic-gate}
5467c478bdstevel@tonic-gate
5477c478bdstevel@tonic-gate/*
5487c478bdstevel@tonic-gate * Emit call to "offsetok" routine.
5497c478bdstevel@tonic-gate */
5507c478bdstevel@tonic-gatevoid
5517c478bdstevel@tonic-gateemit_offsetok(void)
5527c478bdstevel@tonic-gate{
5537c478bdstevel@tonic-gate	emit_call("offsetok", 0);
5547c478bdstevel@tonic-gate}
5557c478bdstevel@tonic-gate
5567c478bdstevel@tonic-gate/*
5577c478bdstevel@tonic-gate * Emit call to printf the sizeof the structure.
5587c478bdstevel@tonic-gate */
5597c478bdstevel@tonic-gatevoid
5607c478bdstevel@tonic-gateemit_sizeof(void)
5617c478bdstevel@tonic-gate{
5627c478bdstevel@tonic-gate	sprintf(arg[0], "\"0t%%d\"");
5637c478bdstevel@tonic-gate	sprintf(arg[1], "sizeof (struct %s)", struct_name);
5647c478bdstevel@tonic-gate	emit_call("printf", 2);
5657c478bdstevel@tonic-gate}
5667c478bdstevel@tonic-gate
5677c478bdstevel@tonic-gate/*
5687c478bdstevel@tonic-gate * Emit call to printf an arbitrary C expression.
5697c478bdstevel@tonic-gate */
5707c478bdstevel@tonic-gatevoid
5717c478bdstevel@tonic-gateemit_expr(void)
5727c478bdstevel@tonic-gate{
5737c478bdstevel@tonic-gate	sprintf(arg[0], "\"0t%%d\"");
5747c478bdstevel@tonic-gate	sprintf(arg[1], "(%s)", format);
5757c478bdstevel@tonic-gate	emit_call("printf", 2);
5767c478bdstevel@tonic-gate}
5777c478bdstevel@tonic-gate
5787c478bdstevel@tonic-gate/*
5797c478bdstevel@tonic-gate * Emit call to set offset to end of struct.
5807c478bdstevel@tonic-gate */
5817c478bdstevel@tonic-gatevoid
5827c478bdstevel@tonic-gateemit_end(void)
5837c478bdstevel@tonic-gate{
5847c478bdstevel@tonic-gate	sprintf(arg[0], "sizeof (struct %s)", struct_name);
5857c478bdstevel@tonic-gate	emit_call("offset", 1);
5867c478bdstevel@tonic-gate}
5877c478bdstevel@tonic-gate
5887c478bdstevel@tonic-gate/*
5897c478bdstevel@tonic-gate * Emit call to subroutine name with nargs arguments from arg array.
5907c478bdstevel@tonic-gate */
5917c478bdstevel@tonic-gatevoid
5927c478bdstevel@tonic-gateemit_call(char *name, int nargs)
5937c478bdstevel@tonic-gate{
5947c478bdstevel@tonic-gate	int i;
5957c478bdstevel@tonic-gate
5967c478bdstevel@tonic-gate	printf("\t%s(", name);		/* name of subroutine */
5977c478bdstevel@tonic-gate	for (i = 0; i < nargs; i++) {
5987c478bdstevel@tonic-gate		if (i > 0) {
5997c478bdstevel@tonic-gate			printf(", ");	/* argument separator */
6007c478bdstevel@tonic-gate		}
6017c478bdstevel@tonic-gate		printf("%s", arg[i]);	/* argument */
6027c478bdstevel@tonic-gate	}
6037c478bdstevel@tonic-gate	printf(");\n");			/* end of call */
6047c478bdstevel@tonic-gate}
605