You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by gs...@apache.org on 2009/01/31 08:30:46 UTC

svn commit: r739515 [1/3] - in /incubator/thrift/branches/c-bindings: ./ compiler/cpp/ compiler/cpp/src/generate/ compiler/cpp/src/parse/ gen-c/ lib/ lib/c/ lib/c/thrift_c/ lib/c/thrift_c/protocol/ lib/c/thrift_c/transport/ test/thorough/

Author: gstein
Date: Sat Jan 31 07:30:45 2009
New Revision: 739515

URL: http://svn.apache.org/viewvc?rev=739515&view=rev
Log:
Committing Ross McFarland's work to the c-bindings branch.

Originally located at:
 http://thrift-rpc.org/?p=thrift.git;a=shortlog;h=refs/heads/pri/rmcfarland/c_bindings_linear

Added:
    incubator/thrift/branches/c-bindings/compiler/cpp/src/generate/t_c_generator.cc
    incubator/thrift/branches/c-bindings/gen-c/
    incubator/thrift/branches/c-bindings/gen-c/Makefile
    incubator/thrift/branches/c-bindings/gen-c/echo.pl
    incubator/thrift/branches/c-bindings/gen-c/main.c
    incubator/thrift/branches/c-bindings/gen-c/valgrind.supp
    incubator/thrift/branches/c-bindings/lib/c/
    incubator/thrift/branches/c-bindings/lib/c/Makefile.am
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/protocol/
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/protocol/thrift_binary_protocol.c
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/protocol/thrift_binary_protocol.h
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/protocol/thrift_protocol.c
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/protocol/thrift_protocol.h
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/thrift.h
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/thrift_client.c
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/thrift_client.h
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/thrift_hash.c
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/thrift_hash.h
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/thrift_struct.c
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/thrift_struct.h
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/transport/
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/transport/thrift_framed.c
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/transport/thrift_framed.h
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/transport/thrift_socket.c
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/transport/thrift_socket.h
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/transport/thrift_transport.c
    incubator/thrift/branches/c-bindings/lib/c/thrift_c/transport/thrift_transport.h
    incubator/thrift/branches/c-bindings/test/thorough/
    incubator/thrift/branches/c-bindings/test/thorough/Makefile
    incubator/thrift/branches/c-bindings/test/thorough/Thorough_server.cpp
    incubator/thrift/branches/c-bindings/test/thorough/case.thrift
    incubator/thrift/branches/c-bindings/test/thorough/main.c
    incubator/thrift/branches/c-bindings/test/thorough/thorough.c
    incubator/thrift/branches/c-bindings/test/thorough/thorough.thrift
Modified:
    incubator/thrift/branches/c-bindings/compiler/cpp/Makefile.am
    incubator/thrift/branches/c-bindings/compiler/cpp/src/parse/t_program.h
    incubator/thrift/branches/c-bindings/configure.ac
    incubator/thrift/branches/c-bindings/lib/Makefile.am

Modified: incubator/thrift/branches/c-bindings/compiler/cpp/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/thrift/branches/c-bindings/compiler/cpp/Makefile.am?rev=739515&r1=739514&r2=739515&view=diff
==============================================================================
--- incubator/thrift/branches/c-bindings/compiler/cpp/Makefile.am (original)
+++ incubator/thrift/branches/c-bindings/compiler/cpp/Makefile.am Sat Jan 31 07:30:45 2009
@@ -43,6 +43,9 @@
 if THRIFT_GEN_cpp
 thrift_SOURCES += src/generate/t_cpp_generator.cc
 endif
+if THRIFT_GEN_c
+thrift_SOURCES += src/generate/t_c_generator.cc
+endif
 if THRIFT_GEN_java
 thrift_SOURCES += src/generate/t_java_generator.cc
 endif

