Header generation working.
authorrjones <rjones>
Wed, 7 Jan 2009 19:38:52 +0000 (19:38 +0000)
committerrjones <rjones>
Wed, 7 Jan 2009 19:38:52 +0000 (19:38 +0000)
.cvsignore
Makefile.am
compile [new file with mode: 0755]
configure.ac
m4/.cvsignore [new file with mode: 0644]
rpcgen_ast.c [new file with mode: 0644]
rpcgen_codegen.c [new file with mode: 0644]
rpcgen_int.h
rpcgen_main.c
rpcgen_parse.y
rpcgen_scan.l

index 3719ab1..987e85c 100644 (file)
@@ -23,6 +23,8 @@ depcomp
 *.loT
 portable-rpcgen
 remote_protocol.x
+remote_protocol.c
+remote_protocol.h
 rpcgen_parse.c
 rpcgen_parse.h
 rpcgen_scan.c
index fb0fcb3..bb251c2 100644 (file)
@@ -1,3 +1,5 @@
+ACLOCAL_AMFLAGS = -I m4
+
 nobase_include_HEADERS = rpc/rpc.h rpc/types.h rpc/xdr.h
 
 lib_LTLIBRARIES = libportablexdr.la
@@ -14,6 +16,6 @@ BUILT_SOURCES = rpcgen_parse.h
 AM_YFLAGS = -d
 bin_PROGRAMS = portable-rpcgen
 portable_rpcgen_SOURCES = rpcgen_parse.y rpcgen_scan.l \
-       rpcgen_int.h rpcgen_main.c
+       rpcgen_int.h rpcgen_main.c rpcgen_ast.c rpcgen_codegen.c
 portable_rpcgen_CFLAGS = -Wall
 #portable_rpcgen_CFLAGS += -DYYDEBUG
diff --git a/compile b/compile
new file mode 100755 (executable)
index 0000000..1b1d232
--- /dev/null
+++ b/compile
@@ -0,0 +1,142 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2005-05-14.22
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+       # configure might choose to run compile as `compile cc -o foo foo.c'.
+       # So we strip `-o arg' only if arg is an object.
+       eat=1
+       case $2 in
+         *.o | *.obj)
+           ofile=$2
+           ;;
+         *)
+           set x "$@" -o "$2"
+           shift
+           ;;
+       esac
+       ;;
+      *.c)
+       cfile=$1
+       set x "$@" "$1"
+       shift
+       ;;
+      *)
+       set x "$@" "$1"
+       shift
+       ;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no `-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # `.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
index 95d2f2b..97ac4bf 100644 (file)
@@ -3,15 +3,20 @@ AM_INIT_AUTOMAKE
 
 AC_CONFIG_HEADERS([config.h])
 
+AC_CONFIG_MACRO_DIR([m4])
+
 AC_CANONICAL_HOST
 AC_PROG_CC
-AC_CHECK_PROGS(AR, ar)
+AM_PROG_CC_C_O
+
 AC_PROG_INSTALL
 AC_PROG_LIBTOOL
 
 AC_PROG_LEX
 AC_PROG_YACC
 
+AC_CHECK_PROGS(AR, ar)
+
 dnl Look for an external 'cpp' program which can run on a file with any
 dnl extension.  The normal CPP can only run on files with a '.c'
 dnl extension, therefore we prefer to use /usr/bin/cpp if it exists.
