From 454515776b24e20fd92c9259086088e05aa1b357 Mon Sep 17 00:00:00 2001 From: rjones Date: Mon, 12 Jan 2009 15:25:05 +0000 Subject: [PATCH] Seems to create a reasonable .c and .h file now. --- .cvsignore | 3 + rpcgen_ast.c | 4 +- rpcgen_codegen.c | 335 +++++++++++++++++++++++++++++++++++++++++++++++-------- rpcgen_int.h | 10 +- rpcgen_main.c | 12 +- rpcgen_parse.y | 66 ++++++----- rpcgen_scan.l | 2 +- 7 files changed, 349 insertions(+), 83 deletions(-) diff --git a/.cvsignore b/.cvsignore index 987e85c..7d2416d 100644 --- a/.cvsignore +++ b/.cvsignore @@ -28,3 +28,6 @@ remote_protocol.h rpcgen_parse.c rpcgen_parse.h rpcgen_scan.c +test.x +test.c +test.h diff --git a/rpcgen_ast.c b/rpcgen_ast.c index e1caa99..baade6a 100644 --- a/rpcgen_ast.c +++ b/rpcgen_ast.c @@ -26,13 +26,12 @@ #include "rpcgen_int.h" struct type * -new_type (enum type_enum type, int sgn, char *ident, char *len) +new_type (enum type_enum type, int sgn, char *ident) { struct type *r = malloc (sizeof *r); r->type = type; r->sgn = sgn; r->ident = ident; - r->len = len; return r; } @@ -41,7 +40,6 @@ free_type (struct type *t) { if (t) { free (t->ident); - free (t->len); free (t); } } diff --git a/rpcgen_codegen.c b/rpcgen_codegen.c index 3184884..9677a2a 100644 --- a/rpcgen_codegen.c +++ b/rpcgen_codegen.c @@ -26,8 +26,15 @@ #include "rpcgen_int.h" +/* If we're debugging the code generator itself, then #line directives + * aren't useful - we want to see the error in the generated code + * instead. Setting this disables #line directives in the output. + */ +#define DEBUG_CODEGEN 0 + static void gen_line (void); static void gen_decl (int indent, const struct decl *); +static void gen_decl_xdr_call (int indent, const struct decl *, const char *); static void gen_type (const struct type *); static void @@ -45,20 +52,31 @@ spaces (int n) static void gen_line (void) { +#if !DEBUG_CODEGEN if (input_filename) fprintf (yyout, "#line %d \"%s\"\n", yylineno, input_filename); +#endif } static void -write_header_def (void) +write_basename (void) { - const char *p; + const char *p = strrchr (output_filename, '/') ? : output_filename; + const char *q = strrchr (output_filename, '.'); - p = strrchr (output_filename, '/') ? : output_filename; + while (*p && p != q) { + fputc (*p, yyout); + ++p; + } +} - fputs ("RPCGEN_HEADER_", yyout); +static void +write_basename_caps (void) +{ + const char *p = strrchr (output_filename, '/') ? : output_filename; + const char *q = strrchr (output_filename, '.'); - while (*p) { + while (*p && p != q) { if (isalnum (*p)) fputc (toupper (*p), yyout); else @@ -70,9 +88,6 @@ write_header_def (void) void gen_prologue (const char *filename) { - char *basename; - int len; - fprintf (yyout, "/* This file was generated by PortableXDR rpcgen %s\n" " * ANY CHANGES YOU MAKE TO THIS FILE MAY BE LOST!\n" @@ -84,22 +99,20 @@ gen_prologue (const char *filename) switch (output_mode) { case output_c: - len = strlen (filename); - basename = malloc (len + 1); - strcpy (basename, filename); - if (len >= 2 && basename[len-2] == '.') - basename[len-2] = '\0'; - fprintf (yyout, "#include \"%s.h\"\n", basename); - free (basename); + fprintf (yyout, "#include \""); + write_basename (); + fprintf (yyout, ".h\"\n\n"); break; case output_h: - fprintf (yyout, "#ifndef "); - write_header_def (); - fprintf (yyout, "\n#define "); - write_header_def (); + fprintf (yyout, "#ifndef RPCGEN_HEADER_"); + write_basename_caps (); fprintf (yyout, - "\n" + "_H\n" + "#define RPCGEN_HEADER_"); + write_basename_caps (); + fprintf (yyout, + "_H\n" "\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" @@ -107,6 +120,14 @@ gen_prologue (const char *filename) "\n" "#include \n" "#include \n" + "\n" + "/* Use the following symbol in your code to detect whether\n" + " * PortableXDR's rpcgen was used to compile the source file.\n" + " */\n" + "#define PORTABLE_RPCGEN_"); + write_basename_caps (); + fprintf (yyout, + " 1\n" "\n"); break; } @@ -129,9 +150,9 @@ gen_epilogue (void) "}\n" "#endif\n" "\n" - "#endif /* "); - write_header_def (); - fprintf (yyout, " */\n"); + "#endif /* RPCGEN_HEADER_"); + write_basename_caps (); + fprintf (yyout, "_H */\n"); break; } @@ -175,11 +196,25 @@ gen_enum (const char *name, const struct cons *enum_values) break; case output_c: - /* XXX */ + fprintf (yyout, + "bool_t\n" + "xdr_%s (XDR *xdrs, %s *objp)\n" + "{\n" + " if (!xdr_enum (xdrs, (enum_t *) objp))\n" + " return FALSE;\n" + " return TRUE;\n" + "}\n" + "\n", + name, name); break; } } +/* The Sun rpcgen seems to do some sort of inlining optimization based + * on {size of struct|number of elements}(?) We don't do any such + * optimization. Instead we rely on gcc doing the correct level of + * optimization based on inlined functions found in the header files. + */ void gen_struct (const char *name, const struct cons *decls) { @@ -202,7 +237,19 @@ gen_struct (const char *name, const struct cons *decls) break; case output_c: - /* XXX */ + fprintf (yyout, + "bool_t\n" + "xdr_%s (XDR *xdrs, %s *objp)\n" + "{\n", + name, name); + while (decls) { + gen_decl_xdr_call (2, (struct decl *) decls->ptr, "&objp->"); + decls = decls->next; + } + fprintf (yyout, + " return TRUE;\n" + "}\n" + "\n"); break; } } @@ -211,6 +258,9 @@ void gen_union (const char *name, const struct decl *discrim, const struct cons *union_cases) { + char *str; + int len; + gen_line (); switch (output_mode) @@ -221,8 +271,8 @@ gen_union (const char *name, const struct decl *discrim, fprintf (yyout, " union {\n"); while (union_cases) { - struct decl *decl = ((struct union_case *) union_cases->ptr)->decl; - if (decl) gen_decl (4, decl); + struct union_case *uc = (struct union_case *) union_cases->ptr; + if (uc->decl) gen_decl (4, uc->decl); union_cases = union_cases->next; } fprintf (yyout, @@ -235,7 +285,36 @@ gen_union (const char *name, const struct decl *discrim, break; case output_c: - /* XXX */ + fprintf (yyout, + "bool_t\n" + "xdr_%s (XDR *xdrs, %s *objp)\n" + "{\n", + name, name); + gen_decl_xdr_call (2, discrim, "&objp->"); + fprintf (yyout, + " switch (objp->%s) {\n", + discrim->ident); + + len = strlen (name) + 11; + str = malloc (len); + snprintf (str, len, "&objp->%s_u.", name); + + while (union_cases) { + struct union_case *uc = (struct union_case *) union_cases->ptr; + fprintf (yyout, + " case %s:\n", + uc->const_); + gen_decl_xdr_call (4, uc->decl, str); + fprintf (yyout, + " break;\n"); + union_cases = union_cases->next; + } + fprintf (yyout, + " }\n" + " return TRUE;\n" + "}\n" + "\n"); + free (str); break; } } @@ -243,15 +322,33 @@ gen_union (const char *name, const struct decl *discrim, void gen_typedef (const struct decl *decl) { - if (output_mode == output_h) { - gen_line (); - fputs ("typedef ", yyout); - gen_decl (0, decl); - fprintf (yyout, - "extern bool_t xdr_%s (XDR *, %s *);\n" - "\n", - decl->ident, decl->ident); - } + gen_line (); + + switch (output_mode) + { + case output_h: + fputs ("typedef ", yyout); + gen_decl (0, decl); + + fprintf (yyout, + "extern bool_t xdr_%s (XDR *, %s *);\n" + "\n", + decl->ident, decl->ident); + break; + + case output_c: + fprintf (yyout, + "bool_t\n"); + fprintf (yyout, "xdr_%s (XDR *xdrs, %s *objp)\n", + decl->ident, decl->ident); + fprintf (yyout, "{\n"); + gen_decl_xdr_call (2, decl, "&objp->"); + fprintf (yyout, + " return TRUE;\n" + "}\n" + "\n"); + break; + } } static void @@ -261,6 +358,24 @@ gen_decl (int indent, const struct decl *decl) switch (decl->decl_type) { + case decl_type_string: + fprintf (yyout, "char *%s;\n", decl->ident); + break; + + case decl_type_opaque_fixed: + fprintf (yyout, "char %s[%s];\n", decl->ident, decl->len); + break; + + case decl_type_opaque_variable: + fprintf (yyout, "struct {\n"); + spaces (indent+2); + fprintf (yyout, "uint32_t %s_len;\n", decl->ident); + spaces (indent+2); + fprintf (yyout, "char *%s_val;\n", decl->ident); + spaces (indent); + fprintf (yyout, "} %s;\n", decl->ident); + break; + case decl_type_simple: gen_type (decl->type); fprintf (yyout, " %s;\n", decl->ident); @@ -289,6 +404,144 @@ gen_decl (int indent, const struct decl *decl) } } +static const char * +xdr_func_of_simple_type (const struct type *type) +{ + const char *r; + + /* The caller supplies the "xdr_" prefix. */ + switch (type->type) { + case type_char: + if (type->sgn) r = "char"; else r = "u_char"; + break; + case type_short: + if (type->sgn) r = "short"; else r = "u_short"; + break; + case type_int: + if (type->sgn) r = "int"; else r = "u_int"; + break; + case type_hyper: + if (type->sgn) r = "quad_t"; else r = "u_quad_t"; + break; + case type_double: + r = "double"; + break; + case type_bool: + r = "bool"; + break; + case type_ident: + r = type->ident; + break; + default: abort (); /* Avoid GCC warning. */ + } + return r; +} + +/* Caller must free the result. */ +static char * +sizeof_simple_type (const struct type *type) +{ + int len; + char *str, *r; + + switch (type->type) { + case type_char: + r = strdup ("1"); /* Note: fixed by the XDR RFC. */ + break; + case type_short: + r = strdup ("2"); + break; + case type_int: + r = strdup ("4"); + break; + case type_hyper: + r = strdup ("8"); + break; + case type_double: + r = strdup ("8"); + break; + case type_bool: + r = strdup ("4"); + break; + case type_ident: + len = strlen (type->ident) + 10; + str = malloc (len); + snprintf (str, len, "sizeof (%s)", type->ident); + r = str; + break; + default: abort (); /* Avoid GCC warning. */ + } + + return r; +} + +static void +gen_decl_xdr_call (int indent, const struct decl *decl, const char *struct_name) +{ + char *str; + char *len_str; + + spaces (indent); + + switch (decl->decl_type) + { + case decl_type_string: + if (decl->len) + fprintf (yyout, "if (!xdr_string (xdrs, objp, %s))\n", decl->len); + else + fprintf (yyout, "if (!xdr_string (xdrs, objp, ~0))\n"); + break; + + case decl_type_opaque_fixed: + fprintf (yyout, "if (!xdr_opaque (xdrs, &objp, %s))\n", decl->len); + break; + + case decl_type_opaque_variable: + len_str = decl->len ? : "~0"; + fprintf (yyout, + "if (!xdr_bytes (xdrs, %s%s.%s_val, %s%s.%s_len, %s))\n", + struct_name, decl->ident, decl->ident, + struct_name, decl->ident, decl->ident, len_str); + break; + + case decl_type_simple: + fprintf (yyout, "if (!xdr_%s (xdrs, %s%s))\n", + xdr_func_of_simple_type (decl->type), struct_name, decl->ident); + break; + + case decl_type_fixed_array: + str = sizeof_simple_type (decl->type); + fprintf (yyout, + "if (!xdr_vector (xdrs, %s%s, %s, %s, (xdrproc_t) xdr_%s))\n", + struct_name, decl->ident, decl->len, + str, xdr_func_of_simple_type (decl->type)); + free (str); + break; + + case decl_type_variable_array: + str = sizeof_simple_type (decl->type); + len_str = decl->len ? : "~0"; + fprintf (yyout, + "if (!xdr_array (xdrs, %s%s.%s_val, %s%s.%s_len, %s, %s, (xdrproc_t) xdr_%s))\n", + struct_name, decl->ident, decl->ident, + struct_name, decl->ident, decl->ident, + len_str, + str, xdr_func_of_simple_type (decl->type)); + free (str); + break; + + case decl_type_pointer: + str = sizeof_simple_type (decl->type); + fprintf (yyout, "if (!xdr_pointer (xdrs, objp, %s, (xdrproc_t) xdr_%s))\n", + str, xdr_func_of_simple_type (decl->type)); + free (str); + break; + } + + spaces (indent+2); + fprintf (yyout, "return FALSE;\n"); +} + static void gen_type (const struct type *type) { @@ -318,14 +571,6 @@ gen_type (const struct type *type) fputs ("double", yyout); break; - case type_string: - fputs ("char *", yyout); - break; - - case type_opaque: - fputs ("char", yyout); - break; - case type_bool: fputs ("bool_t", yyout); break; diff --git a/rpcgen_int.h b/rpcgen_int.h index 9271326..b551516 100644 --- a/rpcgen_int.h +++ b/rpcgen_int.h @@ -37,7 +37,7 @@ extern enum output_mode output_mode; enum type_enum { type_char, type_short, type_int, type_hyper, type_double, - type_string, type_opaque, type_bool, + type_bool, type_ident, }; @@ -45,13 +45,15 @@ struct type { enum type_enum type; int sgn; /* true if signed, false if unsigned */ char *ident; - char *len; /* length (only for strings) */ }; -extern struct type *new_type (enum type_enum, int, char *, char *); +extern struct type *new_type (enum type_enum, int, char *); extern void free_type (struct type *); enum decl_type { + decl_type_string, /* string foo; (len is optional) */ + decl_type_opaque_fixed, /* opaque foo[len]; */ + decl_type_opaque_variable, /* opaque foo; */ decl_type_simple, /* type ident; */ decl_type_fixed_array, /* type ident[len]; */ decl_type_variable_array, /* type ident; (len is optional) */ @@ -60,7 +62,7 @@ enum decl_type { struct decl { enum decl_type decl_type; - struct type *type; + struct type *type; /* NULL for string & opaque types. */ char *ident; char *len; }; diff --git a/rpcgen_main.c b/rpcgen_main.c index a2e97b7..b7970fb 100644 --- a/rpcgen_main.c +++ b/rpcgen_main.c @@ -60,15 +60,21 @@ main (int argc, char *argv[]) /*-- Options supported by any rpcgen that we don't support. --*/ case 'D': case 'T': case 'K': case 'l': case 'm': case 't': case 's': - error ("option '%c' is not supported by this PortableXDR rpcgen.\nYou may need to use an alternative rpcgen program instead.", opt); + error ("option '%c' is not supported by this PortableXDR rpcgen.\n" + "You may need to use an alternative rpcgen program instead.", + opt); /*-- Options supported only by GNU rpcgen that we don't support. --*/ case 'I': case 'n': - error ("option '%c' is not supported by this PortableXDR rpcgen.\nIf you were expecting to use GNU rpcgen, try /usr/bin/rpcgen on a GNU host.", opt); + error ("option '%c' is not supported by this PortableXDR rpcgen.\n" + "If you were expecting to use GNU rpcgen, try /usr/bin/rpcgen on a GNU host.", + opt); /*-- Options supported only by BSD rpcgen that we don't support. --*/ case 'A': case 'M': case 'L': case 'S': - error ("option '%c' is not supported by this PortableXDR rpcgen.\nIf you were expecting to use BSD rpcgen, try /usr/bin/rpcgen on a BSD host.", opt); + error ("option '%c' is not supported by this PortableXDR rpcgen.\n" + "If you were expecting to use BSD rpcgen, try /usr/bin/rpcgen on a BSD host.", + opt); /*-- Options that we do support. --*/ case 'c': diff --git a/rpcgen_parse.y b/rpcgen_parse.y index 5ccc7dd..2923325 100644 --- a/rpcgen_parse.y +++ b/rpcgen_parse.y @@ -38,7 +38,7 @@ extern void yyerror (const char *str); %type const %type decl %type simple_decl fixed_array_decl variable_array_decl pointer_decl -%type string_decl +%type string_decl opaque_decl %type enum_value %type union_case %type decls enum_values union_cases @@ -132,6 +132,7 @@ decls : decl ';' ; decl : string_decl + | opaque_decl | simple_decl | fixed_array_decl | variable_array_decl @@ -141,15 +142,22 @@ decl : string_decl string_decl : STRING IDENT '<' const '>' { - $$ = new_decl (decl_type_simple, - new_type (type_string, 0, NULL, $4), - $2, NULL); + $$ = new_decl (decl_type_string, NULL, $2, $4); } | STRING IDENT '<' '>' { - $$ = new_decl (decl_type_simple, - new_type (type_string, 0, NULL, NULL), - $2, NULL); + $$ = new_decl (decl_type_string, NULL, $2, NULL); + } + ; + +opaque_decl + : OPAQUE IDENT '[' const ']' + { + $$ = new_decl (decl_type_opaque_fixed, NULL, $2, $4); + } + | OPAQUE IDENT '<' const '>' + { + $$ = new_decl (decl_type_opaque_variable, NULL, $2, $4); } ; @@ -215,44 +223,48 @@ const : INTLIT | IDENT ; -/* Types. Note 'string' and 'void' are handled by special cases above. */ +/* Types. Note 'string', 'opaque' and 'void' are handled by + * special cases above. + */ type_ident : CHAR - { $$ = new_type (type_char, 1, NULL, NULL); } + /* NB: Unlike SunRPC we make char explicitly signed. This + * will give some warnings in GCC if you mix PortableXDR + * code with SunRPC headers or vice versa. + */ + { $$ = new_type (type_char, 1, NULL); } | SIGNED CHAR - { $$ = new_type (type_char, 1, NULL, NULL); } + { $$ = new_type (type_char, 1, NULL); } | UNSIGNED CHAR - { $$ = new_type (type_char, 0, NULL, NULL); } + { $$ = new_type (type_char, 0, NULL); } | SHORT - { $$ = new_type (type_short, 1, NULL, NULL); } + { $$ = new_type (type_short, 1, NULL); } | SIGNED SHORT - { $$ = new_type (type_short, 1, NULL, NULL); } + { $$ = new_type (type_short, 1, NULL); } | UNSIGNED SHORT - { $$ = new_type (type_short, 0, NULL, NULL); } + { $$ = new_type (type_short, 0, NULL); } | INT - { $$ = new_type (type_int, 1, NULL, NULL); } + { $$ = new_type (type_int, 1, NULL); } | SIGNED INT - { $$ = new_type (type_int, 1, NULL, NULL); } + { $$ = new_type (type_int, 1, NULL); } | UNSIGNED INT - { $$ = new_type (type_int, 0, NULL, NULL); } + { $$ = new_type (type_int, 0, NULL); } | HYPER - { $$ = new_type (type_hyper, 1, NULL, NULL); } + { $$ = new_type (type_hyper, 1, NULL); } | SIGNED HYPER - { $$ = new_type (type_hyper, 1, NULL, NULL); } + { $$ = new_type (type_hyper, 1, NULL); } | UNSIGNED HYPER - { $$ = new_type (type_hyper, 0, NULL, NULL); } + { $$ = new_type (type_hyper, 0, NULL); } | SIGNED - { $$ = new_type (type_int, 1, NULL, NULL); } + { $$ = new_type (type_int, 1, NULL); } | UNSIGNED - { $$ = new_type (type_int, 0, NULL, NULL); } + { $$ = new_type (type_int, 0, NULL); } | DOUBLE - { $$ = new_type (type_double, 0, NULL, NULL); } - | OPAQUE - { $$ = new_type (type_opaque, 0, NULL, NULL); } + { $$ = new_type (type_double, 0, NULL); } | BOOL - { $$ = new_type (type_bool, 0, NULL, NULL); } + { $$ = new_type (type_bool, 0, NULL); } | IDENT - { $$ = new_type (type_ident, 0, $1, NULL); } + { $$ = new_type (type_ident, 0, $1); } ; %% diff --git a/rpcgen_scan.l b/rpcgen_scan.l index 4ab278d..10ed056 100644 --- a/rpcgen_scan.l +++ b/rpcgen_scan.l @@ -52,7 +52,7 @@ WS [[:space:]]+ if (filename == NULL) perrorf ("malloc"); if (sscanf (yytext+2, "%d \"%[^\"]\"", &lineno, filename) == 2) { - yylineno = lineno; + yylineno = lineno-1; free (input_filename); input_filename = filename; } -- 1.8.3.1