#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define streq(s1, s2) (strcmp(s1, s2) == 0)
#define LINELEN 1024
#define STRLEN 128
#define NARGS 5
#define FSTR_PTR "POINTER"
#define FSTR_LONG_DEC "LONGDEC"
#define FSTR_LONG_OCT "LONGOCT"
#define FSTR_ULONG_DEC "ULONGDEC"
#define FSTR_ULONG_HEX "ULONGHEX"
#define FSTR_ULONG_OCT "ULONGOCT"
#define PTR_HEX 0
#define LONG_DEC 1
#define LONG_OCT 2
#define ULONG_DEC 3
#define ULONG_HEX 4
#define ULONG_OCT 5
#define FMT_ENTRIES 6
#define PRINT 6
#define INDIRECT 7
#define OFFSETOK 8
#define SIZEOF 9
#define END 10
#define OFFSET 11
#define EXPR 12
#define CPP -2
typedef struct adbgen_fmt {
char *f_str;
char f_char;
} adbgen_fmt_t;
char struct_name[STRLEN];
char member[STRLEN];
char format[STRLEN];
char arg[NARGS][STRLEN];
char *ptr_hex_fmt;
char *long_dec_fmt;
char *ulong_dec_fmt;
char *ulong_hex_fmt;
char *long_oct_fmt;
char *ulong_oct_fmt;
int line_no = 1;
int specsize;
int state;
adbgen_fmt_t adbgen_fmt_tbl [FMT_ENTRIES] = {
{FSTR_PTR},
{FSTR_LONG_DEC},
{FSTR_LONG_OCT},
{FSTR_ULONG_DEC},
{FSTR_ULONG_HEX},
{FSTR_ULONG_OCT}
};
void emit_call(char *name, int nargs);
void emit_end(void);
void emit_expr(void);
void emit_indirect(void);
void emit_offset(void);
void emit_offsetok(void);
void emit_print(void);
void emit_printf(char *cp);
void emit_sizeof(void);
void generate(void);
int get_type(void);
int nextchar(char *cp);
void read_spec(void);
char *start_printf(void);
int
main(int argc, char **argv)
{
char *cp;
int c;
int warn_flag = 0;
int is_lp64 = 0;
char *usage = "adbgen1 [-w] [-m ilp32|lp64] < <macro file>\n";
while ((c = getopt(argc, argv, "m:w")) != EOF) {
switch (c) {
case 'm':
if (streq(optarg, "ilp32"))
is_lp64 = 0;
else if (streq(optarg, "lp64"))
is_lp64 = 1;
else
fprintf(stderr, usage);
break;
case 'w':
warn_flag++;
break;
case '?':
fprintf(stderr, usage);
break;
}
}
if (is_lp64) {
adbgen_fmt_tbl[PTR_HEX].f_char = 'J';
adbgen_fmt_tbl[LONG_DEC].f_char = 'e';
adbgen_fmt_tbl[LONG_OCT].f_char = 'g';
adbgen_fmt_tbl[ULONG_DEC].f_char = 'E';
adbgen_fmt_tbl[ULONG_HEX].f_char = 'J';
adbgen_fmt_tbl[ULONG_OCT].f_char = 'G';
} else {
adbgen_fmt_tbl[PTR_HEX].f_char = 'X';
adbgen_fmt_tbl[LONG_DEC].f_char = 'D';
adbgen_fmt_tbl[LONG_OCT].f_char = 'Q';
adbgen_fmt_tbl[ULONG_DEC].f_char = 'U';
adbgen_fmt_tbl[ULONG_HEX].f_char = 'X';
adbgen_fmt_tbl[ULONG_OCT].f_char = 'O';
}
cp = struct_name;
while ((c = nextchar(NULL)) != '\n') {
if (c == EOF) {
fprintf(stderr, "Premature EOF\n");
exit(1);
}
if (c == CPP)
continue;
*cp++ = (char)c;
}
*cp = '\0';
printf("\n");
printf("#include <sys/types.h>\n");
printf("#include <sys/inttypes.h>\n");
printf("\n\n");
printf("int do_fmt(char *acp);\n");
printf("void format(char *name, size_t size, char *fmt);\n");
printf("void indirect(off_t offset, size_t size, "
"char *base, char *member);\n");
printf("void offset(off_t off);\n");
printf("void offsetok(void);\n");
printf("\n\n");
printf("main(int argc, char *argv[])\n");
printf("{\n");
if (warn_flag) {
printf("\textern int warnings;\n\n\twarnings = 0;\n");
}
cp = start_printf();
while ((c = nextchar(cp)) != EOF) {
switch (c) {
case '"':
*cp++ = '\\';
*cp++ = '"';
break;
case '\n':
*cp++ = '\\';
*cp++ = 'n';
break;
case '{':
emit_printf(cp);
read_spec();
generate();
cp = start_printf();
break;
case CPP:
cp = start_printf();
break;
default:
*cp++ = c;
break;
}
if (cp - arg[1] >= STRLEN - 10) {
emit_printf(cp);
cp = start_printf();
}
}
emit_printf(cp);
printf("\n\tif (argc > 1 && strcmp(argv[1], \"-e\") == 0) {\n");
printf("\t\textern int warns;\n\n");
printf("\t\tif (warns)\n");
printf("\t\t\treturn (1);\n");
printf("\t}\n");
printf("\treturn (0);\n");
printf("}\n");
return (0);
}
int
nextchar(char *cp)
{
int c;
static int newline = 1;
c = getchar();
while (newline) {
switch (c) {
case '#':
if (state)
emit_printf(cp);
do {
putchar(c);
c = getchar();
if (c == EOF)
return (c);
} while (c != '\n');
putchar(c);
line_no++;
return (CPP);
case '\n':
if (state)
emit_printf(cp);
putchar(c);
c = getchar();
line_no++;
break;
default:
newline = 0;
break;
}
}
if (c == '\n') {
newline++;
line_no++;
}
return (c);
}
char *
start_printf(void)
{
char *cp;
strcpy(arg[0], "\"%s\"");
cp = arg[1];
*cp++ = '"';
state = 1;
return (cp);
}
void
emit_printf(cp)
char *cp;
{
*cp++ = '"';
*cp = '\0';
emit_call("printf", 2);
state = 0;
}
void
read_spec(void)
{
char *cp;
int c;
int nesting;
cp = member;
specsize = 1;
nesting = 0;
while ((c = nextchar(NULL)) != '}' || (c == '}' && nesting)) {
switch (c) {
case EOF:
fprintf(stderr, "Unexpected EOF inside {}\n");
exit(1);
case '\n':
fprintf(stderr, "Newline not allowed in {}, line %d\n",
line_no);
exit(1);
case '#':
fprintf(stderr, "# not allowed in {}, line %d\n",
line_no);
exit(1);
case ',':
if (specsize == 2) {
fprintf(stderr, "Excessive commas in {}, ");
fprintf(stderr, "line %d\n", line_no);
exit(1);
}
specsize = 2;
*cp = '\0';
cp = format;
break;
case '{':
if (!nesting) {
nesting = 1;
*cp++ = c;
} else {
fprintf(stderr, "Too many {'s, line %d\n",
line_no);
exit(1);
}
break;
case '}':
*cp++ = c;
nesting = 0;
break;
default:
*cp++ = c;
break;
}
}
*cp = '\0';
if (cp == member) {
specsize = 0;
}
}
int
get_type(void)
{
int i;
if (specsize == 1) {
if (streq(member, "SIZEOF")) {
return (SIZEOF);
}
if (streq(member, "OFFSETOK")) {
return (OFFSETOK);
}
if (streq(member, "END")) {
return (END);
}
for (i = 0; i < FMT_ENTRIES; i++)
if (streq(member, adbgen_fmt_tbl[i].f_str))
return (i);
return (OFFSET);
}
if (specsize == 2) {
if (member[0] == '*') {
return (INDIRECT);
}
if (streq(member, "EXPR")) {
return (EXPR);
}
return (PRINT);
}
fprintf(stderr, "Invalid specification, line %d\n", line_no);
exit(1);
}
void
generate(void)
{
char *cp;
int type;
type = get_type();
switch (type) {
case PTR_HEX:
case LONG_DEC:
case LONG_OCT:
case ULONG_DEC:
case ULONG_HEX:
case ULONG_OCT:
cp = start_printf();
*cp++ = adbgen_fmt_tbl[type].f_char;
emit_printf(cp);
break;
case PRINT:
emit_print();
break;
case OFFSET:
emit_offset();
break;
case INDIRECT:
emit_indirect();
break;
case OFFSETOK:
emit_offsetok();
break;
case SIZEOF:
emit_sizeof();
break;
case EXPR:
emit_expr();
break;
case END:
emit_end();
break;
default:
fprintf(stderr, "Internal error in generate\n");
exit(1);
}
}
void
emit_print(void)
{
char *cp;
char fmt_request[STRLEN];
int i;
char number[STRLEN];
emit_offset();
sprintf(arg[0], "\"%s\"", member);
sprintf(arg[1], "sizeof ((struct %s *)0)->%s",
struct_name, member);
for (cp = format, i = 0; *cp >= '0' && *cp <= '9' && *cp != '\0';
cp++, i++)
number[i] = *cp;
number[i] = '\0';
for (i = 0; i < FMT_ENTRIES; i++) {
(void) sprintf(fmt_request, "{%s}", adbgen_fmt_tbl[i].f_str);
if (streq(cp, fmt_request)) {
sprintf(arg[2], "\"%s%c\"",
number, adbgen_fmt_tbl[i].f_char);
break;
}
}
if (i == FMT_ENTRIES)
sprintf(arg[2], "\"%s\"", format);
emit_call("format", 3);
}
void
emit_offset(void)
{
sprintf(arg[0], "(off_t) &(((struct %s *)0)->%s)",
struct_name, member);
emit_call("offset", 1);
}
void
emit_indirect(void)
{
sprintf(arg[0], "(off_t) &(((struct %s *)0)->%s)",
struct_name, member+1);
sprintf(arg[1], "sizeof ((struct %s *)0)->%s", struct_name, member+1);
sprintf(arg[2], "\"%s\"", format);
sprintf(arg[3], "\"%s\"", member);
emit_call("indirect", 4);
}
void
emit_offsetok(void)
{
emit_call("offsetok", 0);
}
void
emit_sizeof(void)
{
sprintf(arg[0], "\"0t%%d\"");
sprintf(arg[1], "sizeof (struct %s)", struct_name);
emit_call("printf", 2);
}
void
emit_expr(void)
{
sprintf(arg[0], "\"0t%%d\"");
sprintf(arg[1], "(%s)", format);
emit_call("printf", 2);
}
void
emit_end(void)
{
sprintf(arg[0], "sizeof (struct %s)", struct_name);
emit_call("offset", 1);
}
void
emit_call(char *name, int nargs)
{
int i;
printf("\t%s(", name);
for (i = 0; i < nargs; i++) {
if (i > 0) {
printf(", ");
}
printf("%s", arg[i]);
}
printf(");\n");
}