diff --git a/m4/.cvsignore b/m4/.cvsignore
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rpcgen_ast.c b/rpcgen_ast.c
new file mode 100644 (file)
index 0000000..e1caa99
--- /dev/null
@@ -0,0 +1,147 @@
+/* -*- 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 "rpcgen_int.h"
+
+struct type *
+new_type (enum type_enum type, int sgn, char *ident, char *len)
+{
+  struct type *r = malloc (sizeof *r);
+  r->type = type;
+  r->sgn = sgn;
+  r->ident = ident;
+  r->len = len;
+  return r;
+}
+
+void
+free_type (struct type *t)
+{
+  if (t) {
+    free (t->ident);
+    free (t->len);
+    free (t);
+  }
+}
+
+struct decl *
+new_decl (enum decl_type decl_type, struct type *type,
+         char *ident, char *len)
+{
+  struct decl *r = malloc (sizeof *r);
+  r->decl_type = decl_type;
+  r->type = type;
+  r->ident = ident;
+  r->len = len;
+  return r;
+}
+
+void
+free_decl (struct decl *d)
+{
+  if (d) {
+    free_type (d->type);
+    free (d->ident);
+    free (d->len);
+    free (d);
+  }
+}
+
+struct enum_value *
+new_enum_value (char *ident, char *value)
+{
+  struct enum_value *r = malloc (sizeof *r);
+  r->ident = ident;
+  r->value = value;
+  return r;
+}
+
+void
+free_enum_value (struct enum_value *v)
+{
+  if (v) {
+    free (v->ident);
+    free (v->value);
+    free (v);
+  }
+}
+
+struct union_case *
+new_union_case (enum union_case_type type, char *const_, struct decl *decl)
+{
+  struct union_case *r = malloc (sizeof *r);
+  r->type = type;
+  r->const_ = const_;
+  r->decl = decl;
+  return r;
+}
+
+void
+free_union_case (struct union_case *c)
+{
+  if (c) {
+    free (c->const_);
+    free_decl (c->decl);
+    free (c);
+  }
+}
+
+struct cons *
+new_cons (struct cons *next, void *ptr, free_fn free)
+{
+  struct cons *r = malloc (sizeof *r);
+  r->next = next;
+  r->ptr = ptr;
+  r->free = free;
+  return r;
+}
+
+static struct cons *
+list_rev_append (struct cons *xs1, struct cons *xs2)
+{
+  if (!xs1) return xs2;
+  else {
+    struct cons *tail = xs1->next;
+    xs1->next = xs2;
+    return list_rev_append (tail, xs1);
+  }
+}
+
+struct cons *
+list_rev (struct cons *xs)
+{
+  return list_rev_append (xs, NULL);
+}
+
+void
+list_free (struct cons *xs)
+{
+  if (xs) {
+    struct cons *next = xs->next;
+    if (xs->free) xs->free (xs->ptr);
+    free (xs);
+    list_free (next);
+  }
+}
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;
+    }
+}
index e372295..9271326 100644 (file)
 #ifndef RPCGEN_INT_H
 #define RPCGEN_INT_H
 
+/* Current input file (updated by # line directives in the source). */
 extern char *input_filename;
 
+/* Current output file. */
+extern const char *output_filename;
+
+/* Current output mode. */
+enum output_mode {
+  output_c = 0,
+  output_h = 1,
+};
+extern enum output_mode output_mode;
+
+/* Abstract syntax tree types. */
+enum type_enum {
+  type_char, type_short, type_int, type_hyper,
+  type_double,
+  type_string, type_opaque, type_bool,
+  type_ident,
+};
+
+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 void free_type (struct type *);
+
+enum decl_type {
+  decl_type_simple,            /* type ident; */
+  decl_type_fixed_array,       /* type ident[len]; */
+  decl_type_variable_array,    /* type ident<len>; (len is optional) */
+  decl_type_pointer,           /* type *ident; */
+};
+
+struct decl {
+  enum decl_type decl_type;
+  struct type *type;
+  char *ident;
+  char *len;
+};
+
+extern struct decl *new_decl (enum decl_type, struct type *, char *, char *);
+extern void free_decl (struct decl *);
+
+struct enum_value {
+  char *ident;
+  char *value;
+};
+
+extern struct enum_value *new_enum_value (char *, char *);
+extern void free_enum_value (struct enum_value *);
+
+enum union_case_type {
+  union_case_normal,           /* case const: decl; */
+  union_case_default_void,     /* default: void; */
+  union_case_default_decl,     /* default: decl; */
+};
+
+struct union_case {
+  enum union_case_type type;
+  char *const_;
+  struct decl *decl;
+};
+
+extern struct union_case *new_union_case (enum union_case_type, char *, struct decl *);
+extern void free_union_case (struct union_case *);
+
+typedef void (*free_fn) (void *);
+
+struct cons {
+  struct cons *next; /* cdr/tail */
+  void *ptr; /* car/head */
+  free_fn free; /* free the head element */
+};
+
+extern struct cons *new_cons (struct cons *, void *, free_fn);
+extern struct cons *list_rev (struct cons *);
+extern void list_free (struct cons *);
+
+/* Code generator functions. */
+extern void gen_prologue (const char *filename);
+extern void gen_epilogue (void);
+extern void gen_const (const char *name, const char *value);
+extern void gen_enum (const char *name, const struct cons *enum_values);
+extern void gen_struct (const char *name, const struct cons *decls);
+extern void gen_union (const char *name, const struct decl *discrim, const struct cons *union_cases);
+extern void gen_typedef (const struct decl *decl);
+
 /* Global functions used by the scanner. */
 extern void start_string (void);
 extern char *end_string (void);