Added: incubator/thrift/branches/c-bindings/compiler/cpp/src/generate/t_c_generator.cc
URL: http://svn.apache.org/viewvc/incubator/thrift/branches/c-bindings/compiler/cpp/src/generate/t_c_generator.cc?rev=739515&view=auto
==============================================================================
--- incubator/thrift/branches/c-bindings/compiler/cpp/src/generate/t_c_generator.cc (added)
+++ incubator/thrift/branches/c-bindings/compiler/cpp/src/generate/t_c_generator.cc Sat Jan 31 07:30:45 2009
@@ -0,0 +1,2082 @@
+// Copyright (c) 2007- RM
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+
+/**
+ * TODO:
+ * - use glib stuff where it can be since we'll require it for the code
+ *   we produce, g_strdup is an example. also may help with intl support
+ * - use G_UNLIKELY where approrate
+ * - collections stuff needs LOTS of work
+ * - all protocol write methods (and others too) that take gerrors need to have
+ *   their return values checked and abrt things accordingly... 
+ */
+
+#include <cassert>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <boost/lexical_cast.hpp>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#include "platform.h"
+#include "t_oop_generator.h"
+
+using namespace std;
+
+// TODO: more of these
+string initial_caps_to_underscores(string name)
+{
+  char buf[256];
+  const char * tmp = name.c_str();
+  int pos = 0;
+  buf[pos] = tolower(tmp[pos]);
+  pos++;
+  for (unsigned int i = pos; i < name.length(); i++)
+  {
+    buf[pos] = tolower(tmp[i]);
+    if (buf[pos] != tmp[i])
+    {
+      // we just lowercase'd it
+      buf[pos+1] = buf[pos];
+      buf[pos] = '_';
+      pos++;
+    }
+    pos++;
+  }
+  buf[pos] = '\0';
+
+  return buf;
+}
+
+string to_upper_case(string name)
+{
+  char tmp[256];
+  strncpy (tmp, name.c_str(), name.length ());
+  for (unsigned int i = 0; i < strlen(tmp); i++)
+    tmp[i] = toupper(tmp[i]);
+  tmp[name.length()] = '\0';
+  return tmp;
+}
+
+/**
+ * C code generator. This is legitimacy incarnate.
+ *
+ * @author Mark Slee <mc...@facebook.com>
+ */
+class t_c_generator : public t_oop_generator {
+ public:
+  t_c_generator(
+      t_program* program,
+      const map<string, string>& parsed_options,
+      const string& option_string)
+    : t_oop_generator(program)
+  {
+    this->out_dir_base_ = "gen-c";
+
+    this->nspace = program_->get_namespace("c");
+    if (this->nspace.empty())
+      this->nspace = "Thrift";
+    else
+      this->nspace = "Thrift." + this->nspace;
+
+    char * tmp = strdup(this->nspace.c_str());
+    for (unsigned int i = 0; i < strlen(tmp); i++)
+    {
+      if (tmp[i] == '.')
+        tmp[i] = '_';
+      tmp[i] = tolower(tmp[i]);
+    }
+    this->nspace_u = tmp;
+    this->nspace_u += "_";
+
+    for (unsigned int i = 0; i < strlen(tmp); i++)
+      tmp[i] = toupper(tmp[i]);
+    this->nspace_uc = tmp;
+    this->nspace_uc += "_";
+
+    free(tmp);
+
+    tmp = strdup(this->nspace.c_str());
+    int pos = 0;
+    for (unsigned int i = 0; i < strlen(tmp); i++)
+    {
+      if (tmp[i] != '.')
+      {
+        tmp[pos] = tmp[i];
+        pos++;
+      }
+    }
+    this->nspace = string(tmp, pos);
+    free(tmp);
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator();
+  void close_generator();
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef);
+  void generate_enum(t_enum* tenum);
+  void generate_consts(vector<t_const*> consts);
+  void generate_struct(t_struct* tstruct);
+  void generate_service(t_service* tservice);
+  void generate_xception (t_struct* txception);
+
+ private:
+
+  /**
+   * File streams, stored here to avoid passing them as parameters to every
+   * function.
+   */
+
+  ofstream f_types_;
+  ofstream f_types_impl_;
+  std::ofstream f_header_;
+  std::ofstream f_service_;
+
+  string nspace;
+  string nspace_u;
+  string nspace_uc;
+
+  /** 
+   * helper functions
+   */
+
+  void generate_service_client(t_service* tservice);
+
+  void generate_object(t_struct* tstruct);
+
+  void generate_struct_writer(ofstream& out, t_struct* tstruct, 
+                              string this_name, string this_get="", 
+                              bool is_function=true);
+  void generate_struct_reader(std::ofstream& out, t_struct* tstruct, 
+                              string this_name, string this_get="",
+                              bool is_function=true);
+
+  void generate_serialize_field(ofstream& out, t_field* tfield,
+                                string prefix, string suffix, 
+                                int error_ret);
+  void generate_serialize_struct(ofstream& out, t_struct* tstruct,
+                                 string prefix, int error_ret);
+  void generate_serialize_container(ofstream& out, t_type* ttype,
+                                    string prefix, int error_ret);
+  void generate_serialize_map_element(ofstream& out, t_map* tmap, string key,
+                                      string value, int error_ret);
+  void generate_serialize_set_element(ofstream& out, t_set* tmap, 
+                                      string element, int error_ret);
+  void generate_serialize_list_element(ofstream& out, t_list* tlist,
+                                       string list, string index, 
+                                       int error_ret);
+
+  void generate_deserialize_field(std::ofstream& out, t_field* tfield,
+                                  std::string prefix, std::string suffix,
+                                  int error_ret);
+  void generate_deserialize_struct(std::ofstream& out, t_struct* tstruct,
+                                   std::string prefix, int error_ret);
+  void generate_deserialize_xception(std::ofstream& out, t_struct* tstruct,
+                                     std::string prefix, int error_ret);
+  void generate_deserialize_container(std::ofstream& out, t_type* ttype,
+                                      std::string prefix, int error_ret);
+  string generate_new_hash_from_type(t_type * ttype);
+  string generate_new_array_from_type(t_type * ttype);
+  void generate_deserialize_set_element(std::ofstream& out, t_set* tset,
+                                        std::string prefix, int error_ret);
+  void generate_deserialize_map_element(std::ofstream& out, t_map* tmap,
+                                        std::string prefix, int error_ret);
+  void generate_deserialize_list_element(std::ofstream& out, t_list* tlist,
+                                         std::string prefix, std::string index, 
+                                         int error_ret);
+
+  std::string function_signature(t_function* tfunction);
+  std::string argument_list(t_struct* tstruct, bool name_params=true);
+  std::string type_name(t_type* ttype, bool in_typedef=false, bool is_const=false);
+  string base_type_name(t_base_type::t_base tbase);
+  string type_to_enum(t_type * type);
+  string constant_value(t_type * type, t_const_value * value);
+  std::string declare_field(t_field* tfield, bool init=false, bool pointer=false, bool constant=false, bool reference=false);
+
+  bool is_complex_type(t_type* ttype) {
+    ttype = get_true_type(ttype);
+
+    return
+      ttype->is_container() ||
+      ttype->is_struct() ||
+      ttype->is_xception() ||
+      (ttype->is_base_type() && (((t_base_type*)ttype)->get_base() == t_base_type::TYPE_STRING));
+  }
+
+};
+
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_c_generator::init_generator() {
+  // Make output directory
+  MKDIR(get_out_dir().c_str());
+
+  string program_name_u = initial_caps_to_underscores(program_name_);
+
+  // Make output file
+  string f_types_name = get_out_dir()+program_name_u+"_types.h";
+  f_types_.open(f_types_name.c_str());
+
+  string f_types_impl_name = get_out_dir()+program_name_u+"_types.c";
+  f_types_impl_.open(f_types_impl_name.c_str());
+
+  // Print header
+  f_types_ <<
+    autogen_comment();
+  f_types_impl_ <<
+    autogen_comment();
+
+  string program_name_uc = to_upper_case (program_name_u);
+
+  // Start ifndef
+  f_types_ <<
+    "#ifndef " << program_name_uc << "_TYPES_H" << endl <<
+    "#define " << program_name_uc << "_TYPES_H" << endl <<
+    endl;
+
+  // Include base types
+  f_types_ <<
+    "/* base includes */" << endl <<
+    "#include <protocol/thrift_protocol.h>" << endl <<
+    "#include <thrift_struct.h>" << endl <<
+    "#include <glib-object.h>" << endl <<
+    endl;
+
+  // Include other Thrift includes
+  const vector<t_program*>& includes = program_->get_includes();
+  for (size_t i = 0; i < includes.size(); ++i) {
+    f_types_ <<
+      "/* other thrift includes */" << endl <<
+      "#include \"" << includes[i]->get_name() << "_types.h\"" << endl;
+  }
+  f_types_ << endl;
+
+  // Include custom headers
+  const vector<string>& c_includes = program_->get_c_includes();
+  f_types_ << "/* custom thrift includes */" << endl;
+  for (size_t i = 0; i < c_includes.size(); ++i) {
+    if (c_includes[i][0] == '<') {
+      f_types_ <<
+        "#include " << c_includes[i] << endl;
+    } else {
+      f_types_ <<
+        "#include \"" << c_includes[i] << "\"" << endl;
+    }
+  }
+  f_types_ <<
+    endl;
+
+  // Include the types file
+  f_types_impl_ <<
+    endl <<
+    "#include \"" << program_name_u << "_types.h\"" << endl <<
+    "#include <thrift.h>" << endl <<
+    endl;
+
+  f_types_ << 
+    "/* begin types */" << endl << endl;
+}
+
+/**
+ * Closes the output files.
+ */
+void t_c_generator::close_generator() {
+
+  string program_name_uc = to_upper_case
+    (initial_caps_to_underscores(program_name_));
+
+  // Close ifndef
+  f_types_ <<
+    "#endif /* " << program_name_uc << "_TYPES_H */" << endl;
+
+  // Close output file
+  f_types_.close();
+  f_types_impl_.close();
+}
+
+/**
+ * Generates a typedef. This is just a simple 1-liner in C
+ *
+ * @param ttypedef The type definition
+ */
+void t_c_generator::generate_typedef(t_typedef* ttypedef) {
+  f_types_ <<
+    indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << 
+    this->nspace << ttypedef->get_symbolic() << ";" << endl << endl;
+}
+
+/**
+ * Generates code for an enumerated type. In C, this is essentially the same
+ * as the thrift definition itself, using the enum keyword in C.
+ *
+ * @param tenum The enumeration
+ */
+void t_c_generator::generate_enum(t_enum* tenum) {
+
+  string name = tenum->get_name();
+  string name_uc = to_upper_case(initial_caps_to_underscores(name));
+
+  // TODO: look in to using glib's enum facilities
+  f_types_ <<
+    indent() << "typedef enum _" << this->nspace << name << 
+    " " << this->nspace << name << ";" << endl <<
+    indent() << "enum _" << this->nspace << name << " {" << endl;
+    
+  indent_up();
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  bool first = true;
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    if (first) {
+      first = false;
+    } else {
+      f_types_ << "," << endl;
+    }
+    f_types_ <<
+      indent() << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name();
+    if ((*c_iter)->has_value()) {
+      f_types_ <<
+        " = " << (*c_iter)->get_value();
+    }
+  }
+
+  indent_down();
+  f_types_ <<
+    endl <<
+    "};" << endl <<
+    endl;
+}
+  
+void t_c_generator::generate_struct(t_struct* tstruct)
+{
+  f_types_ << "/* struct */" << endl;
+  generate_object(tstruct);
+}
+
+void t_c_generator::generate_xception(t_struct* tstruct)
+{
+  string name = tstruct->get_name();
+  string name_u = initial_caps_to_underscores (name);
+  string name_uc = to_upper_case (name_u);
+
+  f_types_ << "/* exception */" << endl <<
+      "typedef enum" << endl <<
+      "{" << endl <<
+      "    " << this->nspace_uc << name_uc << "_ERROR_CODE," << endl <<
+      "} " << this->nspace << name << "Error;" << endl <<
+      endl <<
+      "GQuark " << this->nspace_u << name_u << "_error_quark (void);" << endl <<
+      "#define " << this->nspace_uc << name_uc << "_ERROR (" << this->nspace_u << name_u << "_error_quark ())" << endl <<
+      endl <<
+      "gint32 " << this->nspace_u << name_u << "_ex_read (GError ** ex, ThriftProtocol * protocol, GError ** error);" << endl <<
+      endl;
+
+  /* TODO: this is a HACK */
+  f_types_impl_ << 
+    "gint32 " << this->nspace_u << name_u << "_ex_read (GError ** ex, ThriftProtocol * protocol, GError ** error)" << endl <<
+    "{" << endl <<
+    "    gint32 ret;" << endl <<
+    "    gint32 xfer = 0;" << endl <<
+    "    gchar * name;" << endl <<
+    "    ThriftType ftype;" << endl <<
+    "    gint16 fid;" << endl <<
+    endl <<
+    "    if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)" << endl <<
+    "        return -1;" << endl <<
+    "    xfer += ret;" << endl <<
+    "    if (name) g_free (name);" << endl <<
+    endl <<
+    "    while (1)" << endl <<
+    "    {" << endl <<
+    "        if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype, &fid, error)) < 0)" << endl <<
+    "            return -1;" << endl <<
+    "        xfer += ret;" << endl <<
+    "        if (name) g_free (name);" << endl <<
+    "        if (ftype == T_STOP) {" << endl <<
+    "            break;" << endl <<
+    "        }" << endl <<
+    "        switch (fid)" << endl <<
+    "        {" << endl;
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    t_field * field = (*f_iter);
+    if (field->get_name() == "what")
+    {
+      f_types_impl_ << 
+        "            case " << field->get_key() << ":" << endl <<
+        "                if (ftype == T_STRING) {" << endl <<
+        "                    gchar * what;" << endl <<
+        "                    if ((ret = thrift_protocol_read_string (protocol, &what, error)) < 0)" << endl <<
+        "                        return -1;" << endl <<
+        "                    xfer += ret;" << endl <<
+        "                    g_set_error (ex, 0, 0, \"%s\", what);" << endl <<
+        "                    if (what) g_free (what);" << endl <<
+        "                }" << endl <<
+        "                else" << endl <<
+        "                {" << endl <<
+        "                    if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl <<
+        "                        return -1;" << endl <<
+        "                    xfer += ret;" << endl <<
+        "                }" << endl <<
+        "                break;" << endl;
+    }
+    else
+    {
+      f_types_impl_ <<
+        "            case " << field->get_key() << ":" << endl <<
+        "                if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl <<
+        "                    return -1;" << endl <<
+        "                xfer += ret;" << endl <<
+        "                break;" << endl;
+    }
+  }
+
+  f_types_impl_ <<
+    "            default:" << endl <<
+    "                if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl <<
+    "                    return -1;" << endl <<
+    "                xfer += ret;" << endl <<
+    "                break;" << endl <<
+    "        }" << endl <<
+    "        if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)" << endl <<
+    "            return -1;" << endl <<
+    "        xfer += ret;" << endl <<
+    "    }" << endl <<
+    endl <<
+    "    if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)" << endl <<
+    "        return -1;" << endl <<
+    "    xfer += ret;" << endl <<
+    endl <<
+    "    return xfer;" << endl <<
+    "}" << endl <<
+    endl;
+}
+
+void t_c_generator::generate_object(t_struct* tstruct)
+{
+  string name = tstruct->get_name();
+
+  char buf[256];
+  const char * tmp;
+
+  tmp = name.c_str();
+  int pos = 0;
+  buf[pos] = tolower(tmp[pos]);
+  pos++;
+  for (unsigned int i = pos; i < name.length(); i++)
+  {
+    buf[pos] = tolower(tmp[i]);
+    if (buf[pos] != tmp[i])
+    {
+      // we just lowercase'd it
+      buf[pos+1] = buf[pos];
+      buf[pos] = '_';
+      pos++;
+    }
+    pos++;
+  }
+  buf[pos] = '\0';
+  string name_u = buf;
+  name_u += "_";
+
+  for (unsigned int i = 0; i < strlen(buf); i++)
+    buf[i] = toupper(buf[i]);
+  string name_uc = buf;
+
+  f_types_ << 
+    "typedef struct _" << this->nspace << name << " " << this->nspace << name << ";" << endl <<
+    "struct _" << this->nspace << name << endl <<
+    "{ " << endl <<
+    "    ThriftStruct parent; " << endl << 
+    endl << 
+    "    /* private */" << endl;
+
+  vector<t_field*>::const_iterator m_iter;
+  const vector<t_field*>& members = tstruct->get_members();
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    f_types_ << "    " << type_name(t) << " " << (*m_iter)->get_name() << ";" << endl;
+  }
+
+  f_types_ << 
+    "}; " << endl <<
+    "typedef struct _" << this->nspace << name << "Class " << this->nspace << name << "Class;" << endl <<
+    "struct _" << this->nspace << name << "Class" << endl <<
+    "{ " << endl <<
+    "    ThriftStructClass parent; " << endl <<
+    "}; " << endl <<
+    "GType " << this->nspace_u << name_u << "get_type (void);" << endl <<
+    "#define " << this->nspace_uc << "TYPE_" << name_uc << " (" << this->nspace_u << name_u << "get_type ())" << endl <<
+    "#define " << this->nspace_uc << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << name_uc << ", " << this->nspace << name << "))" << endl <<
+    "#define " << this->nspace_uc << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_" << name_uc << ", " << this->nspace << name << "Class))" << endl <<
+    "#define " << this->nspace_uc << "IS_" << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_" << name_uc << "))" << endl << 
+    "#define " << this->nspace_uc << "IS_" << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << name_uc << "))" << endl <<
+    "#define " << this->nspace_uc << name_uc << "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_" << name_uc << ", " << this->nspace << name << "Class))" << endl << 
+    endl;
+
+  string this_get = this->nspace + name + " * this_object = " +
+    this->nspace_uc + name_uc + "(object);";
+
+  generate_struct_writer (f_types_impl_, tstruct, "this_object->", this_get);
+
+  generate_struct_reader (f_types_impl_, tstruct, "this_object->", this_get);
+
+  f_types_impl_ <<
+    "void " << this->nspace_u << name_u << "instance_init (" << this->nspace << name << " * object)" << endl <<
+    "{" << endl;
+
+  indent_up();
+    
+  indent (f_types_impl_) << "THRIFT_UNUSED_VAR (object);" << endl;
+
+  /* TODO: init's for pointers (NULL) and containers as appro. */
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_type* t = get_true_type((*m_iter)->get_type());
+    if (t->is_base_type()) {
+      // only have init's for base types
+      string dval = " = ";
+      if (t->is_enum()) {
+        dval += "(" + type_name(t) + ")";
+      }
+      t_const_value* cv = (*m_iter)->get_value();
+      if (cv != NULL) {
+        dval += constant_value(t, cv);
+      } else {
+        dval += t->is_string() ? "NULL" : "0";
+      }
+      indent(f_types_impl_) << "object->" << (*m_iter)->get_name() << 
+        dval << ";" << endl;
+    } else if (t->is_struct()) {
+      string name = (*m_iter)->get_name();
+      string type_name_uc = to_upper_case 
+        (initial_caps_to_underscores((*m_iter)->get_type()->get_name()));
+      indent (f_types_impl_) << "object->" << name << " = g_object_new (" << this->nspace_uc << "TYPE_" << type_name_uc << ", NULL);" << endl;
+    } else if (t->is_xception()) {
+      string name = (*m_iter)->get_name();
+      indent (f_types_impl_) << "object->" << name << " = NULL;" << endl;
+    } else if (t->is_container()) {
+      string name = (*m_iter)->get_name();
+      indent (f_types_impl_) << "/* object->" << name << " = not-implemented; */" << endl;
+    }
+  }
+
+  /* TODO: finalize method that free's memory and otherwise cleans up */
+  indent_down();
+  f_types_impl_ << "}" << endl <<
+    endl <<
+    "void " << this->nspace_u << name_u << "class_init (ThriftStructClass * thrift_struct_class)" << endl <<
+    "{" << endl <<
+    /* TODO: make members properties... */
+    "  thrift_struct_class->read = " << this->nspace_u << name_u << "read;" << endl <<
+    "  thrift_struct_class->write = " << this->nspace_u << name_u << "write;" << endl <<
+    "}" << endl <<
+    endl <<
+    "GType " << this->nspace_u << name_u << "get_type (void)" << endl <<
+    "{" << endl <<
+    "  static GType type = 0;" << endl << 
+    endl <<
+    "  if (type == 0) " << endl <<
+    "  {" << endl <<
+    "    static const GTypeInfo type_info = " << endl <<
+    "    {" << endl <<
+    "      sizeof (" << this->nspace << name << "Class)," << endl <<
+    "      NULL, /* base_init */" << endl <<
+    "      NULL, /* base_finalize */" << endl <<
+    "      (GClassInitFunc)" << this->nspace_u << name_u << "class_init," << endl <<
+    "      NULL, /* class_finalize */" << endl <<
+    "      NULL, /* class_data */" << endl <<
+    "      sizeof (" << this->nspace << name << ")," << endl <<
+    "      0, /* n_preallocs */" << endl <<
+    "      (GInstanceInitFunc)" << this->nspace_u << name_u << "instance_init," << endl <<
+    "      NULL, /* value_table */" << endl <<
+    "    };" << endl << 
+    endl <<
+    "    type = g_type_register_static (THRIFT_TYPE_STRUCT, " << endl <<
+    "                                   \"" << this->nspace << name << "Type\"," << endl << 
+    "                                   &type_info, 0);" << endl <<
+    "  }" << endl << 
+    endl << 
+    "  return type;" << endl << 
+    "}" << endl << 
+    endl;
+}
+
+/**
+ * Generates the write function.
+ *
+ * @param out Stream to write to
+ * @param tstruct The struct
+ */
+void t_c_generator::generate_struct_writer(ofstream& out, t_struct* tstruct,
+                                           string this_name, string this_get,
+                                           bool is_function) {
+  string name = tstruct->get_name();
+  string name_u = initial_caps_to_underscores (name);
+  string name_uc = to_upper_case (name_u);
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  int error_ret = 0;
+
+  if (is_function) {
+    error_ret = -1;
+    indent(out) <<
+      "gint32 " << this->nspace_u << name_u <<
+      "_write (ThriftStruct * object, ThriftProtocol * protocol, GError ** error)" << endl;
+  }
+
+  indent(out) << "{" << endl;
+  indent_up();
+
+  out << 
+    indent() << "gint32 ret;" << endl <<
+    indent() << "gint32 xfer = 0;" << endl;
+
+  indent(out) << this_get << endl;
+
+  out << 
+    indent() << "if ((ret = thrift_protocol_write_struct_begin (protocol, \"" << name << "\", error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl <<
+    indent() << "xfer += ret;" << endl;
+
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    // TODO: optional fields
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
+      indent(out) << "if (this->__isset." << (*f_iter)->get_name() << ") {" << endl;
+      indent_up();
+    }
+    // Write field header
+    out <<
+      indent() << "if ((ret = thrift_protocol_write_field_begin (protocol, " <<
+      "\"" << (*f_iter)->get_name() << "\", " <<
+      type_to_enum((*f_iter)->get_type()) << ", " <<
+      (*f_iter)->get_key() << ", error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl;
+    // Write field contents
+    generate_serialize_field(out, *f_iter, this_name, "", error_ret);
+    // Write field closer
+    out <<
+      indent() << "if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl;
+    if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
+      indent_down();
+      indent(out) << '}' << endl;
+    }
+  }
+
+  // Write the struct map
+  out <<
+    indent() << "if ((ret = thrift_protocol_write_field_stop(protocol, error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl <<
+    indent() << "xfer += ret;" << endl <<
+    indent() << "if ((ret = thrift_protocol_write_struct_end(protocol, error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl <<
+    indent() << "xfer += ret;" << endl;
+
+  if (is_function)
+    indent(out) << "return xfer;" << endl;
+
+  indent_down();
+  indent(out) <<
+    "}" << endl <<
+    endl;
+}
+
+/**
+ * Makes a helper function to gen a struct reader.
+ *
+ * @param out Stream to write to
+ * @param tstruct The struct
+ */
+void t_c_generator::generate_struct_reader(ofstream& out, t_struct* tstruct,
+                                           string this_name, string this_get,
+                                           bool is_function) {
+  string name = tstruct->get_name();
+  string name_u = initial_caps_to_underscores (name);
+  string name_uc = to_upper_case (name_u);
+
+  int error_ret = 0;
+
+  if (is_function) {
+    error_ret = -1;
+    indent(out) <<
+      "gint32 " << this->nspace_u << name_u << 
+      "_read (ThriftStruct * object, ThriftProtocol * protocol, GError ** error)" << endl;
+  }
+
+  indent(out) << "{" << endl;
+  indent_up();
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+
+  // Declare stack tmp variables
+  out <<
+    indent() << "gint32 ret;" << endl <<
+    indent() << "gint32 xfer = 0;" << endl <<
+    indent() << "gchar * name;" << endl <<
+    indent() << "ThriftType ftype;" << endl <<
+    indent() << "gint16 fid;" << endl <<
+    endl <<
+    indent() << "if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl <<
+    indent() << "xfer += ret;" << endl <<
+    indent() << "if (name) g_free (name);" << endl << 
+    indent() << this_get << endl;
+
+  // Required variables aren't in __isset, so we need tmp vars to check them.
+  // TODO: optional vars
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
+      indent(out) << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
+  }
+  out << endl;
+
+
+  // Loop over reading in fields
+  indent(out) <<
+    "while (1)" << endl;
+  scope_up(out);
+
+  // Read beginning field marker
+  out <<
+    indent() << "if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype, &fid, error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl <<
+    indent() << "xfer += ret;" << endl <<
+    indent() << "if (name) g_free (name);" << endl;
+
+  // Check for field STOP marker
+  out <<
+    indent() << "if (ftype == T_STOP) {" << endl <<
+    indent() << "  break;" << endl <<
+    indent() << "}" << endl;
+
+  // Switch statement on the field we are reading
+  indent(out) <<
+    "switch (fid)" << endl;
+
+  scope_up(out);
+
+  // Generate deserialization code for known cases
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+
+    indent(out) <<
+      "case " << (*f_iter)->get_key() << ":" << endl;
+    indent_up();
+    indent(out) <<
+      "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
+    indent_up();
+
+    generate_deserialize_field(out, *f_iter, this_name, "", error_ret);
+
+    indent_down();
+    out <<
+      indent() << "} else {" << endl <<
+      indent() << "  if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl <<
+      indent() << "    return " << error_ret << ";" << endl <<
+      indent() << "  xfer += ret;" << endl <<
+      indent() << "}" << endl <<
+      indent() << "break;" << endl;
+    indent_down();
+  }
+
+  // In the default case we skip the field
+  out <<
+    indent() << "default:" << endl <<
+    indent() << "  if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl <<
+    indent() << "    return " << error_ret << ";" << endl <<
+    indent() << "  xfer += ret;" << endl <<
+    indent() << "  break;" << endl;
+
+  scope_down(out);
+
+  // Read field end marker
+  out <<
+    indent () << "if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl <<
+    indent() << "xfer += ret;" << endl;
+
+  scope_down(out);
+
+  out <<
+    endl <<
+    indent() << "if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl <<
+    indent() << "xfer += ret;" << endl;
+
+  // Throw if any required fields are missing.
+  // We do this after reading the struct end so that
+  // there might possibly be a chance of continuing.
+  // TODO: fix
+  out << endl;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if ((*f_iter)->get_req() == t_field::T_REQUIRED)
+      out <<
+        indent() << "if (!isset_" << (*f_iter)->get_name() << ')' << endl <<
+        indent() << "  throw TProtocolException(TProtocolException::INVALID_DATA);" << endl;
+  }
+
+  if (is_function)
+    indent(out) << "return xfer;" << endl;
+
+  indent_down();
+  indent(out) <<
+    "}" << endl << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_c_generator::generate_serialize_field(ofstream& out, t_field* tfield,
+                                             string prefix, string suffix, 
+                                             int error_ret) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  string name = prefix + tfield->get_name() + suffix;
+
+  // Do nothing for void types
+  if (type->is_void()) {
+    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
+  }
+
+  if (type->is_struct() || type->is_xception()) {
+    generate_serialize_struct(out, (t_struct*)type, name, error_ret);
+  } else if (type->is_container()) {
+    generate_serialize_container(out, type, name, error_ret);
+  } else if (type->is_base_type() || type->is_enum()) {
+
+    indent(out) <<
+      "if ((ret = thrift_protocol_write_";
+
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw
+          "compiler error: cannot serialize void field in a struct: " + name;
+        break;
+      case t_base_type::TYPE_STRING:
+        if (((t_base_type*)type)->is_binary()) {
+          out << "binary(protocol, " << name;
+        }
+        else {
+          out << "string(protocol, " << name;
+        }
+        break;
+      case t_base_type::TYPE_BOOL:
+        out << "bool(protocol, " << name;
+        break;
+      case t_base_type::TYPE_BYTE:
+        out << "byte(protocol, " << name;
+        break;
+      case t_base_type::TYPE_I16:
+        out << "i16(protocol, " << name;
+        break;
+      case t_base_type::TYPE_I32:
+        out << "i32(protocol, " << name;
+        break;
+      case t_base_type::TYPE_I64:
+        out << "i64(protocol, " << name;
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        out << "double(protocol, " << name;
+        break;
+      default:
+        throw "compiler error: no C writer for base type " + t_base_type::t_base_name(tbase) + name;
+      }
+    } else if (type->is_enum()) {
+      out << "i32(protocol, (gint32)" << name;
+    }
+    out << ", error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl;
+
+  } else {
+    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+           name.c_str(), type_name(type).c_str());
+  }
+}
+
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix  String prefix to attach to all fields
+ */
+void t_c_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct,
+                                              string prefix, int error_ret) {
+  out <<
+    indent() << "if ((ret = thrift_struct_write (THRIFT_STRUCT (" << prefix << "), protocol, error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl << 
+    indent() << "xfer += ret;" << endl;
+}
+
+void t_c_generator::generate_serialize_container(ofstream& out, t_type* ttype,
+                                                 string prefix, int error_ret) {
+  scope_up(out);
+
+  if (ttype->is_map()) {
+    string length = "g_hash_table_size ((GHashTable *)" + prefix + ")";
+    t_type * tkey = ((t_map*)ttype)->get_key_type();
+    t_type * tval = ((t_map*)ttype)->get_val_type();
+    string tkey_name = type_name (tkey);
+    string tval_name = type_name (tval);
+    string tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*";
+    string tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*";
+    out <<
+      indent() << "if ((ret = thrift_protocol_write_map_begin(protocol, " << type_to_enum(tkey) << ", " << type_to_enum(tval) << ", (gint32)" << length << ", error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl <<
+      indent() << "GHashTableIter iter;" << endl <<
+      indent() << tkey_name << tkey_ptr << " key;" << endl <<
+      indent() << tval_name << tval_ptr << " value;" << endl <<
+      indent() << "g_hash_table_iter_init (&iter, (GHashTable *)" << prefix << ");" << endl <<
+      indent() << "while (g_hash_table_iter_next (&iter, (gpointer)&key, (gpointer)&value))" << endl;
+
+    scope_up(out);
+    generate_serialize_map_element(out, (t_map*)ttype, tkey_ptr + "key", tval_ptr + "value", error_ret);
+    scope_down(out);
+
+    out <<
+      indent() << "if ((ret = thrift_protocol_write_map_end(protocol, error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl;
+
+  } else if (ttype->is_set()) {
+    string length = "g_hash_table_size ((GHashTable *)" + prefix + ")";
+    t_type * telem = ((t_set*)ttype)->get_elem_type();
+    string telem_name = type_name (telem);
+    string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*";
+    out <<
+      indent() << "if ((ret = thrift_protocol_write_set_begin(protocol, " << type_to_enum(telem) << ", (gint32)" << length << ", error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl <<
+      indent() << "GHashTableIter iter;" << endl <<
+      indent() << telem_name << telem_ptr << " elem;" << endl <<
+      indent() << "gpointer value;" << endl <<
+      indent() << "g_hash_table_iter_init (&iter, (GHashTable *)" << prefix << ");" << endl <<
+      indent() << "while (g_hash_table_iter_next (&iter, (gpointer)&elem, &value))" << endl;
+
+    scope_up(out);
+    generate_serialize_set_element(out, (t_set*)ttype, telem_ptr + "elem", error_ret);
+    scope_down(out);
+
+    out <<
+      indent() << "if ((ret = thrift_protocol_write_set_end(protocol, error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl;
+
+  } else if (ttype->is_list()) {
+    string length = prefix + "->len";
+    out <<
+      indent() << "if ((ret = thrift_protocol_write_list_begin(protocol, " <<
+      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", (gint32)" <<
+      length << ", error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl <<
+      indent() << "guint i;" << endl <<
+      indent() << "for (i = 0; i < " << length << "; i++)" << endl;
+
+    scope_up(out);
+    generate_serialize_list_element(out, (t_list*)ttype, prefix, "i", error_ret);
+    scope_down(out);
+
+    out <<
+      indent() << "if ((ret = thrift_protocol_write_list_end(protocol, error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl;
+  }
+
+  scope_down(out);
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_c_generator::generate_serialize_map_element(ofstream& out,
+                                                   t_map* tmap,
+                                                   string key,
+                                                   string value,
+                                                   int error_ret) {
+  t_field kfield(tmap->get_key_type(), key);
+  generate_serialize_field(out, &kfield, "", "", error_ret);
+
+  t_field vfield(tmap->get_val_type(), value);
+  generate_serialize_field(out, &vfield, "", "", error_ret);
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_c_generator::generate_serialize_set_element(ofstream& out,
+                                                     t_set* tset,
+                                                     string element,
+                                                     int error_ret) {
+  t_field efield(tset->get_elem_type(), element);
+  generate_serialize_field(out, &efield, "", "", error_ret);
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_c_generator::generate_serialize_list_element(ofstream& out,
+                                                    t_list* tlist,
+                                                    string list,
+                                                    string index, 
+                                                    int error_ret) {
+  t_type * ttype = tlist->get_elem_type();
+
+  // cast is to remove the const
+  string name = "g_ptr_array_index((GPtrArray *)" + list + ", " + index + ")";
+
+  if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw
+            "compiler error: cannot determine array type";
+          break;
+        case t_base_type::TYPE_BOOL:
+          name = "g_array_index (" + list + ", gboolean, " + index + ")";
+          break;
+        case t_base_type::TYPE_BYTE:
+          name = "g_array_index (" + list + ", gint8, " + index + ")";
+          break;
+        case t_base_type::TYPE_I16:
+          name = "g_array_index (" + list + ", gint16, " + index + ")";
+          break;
+        case t_base_type::TYPE_I32:
+          name = "g_array_index (" + list + ", gint32, " + index + ")";
+          break;
+        case t_base_type::TYPE_I64:
+          name = "g_array_index (" + list + ", gint64, " + index + ")";
+          break;
+        case t_base_type::TYPE_DOUBLE:
+          name = "g_array_index (" + list + ", gdouble, " + index + ")";
+          break;
+        case t_base_type::TYPE_STRING:
+          // it's already set correctly
+          break;
+        default:
+          throw "compiler error: no array info for type";
+    }
+  }
+
+  t_field efield(ttype, name);
+  generate_serialize_field(out, &efield, "", "", error_ret);
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_c_generator::generate_deserialize_field(ofstream& out, t_field* tfield,
+                                               string prefix, string suffix,
+                                               int error_ret) {
+  t_type* type = get_true_type(tfield->get_type());
+
+  if (type->is_void()) {
+    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
+      prefix + tfield->get_name();
+  }
+
+  string name = prefix + tfield->get_name() + suffix;
+
+  if (type->is_struct()) {
+    generate_deserialize_struct(out, (t_struct*)type, name, error_ret);
+  } else if (type->is_xception()) {
+    generate_deserialize_xception(out, (t_struct*)type, name, error_ret);
+  } else if (type->is_container()) {
+    generate_deserialize_container(out, type, name, error_ret);
+  } else if (type->is_base_type()) {
+    indent(out) << "if ((ret = thrift_protocol_read_";
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "compiler error: cannot serialize void field in a struct: " + name;
+      break;
+    case t_base_type::TYPE_STRING:
+      if (((t_base_type*)type)->is_binary()) {
+        /* TODO: what about len */
+        out << "binary (protocol, &" << name;
+      }
+      else {
+        out << "string (protocol, &" << name;
+      }
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << "bool (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_BYTE:
+      out << "byte (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_I16:
+      out << "i16 (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_I32:
+      out << "i32 (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_I64:
+      out << "i64 (protocol, &" << name;
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      out << "double (protocol, &" << name;
+      break;
+    default:
+      throw "compiler error: no C reader for base type " + t_base_type::t_base_name(tbase) + name;
+    }
+    out << ", error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl;
+  } else if (type->is_enum()) {
+    string t = tmp("ecast");
+    out <<
+      indent() << "gint32 " << t << ";" << endl <<
+      indent() << "if ((ret = thrift_protocol_read_i32 (protocol, &" << t << ", error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl <<
+      indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl;
+  } else {
+    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+           tfield->get_name().c_str(), type_name(type).c_str());
+  }
+}
+
+/**
+ * Generates an unserializer for a variable. This makes two key assumptions,
+ * first that there is a const char* variable named data that points to the
+ * buffer for deserialization, and that there is a variable protocol which
+ * is a reference to a TProtocol serialization object.
+ */
+void t_c_generator::generate_deserialize_struct(ofstream& out, 
+                                                t_struct* tstruct,
+                                                string prefix, int error_ret) {
+  string name_uc = to_upper_case 
+    (initial_caps_to_underscores (tstruct->get_name()));
+  out <<
+    indent() << prefix << " = g_object_new (" << this->nspace_uc << "TYPE_" << name_uc << ", NULL);" << endl <<
+    indent() << "if ((ret = thrift_struct_read (THRIFT_STRUCT (" << prefix << "), protocol, error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl << 
+    indent() << "xfer += ret;" << endl;
+}
+
+void t_c_generator::generate_deserialize_xception(ofstream& out, 
+                                                  t_struct* tstruct,
+                                                  string prefix, 
+                                                  int error_ret) {
+
+  string name_u = initial_caps_to_underscores (tstruct->get_name());
+
+  out <<
+    indent() << "if ((ret = " << this->nspace_u << name_u << "_ex_read (&" << prefix << ", protocol, error)) < 0)" << endl <<
+    indent() << "  return " << error_ret << ";" << endl << 
+    indent() << "xfer += ret;" << endl;
+}
+
+string t_c_generator::generate_new_hash_from_type(t_type * ttype)
+{
+  if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw
+            "compiler error: cannot determine hash type";
+          break;
+        case t_base_type::TYPE_STRING:
+          return "g_hash_table_new (g_str_hash, g_str_equal);";
+        case t_base_type::TYPE_BOOL:
+          return "g_hash_table_new (thrift_gboolean_hash, thrift_gboolean_equal);";
+        case t_base_type::TYPE_BYTE:
+          return "g_hash_table_new (thrift_gint8_hash, thrift_gint8_equal);";
+        case t_base_type::TYPE_I16:
+          return "g_hash_table_new (thrift_gint16_hash, thrift_gint16_equal);";
+        case t_base_type::TYPE_I32:
+          return "g_hash_table_new (thrift_gint32_hash, thrift_gint32_equal);";
+        case t_base_type::TYPE_I64:
+          return "g_hash_table_new (thrift_gint64_hash, thrift_gint64_equal);";
+        case t_base_type::TYPE_DOUBLE:
+          return "g_hash_table_new (thrift_gdouble_hash, thrift_gdouble_equal);";
+        default:
+          throw "compiler error: no hash table info for type";
+    }
+  }
+  // TODO: for now everything else is just direct
+  return "g_hash_table_new (NULL, NULL);";
+}
+
+string t_c_generator::generate_new_array_from_type(t_type * ttype)
+{
+  if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw
+            "compiler error: cannot determine array type";
+          break;
+        case t_base_type::TYPE_STRING:
+          return "g_ptr_array_new ();";
+        case t_base_type::TYPE_BOOL:
+          return "g_array_new (0, 1, sizeof (gboolean));";
+        case t_base_type::TYPE_BYTE:
+          return "g_array_new (0, 1, sizeof (gint8));";
+        case t_base_type::TYPE_I16:
+          return "g_array_new (0, 1, sizeof (gint16));";
+        case t_base_type::TYPE_I32:
+          return "g_array_new (0, 1, sizeof (gint32));";
+        case t_base_type::TYPE_I64:
+          return "g_array_new (0, 1, sizeof (gint64));";
+        case t_base_type::TYPE_DOUBLE:
+          return "g_array_new (0, 1, sizeof (gdouble));";
+        default:
+          throw "compiler error: no array info for type";
+    }
+  }
+  // TODO: for now everything else is ptr array
+  return "g_ptr_array_new ();";
+}
+
+void t_c_generator::generate_deserialize_container(ofstream& out, t_type* ttype,
+                                                   string prefix, 
+                                                   int error_ret) {
+  /* TODO: treating everything as pointers is not going to work as a long term
+   * solution here */
+
+  scope_up(out);
+
+  // Declare variables, read header
+  if (ttype->is_map()) {
+    t_type * tkey = ((t_map*)ttype)->get_key_type();
+    out <<
+      indent() << "guint32 size;" << endl <<
+      indent() << "ThriftType key_type;" << endl <<
+      indent() << "ThriftType value_type;" << endl <<
+      indent() << "if ((ret = thrift_protocol_read_map_begin (protocol, &key_type, &value_type, &size, error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl <<
+      indent() << "guint32 i;" << endl <<
+      indent() << "*_return = " << generate_new_hash_from_type(tkey) << endl <<
+      indent() << "for (i = 0; i < size; ++i)" << endl;
+
+    scope_up(out);
+    generate_deserialize_map_element(out, (t_map*)ttype, prefix, error_ret);
+    scope_down(out);
+
+    out << 
+      indent() << "if ((ret = thrift_protocol_read_map_end (protocol, error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl;
+
+  } else if (ttype->is_set()) {
+    t_type * telem = ((t_set*)ttype)->get_elem_type();
+    out <<
+      indent() << "guint32 size;" << endl <<
+      indent() << "ThriftType element_type;" << endl <<
+      indent() << "if ((ret = thrift_protocol_read_set_begin (protocol, &element_type, &size, error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl <<
+      indent() << "guint32 i;" << endl <<
+      indent() << "*_return = " << generate_new_hash_from_type(telem) << endl <<
+      indent() << "for (i = 0; i < size; ++i)" << endl;
+
+    scope_up(out);
+    generate_deserialize_set_element(out, (t_set*)ttype, prefix, error_ret);
+    scope_down(out);
+
+    out << 
+      indent() << "if ((ret = thrift_protocol_read_set_end (protocol, error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl;
+
+  } else if (ttype->is_list()) {
+    t_type * telem = ((t_list*)ttype)->get_elem_type();
+    out <<
+      indent() << "guint32 size;" << endl <<
+      indent() << "ThriftType element_type;" << endl <<
+      indent() << "if ((ret = thrift_protocol_read_list_begin (protocol, &element_type, &size, error)) < 0)" << endl << 
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl <<
+      indent() << "guint32 i;" << endl <<
+      indent() << "*_return = " << generate_new_array_from_type (telem) << endl <<
+      indent() << "for (i = 0; i < size; ++i)" << endl;
+
+    scope_up(out);
+    generate_deserialize_list_element(out, (t_list*)ttype, prefix, "i", 
+                                      error_ret);
+    scope_down(out);
+
+    out << 
+      indent() << "if ((ret = thrift_protocol_read_list_end (protocol, error)) < 0)" << endl <<
+      indent() << "  return " << error_ret << ";" << endl <<
+      indent() << "xfer += ret;" << endl;
+
+  }
+
+  scope_down(out);
+}
+
+
+/**
+ * Generates code to deserialize a map
+ */
+void t_c_generator::generate_deserialize_map_element(ofstream& out,
+                                                       t_map* tmap,
+                                                       string prefix,
+                                                       int error_ret) {
+  t_type * tkey = tmap->get_key_type();
+  t_type * tval = tmap->get_val_type();
+  string tkey_name = type_name(tkey);
+  string tval_name = type_name(tval);
+  string tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*";
+  string tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*";
+
+  out <<
+    indent() << tkey_name << tkey_ptr << " key" << (tkey_ptr != "" ? " = g_new (" + tkey_name + ", 1)" : "") << ";" << endl <<
+    indent() << tval_name << tval_ptr << " val" << (tval_ptr != "" ? " = g_new (" + tval_name + ", 1)" : "") << ";" << endl;
+
+  t_field fkey(tkey, tkey_ptr + "key");
+  generate_deserialize_field(out, &fkey, "", "", error_ret);
+  t_field fval(tval, tval_ptr + "val");
+  generate_deserialize_field(out, &fval, "", "", error_ret);
+
+  indent(out) << 
+    "g_hash_table_insert ((GHashTable *)" << prefix << ", (gpointer)key, (gpointer)val);" << endl;
+}
+
+void t_c_generator::generate_deserialize_set_element(ofstream& out,
+                                                       t_set* tset,
+                                                       string prefix,
+                                                       int error_ret) {
+  t_type * telem = tset->get_elem_type();
+  string telem_name = type_name(telem);
+  string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*";
+
+  out <<
+    indent() << telem_name << telem_ptr << " elem" << (telem_ptr != "" ? " = g_new (" + telem_name + ", 1)" : "") << ";" << endl;
+
+  t_field felem(telem, telem_ptr + "elem");
+  generate_deserialize_field(out, &felem, "", "", error_ret);
+
+  indent(out) <<
+    "g_hash_table_insert((GHashTable *)" << prefix << ", (gpointer)elem, (gpointer)1);" << endl;
+}
+
+void t_c_generator::generate_deserialize_list_element(ofstream& out,
+                                                      t_list* tlist,
+                                                      string prefix,
+                                                      string index,
+                                                      int error_ret) {
+  string elem = tmp("_elem");
+  t_field felem(tlist->get_elem_type(), elem);
+  indent(out) << declare_field(&felem, true) << endl;
+  generate_deserialize_field(out, &felem, "", "", error_ret);
+
+  indent(out);
+
+  t_type * ttype = tlist->get_elem_type();
+  if (ttype->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+    switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw
+            "compiler error: cannot determine array type";
+          break;
+        case t_base_type::TYPE_STRING:
+          out << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl;
+          return;
+        case t_base_type::TYPE_BOOL:
+        case t_base_type::TYPE_BYTE:
+        case t_base_type::TYPE_I16:
+        case t_base_type::TYPE_I32:
+        case t_base_type::TYPE_I64:
+        case t_base_type::TYPE_DOUBLE:
+          out << "g_array_append_val (" << prefix << ", " << elem << ");" << endl;
+          return;
+        default:
+          throw "compiler error: no array info for type";
+    }
+  }
+  // TODO: for now everything else is ptr array
+  out << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl;
+}
+
+
+/**
+ * Generates a class that holds all the constants.
+ */
+void t_c_generator::generate_consts(vector<t_const*> consts) {
+
+  f_types_ << "/* constants */" << endl;
+
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type * type = (*c_iter)->get_type();
+    t_const_value * value = (*c_iter)->get_value();
+    f_types_ << 
+      indent() << "#define " << this->nspace_uc << name << " " << constant_value(type, value) << endl;
+  }
+
+  f_types_ << endl;
+}
+
+/**
+ * Generates a thrift service. In C, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_c_generator::generate_service(t_service* tservice) {
+  string svcname = initial_caps_to_underscores (tservice->get_name());
+
+  // Make output files
+  string f_header_name = get_out_dir()+svcname+".h";
+  f_header_.open(f_header_name.c_str());
+
+  string program_name_u = initial_caps_to_underscores (program_name_);
+
+  // Print header file includes
+  f_header_ <<
+    autogen_comment();
+  f_header_ <<
+    "#ifndef " << svcname << "_H" << endl <<
+    "#define " << svcname << "_H" << endl <<
+    endl <<
+    "#include <thrift_client.h>" << endl <<
+    "#include \"" << program_name_u << "_types.h\"" << endl;
+
+  t_service* extends_service = tservice->get_extends();
+  if (extends_service != NULL) {
+    f_header_ <<
+      "#include \"" << extends_service->get_name() << ".h\"" << endl;
+  }
+
+  f_header_ <<
+    endl;
+
+  // Service implementation file includes
+  string f_service_name = get_out_dir()+svcname+".c";
+  f_service_.open(f_service_name.c_str());
+  f_service_ <<
+    autogen_comment();
+  f_service_ <<
+    "#include \"" << svcname << ".h\"" << endl << 
+    "#include <thrift_client.h>" << endl <<
+    "#include <thrift_hash.h>" << endl <<
+    "#include <string.h>" << endl <<
+    endl;
+
+  // Generate all the components
+#if 0
+  generate_service_interface(tservice);
+  generate_service_null(tservice);
+  generate_service_helpers(tservice);
+#endif
+  generate_service_client(tservice);
+#if 0
+  generate_service_processor(tservice);
+  generate_service_multiface(tservice);
+  generate_service_skeleton(tservice);
+#endif
+
+  f_header_ <<
+    "#endif /* " << svcname << "_H */" << endl;
+
+  // Close the files
+  f_service_.close();
+  f_header_.close();
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_c_generator::generate_service_client(t_service* tservice) {
+  string extends = "";
+  string extends_client = "";
+  if (tservice->get_extends() != NULL) {
+    extends = type_name(tservice->get_extends());
+    extends_client = ", public " + extends + "Client";
+  }
+
+  // Generate the header portion
+  f_header_ <<
+    "typedef struct _Thrift" << service_name_ << "Client Thrift" << service_name_ << "Client;" << endl <<
+    "struct _Thrift" << service_name_ << "Client" << endl <<
+    "{" << endl <<
+    "  ThriftClient parent;" << endl <<
+    "};" << endl <<
+    "typedef struct _Thrift" << service_name_ << "ClientClass Thrift" << service_name_ << "ClientClass;" << endl <<
+    "struct _Thrift" << service_name_ << "ClientClass" << endl;
+  scope_up(f_header_);
+  indent(f_header_) << "ThriftClientClass parent;" << endl << endl;
+  indent_down();
+  f_header_ << "};" << endl <<
+      endl;
+
+  string service_name_u = initial_caps_to_underscores(service_name_);
+  string service_name_uc = to_upper_case(service_name_u);
+
+  f_header_ <<
+    "GType thrift_" << service_name_u << "_client_get_type (void);" << endl <<
+    "#define THRIFT_" << service_name_uc << "_TYPE_CLIENT (thrift_" << service_name_u << "_client_get_type ())" << endl <<
+    "#define THRIFT_" << service_name_uc << "_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THRIFT_" << service_name_uc << "_TYPE_CLIENT, Thrift" << service_name_ << "ClientClass))" << endl <<
+    "#define THRIFT_" << service_name_uc << "_CLIENT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), THRIFT_" << service_name_uc << "_TYPE_CLIENT, Thrift" << service_name_ << "ClientClass))" << endl <<
+    "#define THRIFT_" << service_name_uc << "_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THRIFT_" << service_name_uc << "_TYPE_CLIENT))" << endl << 
+    "#define THRIFT_" << service_name_uc << "_IS_CLIENT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), THRIFT_" << service_name_uc << "_TYPE_CLIENT))" << endl <<
+    "#define THRIFT_" << service_name_uc << "_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THRIFT_" << service_name_uc << "_TYPE_CLIENT, Thrift" << service_name_ << "ClientClass))" << endl << 
+    endl;
+
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::const_iterator f_iter;
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string funname = initial_caps_to_underscores((*f_iter)->get_name());
+    t_function send_function(g_type_void,
+                             string("send_") + funname,
+                             (*f_iter)->get_arglist());
+    indent(f_header_) << function_signature(*f_iter) << ";" << endl;
+    indent(f_header_) << function_signature(&send_function) << ";" << endl;
+    if (!(*f_iter)->is_async()) {
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + funname,
+                               &noargs);
+      indent(f_header_) << function_signature(&recv_function) << ";" << endl;
+    }
+  }
+
+  f_header_ << endl;
+
+  // Generate client method implementations
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    string name = (*f_iter)->get_name();
+    string funname = initial_caps_to_underscores(name);
+
+    // Open function
+    indent(f_service_) <<
+      function_signature(*f_iter) << endl;
+    scope_up(f_service_);
+    f_service_ <<
+      indent() << "if (!" << this->nspace_u << "send_" << funname << " (client";
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+
+    // Declare the function arguments
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      f_service_ << ", " << (*fld_iter)->get_name();
+    }
+    f_service_ << ", error))" << endl <<
+      indent() << "  return 0;" << endl;
+
+    if (!(*f_iter)->is_async()) {
+      string ret = (*f_iter)->get_returntype()->is_void() ? "" : ", _return";
+      f_service_ << 
+        indent() << "if (!" << this->nspace_u << "recv_" << funname << " (client" << ret << ", error))" << endl <<
+        indent() << "  return 0;" << endl;
+    }
+    indent(f_service_) << "return 1;" << endl;
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    // Function for sending
+    t_function send_function(g_type_void,
+                             string("send_") + funname,
+                             (*f_iter)->get_arglist());
+
+    // Open the send function
+    indent(f_service_) <<
+      function_signature(&send_function) << endl;
+    scope_up(f_service_);
+
+    // Serialize the request
+    f_service_ <<
+      indent() << "gint32 cseqid = 0;" << endl <<
+      indent() << "ThriftProtocol * protocol = THRIFT_CLIENT (client)->protocol;" << endl <<
+      endl <<
+      indent() << "if (thrift_protocol_write_message_begin (protocol, \"" << name << "\", T_CALL, cseqid, error) < 0)" << endl <<
+      indent() << "  return 0;" << endl <<
+      endl;
+
+    generate_struct_writer (f_service_, arg_struct, "", "", false);
+
+    f_service_ <<
+      indent() << "if (thrift_protocol_write_message_end (protocol, error) < 0)" << endl <<
+      indent() << "  return 0;" << endl <<
+      endl <<
+      indent () << "if (!thrift_transport_flush (protocol->transport, error))" << endl <<
+      indent() << "  return 0;" << endl <<
+      indent () << "if (!thrift_transport_write_end (protocol->transport, error))" << endl <<
+      indent() << "  return 0;" << endl <<
+      endl <<
+      indent() << "return 1;" << endl;
+
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    // Generate recv function only if not an async function
+    if (!(*f_iter)->is_async()) {
+      t_struct noargs(program_);
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + funname, &noargs);
+      // Open function
+      indent(f_service_) <<
+        function_signature(&recv_function) << endl;
+      scope_up(f_service_);
+
+      f_service_ <<
+        endl <<
+        indent() << "gint32 rseqid;" << endl <<
+        indent() << "gchar * fname;" << endl <<
+        indent() << "ThriftMessageType mtype;" << endl <<
+        indent() << "ThriftProtocol * protocol = THRIFT_CLIENT (client)->protocol;" << endl <<
+        endl <<
+        indent() << "if (thrift_protocol_read_message_begin (protocol, &fname, &mtype, &rseqid, error) < 0)" << endl <<
+        indent() << "  return 0;" << endl <<
+        endl <<
+        indent() << "if (mtype == T_EXCEPTION) {" << endl <<
+        indent() << "  /* TODO: ThriftApplicationException x;" << endl <<
+        indent() << "  x.read(iprot_); */" << endl <<
+        indent() << "  thrift_protocol_skip (protocol, T_STRUCT, error);" << endl <<
+        indent() << "  thrift_protocol_read_message_end (protocol, error);" << endl <<
+        indent() << "  thrift_transport_read_end (protocol->transport, error);" << endl <<
+        indent() << "  /* TODO: error handling throw x; */" << endl <<
+        indent() << "  return 0;" << endl <<
+        indent() << "} else if (mtype != T_REPLY) {" << endl <<
+        indent() << "  thrift_protocol_skip (protocol, T_STRUCT, error);" << endl <<
+        indent() << "  thrift_protocol_read_message_end (protocol, error);" << endl <<
+        indent() << "  thrift_transport_read_end (protocol->transport, error);" << endl <<
+        indent() << "  /* TODO: error handling throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::INVALID_MESSAGE_TYPE); */" << endl <<
+        indent() << "  return 0;" << endl <<
+        indent() << "} else if (strncmp (fname, \"" << name << "\", " << name.length () << ") != 0) {" << endl <<
+        indent() << "  thrift_protocol_skip (protocol, T_STRUCT, error);" << endl <<
+        indent() << "  thrift_protocol_read_message_end (protocol, error);" << endl <<
+        indent() << "  thrift_transport_read_end (protocol->transport, error);" << endl <<
+        indent() << "  /* TODO: error handling throw facebook::thrift::TApplicationException(facebook::thrift::TApplicationException::WRONG_METHOD_NAME); */" << endl <<
+        indent() << "  return 0;" << endl <<
+        indent() << "}" << endl <<
+        indent() << "if (fname) g_free (fname);" << endl << 
+        endl;
+
+      t_struct* xs = (*f_iter)->get_xceptions();
+      const std::vector<t_field*>& xceptions = xs->get_members();
+      vector<t_field*>::const_iterator x_iter;
+
+      {
+        t_struct result(program_, tservice->get_name() + "_" + 
+                        (*f_iter)->get_name() + "_result");
+        t_field success((*f_iter)->get_returntype(), "*_return", 0);
+        if (!(*f_iter)->get_returntype()->is_void()) {
+          result.append(&success);
+        }
+
+        for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
+            result.append (*x_iter);
+            indent(f_service_) << "GError * " << (*x_iter)->get_name() << " = NULL;" << endl;
+        }
+
+        generate_struct_reader (f_service_, &result, "", "", false);
+      }
+
+      // TODO: error handling, throw on exceptions etc.
+      f_service_ <<
+        indent() << "if (thrift_protocol_read_message_end (protocol, error) < 0)" << endl <<
+        indent() << "  return 0;" << endl <<
+        endl <<
+        indent() << "if (!thrift_transport_read_end (protocol->transport, error))" << endl <<
+        indent() << "  return 0;" << endl <<
+        endl;
+
+      // copy over any throw exceptions and return failure
+      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
+        f_service_ << 
+          indent() << "if (" << (*x_iter)->get_name() << " != NULL)" << endl <<
+          indent() << "{" << endl <<
+          indent() << "    *error = g_error_copy (" << (*x_iter)->get_name() << ");" << endl <<
+          indent() << "    return 0;" << endl <<
+          indent() << "}" << endl;
+      }
+
+      // Close function
+      indent(f_service_) << "return 1;" << endl;
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+  }
+
+  f_service_ <<
+    "GType thrift_" << service_name_u << "_client_get_type (void)" << endl <<
+    "{" << endl <<
+    "  static GType type = 0;" << endl << 
+    endl <<
+    "  if (type == 0) " << endl <<
+    "  {" << endl <<
+    "    static const GTypeInfo type_info = " << endl <<
+    "    {" << endl <<
+    "      sizeof (Thrift" << service_name_ << "ClientClass)," << endl <<
+    "      NULL, /* base_init */" << endl <<
+    "      NULL, /* base_finalize */" << endl <<
+    "      NULL, /* class_init */" << endl <<
+    "      NULL, /* class_finalize */" << endl <<
+    "      NULL, /* class_data */" << endl <<
+    "      sizeof (Thrift" << service_name_ << "Client)," << endl <<
+    "      0, /* n_preallocs */" << endl <<
+    "      NULL, /* instance_init */" << endl <<
+    "      NULL, /* value_table */" << endl <<
+    "    };" << endl << 
+    endl <<
+    "    type = g_type_register_static (THRIFT_TYPE_CLIENT, " << endl <<
+    "                                   \"Thrift" << service_name_ << "ClientType\"," << endl << 
+    "                                   &type_info, 0);" << endl <<
+    "  }" << endl << 
+    endl << 
+    "  return type;" << endl << 
+    "}" << endl << 
+    endl;
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_c_generator::function_signature(t_function* tfunction) {
+
+  t_type* ttype = tfunction->get_returntype();
+  t_struct* arglist = tfunction->get_arglist();
+  string fname = initial_caps_to_underscores(tfunction->get_name());
+
+  bool has_return = !ttype->is_void();
+  bool has_args = arglist->get_members().size() == 0;
+  return
+    "gboolean " + this->nspace_u + fname + " (Thrift" + service_name_ +
+    "Client * client" + 
+    (has_return ? ", " + type_name(ttype) + "* _return" : "") +
+    (has_args ? "" : (", " + argument_list(arglist))) + ", GError ** error)";
+}
+
+/**
+ * Renders a field list
+ *
+ * @param tstruct The struct definition
+ * @return Comma sepearated list of all field names in that struct
+ */
+string t_c_generator::argument_list(t_struct* tstruct, bool name_params) {
+  string result = "";
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      result += ", ";
+    }
+    /* TODO: get rid of name_params */
+    result += type_name((*f_iter)->get_type(), false, true) + " " +
+      (name_params ? (*f_iter)->get_name() : "/* " + (*f_iter)->get_name() + " */");
+  }
+  return result;
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ * @return Field declaration, i.e. int x = 0;
+ */
+string t_c_generator::declare_field(t_field* tfield, bool init, bool pointer, bool constant, bool reference) {
+  // TODO(mcslee): do we ever need to initialize the field?
+  string result = "";
+  if (constant) {
+    result += "const ";
+  }
+  result += type_name(tfield->get_type());
+  if (pointer) {
+    result += "*";
+  }
+  if (reference) {
+    result += "*";
+  }
+  result += " " + tfield->get_name();
+  if (init) {
+    t_type* type = get_true_type(tfield->get_type());
+
+    if (type->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        break;
+      case t_base_type::TYPE_STRING:
+        result += " = NULL";
+        break;
+      case t_base_type::TYPE_BOOL:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_BYTE:
+      case t_base_type::TYPE_I16:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_I64:
+        result += " = 0";
+        break;
+      case t_base_type::TYPE_DOUBLE:
+        result += " = (gdouble)0";
+        break;
+      default:
+        throw "compiler error: no C initializer for base type " + t_base_type::t_base_name(tbase);
+      }
+    } else if (type->is_enum()) {
+      result += " = (" + type_name(type) + ")0";
+    } else if (tfield->get_type()->is_struct()) {
+      string name_uc = to_upper_case
+        (initial_caps_to_underscores(tfield->get_type()->get_name()));
+      result += " = g_object_new (" + this->nspace_uc + "TYPE_" + name_uc + 
+        ", NULL);";
+    } else if (tfield->get_type()->is_xception()) {
+      /* GError's always need to be set to NULL */  
+      result += " = NULL;";
+    }
+  }
+
+  
+  if (!reference) {
+    result += ";";
+  }
+  return result;
+}
+
+/**
+ * Returns a C type name
+ *
+ * @param ttype The type
+ * @return String of the type name, i.e. std::set<type>
+ */
+string t_c_generator::type_name(t_type* ttype, bool in_typedef, bool is_const) {
+
+  if (ttype->is_base_type()) {
+    string bname = base_type_name(((t_base_type*)ttype)->get_base());
+
+    if (is_const) {
+      return "const " + bname;
+    } else {
+      return bname;
+    }
+  }
+
+  if (ttype->is_xception()) {
+    return "GError *";
+  }
+
+  // Check for a custom overloaded C name
+  if (ttype->is_container()) {
+    string cname;
+
+    t_container* tcontainer = (t_container*) ttype;
+    if (tcontainer->has_cpp_name()) {
+      cname = tcontainer->get_cpp_name();
+    } else if (ttype->is_map()) {
+      cname = "GHashTable *";
+    } else if (ttype->is_set()) {
+      cname = "GHashTable *";
+    } else if (ttype->is_list()) {
+
+      // TODO: for now everything else is ptr array
+      cname = "GPtrArray *";
+      t_type * etype = ((t_list*)ttype)->get_elem_type();
+      if (etype->is_base_type()) {
+        t_base_type::t_base tbase = ((t_base_type*)etype)->get_base();
+        switch (tbase) {
+            case t_base_type::TYPE_VOID:
+              throw "compiler error: cannot determine array type";
+            case t_base_type::TYPE_STRING:
+              break;
+            case t_base_type::TYPE_BOOL:
+            case t_base_type::TYPE_BYTE:
+            case t_base_type::TYPE_I16:
+            case t_base_type::TYPE_I32:
+            case t_base_type::TYPE_I64:
+            case t_base_type::TYPE_DOUBLE:
+              cname = "GArray *";
+              break;
+            default:
+              throw "compiler error: no array info for type";
+        }
+      }
+    }
+
+    if (is_const) {
+      return "const " + cname;
+    } else {
+      return cname;
+    }
+  }
+
+  // Check if it needs to be namespaced
+  string pname = this->nspace + ttype->get_name();
+
+  if (is_complex_type(ttype)) {
+    pname += " *";
+  }
+
+  if (is_const) {
+    return "const " + pname;
+  } else {
+    return pname;
+  }
+}
+
+
+/**
+ * Returns the C type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ * @return Explicit C type, i.e. "gint32"
+ */
+string t_c_generator::base_type_name(t_base_type::t_base tbase) {
+  switch (tbase) {
+  case t_base_type::TYPE_VOID:
+    return "void";
+  case t_base_type::TYPE_STRING:
+    return "gchar *";
+  case t_base_type::TYPE_BOOL:
+    return "gboolean";
+  case t_base_type::TYPE_BYTE:
+    return "gint8";
+  case t_base_type::TYPE_I16:
+    return "gint16";
+  case t_base_type::TYPE_I32:
+    return "gint32";
+  case t_base_type::TYPE_I64:
+    return "gint64";
+  case t_base_type::TYPE_DOUBLE:
+    return "gdouble";
+  default:
+    throw "compiler error: no C base type name for base type " + t_base_type::t_base_name(tbase);
+  }
+}
+
+string t_c_generator::type_to_enum(t_type* type) {
+  type = get_true_type(type);
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_VOID:
+      throw "NO T_VOID CONSTRUCT";
+    case t_base_type::TYPE_STRING:
+      return "T_STRING";
+    case t_base_type::TYPE_BOOL:
+      return "T_BOOL";
+    case t_base_type::TYPE_BYTE:
+      return "T_BYTE";
+    case t_base_type::TYPE_I16:
+      return "T_I16";
+    case t_base_type::TYPE_I32:
+      return "T_I32";
+    case t_base_type::TYPE_I64:
+      return "T_I64";
+    case t_base_type::TYPE_DOUBLE:
+      return "T_DOUBLE";
+    }
+  } else if (type->is_enum()) {
+    return "T_I32";
+  } else if (type->is_struct()) {
+    return "T_STRUCT";
+  } else if (type->is_xception()) {
+    return "T_STRUCT";
+  } else if (type->is_map()) {
+    return "T_MAP";
+  } else if (type->is_set()) {
+    return "T_SET";
+  } else if (type->is_list()) {
+    return "T_LIST";
+  }
+
+  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
+}
+
+/**
+ *
+ */
+string t_c_generator::constant_value(t_type * type, t_const_value * value) {
+
+  ostringstream render;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      render << "\"" + value->get_string() + "\"";
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() != 0) ? 1 : 0);
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    render << "(" << type_name(type) << ")" << value->get_integer();
+  } else {
+    /* TODO: what is this case 
+    string t = tmp("tmp");
+    indent(out) << type_name(type) << " " << t << ";" << endl;
+    print_const_value(out, t, type, value);
+    render << t;
+    */
+    render << "\"not yet supported\"";
+  }
+
+  return render.str();
+}
+
+THRIFT_REGISTER_GENERATOR(c, "C", "");

