+/* -*- 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;
+ }
+}