#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
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
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"
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"
"\n"
"#include <stdint.h>\n"
"#include <rpc/rpc.h>\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;
}
"}\n"
"#endif\n"
"\n"
- "#endif /* ");
- write_header_def ();
- fprintf (yyout, " */\n");
+ "#endif /* RPCGEN_HEADER_");
+ write_basename_caps ();
+ fprintf (yyout, "_H */\n");
break;
}
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)
{
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;
}
}
gen_union (const char *name, const struct decl *discrim,
const struct cons *union_cases)
{
+ char *str;
+ int len;
+
gen_line ();
switch (output_mode)
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,
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;
}
}
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
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);
}
}
+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)
{
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;
%type <str> const
%type <decl> decl
%type <decl> simple_decl fixed_array_decl variable_array_decl pointer_decl
-%type <decl> string_decl
+%type <decl> string_decl opaque_decl
%type <enum_value> enum_value
%type <union_case> union_case
%type <list> decls enum_values union_cases
;
decl : string_decl
+ | opaque_decl
| simple_decl
| fixed_array_decl
| variable_array_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);
}
;
| 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); }
;
%%