Modified: incubator/thrift/branches/c-bindings/compiler/cpp/src/parse/t_program.h
URL: http://svn.apache.org/viewvc/incubator/thrift/branches/c-bindings/compiler/cpp/src/parse/t_program.h?rev=739515&r1=739514&r2=739515&view=diff
==============================================================================
--- incubator/thrift/branches/c-bindings/compiler/cpp/src/parse/t_program.h (original)
+++ incubator/thrift/branches/c-bindings/compiler/cpp/src/parse/t_program.h Sat Jan 31 07:30:45 2009
@@ -168,6 +168,15 @@
     return cpp_includes_;
   }
 
+  void add_c_include(std::string path) {
+    c_includes_.push_back(path);
+  }
+
+  const std::vector<std::string>& get_c_includes() {
+    return c_includes_;
+  }
+
+
   void set_php_namespace(std::string php_namespace) {
     php_namespace_ = php_namespace;
   }
@@ -222,6 +231,9 @@
   // C++ extra includes
   std::vector<std::string> cpp_includes_;
 
+  // C extra includes
+  std::vector<std::string> c_includes_;
+
   // PHP namespace
   std::string php_namespace_;
 

Modified: incubator/thrift/branches/c-bindings/configure.ac
URL: http://svn.apache.org/viewvc/incubator/thrift/branches/c-bindings/configure.ac?rev=739515&r1=739514&r2=739515&view=diff
==============================================================================
--- incubator/thrift/branches/c-bindings/configure.ac (original)
+++ incubator/thrift/branches/c-bindings/configure.ac Sat Jan 31 07:30:45 2009
@@ -49,6 +49,15 @@
 AM_CONDITIONAL([WITH_JAVA],
                [test -n "$ANT" -a -n "$JAVA" -a -n "$JAVAC"])
 
