Files
android_development/tools/emulator/opengl/host/tools/emugen/ApiGen.cpp
Jacky Romano ea3a3584f5 emugen: generate wrapper library files
Add functionality to generate a wrapper library. A wrapper library includes:
1. entry points
2. dispatch table (accessed from the library entry points)
3. dispatch table accessor callback
4. dispatch table initialization function

Note that the dispatch table initialization function used to be part of the decoder. This
change moves it to be part of the dispatch table layer where it belongs.

Change-Id: Ide6764a17cc029056f9946e778a513cdc2a49003
2011-05-03 14:40:52 +02:00

834 lines
30 KiB
C++

/*
* 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 || side == WRAPPER_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");
}
// init function
fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n");
fprintf(fp, "};\n");
fprintf(fp, "\n#endif\n");
fclose(fp);
return 0;
}
int ApiGen::genEntryPoints(const std::string & filename, SideType side)
{
if (side != CLIENT_SIDE && side != WRAPPER_SIDE) {
fprintf(stderr, "Entry points are only defined for Client and Wrapper components\n");
return -999;
}
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(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(side));
fprintf(fp,
"void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n\n",
m_basename.c_str(), sideString(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(side));
bool shouldReturn = !e->retval().isVoid();
bool shouldCallWithContext = (side == CLIENT_SIDE);
fprintf(fp, "\t %sctx->%s(%s",
shouldReturn ? "return " : "",
e->name().c_str(),
shouldCallWithContext ? "ctx" : "");
size_t nvars = e->vars().size();
for (size_t j = 0; j < nvars; j++) {
if (!e->vars()[j].isVoid()) {
fprintf(fp, "%s %s",
j != 0 || shouldCallWithContext ? "," : "",
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, "\n};\n\n");
fprintf(fp, "#endif");
fclose(fp);
return 0;
}
int ApiGen::genContextImpl(const std::string &filename, SideType side)
{
FILE *fp = fopen(filename.c_str(), "wt");
if (fp == NULL) {
perror(filename.c_str());
return -1;
}
printHeader(fp);
std::string classname = m_basename + "_" + sideString(side) + "_context_t";
size_t n = size();
fprintf(fp, "\n\n#include <string.h>\n");
fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(side));
fprintf(fp, "#include <stdio.h>\n\n");
// init function;
fprintf(fp, "int %s::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)\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\", userData); 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");
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\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_TmpBuffAlloc = 0, PASS_MemAlloc, 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");
bool totalTmpBuffExist = false;
std::string totalTmpBuffOffset = "0";
std::string *tmpBufOffset = new std::string[e->vars().size()];
// construct retval type string
std::string retvalType;
if (!e->retval().isVoid()) {
retvalType = e->retval().type()->name();
}
for (int pass = PASS_TmpBuffAlloc; pass < PASS_LAST; pass++) {
if (pass == PASS_FunctionCall && !e->retval().isVoid() && !e->retval().isPointer()) {
fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(),
totalTmpBuffOffset.c_str());
}
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 { // out pointer;
if (pass == PASS_TmpBuffAlloc) {
fprintf(fp, "\t\t\tsize_t tmpPtr%uSize = (size_t)*(unsigned int *)(ptr + %s);\n",
(uint) j, varoffset.c_str());
if (!totalTmpBuffExist)
fprintf(fp, "\t\t\tsize_t totalTmpSize = tmpPtr%uSize;\n", (uint)j);
else
fprintf(fp, "\t\t\ttotalTmpSize += tmpPtr%uSize;\n", (uint)j);
tmpBufOffset[j] = totalTmpBuffOffset;
char tmpPtrName[16];
sprintf(tmpPtrName," + tmpPtr%uSize", (uint)j);
totalTmpBuffOffset += std::string(tmpPtrName);
totalTmpBuffExist = true;
} else if (pass == PASS_MemAlloc) {
fprintf(fp, "\t\t\tunsigned char *tmpPtr%u = &tmpBuf[%s];\n",
(uint)j, tmpBufOffset[j].c_str());
} 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_TmpBuffAlloc) {
if (!e->retval().isVoid() && !e->retval().isPointer()) {
if (!totalTmpBuffExist)
fprintf(fp, "\t\t\tsize_t totalTmpSize = sizeof(%s);\n", retvalType.c_str());
else
fprintf(fp, "\t\t\ttotalTmpSize += sizeof(%s);\n", retvalType.c_str());
totalTmpBuffExist = true;
}
if (totalTmpBuffExist) {
fprintf(fp, "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
}
}
if (pass == PASS_Epilog) {
// send back out pointers data as well as retval
if (totalTmpBuffExist) {
fprintf(fp, "\t\t\tstream->flush();\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");
delete [] tmpBufOffset;
}
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;
}