X-Git-Url: http://git.annexia.org/?p=portablexdr.git;a=blobdiff_plain;f=rpcgen_codegen.c;h=9677a2af8dd6f56a08b7739147ac69cd6ce96724;hp=3184884947be7ee26e2fb38573123ab09634fe8b;hb=454515776b24e20fd92c9259086088e05aa1b357;hpb=1b9cc11ece64ac12f63e6c96e32b404b32fb0f32 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;