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