aboutsummaryrefslogtreecommitdiffstats
path: root/emulator
diff options
context:
space:
mode:
authorJacky Romano <jr@graphtech.co.il>2011-02-10 11:04:25 +0200
committerJacky Romano <jr@graphtech.co.il>2011-02-25 16:38:35 +0200
commit08d9695a7338f2545a7391ddb495d31b855f0c77 (patch)
tree6174af5a8397c45994a53e96c9925fc1acbb5ffa /emulator
parent45d1ca96fdac3505c43aa58b1b932621d3057235 (diff)
downloadsdk-08d9695a7338f2545a7391ddb495d31b855f0c77.zip
sdk-08d9695a7338f2545a7391ddb495d31b855f0c77.tar.gz
sdk-08d9695a7338f2545a7391ddb495d31b855f0c77.tar.bz2
Emugen : A tool to generate wire protocol code
Emugen is a tool that can be used to generate code that deals with marshaling/unmarshaling request to/from a wire-protocol. Its input is an API defintion files and its output is C++ source code for the client (caller) and the server (callee) sides. See README file for more details. Change-Id: I45beea6657fae0887d2b4d92933213ecc20d2525
Diffstat (limited to 'emulator')
-rw-r--r--emulator/opengl/host/tools/emugen/Android.mk10
-rw-r--r--emulator/opengl/host/tools/emugen/ApiGen.cpp771
-rw-r--r--emulator/opengl/host/tools/emugen/ApiGen.h78
-rw-r--r--emulator/opengl/host/tools/emugen/EntryPoint.cpp335
-rw-r--r--emulator/opengl/host/tools/emugen/EntryPoint.h64
-rw-r--r--emulator/opengl/host/tools/emugen/README292
-rw-r--r--emulator/opengl/host/tools/emugen/TypeFactory.cpp135
-rw-r--r--emulator/opengl/host/tools/emugen/TypeFactory.h37
-rw-r--r--emulator/opengl/host/tools/emugen/Var.h94
-rw-r--r--emulator/opengl/host/tools/emugen/VarType.h76
-rw-r--r--emulator/opengl/host/tools/emugen/errors.h24
-rw-r--r--emulator/opengl/host/tools/emugen/main.cpp147
-rw-r--r--emulator/opengl/host/tools/emugen/strUtils.cpp49
-rw-r--r--emulator/opengl/host/tools/emugen/strUtils.h33
14 files changed, 2145 insertions, 0 deletions
diff --git a/emulator/opengl/host/tools/emugen/Android.mk b/emulator/opengl/host/tools/emugen/Android.mk
new file mode 100644
index 0000000..fcd7b24
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/Android.mk
@@ -0,0 +1,10 @@
+
+LOCAL_PATH:=$(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := debug
+LOCAL_SRC_FILES := ApiGen.cpp EntryPoint.cpp main.cpp strUtils.cpp TypeFactory.cpp
+LOCAL_MODULE := emugen
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/emulator/opengl/host/tools/emugen/ApiGen.cpp b/emulator/opengl/host/tools/emugen/ApiGen.cpp
new file mode 100644
index 0000000..ffa71d8
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/ApiGen.cpp
@@ -0,0 +1,771 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "ApiGen.h"
+#include "EntryPoint.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "strUtils.h"
+#include <errno.h>
+#include <sys/types.h>
+
+
+EntryPoint * ApiGen::findEntryByName(const std::string & name)
+{
+ EntryPoint * entry = NULL;
+
+ size_t n = this->size();
+ for (size_t i = 0; i < n; i++) {
+ if (at(i).name() == name) {
+ entry = &(at(i));
+ break;
+ }
+ }
+ return entry;
+}
+
+void ApiGen::printHeader(FILE *fp) const
+{
+ fprintf(fp, "// Generated Code - DO NOT EDIT !!\n");
+ fprintf(fp, "// generated by 'emugen'\n");
+}
+
+int ApiGen::genProcTypes(const std::string &filename, SideType side)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+ printHeader(fp);
+
+ fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", m_basename.c_str(), sideString(side));
+ fprintf(fp, "#define __%s_%s_proc_t_h\n", m_basename.c_str(), sideString(side));
+ fprintf(fp, "\n\n");
+ fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
+
+ for (size_t i = 0; i < size(); i++) {
+ EntryPoint *e = &at(i);
+
+ fprintf(fp, "typedef ");
+ e->retval().printType(fp);
+ fprintf(fp, " (* %s_%s_proc_t) (", e->name().c_str(), sideString(side));
+ if (side == CLIENT_SIDE) { fprintf(fp, "void * ctx"); }
+ if (e->customDecoder() && side == SERVER_SIDE) { fprintf(fp, "void *ctx"); }
+
+ VarsArray & evars = e->vars();
+ size_t n = evars.size();
+
+ for (size_t j = 0; j < n; j++) {
+ if (!evars[j].isVoid()) {
+ if (j != 0 || side == CLIENT_SIDE || (side == SERVER_SIDE && e->customDecoder())) fprintf(fp, ", ");
+ evars[j].printType(fp);
+ }
+ }
+ fprintf(fp, ");\n");
+ }
+ fprintf(fp, "\n\n#endif\n");
+ return 0;
+}
+
+int ApiGen::genContext(const std::string & filename, SideType side)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+ printHeader(fp);
+
+ fprintf(fp, "#ifndef __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
+ fprintf(fp, "#define __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
+
+ // fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
+ fprintf(fp, "\n#include \"%s_%s_proc.h\"\n", m_basename.c_str(), sideString(side));
+
+ StringVec & contextHeaders = side == CLIENT_SIDE ? m_clientContextHeaders : m_serverContextHeaders;
+ for (size_t i = 0; i < contextHeaders.size(); i++) {
+ fprintf(fp, "#include %s\n", contextHeaders[i].c_str());
+ }
+ fprintf(fp, "\n");
+
+ fprintf(fp, "\nstruct %s_%s_context_t {\n\n", m_basename.c_str(), sideString(side));
+ for (size_t i = 0; i < size(); i++) {
+ EntryPoint *e = &at(i);
+ fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
+ }
+ // accessors
+ fprintf(fp, "\t//Accessors \n");
+
+ for (size_t i = 0; i < size(); i++) {
+ EntryPoint *e = &at(i);
+ const char *n = e->name().c_str();
+ const char *s = sideString(side);
+ fprintf(fp, "\tvirtual %s_%s_proc_t set_%s(%s_%s_proc_t f) { %s_%s_proc_t retval = %s; %s = f; return retval;}\n", n, s, n, n, s, n, s, n, n);
+ }
+
+ // virtual destructor
+ fprintf(fp, "\t virtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side));
+ // accessor
+ if (side == CLIENT_SIDE) {
+ fprintf(fp, "\n\ttypedef %s_%s_context_t *CONTEXT_ACCESSOR_TYPE(void);\n",
+ m_basename.c_str(), sideString(side));
+ fprintf(fp, "\tvoid setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n");
+ }
+
+ fprintf(fp, "};\n");
+
+ fprintf(fp, "\n#endif\n");
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::genClientEntryPoints(const std::string & filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return errno;
+ }
+
+ printHeader(fp);
+ fprintf(fp, "#include <stdio.h>\n");
+ fprintf(fp, "#include <stdlib.h>\n");
+ fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(CLIENT_SIDE));
+ fprintf(fp, "\n");
+
+ fprintf(fp, "extern \"C\" {\n");
+
+ for (size_t i = 0; i < size(); i++) {
+ fprintf(fp, "\t"); at(i).print(fp, false); fprintf(fp, ";\n");
+ }
+ fprintf(fp, "};\n\n");
+
+ fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n",
+ m_basename.c_str(), sideString(CLIENT_SIDE));
+
+ fprintf(fp,
+ "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n\n",
+ m_basename.c_str(), sideString(CLIENT_SIDE));
+
+
+ for (size_t i = 0; i < size(); i++) {
+ EntryPoint *e = &at(i);
+ e->print(fp);
+ fprintf(fp, "{\n");
+ fprintf(fp, "\t %s_%s_context_t * ctx = getCurrentContext(); \n",
+ m_basename.c_str(), sideString(CLIENT_SIDE));
+
+ bool shouldReturn = !e->retval().isVoid();
+
+ fprintf(fp, "\t %sctx->%s(ctx",
+ shouldReturn ? "return " : "",
+ e->name().c_str());
+ size_t nvars = e->vars().size();
+
+ for (size_t j = 0; j < nvars; j++) {
+ if (!e->vars()[j].isVoid()) {
+ fprintf(fp, ", %s", e->vars()[j].name().c_str());
+ }
+ }
+ fprintf(fp, ");\n");
+ fprintf(fp, "}\n\n");
+ }
+ fclose(fp);
+ return 0;
+}
+
+
+int ApiGen::genOpcodes(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return errno;
+ }
+
+ printHeader(fp);
+ fprintf(fp, "#ifndef __GUARD_%s_opcodes_h_\n", m_basename.c_str());
+ fprintf(fp, "#define __GUARD_%s_opcodes_h_\n\n", m_basename.c_str());
+ for (size_t i = 0; i < size(); i++) {
+ fprintf(fp, "#define OP_%s \t\t\t\t\t%u\n", at(i).name().c_str(), (unsigned int)i + m_baseOpcode);
+ }
+ fprintf(fp, "#define OP_last \t\t\t\t\t%u\n", (unsigned int)size() + m_baseOpcode);
+ fprintf(fp,"\n\n#endif\n");
+ fclose(fp);
+ return 0;
+
+}
+int ApiGen::genAttributesTemplate(const std::string &filename )
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ for (size_t i = 0; i < size(); i++) {
+ if (at(i).hasPointers()) {
+ fprintf(fp, "#");
+ at(i).print(fp);
+ fprintf(fp, "%s\n\n", at(i).name().c_str());
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::genEncoderHeader(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ printHeader(fp);
+ std::string classname = m_basename + "_encoder_context_t";
+
+ fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
+ fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
+
+ fprintf(fp, "#include \"IOStream.h\"\n");
+ fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(CLIENT_SIDE));
+
+ for (size_t i = 0; i < m_encoderHeaders.size(); i++) {
+ fprintf(fp, "#include %s\n", m_encoderHeaders[i].c_str());
+ }
+ fprintf(fp, "\n");
+
+ fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
+ classname.c_str(), m_basename.c_str(), sideString(CLIENT_SIDE));
+ fprintf(fp, "\tIOStream *m_stream;\n\n");
+
+ fprintf(fp, "\t%s(IOStream *stream);\n\n", classname.c_str());
+ fprintf(fp, "\n};\n\n");
+
+ fprintf(fp,"extern \"C\" {\n");
+
+ for (size_t i = 0; i < size(); i++) {
+ fprintf(fp, "\t");
+ at(i).print(fp, false, "_enc", /* classname + "::" */"", "void *self");
+ fprintf(fp, ";\n");
+ }
+ fprintf(fp, "};\n");
+ fprintf(fp, "#endif");
+
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::genEncoderImpl(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ printHeader(fp);
+ fprintf(fp, "\n\n#include <string.h>\n");
+ fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
+ fprintf(fp, "#include \"%s_enc.h\"\n\n\n", m_basename.c_str());
+ fprintf(fp, "#include <stdio.h>\n");
+ std::string classname = m_basename + "_encoder_context_t";
+ size_t n = size();
+
+ // unsupport printout
+ fprintf(fp, "static void enc_unsupported()\n{\n\tfprintf(stderr, \"Function is unsupported\\n\");\n}\n\n");
+
+ // entry points;
+ for (size_t i = 0; i < n; i++) {
+ EntryPoint *e = &at(i);
+
+ if (e->unsupported()) continue;
+
+
+ e->print(fp, true, "_enc", /* classname + "::" */"", "void *self");
+ fprintf(fp, "{\n");
+
+ fprintf(fp, "\n\t%s *ctx = (%s *)self;\n\n",
+ classname.c_str(),
+ classname.c_str());
+
+ // size calculation ;
+ fprintf(fp, "\t size_t packetSize = ");
+
+ VarsArray & evars = e->vars();
+ size_t nvars = evars.size();
+ size_t npointers = 0;
+ for (size_t j = 0; j < nvars; j++) {
+ fprintf(fp, "%s ", j == 0 ? "" : " +");
+ if (evars[j].isPointer()) {
+ npointers++;
+
+ if (evars[j].lenExpression() == "") {
+ fprintf(stderr, "%s: data len is undefined for '%s'\n",
+ e->name().c_str(), evars[j].name().c_str());
+ }
+
+ if (evars[j].nullAllowed()) {
+ fprintf(fp, "(%s != NULL ? %s : 0)",
+ evars[j].name().c_str(),
+ evars[j].lenExpression().c_str());
+ } else {
+ if (evars[j].pointerDir() == Var::POINTER_IN ||
+ evars[j].pointerDir() == Var::POINTER_INOUT) {
+ fprintf(fp, "%s", evars[j].lenExpression().c_str());
+ } else {
+ fprintf(fp, "0");
+ }
+ }
+ } else {
+ fprintf(fp, "%u", (unsigned int) evars[j].type()->bytes());
+ }
+ }
+ fprintf(fp, " %s 8 + %u * 4;\n", nvars != 0 ? "+" : "", (unsigned int) npointers);
+
+ // allocate buffer from the stream;
+ fprintf(fp, "\t unsigned char *ptr = ctx->m_stream->alloc(packetSize);\n\n");
+
+ // encode into the stream;
+ fprintf(fp, "\t*(unsigned int *)(ptr) = OP_%s; ptr += 4;\n", e->name().c_str());
+ fprintf(fp, "\t*(unsigned int *)(ptr) = (unsigned int) packetSize; ptr += 4;\n\n");
+
+ // out variables
+ for (size_t j = 0; j < nvars; j++) {
+ if (evars[j].isPointer()) {
+ // encode a pointer header
+ if (evars[j].nullAllowed()) {
+ fprintf(fp, "\t*(unsigned int *)(ptr) = (%s != NULL) ? %s : 0; ptr += 4; \n",
+ evars[j].name().c_str(), evars[j].lenExpression().c_str());
+ } else {
+ fprintf(fp, "\t*(unsigned int *)(ptr) = %s; ptr += 4; \n",
+ evars[j].lenExpression().c_str());
+ }
+
+ Var::PointerDir dir = evars[j].pointerDir();
+ if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
+ if (evars[j].nullAllowed()) {
+ fprintf(fp, "\tif (%s != NULL) ", evars[j].name().c_str());
+ } else {
+ fprintf(fp, "\t");
+ }
+
+ if (evars[j].packExpression().size() != 0) {
+ fprintf(fp, "%s;", evars[j].packExpression().c_str());
+ } else {
+ fprintf(fp, "memcpy(ptr, %s, %s);",
+ evars[j].name().c_str(),
+ evars[j].lenExpression().c_str());
+ }
+
+ fprintf(fp, "ptr += %s;\n", evars[j].lenExpression().c_str());
+ }
+ } else {
+ // encode a non pointer variable
+ if (!evars[j].isVoid()) {
+ fprintf(fp, "\t*(%s *) (ptr) = %s; ptr += %u;\n",
+ evars[j].type()->name().c_str(), evars[j].name().c_str(),
+ (uint) evars[j].type()->bytes());
+ }
+ }
+ }
+ // in variables;
+ for (size_t j = 0; j < nvars; j++) {
+ if (evars[j].isPointer()) {
+ Var::PointerDir dir = evars[j].pointerDir();
+ if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
+ if (evars[j].nullAllowed()) {
+ fprintf(fp, "\tif (%s != NULL) ctx->m_stream->readback(%s, %s);\n",
+ evars[j].name().c_str(),
+ evars[j].name().c_str(),
+ evars[j].lenExpression().c_str());
+ } else {
+ fprintf(fp, "\tctx->m_stream->readback(%s, %s);\n",
+ evars[j].name().c_str(),
+ evars[j].lenExpression().c_str());
+ }
+ }
+ }
+ }
+ // todo - return value for pointers
+ if (e->retval().isPointer()) {
+ fprintf(stderr, "WARNING: %s : return value of pointer is unsupported\n",
+ e->name().c_str());
+ fprintf(fp, "\t return NULL;\n");
+ } else if (e->retval().type()->name() != "void") {
+ fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
+ fprintf(fp, "\tctx->m_stream->readback(&retval, %u);\n",(uint) e->retval().type()->bytes());
+ fprintf(fp, "\treturn retval;\n");
+ }
+ fprintf(fp, "}\n\n");
+ }
+
+ // constructor
+ fprintf(fp, "%s::%s(IOStream *stream)\n{\n", classname.c_str(), classname.c_str());
+ fprintf(fp, "\tm_stream = stream;\n\n");
+
+ for (size_t i = 0; i < n; i++) {
+ EntryPoint *e = &at(i);
+ if (e->unsupported()) {
+ fprintf(fp, "\tset_%s((%s_%s_proc_t)(enc_unsupported));\n", e->name().c_str(), e->name().c_str(), sideString(CLIENT_SIDE));
+ } else {
+ fprintf(fp, "\tset_%s(%s_enc);\n", e->name().c_str(), e->name().c_str());
+ }
+ /**
+ if (e->unsupsported()) {
+ fprintf(fp, "\tmemcpy((void *)(&%s), (const void *)(&enc_unsupported), sizeof(%s));\n",
+ e->name().c_str(),
+ e->name().c_str());
+ } else {
+ fprintf(fp, "\t%s = %s_enc;\n", e->name().c_str(), e->name().c_str());
+ }
+ **/
+ }
+ fprintf(fp, "}\n\n");
+
+ fclose(fp);
+ return 0;
+}
+
+
+int ApiGen::genDecoderHeader(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ printHeader(fp);
+ std::string classname = m_basename + "_decoder_context_t";
+
+ fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
+ fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
+
+ fprintf(fp, "#include \"IOStream.h\" \n");
+ fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE));
+
+ for (size_t i = 0; i < m_decoderHeaders.size(); i++) {
+ fprintf(fp, "#include %s\n", m_decoderHeaders[i].c_str());
+ }
+ fprintf(fp, "\n");
+
+ fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
+ classname.c_str(), m_basename.c_str(), sideString(SERVER_SIDE));
+ fprintf(fp, "\tsize_t decode(void *buf, size_t bufsize, IOStream *stream);\n");
+ fprintf(fp, "\tint init( void *(*getProc)(const char *name));\n");
+ fprintf(fp, "\n};\n\n");
+ fprintf(fp, "#endif");
+
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::genDecoderImpl(const std::string &filename)
+{
+ FILE *fp = fopen(filename.c_str(), "wt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+
+ printHeader(fp);
+
+ std::string classname = m_basename + "_decoder_context_t";
+
+ size_t n = size();
+
+ fprintf(fp, "\n\n#include <string.h>\n");
+ fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
+ fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str());
+ fprintf(fp, "#include <stdio.h>\n");
+
+ // init function;
+ fprintf(fp, "int %s::init(void *(*getProc)(const char *))\n{\n", classname.c_str());
+ fprintf(fp, "\tvoid *ptr;\n\n");
+ for (size_t i = 0; i < n; i++) {
+ EntryPoint *e = &at(i);
+ fprintf(fp, "\tptr = getProc(\"%s\"); set_%s((%s_%s_proc_t)ptr);\n",
+ e->name().c_str(),
+ e->name().c_str(),
+ e->name().c_str(),
+ sideString(SERVER_SIDE));
+
+ }
+ fprintf(fp, "\treturn 0;\n");
+ fprintf(fp, "}\n\n");
+
+ // decoder switch;
+ fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream)\n{\n", classname.c_str());
+ fprintf(fp,
+ " \n\
+\tsize_t pos = 0;\n\
+\tif (len < 8) return pos; \n\
+\tunsigned char *ptr = (unsigned char *)buf;\n\
+\tbool unknownOpcode = false; \n\
+\twhile ((len - pos >= 8) && !unknownOpcode) { \n\
+\t\tvoid *params[%u]; \n\
+\t\tint opcode = *(int *)ptr; \n\
+\t\tunsigned int packetLen = *(int *)(ptr + 4);\n\
+\t\tif (len - pos < packetLen) return pos; \n\
+\t\tswitch(opcode) {\n",
+ (uint) m_maxEntryPointsParams);
+
+ for (size_t f = 0; f < n; f++) {
+ enum Pass_t { PASS_MemAlloc = 0, PASS_DebugPrint, PASS_FunctionCall, PASS_Epilog, PASS_LAST };
+ EntryPoint *e = &at(f);
+ // construct a printout string;
+ std::string printString = "";
+ for (size_t i = 0; i < e->vars().size(); i++) {
+ Var *v = &e->vars()[i];
+ if (!v->isVoid()) printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " ";
+ }
+ printString += "";
+ // TODO - add for return value;
+
+ fprintf(fp, "\t\t\tcase OP_%s:\n", e->name().c_str());
+ fprintf(fp, "\t\t\t{\n");
+
+ for (int pass = PASS_MemAlloc; pass < PASS_LAST; pass++) {
+ if (pass == PASS_FunctionCall && !e->retval().isVoid()) {
+ fprintf(fp, "\t\t\t%s %s retval = ", e->retval().type()->name().c_str(), e->retval().isPointer() ? "*" : "");
+ }
+
+
+ if (pass == PASS_FunctionCall) {
+ fprintf(fp, "\t\t\tthis->%s(", e->name().c_str());
+ if (e->customDecoder()) {
+ fprintf(fp, "this"); // add a context to the call
+ }
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp, "#ifdef DEBUG_PRINTOUT\n");
+ fprintf(fp, "\t\t\tfprintf(stderr,\"%s(%s)\\n\"", e->name().c_str(), printString.c_str());
+ if (e->vars().size() > 0 && !e->vars()[0].isVoid()) fprintf(fp, ",");
+ }
+
+ std::string varoffset = "8"; // skip the header
+ VarsArray & evars = e->vars();
+ // allocate memory for out pointers;
+ for (size_t j = 0; j < evars.size(); j++) {
+ Var *v = & evars[j];
+ if (!v->isVoid()) {
+ if ((pass == PASS_FunctionCall) && (j != 0 || e->customDecoder())) fprintf(fp, ", ");
+ if (pass == PASS_DebugPrint && j != 0) fprintf(fp, ", ");
+
+ if (!v->isPointer()) {
+ if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) {
+ fprintf(fp, "*(%s *)(ptr + %s)", v->type()->name().c_str(), varoffset.c_str());
+ }
+ varoffset += " + " + toString(v->type()->bytes());
+ } else {
+ if (v->pointerDir() == Var::POINTER_IN || v->pointerDir() == Var::POINTER_INOUT) {
+ if (pass == PASS_MemAlloc && v->pointerDir() == Var::POINTER_INOUT) {
+ fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
+ (uint) j, varoffset.c_str());
+ fprintf(fp, "unsigned char *tmpPtr%u = (ptr + %s + 4);\n",
+ (uint) j, varoffset.c_str());
+ }
+ if (pass == PASS_FunctionCall) {
+ fprintf(fp, "(%s *)(ptr + %s + 4)",
+ v->type()->name().c_str(), varoffset.c_str());
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp, "(%s *)(ptr + %s + 4), *(unsigned int *)(ptr + %s)",
+ v->type()->name().c_str(), varoffset.c_str(),
+ varoffset.c_str());
+ }
+ varoffset += " + 4 + *(size_t *)(ptr +" + varoffset + ")";
+ } else { // in pointer;
+ if (pass == PASS_MemAlloc) {
+ fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
+ (uint) j, varoffset.c_str());
+ fprintf(fp, "\t\t\tunsigned char *tmpPtr%u = new unsigned char[tmpPtr%uSize];\n",
+ (uint)j, (uint)j);
+ } else if (pass == PASS_FunctionCall) {
+ fprintf(fp, "(%s *)(tmpPtr%u)", v->type()->name().c_str(), (uint) j);
+ } else if (pass == PASS_DebugPrint) {
+ fprintf(fp, "(%s *)(tmpPtr%u), *(unsigned int *)(ptr + %s)",
+ v->type()->name().c_str(), (uint) j,
+ varoffset.c_str());
+ }
+ varoffset += " + 4";
+ }
+ }
+ }
+ }
+
+ if (pass == PASS_FunctionCall || pass == PASS_DebugPrint) fprintf(fp, ");\n");
+ if (pass == PASS_DebugPrint) fprintf(fp, "#endif\n");
+
+ if (pass == PASS_Epilog) {
+ // send back out pointers data;
+ for (size_t j = 0; j < evars.size(); j++) {
+ Var *v = &evars[j];
+ if (v->isPointer() && (v->pointerDir() == Var::POINTER_OUT || v->pointerDir() == Var::POINTER_INOUT)) {
+ fprintf(fp, "\t\t\tstream->writeFully(tmpPtr%u, tmpPtr%uSize);\n", (uint) j, (uint) j);
+ if (v->pointerDir() == Var::POINTER_OUT) fprintf(fp, "delete tmpPtr%u;\n", (uint) j);
+ }
+ }
+ if (!e->retval().isVoid() && !e->retval().isPointer()) {
+ fprintf(fp, "\t\t\tstream->writeFully(&retval, sizeof(retval));\n");
+ }
+ fprintf(fp, "\t\t\tpos += *(int *)(ptr + 4);\n");
+ fprintf(fp, "\t\t\tptr += *(int *)(ptr + 4);\n");
+ }
+ } // pass;
+ fprintf(fp, "\t\t\t}\n");
+ fprintf(fp, "\t\t\tbreak;\n");
+ }
+ fprintf(fp, "\t\t\tdefault:\n");
+ fprintf(fp, "\t\t\t\tunknownOpcode = true;\n");
+ fprintf(fp, "\t\t} //switch\n");
+ fprintf(fp, "\t} // while\n");
+ fprintf(fp, "\treturn pos;\n");
+ fprintf(fp, "}\n");
+
+ fclose(fp);
+ return 0;
+}
+
+int ApiGen::readSpec(const std::string & filename)
+{
+ FILE *specfp = fopen(filename.c_str(), "rt");
+ if (specfp == NULL) {
+ return -1;
+ }
+
+ char line[1000];
+ unsigned int lc = 0;
+ while (fgets(line, sizeof(line), specfp) != NULL) {
+ lc++;
+ EntryPoint ref;
+ if (ref.parse(lc, std::string(line))) {
+ push_back(ref);
+ updateMaxEntryPointsParams(ref.vars().size());
+ }
+ }
+ fclose(specfp);
+ return 0;
+}
+
+int ApiGen::readAttributes(const std::string & attribFilename)
+{
+ enum { ST_NAME, ST_ATT } state;
+
+ FILE *fp = fopen(attribFilename.c_str(), "rt");
+ if (fp == NULL) {
+ perror(attribFilename.c_str());
+ return -1;
+ }
+ char buf[1000];
+
+ state = ST_NAME;
+ EntryPoint *currentEntry = NULL;
+ size_t lc = 0;
+ bool globalAttributes = false;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ lc++;
+ std::string line(buf);
+ if (line.size() == 0) continue; // could that happen?
+
+ if (line.at(0) == '#') continue; // comment
+
+ size_t first = line.find_first_not_of(" \t\n");
+ if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME;
+
+ line = trim(line);
+ if (line.size() == 0 || line.at(0) == '#') continue;
+
+ switch(state) {
+ case ST_NAME:
+ if (line == "GLOBAL") {
+ globalAttributes = true;
+ } else {
+ globalAttributes = false;
+ currentEntry = findEntryByName(line);
+ if (currentEntry == NULL) {
+ fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str());
+ }
+ }
+ state = ST_ATT;
+ break;
+ case ST_ATT:
+ if (globalAttributes) {
+ setGlobalAttribute(line, lc);
+ } else if (currentEntry != NULL) {
+ currentEntry->setAttribute(line, lc);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+
+int ApiGen::setGlobalAttribute(const std::string & line, size_t lc)
+{
+ size_t pos = 0;
+ size_t last;
+ std::string token = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+
+ if (token == "base_opcode") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ if (str.size() == 0) {
+ fprintf(stderr, "line %u: missing value for base_opcode\n", (uint) lc);
+ } else {
+ setBaseOpcode(atoi(str.c_str()));
+ }
+ } else if (token == "encoder_headers") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ while (str.size() != 0) {
+ encoderHeaders().push_back(str);
+ str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ }
+ } else if (token == "client_context_headers") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ while (str.size() != 0) {
+ clientContextHeaders().push_back(str);
+ str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ }
+ } else if (token == "server_context_headers") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ while (str.size() != 0) {
+ serverContextHeaders().push_back(str);
+ str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ }
+ } else if (token == "decoder_headers") {
+ std::string str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ while (str.size() != 0) {
+ decoderHeaders().push_back(str);
+ str = getNextToken(line, pos, &last, WHITESPACE);
+ pos = last;
+ }
+ }
+ else {
+ fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str());
+ }
+
+ return 0;
+}
+
diff --git a/emulator/opengl/host/tools/emugen/ApiGen.h b/emulator/opengl/host/tools/emugen/ApiGen.h
new file mode 100644
index 0000000..3c7fd27
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/ApiGen.h
@@ -0,0 +1,78 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __API_GEN_H_
+#define __API_GEN_H_
+
+#include <vector>
+#include <string.h>
+#include "EntryPoint.h"
+
+
+class ApiGen : public std::vector<EntryPoint> {
+
+public:
+ typedef std::vector<std::string> StringVec;
+ typedef enum { CLIENT_SIDE, SERVER_SIDE } SideType;
+
+ ApiGen(const std::string & basename) :
+ m_basename(basename),
+ m_maxEntryPointsParams(0),
+ m_baseOpcode(0)
+ { }
+ virtual ~ApiGen() {}
+ int readSpec(const std::string & filename);
+ int readAttributes(const std::string & attribFilename);
+ size_t maxEntryPointsParams() { return m_maxEntryPointsParams; }
+ void updateMaxEntryPointsParams(size_t val) {
+ if (m_maxEntryPointsParams == 0 || val > m_maxEntryPointsParams) m_maxEntryPointsParams = val;
+ }
+ int baseOpcode() { return m_baseOpcode; }
+ void setBaseOpcode(int base) { m_baseOpcode = base; }
+
+ const char *sideString(SideType side) { return (side == CLIENT_SIDE) ? "client" : "server"; }
+
+ StringVec & clientContextHeaders() { return m_clientContextHeaders; }
+ StringVec & encoderHeaders() { return m_encoderHeaders; }
+ StringVec & serverContextHeaders() { return m_serverContextHeaders; }
+ StringVec & decoderHeaders() { return m_decoderHeaders; }
+
+ EntryPoint * findEntryByName(const std::string & name);
+ int genOpcodes(const std::string &filename);
+ int genAttributesTemplate(const std::string &filename);
+ int genProcTypes(const std::string &filename, SideType side);
+
+ int genContext(const std::string &filename, SideType side);
+ int genClientEntryPoints(const std::string &filename);
+
+ int genEncoderHeader(const std::string &filename);
+ int genEncoderImpl(const std::string &filename);
+
+ int genDecoderHeader(const std::string &filename);
+ int genDecoderImpl(const std::string &filename);
+
+protected:
+ virtual void printHeader(FILE *fp) const;
+ std::string m_basename;
+ StringVec m_clientContextHeaders;
+ StringVec m_encoderHeaders;
+ StringVec m_serverContextHeaders;
+ StringVec m_decoderHeaders;
+ size_t m_maxEntryPointsParams; // record the maximum number of parameters in the entry points;
+ int m_baseOpcode;
+ int setGlobalAttribute(const std::string & line, size_t lc);
+};
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/EntryPoint.cpp b/emulator/opengl/host/tools/emugen/EntryPoint.cpp
new file mode 100644
index 0000000..d9b5499
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/EntryPoint.cpp
@@ -0,0 +1,335 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <stdio.h>
+#include "EntryPoint.h"
+#include <string>
+#include "TypeFactory.h"
+#include "strUtils.h"
+#include <sstream>
+
+
+EntryPoint::EntryPoint()
+{
+ reset();
+}
+
+EntryPoint::~EntryPoint()
+{
+}
+
+void EntryPoint::reset()
+{
+ m_unsupported = false;
+ m_customDecoder = false;
+ m_vars.empty();
+}
+
+bool parseTypeField(const std::string & f, std::string *vartype, bool *pointer_type, std::string *varname)
+{
+ size_t pos = 0, last;
+ bool done = false;
+
+
+ *vartype = "";
+ if (varname != NULL) *varname = "";
+ *pointer_type = false;
+
+ enum { ST_TYPE, ST_NAME, ST_END } state = ST_TYPE;
+
+ while(!done) {
+
+ std::string str = getNextToken(f, pos, &last, WHITESPACE);
+ if (str.size() == 0) break;
+
+ switch(state) {
+ case ST_TYPE:
+ if (str == "const") {
+ pos = last;
+ } else {
+ // must be a type name;
+ *vartype = str;
+ // do we have an astriks at the end of the name?
+ if (vartype->at(vartype->size() - 1) == '*') {
+ *pointer_type = true;
+ // remove the astriks
+ (*vartype)[vartype->size() - 1] = ' ';
+ *vartype = trim(*vartype);
+ }
+ state = ST_NAME;
+ pos = last;
+ }
+ break;
+ case ST_NAME:
+ if (str.size() == 0) {
+ done = true;
+ } else if (str == "*") {
+ *pointer_type = true;
+ // remove the leading astriks;
+ pos = last;
+ } else if (varname == NULL) {
+ done = true;
+ } else {
+ if (str[0] == '*') {
+ *pointer_type = true;
+ str[0] = ' ';
+ str = trim(str);
+ }
+ *varname = str;
+ done = true;
+ }
+ break;
+ case ST_END:
+ break;
+ }
+ }
+ return true;
+}
+
+// return true for valid line (need to get into the entry points list)
+bool EntryPoint::parse(unsigned int lc, const std::string & str)
+{
+ size_t pos, last;
+ std::string field;
+
+ reset();
+ std::string linestr = trim(str);
+
+ if (linestr.size() == 0) return false;
+ if (linestr.at(0) == '#') return false;
+
+ // skip PREFIX
+ field = getNextToken(linestr, 0, &last, "(");
+ pos = last + 1;
+ // return type
+ field = getNextToken(linestr, pos, &last, ",)");
+ std::string retTypeName;
+ bool pointer_type;
+ if (!parseTypeField(field, &retTypeName, &pointer_type, NULL)) {
+ fprintf(stderr, "line: %d: Parsing error in field <%s>\n", lc, field.c_str());
+ return false;
+ }
+ pos = last + 1;
+ const VarType *theType = TypeFactory::instance()->getVarTypeByName(retTypeName);
+ if (theType->name() == "UNKNOWN") {
+ fprintf(stderr, "UNKNOWN retval: %s\n", linestr.c_str());
+ }
+
+ m_retval.init(std::string(""), theType, pointer_type, std::string(""), Var::POINTER_OUT, std::string(""));
+
+ // function name
+ m_name = getNextToken(linestr, pos, &last, ",)");
+ pos = last + 1;
+
+ // parameters;
+ int nvars = 0;
+ while (pos < linestr.size() - 1) {
+ field = getNextToken(linestr, pos, &last, ",)");
+ std::string vartype, varname;
+ if (!parseTypeField(field, &vartype, &pointer_type, &varname)) {
+ fprintf(stderr, "line: %d: Parsing error in field <%s>\n", lc, field.c_str());
+ return false;
+ }
+ nvars++;
+ const VarType *v = TypeFactory::instance()->getVarTypeByName(vartype);
+ if (v->id() == 0) {
+ fprintf(stderr, "%d: Unknown type: %s\n", lc, vartype.c_str());
+ } else {
+ if (varname == "" &&
+ !(v->name() == "void" && !pointer_type)) {
+ std::ostringstream oss;
+ oss << "var" << nvars;
+ varname = oss.str();
+ }
+
+ m_vars.push_back(Var(varname, v, pointer_type, std::string(""), Var::POINTER_IN, ""));
+ }
+ pos = last + 1;
+ }
+ return true;
+}
+
+void EntryPoint::print(FILE *fp, bool newline,
+ const std::string & name_suffix,
+ const std::string & name_prefix,
+ const std::string & ctx_param ) const
+{
+ fprintf(fp, "%s%s %s%s%s(",
+ m_retval.type()->name().c_str(),
+ m_retval.isPointer() ? "*" : "",
+ name_prefix.c_str(),
+ m_name.c_str(),
+ name_suffix.c_str());
+
+ if (ctx_param != "") fprintf(fp, "%s ", ctx_param.c_str());
+
+ for (size_t i = 0; i < m_vars.size(); i++) {
+ if (m_vars[i].isVoid()) continue;
+ if (i != 0 || ctx_param != "") fprintf(fp, ", ");
+ fprintf(fp, "%s %s%s", m_vars[i].type()->name().c_str(),
+ m_vars[i].isPointer() ? "*" : "",
+ m_vars[i].name().c_str());
+ }
+ fprintf(fp, ")%s", newline? "\n" : "");
+}
+
+Var * EntryPoint::var(const std::string & name)
+{
+ Var *v = NULL;
+ for (size_t i = 0; i < m_vars.size(); i++) {
+ if (m_vars[i].name() == name) {
+ v = &m_vars[i];
+ break;
+ }
+ }
+ return v;
+}
+
+bool EntryPoint::hasPointers()
+{
+ bool pointers = false;
+ if (m_retval.isPointer()) pointers = true;
+ if (!pointers) {
+ for (size_t i = 0; i < m_vars.size(); i++) {
+ if (m_vars[i].isPointer()) {
+ pointers = true;
+ break;
+ }
+ }
+ }
+ return pointers;
+}
+
+int EntryPoint::setAttribute(const std::string &line, size_t lc)
+{
+ size_t pos = 0;
+ size_t last;
+ std::string token = getNextToken(line, 0, &last, WHITESPACE);
+
+ if (token == "len") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'len' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+ // set the size expression into var
+ pos = last;
+ v->setLenExpression(line.substr(pos));
+ } else if (token == "dir") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'dir' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+
+ pos = last;
+ std::string pointerDirStr = getNextToken(line, pos, &last, WHITESPACE);
+ if (pointerDirStr.size() == 0) {
+ fprintf(stderr, "ERROR: %u: missing pointer directions\n", (unsigned int)lc);
+ return -3;
+ }
+
+ if (pointerDirStr == "out") {
+ v->setPointerDir(Var::POINTER_OUT);
+ } else if (pointerDirStr == "inout") {
+ v->setPointerDir(Var::POINTER_INOUT);
+ } else if (pointerDirStr == "in") {
+ v->setPointerDir(Var::POINTER_IN);
+ } else {
+ fprintf(stderr, "ERROR: %u: unknow pointer direction %s\n", (unsigned int)lc, pointerDirStr.c_str());
+ }
+ } else if (token == "var_flag") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'var_flag' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+ pos = last;
+ std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+ if (flag.size() == 0) {
+ fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+ return -3;
+ }
+
+ if (flag == "nullAllowed") {
+ if (v->isPointer()) {
+ v->setNullAllowed(true);
+ } else {
+ fprintf(stderr, "WARNING: %u: setting nullAllowed for non-pointer variable %s\n",
+ (unsigned int) lc, v->name().c_str());
+ }
+ } else {
+ fprintf(stderr, "WARNING: %u: unknow flag %s\n", (unsigned int)lc, flag.c_str());
+ }
+ } else if (token == "custom_pack") {
+ pos = last;
+ std::string varname = getNextToken(line, pos, &last, WHITESPACE);
+
+ if (varname.size() == 0) {
+ fprintf(stderr, "ERROR: %u: Missing variable name in 'custom_pack' attribute\n", (unsigned int)lc);
+ return -1;
+ }
+ Var * v = var(varname);
+ if (v == NULL) {
+ fprintf(stderr, "ERROR: %u: variable %s is not a parameter of %s\n",
+ (unsigned int)lc, varname.c_str(), name().c_str());
+ return -2;
+ }
+ // set the size expression into var
+ pos = last;
+ v->setPackExpression(line.substr(pos));
+ } else if (token == "flag") {
+ pos = last;
+ std::string flag = getNextToken(line, pos, &last, WHITESPACE);
+ if (flag.size() == 0) {
+ fprintf(stderr, "ERROR: %u: missing flag\n", (unsigned int) lc);
+ return -4;
+ }
+
+ if (flag == "unsupported") {
+ setUnsupported(true);
+ } else if (flag == "custom_decoder") {
+ setCustomDecoder(true);
+ } else {
+ fprintf(stderr, "WARNING: %u: unknown flag %s\n", (unsigned int)lc, flag.c_str());
+ }
+ } else {
+ fprintf(stderr, "WARNING: %u: unknown attribute %s\n", (unsigned int)lc, token.c_str());
+ }
+
+ return 0;
+}
diff --git a/emulator/opengl/host/tools/emugen/EntryPoint.h b/emulator/opengl/host/tools/emugen/EntryPoint.h
new file mode 100644
index 0000000..c417bda
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/EntryPoint.h
@@ -0,0 +1,64 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __EntryPoint__H__
+#define __EntryPoint__H__
+
+#include <string>
+#include <vector>
+#include <stdio.h>
+
+#include "Var.h"
+
+//---------------------------------------------------
+
+typedef std::vector<Var> VarsArray;
+
+class EntryPoint {
+public:
+ EntryPoint();
+ virtual ~EntryPoint();
+ bool parse(unsigned int lc, const std::string & str);
+ void reset(); // reset the class to empty;
+ void print(FILE *fp = stdout, bool newline = true,
+ const std::string & name_suffix = std::string(""),
+ const std::string & name_prefix = std::string(""),
+ const std::string & ctx_param = std::string("")) const;
+ const std::string & name() const { return m_name; }
+ VarsArray & vars() { return m_vars; }
+ Var & retval() { return m_retval; }
+ Var * var(const std::string & name);
+ bool hasPointers();
+ bool unsupported() const { return m_unsupported; }
+ void setUnsupported(bool state) { m_unsupported = state; }
+ bool customDecoder() { return m_customDecoder; }
+ void setCustomDecoder(bool state) { m_customDecoder = state; }
+ int setAttribute(const std::string &line, size_t lc);
+
+private:
+ enum { PR_RETVAL = 0, PR_NAME, PR_VARS, PR_DONE } prState;
+ std::string m_name;
+ Var m_retval;
+ VarsArray m_vars;
+ bool m_unsupported;
+ bool m_customDecoder;
+
+ void err(unsigned int lc, const char *msg) {
+ fprintf(stderr, "line %d: %s\n", lc, msg);
+ }
+};
+
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/README b/emulator/opengl/host/tools/emugen/README
new file mode 100644
index 0000000..18c3edb
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/README
@@ -0,0 +1,292 @@
+Introduction:
+
+The emugen tool is a tool to generate a wire protocol implementation
+based on provided API. The tool generates c++ encoder code that takes
+API calls and encodes them into the wire and decoder code that decodes
+the wire stream and calls server matching API.
+
+The following paragraphs includes the following:
+ * Wire Protocol Description
+ * Input files description & format
+ * Generated code description.
+
+
+Note: In this document, the caller is referred to as Encoder or Client
+and the callee is referred to as the Decoder or Server. These terms
+are used interchangeably by the context.
+
+
+
+Wire Protocol packet structure:
+
+A general Encoder->Decoder packet is structured as following:
+struct Packet {
+ unsigned int opcode;
+ unsigned int packet_len;
+ … parameter 1
+ … parameter 2
+};
+A general Decoder->Encoder reply is expected to be received in the
+context of the ‘call’ that triggered it, thus it includes the reply
+data only, with no context headers. In precise term terms, a reply
+packet will look like:
+
+struct {
+ ...// reply data
+};
+
+consider the following function call:
+int foo(int p1, short s1)
+will be encoded into :
+{
+ 101, // foo opcode
+ 14, // sizeof(opcode) + sizeof(packet_len) + sizeof(int) + sizeof(short)
+ p1, // 4 bytes
+ s1 // 4 bytes
+}
+
+Since ‘foo’ returns value, the caller is expected to read back the return packet from the server->client stream. The return value in this example is in thus the return packet is:
+{
+ int retval;
+}
+
+
+Pointer decoding:
+
+The wire protocol also allows exchanging of pointer data
+(arrays). Pointers are defined with directions:
+
+ in : Data is sent from the caller to the calle
+ out: Data is sent from the callee to the caller
+ in_out: data is sent from the caller and return in place.
+
+‘in’ and ‘in_out’ encoded with their len:
+{
+ unsinged int pointer_data_len;
+ unsigned char data[pointer_data_len];… // pointer data
+}
+
+‘out’ pointers are encoded by data length only:
+{
+unsigned int pointer_data_len;
+}
+
+‘out’ and ‘in_out’ pointer’s data is returned in the return
+packet. For example, consider the following call:
+
+int foo(int n, int *ptr); // assume that ‘data’ is in_out pointer which contains ‘n’ ints
+
+The caller packet will have the following form:
+{
+ 101, // foo opcode
+ xx, sizeof(opcode) + sizeof(datalen) + sizeof(int) + sizeof(unsigned int) + n * sizeof(int);
+ n, // the n parameter
+ n * sizeof(int), // size of the data in ptr
+ … // n* sizeof(int) bytes
+}
+
+The return packet is;
+{
+ …. // n * sizeof(int) bytes of data return in ptr
+ retval // sizeof(int) - the return value of the function;
+}
+
+Endianess
+
+The Wire protocol is designed to impose minimum overhead on the client
+side. Thus, the data endianness that is sent across the wire is
+determined by the ‘client’ side. It is up to the server side to
+determine the client endianess and marshal the packets as required.
+
+
+
+Emugen input files - protocol specification
+
+The protocol generated by emugen consists of two input files:
+
+1. basename.in - A sepcification of the protocol RPC procedures. This
+part of the specification is expected to be generated automatically
+from c/c++ header files or similar.
+
+‘basename’ is the basename for the protocol and will be used to prefix
+the files that are generated for this protocol. A line in the .in
+file has the following format:
+
+[prefix](retvalType, FuncName, <param type> [param name],...)
+where
+ retvalType - The function return value type
+ FuncName - function name
+ <param type> mandatory parameter type
+ [param name] - optional parameter name
+Examples:
+GL_ENTRY(void, glVertex1f, float v)
+XXX(int *, foo, int n, float, short)
+XXX(void, glFlush, void)
+
+Note: Empty lines in the file are ignored. A line starts with # is a comment
+
+2. basename.attrib - Attributes information of the API.
+This file includes additional flags, pointers datalen information and
+global attributes of the protocol. For uptodate format of the file,
+please refer to the specification file in the project source
+tree. The format of the .attrib file is described below.
+
+3. basename.types - Types information
+
+This files describes the types that are described by the API. A type
+is defined as follows:
+<type name> <size in bits> <print format string>
+where:
+<type name> is the name of the type as described in the API
+<size in bits> 0, 8, 16, 32 sizes are accepted
+<print format string> a string to format the value of the type, as acceted by printf(3)
+
+example:
+GLint 32 %d
+
+Encoder generated code files
+
+In order to generate the encoder files, one should run the ‘emugen’
+tool as follows:
+
+emugen -i <input directory> -E <encoder files output directory> <basename>
+where:
+ <input directory> containes the api specification files (basename.in + basename.attrib)
+ <encoder directory> - a directory name to generate the encoder output files
+ basename - The basename for the api.
+
+Assuming the basename is ‘api’, The following files are generated:
+
+api_opcodes.h - defines the protocol opcodes. The first opcode value
+is 0, unless defined otherwise in the .attrib file
+
+api_entry.cpp - defines entry points for the functions that are
+defined by the protocol. this File also includes a function call
+‘setContextAccessor(void *(*f)()). This function should be used to
+provide a callback function that is used by the functions to access
+the encoder context. For example, such callback could fetch the
+context from a Thread Local Storage (TLS) location.
+
+api_client_proc.h - type defintions for the protocol procedures.
+
+api_client_context.h - defines the client side dispatch table data
+structure that stores the encoding functions. This data structure also
+includes ‘accessors’ methods such that library user can override
+default entries for special case handling.
+
+api_enc.h - This header file defines the encoder data strcuture. The
+encoder data structure inherits its functionality from the
+‘client_context’ class above and adds encoding and streaming
+functionality.
+
+api_enc.cpp - Encoder implementation.
+
+5.1.2.2 Decoder generated files
+In order to generate the decoder files, one should run the ‘emugen’
+tool as follows:
+emugen -i <input directory> -D <decoder files output directory> basename
+where:
+ <input directory> containes the api specification files (basename.in + basename.attrib)
+ <decoder directory> - a directory name to generate the decoder output files
+ basename - The basename for the api.
+
+With resepct to the example above, Emugen will generate the following
+files:
+
+api_opcodes.h - Protocol opcodes
+
+api_server_proc.h - type definitions for the server side procedures
+
+api_server_context.h - dispatch table the encoder functions
+
+api_dec.h - Decoder header file
+
+api_dec.cpp - Decoder implementation. In addtion, this file includes
+an intiailization function that uses a user provided callback to
+initialize the API server implementation. An example for such
+initialization is loading a set of functions from a shared library
+module.
+
+.attrib file format description:
+
+The .attrib file is an input file to emugen and is used to provide
+ additional information that is required for the code generation.
+The file format is as follows:
+
+a line that starts with # is ignored (comment)
+a empty line just whitespace of (" " "\t" "\n") is ignored.
+
+The file is divided into 'sections', each describes a specific API
+function call. A section starts with the name of the function in
+column 0.
+
+A section that starts with the reserved word 'GLOBAL' provides global
+attributes.
+
+below are few sections examples:
+
+GLOBAL
+ encoder_headers string.h kuku.h
+
+glVertex3fv
+ len data (size)
+glTexImage2D
+ len pixels (pixels == NULL? 0 : (format_pixel_size(internalformat) * width * height * type_size(type)))
+
+
+Global section flags description:
+
+base_opcode
+ set the base opcode value for this api
+ format: base_opcode 100
+
+encoder_headers
+ a list of headers that will be included in the encoder header file
+ format: encoder_headers <stdio.h> "kuku.h"
+
+client_context_headers
+ a list of headers that will be included in the client context header file
+ format: client_context_headers <stdio.h> "kuku.h"
+
+decoder_headers
+ a list of headers that will be included in the decoder header file
+ format: decoder_headers <stdio.h> "kuku.h"
+
+server_context_headers
+ a list of headers that will be included in the server context header file
+ format: server_context_headers <stdio.h> "kuku.h"
+
+
+Entry point flags description:
+
+ len
+ desciption : provide an expression to calcualte an expression data len
+ format: len <var name> <c expression that calcluates the data len>
+
+custom_pack
+ description: provide an expression to pack data into the stream.
+ format: custom_pack <var name> <c++ expression that pack data from var into the stream>
+ The stream is represented by a (unsigned char *)ptr. The expression may also refer
+ to other function parameters. In addition, the expression may refer to 'void *self' which
+ is the encoding context as provided by the caller.
+
+ dir
+ description : set a pointer direction (in - for data that goes
+ to the codec, out from data that returns from the codec.
+ format: dir <varname> <[in | out | inout]>
+
+ var_flag
+ description : set variable flags
+ format: var_flag <varname> < nullAllowed | ... >
+
+ flag
+ description: set entry point flag;
+ format: flag < unsupported | ... >
+ supported flags are:
+ unsupported - The encoder side implementation is pointed to "unsuppored reporting function".
+ custom_decoder - The decoder is expected to be provided with
+ custom implementation. The call to the
+ deocder function includes a pointer to the
+ context
+
+
diff --git a/emulator/opengl/host/tools/emugen/TypeFactory.cpp b/emulator/opengl/host/tools/emugen/TypeFactory.cpp
new file mode 100644
index 0000000..709807e
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/TypeFactory.cpp
@@ -0,0 +1,135 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "TypeFactory.h"
+#include "VarType.h"
+#include <string>
+#include <map>
+#include <stdio.h>
+#include <stdlib.h>
+#include "strUtils.h"
+
+
+TypeFactory * TypeFactory::m_instance = NULL;
+
+static Var0 g_var0;
+static Var8 g_var8;
+static Var16 g_var16;
+static Var32 g_var32;
+
+typedef std::map<std::string, VarType> TypeMap;
+static TypeMap g_varMap;
+static bool g_initialized = false;
+static int g_typeId = 0;
+
+
+static VarConverter * getVarConverter(int size)
+{
+ VarConverter *v = NULL;
+
+ switch(size) {
+ case 0: v = &g_var0; break;
+ case 8: v = &g_var8; break;
+ case 16: v = &g_var16; break;
+ case 32: v = &g_var32; break;
+ }
+ return v;
+}
+
+#define ADD_TYPE(name, size, printformat) \
+ g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, &g_var##size,printformat)));
+
+void TypeFactory::initBaseTypes()
+{
+ g_initialized = true;
+ ADD_TYPE("UNKNOWN", 0, "0x%x");
+ ADD_TYPE("void", 0, "0x%x");
+ ADD_TYPE("char", 8, "%c");
+ ADD_TYPE("int", 32, "%d");
+ ADD_TYPE("float", 32, "%d");
+ ADD_TYPE("short", 16, "%d");
+}
+
+int TypeFactory::initFromFile(const std::string &filename)
+{
+ if (!g_initialized) {
+ initBaseTypes();
+ }
+
+ FILE *fp = fopen(filename.c_str(), "rt");
+ if (fp == NULL) {
+ perror(filename.c_str());
+ return -1;
+ }
+ char line[1000];
+ int lc = 0;
+ while(fgets(line, sizeof(line), fp) != NULL) {
+ lc++;
+ std::string str = trim(line);
+ if (str.size() == 0 || str.at(0) == '#') {
+ continue;
+ }
+ size_t pos = 0, last;
+ std::string name;
+ name = getNextToken(str, pos, &last, WHITESPACE);
+ if (name.size() == 0) {
+ fprintf(stderr, "Error: %d : missing type name\n", lc);
+ return -2;
+ }
+ pos = last + 1;
+ std::string size;
+ size = getNextToken(str, pos, &last, WHITESPACE);
+ if (size.size() == 0) {
+ fprintf(stderr, "Error: %d : missing type width\n", lc);
+ return -2;
+ }
+ pos = last + 1;
+ std::string printString;
+ printString = getNextToken(str, pos, &last, WHITESPACE);
+ if (printString.size() == 0) {
+ fprintf(stderr, "Error: %d : missing print-string\n", lc);
+ return -2;
+ }
+
+ VarConverter *v = getVarConverter(atoi(size.c_str()));
+ if (v == NULL) {
+ fprintf(stderr, "Error: %d : unknown var width: %d\n", lc, atoi(size.c_str()));
+ return -1;
+ }
+
+ if (getVarTypeByName(name)->id() != 0) {
+ fprintf(stderr,
+ "Warining: %d : type %s is already known, definition in line %d is taken\n",
+ lc, name.c_str(), lc);
+ }
+ g_varMap.insert(std::pair<std::string, VarType>(name, VarType(g_typeId++, name, v ,printString)));
+ }
+ g_initialized = true;
+ return 0;
+}
+
+
+const VarType * TypeFactory::getVarTypeByName(const std::string & type)
+{
+ if (!g_initialized) {
+ initBaseTypes();
+ }
+ TypeMap::iterator i = g_varMap.find(type);
+ if (i == g_varMap.end()) {
+ i = g_varMap.find("UNKNOWN");
+ }
+ return &(i->second);
+}
+
diff --git a/emulator/opengl/host/tools/emugen/TypeFactory.h b/emulator/opengl/host/tools/emugen/TypeFactory.h
new file mode 100644
index 0000000..deee2ca
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/TypeFactory.h
@@ -0,0 +1,37 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __TYPE__FACTORY__H__
+#define __TYPE__FACTORY__H__
+
+#include <string>
+#include "VarType.h"
+
+class TypeFactory {
+public:
+ static TypeFactory *instance() {
+ if (m_instance == NULL) {
+ m_instance = new TypeFactory;
+ }
+ return m_instance;
+ }
+ const VarType * getVarTypeByName(const std::string &type);
+ int initFromFile(const std::string &filename);
+private:
+ static TypeFactory *m_instance;
+ void initBaseTypes();
+ TypeFactory() {}
+};
+#endif
diff --git a/emulator/opengl/host/tools/emugen/Var.h b/emulator/opengl/host/tools/emugen/Var.h
new file mode 100644
index 0000000..ef9f7c2
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/Var.h
@@ -0,0 +1,94 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __VAR__H__
+#define __VAR__H__
+
+#include "VarType.h"
+#include <string>
+#include <stdio.h>
+
+class Var {
+public:
+ // pointer data direction - from the client point of view.
+ typedef enum { POINTER_OUT = 0x1, POINTER_IN = 0x2, POINTER_INOUT = 0x3 } PointerDir;
+ Var() :
+ m_name(""),
+ m_type(NULL),
+ m_pointer(false),
+ m_lenExpression(""),
+ m_pointerDir(POINTER_IN),
+ m_nullAllowed(false),
+ m_packExpression("")
+
+ {
+ }
+
+ Var(const std::string & name,
+ const VarType * vartype,
+ bool isPointer,
+ const std::string & lenExpression,
+ PointerDir dir,
+ const std::string &packExpression) :
+ m_name(name),
+ m_type(const_cast<VarType *>(vartype)),
+ m_pointer(isPointer),
+ m_lenExpression(lenExpression),
+ m_pointerDir(dir),
+ m_nullAllowed(false),
+ m_packExpression(packExpression)
+ {
+ }
+
+ void init(const std::string name, const VarType * vartype,
+ bool isPointer, std::string lenExpression,
+ PointerDir dir, std::string packExpression) {
+ m_name = name;
+ m_type = vartype;
+ m_pointer = isPointer;
+ m_lenExpression = lenExpression;
+ m_packExpression = packExpression;
+ m_pointerDir = dir;
+ m_nullAllowed = false;
+
+ }
+
+ const std::string & name() const { return m_name; }
+ const VarType * type() const { return m_type; }
+ bool isPointer() const { return m_pointer; }
+ bool isVoid() const { return ((m_type->bytes() == 0) && (m_pointer == false)); }
+ const std::string & lenExpression() const { return m_lenExpression; }
+ const std::string & packExpression() const { return(m_packExpression); }
+ void setLenExpression(const std::string & lenExpression) { m_lenExpression = lenExpression; }
+ void setPackExpression(const std::string & packExpression) { m_packExpression = packExpression; }
+ void setPointerDir(PointerDir dir) { m_pointerDir = dir; }
+ PointerDir pointerDir() { return m_pointerDir; }
+ void setNullAllowed(bool state) { m_nullAllowed = state; }
+ bool nullAllowed() const { return m_nullAllowed; }
+ void printType(FILE *fp) { fprintf(fp, "%s%s", m_type->name().c_str(), m_pointer ? "*" : ""); }
+ void printTypeName(FILE *fp) { printType(fp); fprintf(fp, " %s", m_name.c_str()); }
+
+private:
+ std::string m_name;
+ const VarType * m_type;
+ bool m_pointer; // is this variable a pointer;
+ std::string m_lenExpression; // an expression to calcualte a pointer data size
+ PointerDir m_pointerDir;
+ bool m_nullAllowed;
+ std::string m_packExpression; // an expression to pack data into the stream
+
+};
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/VarType.h b/emulator/opengl/host/tools/emugen/VarType.h
new file mode 100644
index 0000000..a0718bb
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/VarType.h
@@ -0,0 +1,76 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef __VARTYPE__H__
+#define __VARTYPE__H__
+
+#include <string>
+
+class VarConverter {
+public:
+ VarConverter(size_t bytes) : m_bytes(bytes) {}
+ size_t bytes() const { return m_bytes; }
+private:
+ size_t m_bytes;
+};
+
+class Var8 : public VarConverter {
+public:
+ Var8() : VarConverter(1) {}
+};
+
+class Var16 : public VarConverter {
+public:
+ Var16() : VarConverter(2) {}
+};
+
+class Var32 : public VarConverter {
+public:
+ Var32() : VarConverter(4) {}
+};
+
+class Var0 : public VarConverter {
+public:
+ Var0() : VarConverter(0) {}
+};
+
+
+class VarType {
+public:
+ VarType() :
+ m_id(0), m_name("default_constructed"), m_converter(NULL), m_printFomrat("0x%x")
+ {
+ }
+
+ VarType(size_t id, const std::string & name, const VarConverter * converter, const std::string & printFormat ) :
+ m_id(id), m_name(name), m_converter(const_cast<VarConverter *>(converter)), m_printFomrat(printFormat)
+ {
+ }
+
+ ~VarType()
+ {
+ }
+ const std::string & name() const { return m_name; }
+ const std::string & printFormat() const { return m_printFomrat; }
+ size_t bytes() const { return m_converter->bytes(); }
+ size_t id() const { return m_id; }
+private:
+ size_t m_id;
+ std::string m_name;
+ VarConverter * m_converter;
+ std::string m_printFomrat;
+};
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/errors.h b/emulator/opengl/host/tools/emugen/errors.h
new file mode 100644
index 0000000..d09c292
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/errors.h
@@ -0,0 +1,24 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef _ERRORS_H_
+#define _ERRORS_H_
+
+#define BAD_USAGE -1
+#define BAD_SPEC_FILE -2
+#define BAD_TYPES_FILE -3
+#define BAD_ATTRIBUTES_FILE -4
+
+#endif
diff --git a/emulator/opengl/host/tools/emugen/main.cpp b/emulator/opengl/host/tools/emugen/main.cpp
new file mode 100644
index 0000000..aefba0a
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/main.cpp
@@ -0,0 +1,147 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include "errors.h"
+#include "EntryPoint.h"
+#include "strUtils.h"
+#include "ApiGen.h"
+#include "TypeFactory.h"
+
+const std::string SPEC_EXTENSION = std::string(".in");
+const std::string ATTRIB_EXTENSION = std::string(".attrib");
+const std::string TYPES_EXTENTION = std::string(".types");
+
+
+void usage(const char *filename)
+{
+ fprintf(stderr, "Usage: %s [options] <base name>\n", filename);
+ fprintf(stderr, "\t-h: This message\n");
+ fprintf(stderr, "\t-E <dir>: generate encoder into dir\n");
+ fprintf(stderr, "\t-D <dir>: generate decoder into dir\n");
+ fprintf(stderr, "\t-i: input dir, local directory by default\n");
+ fprintf(stderr, "\t-T : generate attribute template into the input directory\n\t\tno other files are generated\n");
+}
+
+int main(int argc, char *argv[])
+{
+ std::string encoderDir = "";
+ std::string decoderDir = "";
+ std::string inDir = ".";
+ bool generateAttributesTemplate = false;
+
+ int c;
+ while((c = getopt(argc, argv, "TE:D:i:h")) != -1) {
+ switch(c) {
+ case 'T':
+ generateAttributesTemplate = true;
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ case 'E':
+ encoderDir = std::string(optarg);
+ break;
+ case 'D':
+ decoderDir = std::string(optarg);
+ break;
+ case 'i':
+ inDir = std::string(optarg);
+ break;
+ case ':':
+ fprintf(stderr, "Missing argument !!\n");
+ // fall through
+ default:
+ usage(argv[0]);
+ exit(0);
+ }
+ }
+
+ if (optind >= argc) {
+ fprintf(stderr, "Usage: %s [options] <base name> \n", argv[0]);
+ return BAD_USAGE;
+ }
+
+ if (encoderDir.size() == 0 && decoderDir.size() == 0 && generateAttributesTemplate == false) {
+ fprintf(stderr, "No output specified - aborting\n");
+ return BAD_USAGE;
+ }
+
+ std::string baseName = std::string(argv[optind]);
+ ApiGen apiEntries(baseName);
+
+ // init types;
+ std::string typesFilename = inDir + "/" + baseName + TYPES_EXTENTION;
+
+ if (TypeFactory::instance()->initFromFile(typesFilename) < 0) {
+ fprintf(stderr, "missing or error reading types file: %s...ignored\n", typesFilename.c_str());
+ }
+
+ std::string filename = inDir + "/" + baseName + SPEC_EXTENSION;
+ if (apiEntries.readSpec(filename) < 0) {
+ perror(filename.c_str());
+ return BAD_SPEC_FILE;
+ }
+
+
+ if (generateAttributesTemplate) {
+ apiEntries.genAttributesTemplate(inDir + "/" + baseName + ATTRIB_EXTENSION);
+ exit(0);
+ }
+
+ std::string attribFileName = inDir + "/" + baseName + ATTRIB_EXTENSION;
+ if (apiEntries.readAttributes(attribFileName) < 0) {
+ perror(attribFileName.c_str());
+ fprintf(stderr, "failed to parse attributes\n");
+ exit(1);
+ }
+
+ if (encoderDir.size() != 0) {
+
+ apiEntries.genOpcodes(encoderDir + "/" + baseName + "_opcodes.h");
+ apiEntries.genContext(encoderDir + "/" + baseName + "_client_context.h", ApiGen::CLIENT_SIDE);
+ apiEntries.genProcTypes(encoderDir + "/" + baseName + "_client_proc.h", ApiGen::CLIENT_SIDE);
+
+ apiEntries.genClientEntryPoints(encoderDir + "/" + baseName + "_entry.cpp");
+ apiEntries.genEncoderHeader(encoderDir + "/" + baseName + "_enc.h");
+ apiEntries.genEncoderImpl(encoderDir + "/" + baseName + "_enc.cpp");
+ }
+
+ if (decoderDir.size() != 0) {
+ //apiEntries.genEntryPoints(decoderDir + "/" + baseName + "_entry.cpp", baseName);
+ apiEntries.genOpcodes(decoderDir + "/" + baseName + "_opcodes.h");
+ apiEntries.genProcTypes(decoderDir + "/" + baseName + "_server_proc.h", ApiGen::SERVER_SIDE);
+ apiEntries.genContext(decoderDir + "/" + baseName + "_server_context.h", ApiGen::SERVER_SIDE);
+ apiEntries.genDecoderHeader(decoderDir + "/" + baseName + "_dec.h");
+ apiEntries.genDecoderImpl(decoderDir + "/" + baseName + "_dec.cpp");
+ // generate the encoder type;
+
+ }
+#ifdef DEBUG_DUMP
+ int withPointers = 0;
+ printf("%d functions found\n", int(apiEntries.size()));
+ for (int i = 0; i < apiEntries.size(); i++) {
+ if (apiEntries[i].hasPointers()) {
+ withPointers++;
+ apiEntries[i].print();
+ }
+ }
+ fprintf(stdout, "%d entries has poitners\n", withPointers);
+#endif
+
+}
+
diff --git a/emulator/opengl/host/tools/emugen/strUtils.cpp b/emulator/opengl/host/tools/emugen/strUtils.cpp
new file mode 100644
index 0000000..357054b
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/strUtils.cpp
@@ -0,0 +1,49 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#include "strUtils.h"
+
+using namespace std;
+
+
+std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim)
+{
+ if (str.size() == 0 || pos >= str.size()) return "";
+
+ pos = str.find_first_not_of(WHITESPACE, pos);
+ if (pos == std::string::npos) return "";
+
+ *last = str.find_first_of(delim, pos);
+ if (*last == std::string::npos) *last = str.size();
+ std::string retval = str.substr(pos, *last - pos);
+ retval = trim(retval);
+ return retval;
+}
+
+
+std::string trim(const string & str)
+{
+ string result;
+ string::size_type start = str.find_first_not_of(WHITESPACE, 0);
+ string::size_type end = str.find_last_not_of(WHITESPACE);
+ if (start == string::npos || end == string::npos) {
+ result = string("");
+ } else {
+ result = str.substr(start, end - start + 1);
+ }
+ return result;
+}
+
+
diff --git a/emulator/opengl/host/tools/emugen/strUtils.h b/emulator/opengl/host/tools/emugen/strUtils.h
new file mode 100644
index 0000000..3fa0908
--- /dev/null
+++ b/emulator/opengl/host/tools/emugen/strUtils.h
@@ -0,0 +1,33 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+#ifndef STR_UTILS_H_
+#define STR_UTILS_H_
+
+#include <string>
+#include <sstream>
+
+#define WHITESPACE " \t\n"
+
+std::string trim(const std::string & str);
+std::string getNextToken(const std::string & str, size_t pos, size_t * last, const std::string & delim);
+template <class T> std::string inline toString(const T& t) {
+ std::stringstream ss;
+ ss << t;
+ return ss.str();
+
+}
+
+#endif