+AX_THRIFT_LIB(c, [C], yes)
+if test "$with_c" = "yes";  then
+    m4_define([glib_required_version], [2.16.0])
+    GLIB_PACKAGES="gobject-2.0"
+    PKG_CHECK_MODULES(GLIB, [gobject-2.0 >= glib_required_version],
+                      have_c=yes, have_c=no)
+fi
+AM_CONDITIONAL([WITH_C], [test "$have_c" = "yes"])
+
 AX_THRIFT_LIB(erlang, [Erlang], yes)
 if test "$with_erlang" = "yes";  then
   AC_PATH_PROG([ERLC], [erlc])
@@ -133,6 +142,8 @@
 
 AX_THRIFT_GEN(cpp, [C++], yes)
 AM_CONDITIONAL([THRIFT_GEN_cpp], [test "$ax_thrift_gen_cpp" = "yes"])
+AX_THRIFT_GEN(c, [C], yes)
+AM_CONDITIONAL([THRIFT_GEN_c], [test "$ax_thrift_gen_c" = "yes"])
 AX_THRIFT_GEN(java, [Java], yes)
 AM_CONDITIONAL([THRIFT_GEN_java], [test "$ax_thrift_gen_java" = "yes"])
 AX_THRIFT_GEN(csharp, [C#], yes)
@@ -158,6 +169,7 @@
   Makefile
   compiler/cpp/Makefile
   lib/Makefile
+  lib/c/Makefile
   lib/cpp/Makefile
   lib/cpp/thrift.pc
   lib/cpp/thrift-nb.pc

Added: incubator/thrift/branches/c-bindings/gen-c/Makefile
URL: http://svn.apache.org/viewvc/incubator/thrift/branches/c-bindings/gen-c/Makefile?rev=739515&view=auto
==============================================================================
--- incubator/thrift/branches/c-bindings/gen-c/Makefile (added)
+++ incubator/thrift/branches/c-bindings/gen-c/Makefile Sat Jan 31 07:30:45 2009
@@ -0,0 +1,8 @@
+FILES = thrudoc_types.c thrudoc.c main.c
+CFLAGS = `pkg-config --cflags gobject-2.0` -I$(SANDBOX)/include/thrift_c -g -Wall -W
+LDFLAGS = `pkg-config --libs gobject-2.0` -L$(SANDBOX)/lib -lthrift_c
+
+all: test
+
+test: Makefile $(FILES)
+	gcc -o $@ $(CFLAGS) $(LDFLAGS) $(FILES)

Added: incubator/thrift/branches/c-bindings/gen-c/echo.pl
URL: http://svn.apache.org/viewvc/incubator/thrift/branches/c-bindings/gen-c/echo.pl?rev=739515&view=auto
==============================================================================
--- incubator/thrift/branches/c-bindings/gen-c/echo.pl (added)
+++ incubator/thrift/branches/c-bindings/gen-c/echo.pl Sat Jan 31 07:30:45 2009
@@ -0,0 +1,60 @@
+#!/usr/local/bin/perl
+# file: tcp_echo_serv1.pl
+# usage: tcp_echo_serv1.pl [port]
+# Echo server, TCP version
+
+use strict;
+use Socket;
+use IO::Handle;
+use constant MY_ECHO_PORT => shift @ARGV || 9091;
+
+my ($bytes_out,$bytes_in) = (0,0);
+
+my $port = shift || MY_ECHO_PORT;
+my $protocol = getprotobyname('tcp');
+
+$SIG{'INT'} = sub {
+    print STDERR "bytes_sent = $bytes_out, bytes_received = $bytes_in\n";
+    exit 0;
+};
+
+socket(SOCK, AF_INET, SOCK_STREAM, $protocol) or
+    die "socket() failed: $!";
+setsockopt(SOCK,SOL_SOCKET,SO_REUSEADDR,1) or
+    die "Can't set SO_REUSEADDR: $!";
+
+my $my_addr = sockaddr_in($port,INADDR_ANY);
+bind(SOCK,$my_addr) or
+    die "bind() failed: $!";
+listen(SOCK,SOMAXCONN) or
+    die "listen() failed: $!";
+
+warn "waiting for incoming connections on port $port...\n";
+
+while(1) {
+    next unless my $remote_addr = accept(SESSION,SOCK);
+    my ($port,$hisaddr) = sockaddr_in($remote_addr);
+    warn "Connection from [",inet_ntoa($hisaddr),",$port]\n";
+
+    SESSION->autoflush(1);
+    while(<SESSION>) {
+	$bytes_in += length($_);
+	chomp;
+
+        printf STDERR "#%d\n", length ($_); 
+        foreach my $c (0..length($_)-1)
+        {
+            my $ch = substr($_, $c, 1);
+            printf STDERR "0x%02x\n", ord($ch);
+        }
+        print STDERR "\n";
+
+	my $msg_out = "$_\n\0";
+#	print STDERR $msg_out;
+	print SESSION $msg_out;
+	$bytes_out += length($msg_out);
+    }
+
+    warn "Connection from [",inet_ntoa($hisaddr),",$port] finished\n";
+    close SESSION;
+}