Header generation working.
[portablexdr.git] / rpcgen_codegen.c
diff --git a/rpcgen_codegen.c b/rpcgen_codegen.c
new file mode 100644 (file)
index 0000000..3184884
--- /dev/null
@@ -0,0 +1,337 @@
+/* -*- 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "rpcgen_int.h"
+
+static void gen_line (void);
+static void gen_decl (int indent, const struct decl *);
+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 (input_filename)
+    fprintf (yyout, "#line %d \"%s\"\n", yylineno, input_filename);
+}
+
+static void
+write_header_def (void)
+{
+  const char *p;
+
+  p = strrchr (output_filename, '/') ? : output_filename;
+
+  fputs ("RPCGEN_HEADER_", yyout);
+
+  while (*p) {
+    if (isalnum (*p))
+      fputc (toupper (*p), yyout);
+    else
+      fputc ('_', yyout);
+    ++p;
+  }
+}
+
+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"
+          " * The input file was %s\n"
+          " */\n"
+          "\n",
+          PACKAGE_VERSION, 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);
+      break;
+
+    case output_h:
+      fprintf (yyout, "#ifndef ");
+      write_header_def ();
+      fprintf (yyout, "\n#define ");
+      write_header_def ();
+      fprintf (yyout,
+              "\n"
+              "\n"
+              "#ifdef __cplusplus\n"
+              "extern \"C\" {\n"
+              "#endif\n"
+              "\n"
+              "#include <stdint.h>\n"
+              "#include <rpc/rpc.h>\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 /* ");
+      write_header_def ();
+      fprintf (yyout, " */\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:
+      /* XXX */
+      break;
+    }
+}
+
+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:
+      /* XXX */
+      break;
+    }
+}
+
+void
+gen_union (const char *name, const struct decl *discrim,
+          const struct cons *union_cases)
+{
+  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 decl *decl = ((struct union_case *) union_cases->ptr)->decl;
+       if (decl) gen_decl (4, 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:
+      /* XXX */
+      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);
+  }
+}
+
+static void
+gen_decl (int indent, const struct decl *decl)
+{
+  spaces (indent);
+
+  switch (decl->decl_type)
+    {
+    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 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_double:
+      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;
+
+    case type_ident:
+      fputs (type->ident, yyout);
+      break;
+    }
+}