Seems to create a reasonable .c and .h file now.
authorrjones <rjones>
Mon, 12 Jan 2009 15:25:05 +0000 (15:25 +0000)
committerrjones <rjones>
Mon, 12 Jan 2009 15:25:05 +0000 (15:25 +0000)
.cvsignore
rpcgen_ast.c
rpcgen_codegen.c
rpcgen_int.h
rpcgen_main.c
rpcgen_parse.y
rpcgen_scan.l

index 987e85c..7d2416d 100644 (file)
@@ -28,3 +28,6 @@ remote_protocol.h
 rpcgen_parse.c
 rpcgen_parse.h
 rpcgen_scan.c
+test.x
+test.c
+test.h
index e1caa99..baade6a 100644 (file)
 #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);
   }
 }
index 3184884..9677a2a 100644 (file)
 
 #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 <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;
     }
@@ -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;
index 9271326..b551516 100644 (file)
@@ -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>; (len is optional) */
+  decl_type_opaque_fixed,      /* opaque foo[len]; */
+  decl_type_opaque_variable,   /* opaque foo<len>; */
   decl_type_simple,            /* type ident; */
   decl_type_fixed_array,       /* type ident[len]; */
   decl_type_variable_array,    /* type ident<len>; (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;
 };
index a2e97b7..b7970fb 100644 (file)
@@ -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':
index 5ccc7dd..2923325 100644 (file)
@@ -38,7 +38,7 @@ extern void yyerror (const char *str);
 %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
@@ -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); }
        ;
 
 %%
index 4ab278d..10ed056 100644 (file)
@@ -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;
   }