@@ -34,4 +124,10 @@ extern void error (const char *, ...)
 extern void perrorf (const char *, ...)
   __attribute__((noreturn, format(printf,1,2)));
 
+/* Symbols exported from the scanner and parser. */
+extern FILE *yyin, *yyout;
+extern int yyparse (void);
+extern int yylineno;
+extern int yydebug;
+
 #endif /* RPCGEN_INT_H */
index 6ad467f..a2e97b7 100644 (file)
 
 #include "rpcgen_int.h"
 
+enum output_mode output_mode;
+
 static void print_version (void);
 static void usage (const char *progname);
-static void do_rpcgen (const char *filename);
+static void do_rpcgen (const char *filename, const char *out);
 static char *make_cpp_command (const char *filename);
 
-/* Symbols exported from the scanner. */
-extern FILE *yyin, *yyout;
-extern int yyparse (void);
-extern int yylineno;
-extern int yydebug;
-
 int
 main (int argc, char *argv[])
 {
   int opt;
+  char *filename;
+  int output_modes = 0;
+  char *out = NULL;
 
-  /* To enable debugging in the parser, you also need to compile
-   * with -DYYDEBUG
-   */
-#if 0
+#if YYDEBUG
   yydebug = 1;
 #endif
 
@@ -76,9 +72,16 @@ main (int argc, char *argv[])
 
        /*-- Options that we do support. --*/
       case 'c':
+       output_modes |= 1 << output_c;
+       break;
+
       case 'h':
+       output_modes |= 1 << output_h;
+       break;
+
       case 'o':
-       ;
+       out = optarg;
+       break;
 
        /* None of the other versions of rpcgen support a way to print
         * the version number, which is extremely annoying because
@@ -99,8 +102,25 @@ main (int argc, char *argv[])
   if (optind >= argc)
     error ("expected name of input file after options");
 
-  while (optind < argc)
-    do_rpcgen (argv[optind++]);
+  while (optind < argc) {
+    filename = argv[optind++];
+
+    if (output_modes == 0) {
+      output_mode = output_h;
+      do_rpcgen (filename, out);
+      output_mode = output_c;
+      do_rpcgen (filename, out);
+    } else {
+      if ((output_modes & (1 << output_h)) != 0) {
+       output_mode = output_h;
+       do_rpcgen (filename, out);
+      }
+      if ((output_modes & (1 << output_c)) != 0) {
+       output_mode = output_c;
+       do_rpcgen (filename, out);
+      }
+    }
+  }
 
   exit (0);
 }
@@ -138,16 +158,58 @@ usage (const char *progname)
   exit (0);
 }
 
+/* This is a global so the error functions can delete the output file. */
+const char *output_filename = NULL;
+int unlink_output_filename;
+
 /* Called for each input file. */
 static void
-do_rpcgen (const char *filename)
+do_rpcgen (const char *filename, const char *out)
 {
-  char *cmd;
-  int r;
+  char *cmd, *t = NULL;
+  int r, len;
+  const char *ext;
+
+  /* Open the output file. */
+  switch (output_mode) {
+  case output_c: ext = ".c"; break;
+  case output_h: ext = ".h"; break;
+  default: error ("internal error in do_rpcgen / output_mode");
+  }
+
+  if (out && strcmp (out, "-") == 0) {
+    output_filename = NULL;
+    unlink_output_filename = 0;
+    yyout = stdout;
+  }
+  else if (out) {
+    output_filename = out;
+    unlink_output_filename = 1;
+    yyout = fopen (output_filename, "w");
+    if (yyout == NULL)
+      perrorf ("%s", output_filename);
+  }
+  else {
+    len = strlen (filename);
+    t = malloc (len + 3);
+    if (t == NULL)
+      perrorf ("malloc");
+    strcpy (t, filename);
+    if (len >= 2 && strcmp (t + len - 2, ".x") == 0)
+      strcpy (t + len - 2, ext);
+    else
+      strcat (t, ext);
+    output_filename = t;
+    unlink_output_filename = 1;
+    yyout = fopen (output_filename, "w");
+    if (yyout == NULL)
+      perrorf ("%s", output_filename);
+  }
 
   free (input_filename);
   input_filename = NULL;
 
+  /* Make the CPP command and open a pipe. */
   cmd = make_cpp_command (filename);
 
   yyin = popen (cmd, "r");
@@ -155,9 +217,9 @@ do_rpcgen (const char *filename)
     perrorf ("%s", cmd);
   free (cmd);
 
-  yyout = stdout;
+  gen_prologue (filename);
 
-  /* Parse the input file.  This either succeeds or exits with an error. */
+  /* Parse the input file, this also generates the output as a side-effect. */
   r = yyparse ();
   pclose (yyin);
 
@@ -166,8 +228,17 @@ do_rpcgen (const char *filename)
   else if (r == 2)
     error ("parsing failed because we ran out of memory");
 
+  gen_epilogue ();
+
+  if (yyout != stdout)
+    fclose (yyout);
+  output_filename = NULL;
+  unlink_output_filename = 0;
+
   free (input_filename);
   input_filename = NULL;
+
+  free (t);
 }
 
 /* Concatenate $EXTCPP and filename, and make sure the filename is
@@ -270,6 +341,9 @@ error (const char *fs, ...)
 {
   va_list arg;
 
+  if (output_filename && unlink_output_filename)
+    unlink (output_filename);
+
   if (input_filename == NULL)
     fputs (PACKAGE, stderr);
   else
@@ -291,6 +365,9 @@ perrorf (const char *fs, ...)
   va_list arg;
   int e = errno;
 
+  if (output_filename && unlink_output_filename)
+    unlink (output_filename);
+
   if (input_filename == NULL)
     fputs (PACKAGE, stderr);
   else
index 04b073a..5ccc7dd 100644 (file)
@@ -27,9 +27,21 @@ extern void yyerror (const char *str);
 
 %union {
   char *str;
+  struct type *type;
+  struct decl *decl;
+  struct enum_value *enum_value;
+  struct union_case *union_case;
+  struct cons *list;
 }
 
+%type <type> type_ident
 %type <str> const
+%type <decl> decl
+%type <decl> simple_decl fixed_array_decl variable_array_decl pointer_decl
+%type <decl> string_decl
+%type <enum_value> enum_value
+%type <union_case> union_case
+%type <list> decls enum_values union_cases
 
 %token STRUCT
 %token ENUM
@@ -50,6 +62,7 @@ extern void yyerror (const char *str);
 %token DOUBLE
 %token STRING
 %token OPAQUE
+%token BOOL
 
 /* This is sometimes lumped together with the other types, but
  * the special keyword void can only occur after "default:" in
@@ -73,62 +86,125 @@ stmts      : stmt ';'
        ;
 
 stmt   : ENUM IDENT '{' enum_values '}'
+       {
+         struct cons *enums = list_rev ($4);
+         gen_enum ($2, enums);
+         free ($2);
+         list_free (enums);
+       }
        | STRUCT IDENT '{' decls '}'
+       {
+         struct cons *decls = list_rev ($4);
+         gen_struct ($2, decls);
+         free ($2);
+         list_free (decls);
+       }
        | UNION IDENT SWITCH '(' decl ')' '{' union_cases '}'
+       {
+         struct cons *cases = list_rev ($8);
+         gen_union ($2, $5, cases);
+         free ($2);
+         free_decl ($5);
+         list_free (cases);
+       }
        | TYPEDEF decl
+       {
+         gen_typedef ($2);
+         free_decl ($2);
+       }
        | CONST IDENT '=' const
+       {
+         gen_const ($2, $4);
+         free ($2);
+         free ($4);
+       }
        | PROGRAM
+       {
+         error ("PortableXDR does not support SunRPC program statements");
+       }
        ;
 
 /* Declarations used inside structs and unions.  eg. "int foo;" */
 decls  : decl ';'
+       { $$ = new_cons (NULL, $1, (free_fn) free_decl); }
        | decls decl ';'
+       { $$ = new_cons ($1, $2, (free_fn) free_decl); }
        ;
 
-decl   : simple_decl
+decl   : string_decl
+       | simple_decl
        | fixed_array_decl
        | variable_array_decl
        | pointer_decl
        ;
 
+string_decl
+       : STRING IDENT '<' const '>'
+       {
+         $$ = new_decl (decl_type_simple,
+                        new_type (type_string, 0, NULL, $4),
+                        $2, NULL);
+       }
+       | STRING IDENT '<' '>'
+       {
+         $$ = new_decl (decl_type_simple,
+                        new_type (type_string, 0, NULL, NULL),
+                        $2, NULL);
+       }
+       ;
+
 simple_decl
        : type_ident IDENT
+       { $$ = new_decl (decl_type_simple, $1, $2, NULL); }
        ;
 
 fixed_array_decl
        : type_ident IDENT '[' const ']'
+       { $$ = new_decl (decl_type_fixed_array, $1, $2, $4); }
        ;
 
 variable_array_decl
        : type_ident IDENT '<' const '>'
+       { $$ = new_decl (decl_type_variable_array, $1, $2, $4); }
        | type_ident IDENT '<' '>'
+       { $$ = new_decl (decl_type_variable_array, $1, $2, NULL); }
        ;
 
 pointer_decl
        : type_ident '*' IDENT
+       { $$ = new_decl (decl_type_pointer, $1, $3, NULL); }
        ;
 
 /* Enumerations. */
 enum_values
        : enum_value
+       { $$ = new_cons (NULL, $1, (free_fn) free_enum_value); }
        | enum_values ',' enum_value
+       { $$ = new_cons ($1, $3, (free_fn) free_enum_value); }
        ;
 
 enum_value
        : IDENT
+       { $$ = new_enum_value ($1, NULL); }
        | IDENT '=' const
+       { $$ = new_enum_value ($1, $3); }
        ;
 
 /* Case list inside a union. */
 union_cases
        : union_case ';'
+       { $$ = new_cons (NULL, $1, (free_fn) free_union_case); }
        | union_cases union_case ';'
+       { $$ = new_cons ($1, $2, (free_fn) free_union_case); }
        ;
 
 union_case
        : CASE const ':' decl
+       { $$ = new_union_case (union_case_normal, $2, $4); }
        | DEFAULT ':' VOID
+       { $$ = new_union_case (union_case_default_void, NULL, NULL); }
        | DEFAULT ':' decl
+       { $$ = new_union_case (union_case_default_decl, NULL, $3); }
        ;
 
 /* Constants, which may be integer literals or refer to previously
@@ -139,26 +215,44 @@ const     : INTLIT
        | IDENT
        ;
 
-/* Types. */
+/* Types.  Note 'string' and 'void' are handled by special cases above. */
 type_ident
        : CHAR
+       { $$ = new_type (type_char, 1, NULL, NULL); }
        | SIGNED CHAR
+       { $$ = new_type (type_char, 1, NULL, NULL); }
        | UNSIGNED CHAR
+       { $$ = new_type (type_char, 0, NULL, NULL); }
        | SHORT
+       { $$ = new_type (type_short, 1, NULL, NULL); }
        | SIGNED SHORT
+       { $$ = new_type (type_short, 1, NULL, NULL); }
        | UNSIGNED SHORT
+       { $$ = new_type (type_short, 0, NULL, NULL); }
        | INT
+       { $$ = new_type (type_int, 1, NULL, NULL); }
        | SIGNED INT
+       { $$ = new_type (type_int, 1, NULL, NULL); }
        | UNSIGNED INT
+       { $$ = new_type (type_int, 0, NULL, NULL); }
        | HYPER
+       { $$ = new_type (type_hyper, 1, NULL, NULL); }
        | SIGNED HYPER
+       { $$ = new_type (type_hyper, 1, NULL, NULL); }
        | UNSIGNED HYPER
+       { $$ = new_type (type_hyper, 0, NULL, NULL); }
        | SIGNED
+       { $$ = new_type (type_int, 1, NULL, NULL); }
        | UNSIGNED
+       { $$ = new_type (type_int, 0, NULL, NULL); }
        | DOUBLE
-       | STRING
+       { $$ = new_type (type_double, 0, NULL, NULL); }
        | OPAQUE
+       { $$ = new_type (type_opaque, 0, NULL, NULL); }
+       | BOOL
+       { $$ = new_type (type_bool, 0, NULL, NULL); }
        | IDENT
+       { $$ = new_type (type_ident, 0, $1, NULL); }
        ;
 
 %%
index 061dbbf..4ab278d 100644 (file)
@@ -29,7 +29,8 @@
 
 HEXLIT     "0x"[0-9a-fA-F]+
 DECLIT     0|[1-9][0-9]*
-INTLIT     {HEXLIT}|{DECLIT}
+OCTLIT     0[0-7]+
+INTLIT     {HEXLIT}|{DECLIT}|{OCTLIT}
 IDENT      [a-zA-Z_][a-zA-Z_0-9]*
 WS         [[:space:]]+
 
@@ -51,7 +52,7 @@ WS         [[:space:]]+
   if (filename == NULL) perrorf ("malloc");
 
   if (sscanf (yytext+2, "%d \"%[^\"]\"", &lineno, filename) == 2) {
-    yylineno = lineno - 1;
+    yylineno = lineno;
     free (input_filename);
     input_filename = filename;
   }
@@ -136,6 +137,7 @@ hyper      return HYPER;
 double     return DOUBLE;
 string     return STRING;
 opaque     return OPAQUE;
+bool       return BOOL;
 
 void       return VOID;