/* -*- C -*- * rpcgen - Generate XDR bindings automatically. * Copyright (C) 2008 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #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 spaces (int n) { int i; for (i = 0; i < n; ++i) fputc (' ', yyout); } /* This generates a #line directive referring back to the * original source file. */ static void gen_line (void) { #if !DEBUG_CODEGEN if (input_filename) fprintf (yyout, "#line %d \"%s\"\n", yylineno, input_filename); #endif } static void write_basename (void) { const char *p = strrchr (output_filename, '/') ? : output_filename; const char *q = strrchr (output_filename, '.'); while (*p && p != q) { fputc (*p, yyout); ++p; } } static void write_basename_caps (void) { const char *p = strrchr (output_filename, '/') ? : output_filename; const char *q = strrchr (output_filename, '.'); while (*p && p != q) { if (isalnum (*p)) fputc (toupper (*p), yyout); else fputc ('_', yyout); ++p; } } void gen_prologue (const char *filename) { fprintf (yyout, "/* This file was generated by PortableXDR rpcgen %s\n" " * ANY CHANGES YOU MAKE TO THIS FILE MAY BE LOST!\n" " * The input file was %s\n" " */\n" "\n", PACKAGE_VERSION, filename); switch (output_mode) { case output_c: fprintf (yyout, "#include \""); write_basename (); fprintf (yyout, ".h\"\n\n"); break; case output_h: fprintf (yyout, "#ifndef RPCGEN_HEADER_"); write_basename_caps (); fprintf (yyout, "_H\n" "#define RPCGEN_HEADER_"); write_basename_caps (); fprintf (yyout, "_H\n" "\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n" "\n" "#include \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; } } void gen_epilogue (void) { gen_line (); switch (output_mode) { case output_c: break; case output_h: fprintf (yyout, "\n" "#ifdef __cplusplus\n" "}\n" "#endif\n" "\n" "#endif /* RPCGEN_HEADER_"); write_basename_caps (); fprintf (yyout, "_H */\n"); break; } fprintf (yyout, "\n/* EOF */\n"); } void gen_const (const char *name, const char *value) { if (output_mode == output_h) { gen_line (); fprintf (yyout, "#define %s %s\n", name, value); } } void gen_enum (const char *name, const struct cons *enum_values) { gen_line (); switch (output_mode) { case output_h: fprintf (yyout, "enum %s {\n", name); while (enum_values) { struct enum_value *enum_value = (struct enum_value *) enum_values->ptr; if (enum_value->value) fprintf (yyout, " %s = %s,\n", enum_value->ident, enum_value->value); else fprintf (yyout, " %s,\n", enum_value->ident); enum_values = enum_values->next; } fprintf (yyout, "};\n" "typedef enum %s %s;\n" "extern bool_t xdr_%s (XDR *, %s *);\n" "\n", name, name, name, name); break; case output_c: 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) { gen_line (); switch (output_mode) { case output_h: fprintf (yyout, "struct %s {\n", name); while (decls) { gen_decl (2, (struct decl *) decls->ptr); decls = decls->next; } fprintf (yyout, "};\n" "typedef struct %s %s;\n" "extern bool_t xdr_%s (XDR *, %s *);\n" "\n", name, name, name, name); break; case output_c: 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; } } void gen_union (const char *name, const struct decl *discrim, const struct cons *union_cases) { char *str; int len; gen_line (); switch (output_mode) { case output_h: fprintf (yyout, "struct %s {\n", name); gen_decl (2, discrim); fprintf (yyout, " union {\n"); while (union_cases) { 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, " } %s_u;\n" "};\n" "typedef struct %s %s;\n" "extern bool_t xdr_%s (XDR *, %s *);\n" "\n", name, name, name, name, name); break; case output_c: 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; } } void gen_typedef (const struct decl *decl) { 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 gen_decl (int indent, const struct decl *decl) { spaces (indent); 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); break; case decl_type_fixed_array: gen_type (decl->type); fprintf (yyout, " %s[%s];\n", decl->ident, decl->len); break; case decl_type_variable_array: fprintf (yyout, "struct {\n"); spaces (indent+2); fprintf (yyout, "uint32_t %s_len;\n", decl->ident); spaces (indent+2); gen_type (decl->type); fprintf (yyout, " *%s_val;\n", decl->ident); spaces (indent); fprintf (yyout, "} %s;\n", decl->ident); break; case decl_type_pointer: gen_type (decl->type); fprintf (yyout, " *%s;\n", decl->ident); break; } } 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_float: r = "float"; 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_float: r = strdup ("4"); 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) { switch (type->type) { case type_char: if (type->sgn) fputs ("int8_t", yyout); else fputs ("uint8_t", yyout); break; case type_short: if (type->sgn) fputs ("int16_t", yyout); else fputs ("uint16_t", yyout); break; case type_int: if (type->sgn) fputs ("int32_t", yyout); else fputs ("uint32_t", yyout); break; case type_hyper: if (type->sgn) fputs ("int64_t", yyout); else fputs ("uint64_t", yyout); break; case type_float: fputs ("float", yyout); break; case type_double: fputs ("double", yyout); break; case type_bool: fputs ("bool_t", yyout); break; case type_ident: fputs (type->ident, yyout); break; } }