diff options
author | takeshi_hoshina <takeshi_hoshina@mail.toyota.co.jp> | 2020-10-27 11:16:21 +0900 |
---|---|---|
committer | takeshi_hoshina <takeshi_hoshina@mail.toyota.co.jp> | 2020-10-27 11:16:21 +0900 |
commit | 947c78887e791596d4a5ec2d1079f8b1a049628b (patch) | |
tree | 3981e88eb8764d7180722f8466f36b756dc005af /otherservice/rpc_library/tool | |
parent | 706ad73eb02caf8532deaf5d38995bd258725cb8 (diff) |
basesystem 0.1sandbox/ToshikazuOhiwa/basesystem
Diffstat (limited to 'otherservice/rpc_library/tool')
-rw-r--r-- | otherservice/rpc_library/tool/Makefile | 62 | ||||
-rw-r--r-- | otherservice/rpc_library/tool/apidef.cc | 1104 | ||||
-rw-r--r-- | otherservice/rpc_library/tool/apidef.h | 333 | ||||
-rw-r--r-- | otherservice/rpc_library/tool/apidef.l | 136 | ||||
-rw-r--r-- | otherservice/rpc_library/tool/apidef.y | 615 |
5 files changed, 2250 insertions, 0 deletions
diff --git a/otherservice/rpc_library/tool/Makefile b/otherservice/rpc_library/tool/Makefile new file mode 100644 index 00000000..d4d09637 --- /dev/null +++ b/otherservice/rpc_library/tool/Makefile @@ -0,0 +1,62 @@ +# +# @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION. +# +# 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. +# + +all: rpc_apidef + +clean: + rm -rf $(CLEAN_FILES) + +YACC := bison +YFLAGS := -d -t +LEX := flex +LFLAGS := -d + +CPPFLAGS := -I../library/include -include $(SDKTARGETSYSROOT)/usr/agl/include/agl_types_obsoluted.h +CFLAGS := -Wall -Wno-unused-function -Wno-unused-variable -include $(SDKTARGETSYSROOT)/usr/agl/include/agl_types_obsoluted.h + +rpc_apidef: apidef.tab.o lex.yy.o apidef.o + $(CXX) $(CPPFLAGS) -o $@ $^ + +apidef.tab.o: apidef.tab.h apidef.tab.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $^ + +lex.yy.o: lex.yy.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $^ + +apidef.o: apidef.cc + $(CXX) $(CPPFLAGS) $(CFLAGS) -c $^ + +apidef.tab.h apidef.tab.c: apidef.y + $(YACC) $(YFLAGS) $< + +lex.yy.c: apidef.l apidef.tab.h + $(LEX) $(LFLAGS) $< + +CLEAN_FILES := rpc_apidef *.o apidef.tab.h apidef.tab.c lex.yy.c + +CLEAN_TARGET := clean-all clean-all-sub clean-sub +INSTALL_TARGET := install-header +EMPTY_TARGET := install-prog install-data install-lib install-arlib install-shlib +.PHONY: all install clean $(CLEAN_TARGET) $(INSTALL_TARGET) $(EMPTY_TARGET) + +$(CLEAN_TARGET): clean + +$(INSTALL_TARGET): install + +$(EMPTY_TARGET): + +include ../../other_service.mk + diff --git a/otherservice/rpc_library/tool/apidef.cc b/otherservice/rpc_library/tool/apidef.cc new file mode 100644 index 00000000..5a5df1c2 --- /dev/null +++ b/otherservice/rpc_library/tool/apidef.cc @@ -0,0 +1,1104 @@ +/* + * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION. + * + * 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. + */ + +/** + * @file apidef.cc + * @brief RPC tools--Main processing(Implementations of APIDef classes) + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netinet/in.h> + +#include <other_service/rpc.h> + +#include "apidef.h" +#include "apidef.tab.h" + +static APIDef *API_Def; + +extern "C" { // C interface functions + +void +ApidefDefineId(const char *id) { + if (id != NULL) { + if (API_Def == NULL) { + API_Def = new APIDef(); + } + API_Def->DefineId(id); + } +} + +void +ApidefAddHeader(const char *filename) { + if (filename != NULL) { + if (API_Def == NULL) { + API_Def = new APIDef(); + } + API_Def->AddHeader(filename); + } +} + +int +ApidefPushFunctionArg(int arg_code, int buffer_bytes, int is_pointer, + int is_vararray, int is_array_size, + const char *var_type_name, int in_out, + const char *var_name) { + if (API_Def == NULL) { + API_Def = new APIDef(); + } + return API_Def->AddFunctionArg(arg_code, buffer_bytes, is_pointer, + is_vararray, is_array_size, + var_type_name, in_out, var_name); +} + +void +ApidefProcessFunction(const char *name) { + if (API_Def == NULL) { + API_Def = new APIDef(); + } + API_Def->NameFunction(name); +} + +void +ApidefListFunctions(int with_args) { + if (API_Def != NULL) { + API_Def->Print(with_args); + } +} + +void +ApidefFreeAllocation(void) { + if (API_Def != NULL) { + delete API_Def; + API_Def = NULL; + } +} + +int +ApidefMakeStubs(void) { + if (API_Def != NULL) { + API_Def->MakeStubs(); + return 0; + } else { + return 1; + } +} + +} // extern "C" + +/* + * Retrieving Argument Names Without Decorators + */ +void +Arg::GetUndecolatedName(string& name /* OUT */, int num) { + name = "v"; + if (num > 0) { + /* Making Variable Names Sequential Numbers */ + char num_str[5]; + sprintf(num_str, "%d", num); + name += num_str; + } else { + /* Use a user-supplied pseudo-variable name */ + name = m_name; + } +} + +int +Arg::PrintUndecoratedName(fstream& out, int num) { + /* Pointer argument */ + if (m_is_pointer) { + out << "*"; + } + + if (num > 0) { + /* Making Variable Names Sequential Numbers */ + out << "v" << num; + } else { + /* Use a user-supplied pseudo-variable name */ + out << m_name; + } + + return 0; +} + +/* + * Outputs one argument in a function prototype declaration + * out: Destination file + * num: Handling of Formal Argument Names + * 0 :Formal argument name specified in the API definition file + * Non-zero: Use "v" + specified number(Examples: v1, v2, ...) + */ +int +Arg::PrintPrototype(fstream& out, int num) { + const char *type = TypeCodeString(m_code); + if (type == NULL) { + type = m_type_name.c_str(); + } + if (type == NULL) { + cout << "Internal Error Occurrence!!\n"; + return 1; + } + + /* Const non-output pointers */ + if ((m_in_out & RPC_OUT_ARG) == 0 && (m_bytes != 0 || m_is_pointer != 0)) { + out << "const "; + } + out << type << " "; + if (m_is_pointer && m_bytes == 0) {/* Non-string pointer arguments */ + out << "*"; + } + + if (num > 0) {/* Making variable names sequential numbers */ + out << "v" << num; + } else {/* Use a user-supplied pseudo-variable name */ + out << m_name; + } + + /* Variable-length arrays */ + if (m_is_vararray != 0) { + out << "/* VAR_ARRAY */"; + } + + /* Variable-length arrays length */ + if (m_is_array_size != 0) { + out << "/* VAR_SIZE */"; + } + + /* + * Commenting on OUT/INOUT Arguments + * Maximum number of bytes of a string argument added to a comment + */ + if ((m_in_out & RPC_OUT_ARG) != 0 || m_bytes != 0) { + out << "/* "; + if ((m_in_out & RPC_OUT_ARG) != 0) { + if ((m_in_out & RPC_IN_ARG) != 0) { + out << "IN"; + } + out << "OUT "; + } + if (m_bytes) { + out << m_bytes << "Byte "; + } + out << "*/"; + } + + return 0; +} + +int +Arg::CreateMarshallArgs(fstream& out, int num) { + return CreateMarshallArgs(out, num, (RPC_IN_ARG|RPC_OUT_ARG)); +} + +int +Arg::CreateMarshallArgs(fstream& out, int num, string &array_size_name) { + return CreateMarshallArgs(out, num, (RPC_IN_ARG|RPC_OUT_ARG), array_size_name); +} + +int +Arg::CreateMarshallArgs(fstream& out, int num, int in_out) { + string dummy = ""; + return CreateMarshallArgs(out, num, in_out, dummy); +} + +/* + * The arguments to rpc_marshall_args() are generated for each API argument. + * for each API argument. + * out: Destination file + * num: Number given to the variable name of the argument (Examples: 1 for v1) + * in_out: Specifying the IN or OUT Attributes + * Output only if the argument has the specified attribute + */ +int +Arg::CreateMarshallArgs(fstream& out, int num, int in_out, string &array_size_name) { + if ((m_in_out & in_out) != 0) { + /* + * Collectively passes the argument type, pointer/non-pointer, IN/OUT attribute, + * and the maximum number of bytes of the argument type to one integer. + */ + RPC_marshall_flag flag; + flag.bits.code = m_code & ((1<<RPC_MARSHALL_FLAG_BITS_CODE)-1); + flag.bits.is_vararray = ((array_size_name.size() != 0) ? 1: 0) & + ((1<<RPC_MARSHALL_FLAG_BITS_IS_VARARRAY)-1); + flag.bits.is_pointer = m_is_pointer & ((1<<RPC_MARSHALL_FLAG_BITS_IS_POINTER)-1); + flag.bits.in_out = m_in_out & ((1<<RPC_MARSHALL_FLAG_BITS_IN_OUT)-1); + flag.bits.bytes = (UINT16)(m_bytes); + char str[11]; + sprintf(str, "0x%x", htonl(flag.all)); + out << "\t\t\t" << str; + + /* + * Add size of user-defined type to argument + */ + if (m_code == rpc_USER_DEFINED) { + if (array_size_name.size() != 0) { + out << " + ntohs(sizeof(" << m_type_name << ") * " << array_size_name << ")"; + } else { + out << " + ntohs(sizeof(" << m_type_name << "))"; + } + } else if (array_size_name.size() != 0) { + out << " + ntohs(sizeof(" << TypeCodeString(m_code) << ") * " << array_size_name << ")"; + } + + out << ", v" << num; + return 1; + } else { + return 0; + } +} + +int +Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num) { + return CreateDemarshallArgs(out, deliver_pointer, num, (RPC_IN_ARG|RPC_OUT_ARG)); +} + +int +Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, string &array_size_name) { + return CreateDemarshallArgs(out, deliver_pointer, num, (RPC_IN_ARG|RPC_OUT_ARG), array_size_name); +} + +int +Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out) { + string dummy = ""; + return CreateDemarshallArgs(out, deliver_pointer, num, in_out, dummy); +} + +/* + * The arguments to rpc_demarshall_args() are generated for each API argument. + * for each API argument. + * out: Destination file + * deliver_pointer: Passing a Variable Pointer(non-0) + * num: Number given to the variable name of the argument (Examples: 1 for v1) + * in_out: Specifying the IN or OUT Attributes + * Output only if the argument has the specified attribute + */ +int +Arg::CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out, string &array_size_name) { + if ((m_in_out & in_out) != 0) { + /* + * Collectively passes the argument type, pointer/non-pointer, IN/OUT attribute, + * and the maximum number of bytes of the argument type to one integer. + */ + RPC_marshall_flag flag; + flag.bits.code = m_code & ((1<<RPC_MARSHALL_FLAG_BITS_CODE)-1); + flag.bits.is_vararray = ((array_size_name.size() != 0) ? 1: 0) & + ((1<<RPC_MARSHALL_FLAG_BITS_IS_VARARRAY)-1); + flag.bits.is_pointer = m_is_pointer & ((1<<RPC_MARSHALL_FLAG_BITS_IS_POINTER)-1); + flag.bits.in_out = m_in_out & ((1<<RPC_MARSHALL_FLAG_BITS_IN_OUT)-1); + flag.bits.bytes = (UINT16)(m_bytes); + char str[11]; + sprintf(str, "0x%x", htonl(flag.all)); + out << "\t\t\t" << str; + + /* + * Add size of user-defined type to argument + */ + if (m_code == rpc_USER_DEFINED) { + out << " + ntohs(sizeof(" << m_type_name << "))"; + } + + out << ", "; + if (deliver_pointer) { + /* Pass a pointer */ + out << "&"; + } + out << "v" << num; + return 1; + } else { + return 0; + } +} + +int +Function::AppendArg(int code, int bytes, int is_pointer, + int is_vararray, int is_array_size, + const char *var_type_name, int in_out, const char *var_name) { + if (NumOfArgs() >= RPC_MAX_API_ARG_NUM) { + cout << "Too many API function arguments.\n"; + return -1; + } + Arg *a = new Arg(code, bytes, is_pointer, is_vararray, is_array_size, + var_type_name, in_out, var_name); + m_args.push_back(*a); + delete a; + return 0; +} + +/* + * Generate prototype declarations for a single API function + * out: Destination file + */ +int +Function::PrintPrototype(fstream& out, int server) { + int ret = 0; + + const char *return_type + = server ? RPC_API_SERVER_RETURN : RPC_API_CLIENT_RETURN; +#ifdef DBG_ENABLE + if ((server) || (!rpc_log_enable)) { + out << return_type << " " << m_name << "("; + } else { + out << return_type << " __" << m_name << "("; + } +#else + out << return_type << " " << m_name << "("; +#endif + + list<Arg>::size_type num_args = m_args.size(); + if (num_args > 0) { + list<Arg>::iterator a; + a = m_args.begin(); + for (list<Arg>::size_type i = 1; i <= num_args; ++i, ++a) { + a->PrintPrototype(out); +#ifdef DBG_ENABLE + if ((server) || (!rpc_log_enable)) { + if (i != num_args) { + out << ", "; + } + } else { + out << ", "; + } +#else + if (i != num_args) { + out << ", "; + } +#endif + } + } else { +#ifdef DBG_ENABLE + if ((server) || (!rpc_log_enable)) { + out << "void"; + } +#else + out << "void"; +#endif + } +#ifdef DBG_ENABLE + /* Debug information */ + if ((!server) && (rpc_log_enable)) { + out << "const char *filename, const char *funcname, int line "; + } +#endif + out << ");\n"; + return ret; +} + +#ifdef DBG_ENABLE +int +Function::PrintMacro(fstream& out) { + int ret = 0; + out << "#define " << m_name << "("; + + int num_args = m_args.size(); + if (num_args > 0) { + int i; + char c; + for (i = 1, c = 'a'; i <= num_args; i++, c++) { + out << c; + if (i != num_args) { + out << ", "; + } + } + out << ") \\\n\t"; + + /* Entity */ + out << "__" << m_name << "("; + for (i = 1, c = 'a'; i <= num_args; i++, c++) { + out << c << ", "; + } + out << "__FILE__, __func__, __LINE__)\n"; + } else { /* Without arguments */ + out << ") " << "__" << m_name << "(__FILE__, __func__, __LINE__)\n"; + } + + return ret; +} +#endif + +int +APIDef::MakeHeaderFiles(int server) { + char filename[MAX_FILENAME_LEN+1]; + sprintf(filename, "%s%s", m_lowerid.c_str(), + (server ? SERVER_HEADER_FILE : CLIENT_HEADER_FILE)); + int ret = 0; + + fstream out(filename, ios::out); + if (!out.is_open()) { + cout << "ERROR: File " << filename << " Could not open.\n"; + return 1; + } + cout << "info: Header file " << filename << " Creating.\n"; + + const char *define_str = + server ? SERVER_HEADER_DEFINE : CLIENT_HEADER_DEFINE; + const char *title = server ? SERVER_HEADER_TITLE : CLIENT_HEADER_TITLE; + + out << "#ifndef _" << m_lowerid << define_str << "\n"; + out << "#define _" << m_lowerid << define_str << "\n"; + out << "/*\n"; + out << " * " << m_id << " " << title << " " << filename << "\n"; + out << " *\n"; + out << RPCTOOL_WARNING_STRING << "\n"; + out << " */\n\n"; + + list<string>::iterator i; + for (i = m_headers.begin(); i != m_headers.end(); ++i) { + out << "#include <" << *i << ">\n"; + } + out << "\n"; + + if (server) { + + out << EXTERN_C_START << "\n"; + + out << RPC_API_DISPATCH_RETURN << " " + << m_id << RPC_API_DISPATCH_FUNC_FULL << ";\n"; + + out << "#ifdef RPC_DISPATCH_FUNC\n" + << "#undef RPC_DISPATCH_FUNC\n" + << "#define RPC_DISPATCH_FUNC " << m_id << RPC_API_DISPATCH_FUNC_NAME + << "\n#else /* !RPC_DISPATCH_FUNC */\n" + << "#error \"Please include <rpc.h> first!!\"\n" + << "#endif /* !RPC_DISPATCH_FUNC */\n\n"; + + out << EXTERN_C_END << "\n"; + + } +#ifdef DBG_ENABLE + else if (rpc_log_enable) { + /* DEBUG INFORMATION EMBEDDED MACRO */ + out << "/* Debug information embedded macro definition */\n"; + list<Function>::iterator f; + for (f = m_funcs.begin(); f != m_funcs.end(); ++f) { + if (f->PrintMacro(out) != 0) { + ret = 1; + break; + } + } + out << "\n"; + } +#endif + + out << EXTERN_C_START << "\n"; + + out << "/* API definitions */\n"; + list<Function>::iterator f; + for (f = m_funcs.begin(); f != m_funcs.end(); ++f) { + if (f->PrintPrototype(out, server) != 0) { + ret = 1; + break; + } + } + out << "\n"; + + out << EXTERN_C_END << "\n"; + + out << "#endif /* _" << m_lowerid << define_str << " */\n"; + out.close(); + return ret; +} + +int +Function::PrintServerStub(fstream& out) { + int num_args = NumOfArgs(); + + out << "\tcase " << RPC_API_NUM_PREFIX << m_name << ": {\n"; + + list<Arg>::iterator a = m_args.begin(); + for (int i = 1; i <= num_args; ++i, ++a) { + const char *type = TypeCodeString(a->Code()); + if (type == NULL) { + type = (a->TypeName()).c_str(); + } + if (type == NULL) { + return 1; + } + out << "\t\t" << type << " "; + if (a->Bytes() > 0 || a->IsPointer()) {/* Pointer-passing argument */ + if (a->Bytes() > 0) { + out << "v" << i << " = NULL;\n"; + } else if (a->IsPointer()) { + out << "*v" << i << " = NULL;\n"; + } + } else {/* Pass-by-value argument */ + out << "v" << i << ";\n"; + } + } + if (num_args > 0) { + out << "\t\tif (" << RPC_DEMARSHALL_FUNCTION + << " (args_string, args_size, 1, " << num_args << ",\n"; + /* In the STUB of servers for all pre-call demarshall */ + /* Passing Pointers to Local Variables in Server STUB */ + /* Pointer/ Buffer will alloc the required space in demarshall_arguments() */ + + a = m_args.begin(); + for (int i = 1; i <= num_args; ++i, ++a) { + if (a->IsVararray() != 0) { /* Variable-length arrays */ + a->CreateDemarshallArgs(out, 1, i, m_array_size_name); + } else { + a->CreateDemarshallArgs(out, 1, i); + } + if (i < num_args) { + out << ","; + } + out << "\n"; + } + out << "\t\t ) < 0) {\n"; + out << "\t\t\tgoto _" << m_name << "_Error;\n"; + out << "\t\t}\n"; + } + + out << "\t\tresult = " << m_name << "("; + for (int i = 1; i <= num_args; i++) { + out << "v" << i; + if (i < num_args) { + out << ", "; + } + } + out << ");\n"; + + int to_process = NumOfInOutArgs(RPC_OUT_ARG); + if (to_process > 0) { + /* Only OUT-arguments marshall after the server stub is called. */ + out << "\t\t/*if (result == RPC_OK) {*/\n"; + out << "\t\t *ret_string = " << RPC_MARSHALL_FUNCTION + << "(ret_size, 0, " << to_process << ",\n"; + + a = m_args.begin(); + int processed = 0; + int ret; + for (int i = 1; i <= num_args; ++i, ++a) { + if (a->IsVararray() != 0) { /* Variable-length arrays */ + ret = a->CreateMarshallArgs(out, i, RPC_OUT_ARG, m_array_size_name); + } else { + ret = a->CreateMarshallArgs(out, i, RPC_OUT_ARG); + } + if (ret) { + processed++; + if (processed < to_process) { + out << ","; + } + out << "\n"; + } + } + out << "\t\t );\n" + << "\t\t if (*ret_string == NULL) {\n" + << "\t\t\tresult = " << RPC_API_SERVER_ERROR << ";\n" + << "\t\t }\n" + << "\t\t/*}*/\n"; + } + + if (num_args > 0) { + out << "_" << m_name << "_Error:\n"; + } + int num_pointer_args = 0; + a = m_args.begin(); + for (int i = 1; i <= num_args; ++i, ++a) { + if (a->Bytes() || a->IsPointer()) { + num_pointer_args++; + } + } + if (num_pointer_args > 0) { + int processed = 0; + out << "\t\t" << RPC_MARSHALL_FREE_FUNCTION + << "(" << num_pointer_args << ", "; + a = m_args.begin(); + for (int i = 1; i <= num_args; ++i, ++a) { + if (a->Bytes() || a->IsPointer()) { + out << "v" << i; + processed++; + if (processed < num_pointer_args) { + out << ", "; + } + } + } + out << ");\n"; + } + out << "\t\tbreak;\n\t}\n"; + return 0; +} + +int +APIDef::MakeServerStub(void) { + char filename[MAX_FILENAME_LEN+1]; + sprintf(filename, "%s%s", m_lowerid.c_str(), SERVER_STUB_FILE); + int ret = 0; + + fstream out(filename, ios::out); + if (!out.is_open()) { + cout << "File " << filename << " Could not open.\n"; + return 1; + } + cout << "info: Stub file " << filename << " Creating.\n"; + + const char *title = SERVER_STUB_TITLE; + + out << "/*\n"; + out << " * " << m_id << " " << title << " " << filename << "\n"; + out << " *\n"; + out << RPCTOOL_WARNING_STRING << "\n"; + out << " */\n"; + out << "#include <" RPC_GLOBAL_HEADER_FILE << ">\n"; + out << "#include \"" << m_lowerid << SERVER_HEADER_FILE << "\"\n"; + out << "#include <netinet/in.h> /* for ntohs() */\n\n"; + + int api_num = 1; + list<Function>::iterator f; + + for (f = m_funcs.begin(); f != m_funcs.end(); ++f, ++api_num) { + if (api_num >= (1<<16)) { + cout << "Too many API functions.(Up to 65535)\n"; + return 1; + } + out << "#define " << RPC_API_NUM_PREFIX << f->Name() + << " " << api_num << "\n"; + } + out << "\n"; + + out << "RPC_Result\n"; + out << m_id << RPC_API_DISPATCH_FUNC_FULL << "\n"; + out << "{\n"; + out << "\tRPC_Result result = " << RPC_API_SERVER_ERROR << ";\n"; + out << "\t*ret_string = NULL;\n"; + out << "\tswitch(api_num) {\n"; + + for (f = m_funcs.begin(); f != m_funcs.end(); ++f) { + if (f->PrintServerStub(out) != 0) { + ret = 1; + break; + } + } + + if (ret != 0) { + return ret; + } + + out << "\tdefault:\n\t\tbreak;\n\t}\n"; + out << "\treturn result;\n"; + out << "}\n"; + + return ret; +} + +int +Function::PrintClientStub(const char *moduleid, fstream& out) { + int ret = 0; + + list<Arg>::iterator a; + /* Function Names and Arguments */ + out << RPC_API_CLIENT_RETURN << "\n"; +#ifdef DBG_ENABLE + if (rpc_log_enable) { + out << "__" << m_name << "("; + } else { + out << m_name << "("; + } +#else + out << m_name << "("; +#endif + int num_args = (int)(m_args.size()); + if (num_args > 0) { + a = m_args.begin(); + for (int i = 1; i <= num_args; ++i, ++a) { + if (a->PrintPrototype(out, i)) { + return 1; + } +#ifdef DBG_ENABLE + if (rpc_log_enable) { + out << ", "; + } else { + if (i < num_args) { + out << ", "; + } + } +#else + if (i < num_args) { + out << ", "; + } +#endif + } + } else { +#ifndef DBG_ENABLE + out << "void"; +#else + if (!rpc_log_enable) { + out << "void"; + } +#endif + } +#ifdef DBG_ENABLE + if (rpc_log_enable) { + out << "const char *filename, const char *funcname, int line "; + } +#endif + out << ")\n"; + + out << "{\n"; + + /* Contents of stub functions */ + + /* If the argument is present and the variable-length array does not exist */ + if ((num_args > 0) && (m_array_size_pos == 0)) { + int is_exist_mytype = 0; + /* Restricted specifications */ + out << "#ifdef RPC_STATIC_ASSERT\n"; + out << "\tchar RPC_TOTAL_ARGSIZE_ERROR_in_" << m_name << "[\n"; + out << "\t((("; + a = m_args.begin(); + for (int i = 1; i <= num_args; ++i, ++a) { + if (i > 1) { + out << " + "; + } + out << "sizeof("; + a->PrintUndecoratedName(out, i); + out << ")"; + /* For user types */ + if ((!is_exist_mytype) && (NULL == TypeCodeString(a->Code()))) { + is_exist_mytype = 1; + } + } + out << ") > RPC_MAX_API_ARG_TOTAL_SIZE) ? -1: 1)\n"; + out << "\t]__attribute__((unused));\n"; + + /* Have a user type */ + if (is_exist_mytype) { + char c[3]; + a = m_args.begin(); + for (int i = 1; i <= num_args; ++i, ++a) { + if (NULL == TypeCodeString(a->Code())) { + sprintf(c, "%d", i); + out << "\tchar RPC_ARGSIZE_ERROR_in_" << m_name << "_arg" << c; + out << "[\n\t(sizeof("; + a->PrintUndecoratedName(out, i); + out << ") > RPC_MAX_API_ARG_SIZE) ? -1: 1\n"; + out << "\t]__attribute__((unused));\n"; + } + } + } + + out << "#endif /* RPC_STATIC_ASSERT */\n"; + + } + + out << "\tRPC_Result result = " << RPC_API_CLIENT_ERROR << ";\n"; + out << "\tunsigned int args_size = 0, ret_size;\n"; + out << "\tchar retcode[9];\n"; + + if (num_args > 0) { + /* Advance preparation==Marshalling of arguments */ + out << "\tchar *args_string = " << RPC_MARSHALL_FUNCTION + << "(&args_size, 1, " << num_args << ",\n"; + /* In the clients STUB for all pre-call marshall */ + a = m_args.begin(); + for (int i = 1; i <= num_args; ++i, ++a) { + if (a->IsVararray() != 0) { /* Variable-length arrays */ + a->CreateMarshallArgs(out, i, m_array_size_name); + } else { + a->CreateMarshallArgs(out, i); + } + if (i < num_args) { + out << ","; + } + out << "\n"; + } + out << "\t);\n"; + out << "\tif (args_string == NULL) {\n" + << "\t\tgoto _" << m_name << "_Error;\n\t}\n"; + } else { + out << "\tchar *args_string = NULL;\n"; + } + +#ifdef DBG_ENABLE + if (rpc_log_enable) { + out << "\tif (" << moduleid << "_record_dbg_log(filename, funcname, line, \""; + out << m_name << "\") != 0) {\n"; + out << "\t\tgoto _" << m_name << "_Error;\n\t}\n"; + } +#endif + + /* RPC API call */ + out << "\tchar *ret_string = NULL; /* pgr0431 */\n"; +#ifdef RPC_STRING_ID + out << "\tresult=RPC_API_call(\"" << moduleid << "\", "; +#else + out << "\tresult=RPC_API_call(" << moduleid << "_RPC_ID, "; +#endif + out << RPC_API_NUM_PREFIX << m_name; + out << ", args_string, args_size, &ret_string, &ret_size);\n"; + + // 2007.08.25 To avoid over run within the sscanf + // Locally copies strings needed for determining return values and uses strtol instead of sscanf + // (Since there is no guarantee that the byte sequence to be grabbed by communication is 0-terminated) + out << "\n" + << "\tif (result == RPC_OK && ret_string != NULL) {\n" + << "\t strncpy(retcode, ret_string, 8);\n" + << "\t retcode[8] = '\\0';\n" + << "\t result = (RPC_Result)strtoul(retcode, NULL, 16);\n"; + + /* Post-processing==Arguments de-marshalling, free() */ + int num_of_out_args = NumOfInOutArgs(RPC_OUT_ARG); + if (num_of_out_args > 0) { + out << "\t if (" << RPC_DEMARSHALL_FUNCTION + << "(ret_string + RPC_RETCODE_LEN, ret_size - RPC_RETCODE_LEN, 0, " + << num_of_out_args << ",\n"; + + a = m_args.begin(); + int processed = 0; + int ret; + for (int i = 1; i <= num_args; ++i, ++a) { + if (a->IsVararray() != 0) { /* Variable-length arrays */ + ret = a->CreateDemarshallArgs(out, 0, i, RPC_OUT_ARG, m_array_size_name); + } else { + ret = a->CreateDemarshallArgs(out, 0, i, RPC_OUT_ARG); + } + if (ret) { + processed++; + if (processed < num_of_out_args) { + out << ","; + } + out << "\n"; + } + } + out << "\t ) < 0) {\n" + << "\t\tresult = " << RPC_API_CLIENT_ERROR << ";\n" + << "\t }\n"; + } + + out << "\t} else {\n\t //result = " << RPC_API_CLIENT_ERROR << ";\n" + << "\t}\n"; + + out << "\t" << RPC_RETURN_FREE_FUNCTION << "(ret_string);\n"; + out << "\t" << RPC_MARSHALL_FREE_FUNCTION << "(1, args_string);\n"; + + /* END, RETURN */ +#ifndef DBG_ENABLE + if (num_args) +#else + if ((num_args)||(rpc_log_enable)) +#endif + { + out << "_" << m_name << "_Error:\n"; + } + + out << "\treturn result;\n}\n"; + + return ret; +} + +int +APIDef::MakeClientStub(void) { + char filename[MAX_FILENAME_LEN+1]; + sprintf(filename, "%s%s", m_lowerid.c_str(), CLIENT_STUB_FILE); + int ret = 0; + + fstream out(filename, ios::out); + if (!out.is_open()) { + cout << "File " << filename << " Could not open.\n"; + return 1; + } + cout << "info: Stub file " << filename << " Creating.\n"; + + const char *title = CLIENT_STUB_TITLE; + + out << "/*\n"; + out << " * " << m_id << " " << title << " " << filename << "\n"; + out << " *\n"; + out << RPCTOOL_WARNING_STRING << "\n"; + out << " */\n"; + out << "#include <" RPC_GLOBAL_HEADER_FILE << ">\n"; + out << "#include <" << m_lowerid << CLIENT_HEADER_FILE << ">\n\n"; + out << "#include <stdio.h> /* for sscanf() */\n"; + out << "#include <stdlib.h> /* for getenv() */\n"; + out << "#include <string.h> /* for strncpy() */\n"; + out << "#include <netinet/in.h> /* for ntohs() */\n\n"; + + int api_num = 1; + list<Function>::iterator f; + for (f = m_funcs.begin(); f != m_funcs.end(); ++f, ++api_num) { + if (api_num >= (1<<16)) { + cout << "Too many API functions.(Up to 65535)\n"; + return 1; + } + out << "#define " << RPC_API_NUM_PREFIX << f->Name() + << " " << api_num << "\n"; + } + out << "\n"; + + /* Specification Restriction Debug Constants */ + out << "/*#define RPC_STATIC_ASSERT*/\n"; + out << "\n"; + +#ifdef DBG_ENABLE + if (rpc_log_enable) { + int m_id_work_cnt; + string m_id_work = m_id; + for (m_id_work_cnt = 0; m_id_work_cnt < m_id_work.length(); m_id_work_cnt++) { + m_id_work[m_id_work_cnt] = toupper(m_id_work[m_id_work_cnt]); + } + out << "int\n" << m_id << "_record_dbg_log(const char *filename, " << + "const char *funcname, int line, const char *apiname)\n"; + out << "{\n\t"; + out << "if (getenv(\"" << m_id_work << "_RPC_LOG\") != NULL) {\n\t\t"; + out << "return RPC_record_dbg_log(filename, funcname, line, apiname);\n\t"; + out << "}\n\t"; + out << "return 0;\n"; + out << "}\n\n"; + } +#endif + + /* API definitions */ + for (f = m_funcs.begin(); f != m_funcs.end(); ++f) { + if (f->PrintClientStub(m_id.c_str(), out) != 0) { + ret = 1; + break; + } + } + return ret; +} + +int +Arg::IsArraySize(void) { + if (m_is_array_size != 0) { + if (IsTypeCodeNumeric(m_code) == 1) { + return 1; + } else { + cout << "Variable-length array length specification variables must be integers.\n"; + return -1; + } + } + return 0; +} + +int +Function::CheckFuncArraySize(void) { + int num_args = (int)(m_args.size()); + list<Arg>::iterator a; + a = m_args.begin(); + for (int i = 1; i <= num_args; ++i, ++a) { + int ret = a->IsArraySize(); + if (ret > 0) { + if (m_array_size_pos != 0) + { + cout << "Two or more variable array length specification arguments exist.\n"; + return 1; + } + m_array_size_pos = i; + a->GetUndecolatedName(m_array_size_name, i); + } else if (ret < 0) { + return 1; + } + } + return 0; +} + +int +APIDef::CheckAllArraySize(void) { + list<Function>::iterator f; + for (f = m_funcs.begin(); f != m_funcs.end(); ++f) { + if (f->CheckFuncArraySize() != 0) { + return 1; + } + } + return 0; +} + +int +APIDef::MakeStubs(void) { + if (m_id.size() == 0) { + cout << "The module name is not specified.\n"; + return 1; + } + + if (m_id.size() > MAX_FILENAME_LEN - strlen(SERVER_STUB_FILE)) { + cout << "The module name is too long.\n"; + return 1; + } + + /* Pre-examine the ARRAYSIZE specification */ + //cout << "<check_all_array_size>\n"; + if (CheckAllArraySize() != 0) { + return 1; + } + + //cout << "<MakeHeaderFiles(0)>\n"; + if (MakeHeaderFiles(1) != 0) { + return 1; + } + + //cout << "<MakeHeaderFiles(1)>\n"; + if (MakeHeaderFiles(0) != 0) { + return 1; + } + + if (MakeServerStub() != 0) { + return 1; + } + + if (MakeClientStub() != 0) { + return 1; + } + + return 0; +} + +void +Arg::Print(void) { + cout << "\t"; + if (m_name.size() > 0) { + cout << "Variable name=" << m_name << " "; + } + cout << "Type=" << TypeCodeString(m_code) << "In bytes=" << m_bytes << " "; + if (m_is_pointer) { + cout << "Pointer "; + } + if ((m_in_out & RPC_OUT_ARG) != 0) { + cout << "Output "; + } + cout << "\n"; +} + +void +Function::Print(int with_args) { + printf("Function name=%s\n", m_name.c_str()); + if (with_args) { + list<Arg>::iterator a; + for (a = m_args.begin(); a != m_args.end(); ++a) { + a->Print(); + } + } +} + +void +APIDef::Print(int with_args) { + list<Function>::iterator f; + for (f = m_funcs.begin(); f != m_funcs.end(); ++f) { + f->Print(with_args); + } +} + +void +APIDef::IdTolower(void) { + char *lower = new char[m_id.size() + 1]; + strcpy(lower, m_id.c_str()); + char *p; + for (p = lower; *p; p++) { + *p = (char)(tolower(*p)); + } + m_lowerid = lower; + delete[] lower; +} diff --git a/otherservice/rpc_library/tool/apidef.h b/otherservice/rpc_library/tool/apidef.h new file mode 100644 index 00000000..a73fc49c --- /dev/null +++ b/otherservice/rpc_library/tool/apidef.h @@ -0,0 +1,333 @@ +/* + * @copyright Copyright (c) 2016-2019 TOYOTA MOTOR CORPORATION. + * + * 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. + */ + +/** + * @file apidef.h + * @brief RPC tools--Function/macro definitions and APIDef class definitions + */ +/** @addtogroup RPCtool + * + * @brief Using the RPC Tool (rpc_apidef) + * + * rpc_apidef [CPP option...] API definition file name + * + * - CPP option + * The RPC tool calls the C preprocessor (CPP) internally + * for processing comments and #if directives. + * Here, you can specify options to be given to the CPP, such as symbol definitions + * for conditional branch descriptions in the API definition file. + * - API definition file name + * Pathname to the API definition file. + * The file name must be thread ID + ".api". + * + * The output file is as follows. + * "*" is a lowercase version of the API definition file name preceding ".api". + * - *_api.h(Client header files) + * - *_api_stub.c(Client stub file) + * - *_srvr.h(Server header file) + * - *_srvr_stub.c(Server stub file) + * + * Examples: + * - Examples1: rpc_apidef -DTEST XXX.api + * - Examples2: rpc_apidef XXX.api + * - => Xxx_api.h, xxx_api_stub.c, ... To the output + */ +#ifndef RPC_LIBRARY_TOOL_APIDEF_H_ +#define RPC_LIBRARY_TOOL_APIDEF_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef DBG_ENABLE +extern char rpc_log_enable; +#endif + +/* C++ to C I/F functions */ +const char *TypeCodeString(const int code); +int IsTypeCodeNumeric(const int code); + +/* + * C to C++ I/F functions (APIDef class) + */ +void ApidefDefineId(const char *id); +void ApidefAddHeader(const char *filename); +int ApidefPushFunctionArg(int arg_code, int buffer_bytes, int is_pointer, + int is_vararray, int is_array_size, + const char *var_type_name, int in_out, + const char *var_name); +void ApidefProcessFunction(const char *funcname); +void ApidefListFunctions(int with_args); +void ApidefFreeAllocation(void); +int ApidefMakeStubs(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#define RPC_IN_ARG 0x01 +#define RPC_OUT_ARG 0x02 +#define RPC_INOUT_ARG (RPC_IN_ARG|RPC_OUT_ARG) + +#define MAX_FILENAME_LEN 63 +#define SERVER_HEADER_FILE "_srvr.h" +#define CLIENT_HEADER_FILE "_api.h" +#define SERVER_STUB_FILE "_srvr_stub.c" +#define CLIENT_STUB_FILE "_api_stub.c" +#define SERVER_HEADER_DEFINE "_srvr_h_" +#define CLIENT_HEADER_DEFINE "_api_h_" + +#define SERVER_HEADER_TITLE "Server header files" +#define CLIENT_HEADER_TITLE "Client header files" +#define SERVER_STUB_TITLE "Server stub file" +#define CLIENT_STUB_TITLE "Client stub file" + +#define RPC_MARSHALL_FUNCTION "RPC_marshall_arguments" +#define RPC_DEMARSHALL_FUNCTION "RPC_demarshall_arguments" +#define RPC_MARSHALL_FREE_FUNCTION "RPC_marshall_free" +#define RPC_RETURN_FREE_FUNCTION "RPC_free_return_string" + +#define RPC_API_SERVER_RETURN "RPC_Result" +#define RPC_API_SERVER_ERROR "RPC_ERR_Fatal" +#define RPC_API_CLIENT_RETURN "RPC_Result" +#define RPC_API_CLIENT_ERROR "RPC_ERR_Fatal" +#define RPC_API_DISPATCH_TYPE "RPC_dispatch_func_t" +#define RPC_API_DISPATCH_RETURN "RPC_Result" +#define RPC_API_DISPATCH_FUNC_FULL "_API_dispatch(UINT16 api_num, const char *args_string, unsigned int args_size, char **ret_string, unsigned int *ret_size)" // NOLINT (readability/nolint) +#define RPC_API_DISPATCH_FUNC_NAME "_API_dispatch" +#define RPC_API_NUM_PREFIX "RPC_API_NUM_" +#define RPC_GLOBAL_HEADER_FILE "other_service/rpc.h" + +#define RPCTOOL_WARNING_STRING \ +" * The file created by the RPC tool.This file should not be edited." + +#define EXTERN_C_START \ +"#ifdef __cplusplus\n" \ +"extern \"C\" {\n" \ +"#endif\n" + +#define EXTERN_C_END \ +"#ifdef __cplusplus\n" \ +"}\n" \ +"#endif /* __cplusplus */\n" + +#ifdef __cplusplus +#include <iostream> +#include <fstream> +#include <string> +#include <list> + +using namespace std; // NOLINT (readability/nolint) + +/** @ingroup RPCtool + * @class Arg + * @brief Class that stores and processes the arguments of functions read from the API definition file + */ +class Arg { + protected: + int m_code; + int m_bytes; + int m_is_pointer; + int m_in_out; /* Bit OR of _IN_ARG and _OUT_ARG */ + int m_is_vararray; + int m_is_array_size; + string m_type_name; + string m_name; + + public: + Arg() { + m_code = m_bytes = m_is_pointer = m_in_out = m_is_vararray = m_is_array_size = 0; + } + Arg(int code, int bytes, int is_pointer, + int is_vararray, int is_array_size, + const char *type_name, int in_out, + const char *var_name) { + m_code = code; + m_bytes = bytes; + m_is_pointer = is_pointer; + m_is_vararray = is_vararray; + m_is_array_size = is_array_size; + m_in_out = in_out; + if (type_name) { + m_type_name = type_name; + } + if (var_name) { + m_name = var_name; + } + } + ~Arg() {} + + int Code(void) { return m_code; } + int Bytes(void) { return m_bytes; } + int IsPointer(void) { return m_is_pointer; } + int InOut(void) { return m_in_out; } + string& TypeName(void) { return m_type_name; } + void GetUndecolatedName(string& name, int num); // NOLINT (readability/nolint) + + int PrintUndecoratedName(fstream& out, int num); + int PrintPrototype(fstream& out, int num); + int PrintPrototype(fstream& out) { return PrintPrototype(out, 0); } + + int CreateMarshallArgs(fstream& out, int num); + int CreateMarshallArgs(fstream& out, int num, string &array_size_name); // NOLINT (readability/nolint) + int CreateMarshallArgs(fstream& out, int num, int in_out); + int CreateMarshallArgs(fstream& out, int num, int in_out, string &array_size_name); // NOLINT (readability/nolint) + int CreateDemarshallArgs(fstream& out, int deliver_pointer, int num); + int CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, string &array_size_name); // NOLINT (readability/nolint) + int CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out); + int CreateDemarshallArgs(fstream& out, int deliver_pointer, int num, int in_out, string &array_size_name); // NOLINT (readability/nolint) + + int IsVararray(void) { return m_is_vararray; } + int IsArraySize(void); + void Print(void); +}; + +/** @ingroup RPCtool + * @class Function + * @brief Class that stores and processes function definitions read from the API definition file + */ +class Function { + protected: + string m_name; + list<Arg> m_args; + int m_array_size_pos; + string m_array_size_name; + + public: + Function():m_array_size_name("") { m_array_size_pos = 0; } + ~Function() { + list<Arg>::size_type size = m_args.size(); + for (list<Arg>::size_type i = 0 ; i < size ; i++) { + m_args.begin(); + m_args.pop_front(); + } + } + + const char *Name(void) { return m_name.c_str(); } + void SetName(const char *funcname) { + m_name = funcname; + } + + int NumOfArgs(void) { + return (int)(m_args.size()); // NOLINT (readability/nolint) + } + int NumOfInOutArgs(int in_out) { + int count = 0; + list<Arg>::iterator a; + for (a = m_args.begin(); a != m_args.end(); ++a) { + if ((a->InOut() & in_out) != 0) { + ++count; + } + } + return count; + } + + int AppendArg(int code, int bytes, int is_pointer, + int is_vararray, int is_array_size, + const char *var_type_name, int in_out, const char *var_name); + + int PrintPrototype(fstream& out); + int PrintPrototype(fstream& out, int server); +#ifdef DBG_ENABLE + int PrintMacro(fstream& out); +#endif + + int PrintServerStub(fstream& out); + int PrintClientStub(const char *moduleid, fstream& out); + + int CheckFuncArraySize(void); + void Print(int with_args); +}; + +/** @ingroup RPCtool + * @class APIDef + * @brief Class that stores and processes the result of reading the API definition file + */ +class APIDef { + protected: + list<Function> m_funcs; + Function *m_work; + string m_id; + string m_lowerid; + list<string> m_headers; + + public: + APIDef() { m_work = 0; } + ~APIDef() { + list<Function>::size_type size = m_funcs.size(); + for (list<Function>::size_type i = 0; i < size; i++) { + m_funcs.begin(); + m_funcs.pop_front(); + } + if (m_work != NULL) { + delete m_work; + } + size = m_headers.size(); + for (list<Function>::size_type i = 0; i < size; i++) { + m_headers.begin(); + m_headers.pop_front(); + } + } + + void IdTolower(void); + void DefineId(const char *id) { + m_id = id; + IdTolower(); + } + void AddHeader(const char *filename) { + string str = filename; + m_headers.push_back(str); + } + + int AddFunctionArg(int arg_code, int buffer_bytes, int is_pointer, + int is_vararray, int is_array_size, + const char *var_type_name, int in_out, + const char *var_name) { + if (m_work == NULL) { + m_work = new Function(); + } + return m_work->AppendArg(arg_code, buffer_bytes, is_pointer, + is_vararray, is_array_size, + var_type_name, in_out, var_name); + } + void NameFunction(const char *funcname) { + if (m_work == NULL) { + m_work = new Function(); + } + m_work->SetName(funcname); + + AppendFunction(m_work); + delete m_work; + m_work = NULL; + } + + void AppendFunction(Function *pfunc) { + m_funcs.push_back(*pfunc); + } + + int CheckAllArraySize(void); + + int MakeStubs(void); + void Print(int with_args); + + private: + int MakeHeaderFiles(int server); + int MakeServerStub(void); + int MakeClientStub(void); +}; +#endif /* __cplusplus */ + +#endif // RPC_LIBRARY_TOOL_APIDEF_H_ diff --git a/otherservice/rpc_library/tool/apidef.l b/otherservice/rpc_library/tool/apidef.l new file mode 100644 index 00000000..c2f246a2 --- /dev/null +++ b/otherservice/rpc_library/tool/apidef.l @@ -0,0 +1,136 @@ +/** + * @file apidef.l + * @brief RPC tools--Defining lexical analysis rules for API definition files + * + */ +/** @ingroup RPCtool + * Defining Lexical Analysis Rules for Use with RPC Tools (apidef) + */ +%{ +#include <string.h> +#include <stdlib.h> +#include "apidef.tab.h" +%} + +ALPHA [A-Za-z_] +ALPHANUM [0-9\-A-Za-z_] +ALPHANUMDOT [0-9.\-A-Za-z_/] + +%x include +%s apidef +%x str_num + +%% +INCLUDE { BEGIN(include); return rpc_INCLUDE; } +<include>\< { return '<'; } +<include>{ALPHANUMDOT}+ { + yylval.strval = malloc(strlen(yytext)+1); + strcpy(yylval.strval, yytext); + return rpc_NAME_DOT; + } +<include>\> { BEGIN(INITIAL); return '>'; } +<include>. /* ignore */ + +RPC_Result { BEGIN(apidef); return RPC_RESULT; } + +<apidef>STRING/[0-9]+ { BEGIN(str_num); + yylval.ival = rpc_STRING; return rpc_STRING; } +<str_num>[0-9]+ { + BEGIN(apidef); + sscanf(yytext, "%d", &yylval.ival); + return rpc_NUM; + } +<str_num>. /* ignore */ + +<apidef>{ +char { yylval.ival = rpc_CHAR; return rpc_CHAR; } +int { yylval.ival = rpc_INT; return rpc_INT; } +signed[ \t\n]+int { yylval.ival = rpc_SINT; return rpc_SINT; } +unsigned[ \t\n]+int { yylval.ival = rpc_UINT; return rpc_UINT; } +INT8 { yylval.ival = rpc_INT8; return rpc_INT8; } +INT16 { yylval.ival = rpc_INT16; return rpc_INT16; } +INT32 { yylval.ival = rpc_INT32; return rpc_INT32; } +INT64 { yylval.ival = rpc_INT64; return rpc_INT64; } +UINT8 { yylval.ival = rpc_UINT8; return rpc_UINT8; } +UINT16 { yylval.ival = rpc_UINT16; return rpc_UINT16; } +UINT32 { yylval.ival = rpc_UINT32; return rpc_UINT32; } +UINT64 { yylval.ival = rpc_UINT64; return rpc_UINT64; } +float { yylval.ival = rpc_FLOAT; return rpc_FLOAT; } +double { yylval.ival = rpc_DOUBLE; return rpc_DOUBLE; } +void { yylval.ival = rpc_VOID; return rpc_VOID; } +IN { + fprintf(stderr, + "Specification change: IN Pointer argument needs to be prefixed \"const\" instead of \"IN\".\n" + ); + return rpc_UNKNOWN; + } +OUT { + fprintf(stderr, + "Specification change: OUT argument no longer needs to be prefixed with \"OUT\".\n" + ); + /* ignore */ + } +INOUT { yylval.ival = rpc_INOUT; return rpc_INOUT; } +const { yylval.ival = rpc_CONST; return rpc_CONST; } +VARARRAY { yylval.ival = rpc_VARARRAY; return rpc_VARARRAY; } +ARRAYSIZE { yylval.ival = rpc_ARRAYSIZE; return rpc_ARRAYSIZE; } + +{ALPHA}+{ALPHANUM}* { + yylval.strval = malloc(strlen(yytext)+1); + strcpy(yylval.strval, yytext); + return rpc_NAME; + } + +\( { return '('; } +\) { return ')'; } +\* { return '*'; } +, { return ','; } +\; { BEGIN(INITIAL); return ';'; } + +} /* end of <apidef> */ + +#.*\n /* ignore CPP directives */ + +{ALPHANUMDOT}+ { + fprintf(stderr, "Unknown keyword %s\n", yytext); + return rpc_UNKNOWN; + } + +[ \t\n]+ /* eat up whitespace */ + +%% +#ifdef OLD_STUFFS +%x portdef +%x addr_num +PORT { BEGIN(portdef); return DEFINE_PORT; } +<portdef>[0-9]+ { + BEGIN(INITIAL); + sscanf(yytext, "%d", &yylval.ival); + return NUM; + } + +<apidef>ADDR/[0-9]+ { BEGIN(addr_num); yylval.ival = _ADDR; return _ADDR; } +<addr_num>[0-9]+ { + BEGIN(apidef); + sscanf(yytext, "%d", &yylval.ival); + return NUM; + } +#endif + +/* + * function to free the buffer which flex allocates but not frees + */ +void +free_flex_buffer(void) +{ + yy_delete_buffer(YY_CURRENT_BUFFER); +} + +/* + * dummy function to avoid a warning of not using 'yyunput' + */ +void +dummy(void) +{ + yyunput(0, 0); +} diff --git a/otherservice/rpc_library/tool/apidef.y b/otherservice/rpc_library/tool/apidef.y new file mode 100644 index 00000000..ce20c9c1 --- /dev/null +++ b/otherservice/rpc_library/tool/apidef.y @@ -0,0 +1,615 @@ +/** + * @file apidef.y + * @brief RPC tools--API definition file syntax definition and read/front-end processing + * + */ + +/*---------------------------------------------------------------------------*/ +/* C declarative statement */ +/*---------------------------------------------------------------------------*/ +%{ +#define YYDEBUG 1 +#define YYERROR_VERBOSE 1 + +#include <stdio.h> +#include <stdlib.h> + +/* + * YACC to C I/F functions + */ +extern int yylex(void); /* LEX I/F */ +extern int yyerror(const char *); /* dummy */ + +#include "apidef.h" + +/* YACC to C I/F functions */ +static void AddHeader(const char *header_file); +static int push_function_arg(int arg_type, int num_of_bytes, + int is_pointer, + int is_vararray, int is_array_size, + const char *var_type_name, + int is_out, const char *var_name); +static void process_function(const char *funcname); +static void free_string(char *funcname); + +static int var_type; +static int num_of_bytes; +static int is_pointer; +static int in_out; +static int is_vararray; +static int is_array_size; +static char *var_type_name = NULL; + +%} + +/*---------------------------------------------------------------------------*/ +/* Bison declarations */ +/*---------------------------------------------------------------------------*/ +%union { + int ival; + char *strval; +} + +%token '"' +%left ',' +%left '(' +%right ')' +%left '*' +%token '{' +%token '}' +%token ';' +%token '\n' +%token <strval> rpc_INCLUDE 257 +%token <strval> RPC_RESULT 258 +%token <strval> rpc_NAME_DOT 259 +%token <strval> rpc_NAME 260 +%type <strval> funcdefs funcdef args +%type <strval> nonvoid_args arg var_type +%type <strval> var_primitive_type var_string_type var_user_defined_type +/* +%token <strval> rpc_OUT +*/ +%token <strval> rpc_INOUT 261 +%token <strval> rpc_CONST 262 +%token <strval> rpc_VARARRAY 263 +%token <strval> rpc_ARRAYSIZE 264 +%token <ival> rpc_NUM 265 +%token <strval> rpc_VOID 266 +%token <ival> rpc_CHAR 267 +%token <ival> rpc_INT 268 +%token <ival> rpc_SINT 269 +%token <ival> rpc_UINT 270 +%token <ival> rpc_INT8 271 +%token <ival> rpc_INT16 272 +%token <ival> rpc_INT32 273 +%token <ival> rpc_INT64 274 +%token <ival> rpc_UINT8 275 +%token <ival> rpc_UINT16 276 +%token <ival> rpc_UINT32 277 +%token <ival> rpc_UINT64 278 +%token <ival> rpc_FLOAT 279 +%token <ival> rpc_DOUBLE 280 +%token <ival> rpc_STRING 281 +%token <ival> rpc_USER_DEFINED 282 +%token <ival> rpc_UNKNOWN 283 + +/*---------------------------------------------------------------------------*/ +/* Grammar rule */ +/*---------------------------------------------------------------------------*/ +%% +input: includes funcdefs +; + +includes: /* empty input */ + | includes include +; + +include: rpc_INCLUDE '<' rpc_NAME_DOT '>' + { AddHeader($3); free_string($3); } +; + +funcdefs: funcdef + | funcdefs funcdef +; + +funcdef: RPC_RESULT rpc_NAME '(' args ')' ';' + { process_function($2); free_string($2);} +; + +args: rpc_VOID + | nonvoid_args +; + +nonvoid_args: arg + | nonvoid_args ',' arg +; + +arg: var_type rpc_NAME + { + if (push_function_arg(var_type, num_of_bytes, is_pointer, + is_vararray, is_array_size, + var_type_name, in_out, $2) < 0) { + YYERROR; + } + if (var_type_name) { free_string(var_type_name); } + var_type_name = NULL; + free_string($2); + } + | var_type + { + if (push_function_arg(var_type, num_of_bytes, is_pointer, + is_vararray, is_array_size, + var_type_name, in_out, NULL) < 0) { + YYERROR; + } + if (var_type_name) { free_string(var_type_name); } + var_type_name = NULL; + } +; + +/* + * Standard IN pointers are not allowed. + * When used as an array address, it is not clear how many bytes to copy. + * ->You are asked to declare the type and pass the address. + * Otherwise, you can simply pass it by value. + */ +var_type: var_primitive_type /* INT8, .. DOUBLE */ + { is_pointer = 0; is_vararray = 0; is_array_size = 0; in_out =RPC_IN_ARG; } + | var_primitive_type '*' /* OUT INT8 *, ... OUT DOUBLE * */ + { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_OUT_ARG; } + /* if allow primitive IN pointer + | rpc_CONST var_primitive_type '*' + { is_pointer = 1; in_out = RPC_IN_ARG; } + */ + | var_string_type + /* OUT STRING128, ... */ + { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_OUT_ARG; } + | rpc_CONST var_string_type + /* IN STRING128, ... */ + { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_IN_ARG; } + | var_user_defined_type + { is_pointer = 0; is_vararray = 0; is_array_size = 0; in_out = RPC_IN_ARG; } + | var_user_defined_type '*' + { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_OUT_ARG; } + | rpc_CONST var_user_defined_type '*' + { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_IN_ARG; } + + /* INOUT specification */ + | rpc_INOUT var_string_type + /* IN STRING128, ... */ + { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_INOUT_ARG; } + | rpc_INOUT var_user_defined_type '*' + { is_pointer = 1; is_vararray = 0; is_array_size = 0; in_out = RPC_INOUT_ARG; } + + /* Variable-length arrays */ + | rpc_CONST rpc_VARARRAY var_primitive_type '*' + { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_IN_ARG; } + | rpc_VARARRAY var_primitive_type '*' + { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_OUT_ARG; } + | rpc_INOUT rpc_VARARRAY var_primitive_type '*' + { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_INOUT_ARG; } + | rpc_CONST rpc_VARARRAY var_user_defined_type '*' + { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_IN_ARG; } + | rpc_VARARRAY var_user_defined_type '*' + { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_OUT_ARG; } + | rpc_INOUT rpc_VARARRAY var_user_defined_type '*' + { is_pointer = 1; is_vararray = 1; is_array_size = 0; in_out = RPC_INOUT_ARG; } + + /* Variable length array size */ + | rpc_ARRAYSIZE var_primitive_type + { is_pointer = 0; is_vararray = 0; is_array_size = 1; in_out = RPC_IN_ARG; } +; + +var_primitive_type: + rpc_CHAR { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_INT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_SINT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_UINT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_INT8 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_UINT8 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_INT16 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_UINT16 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_INT32 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_UINT32 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_INT64 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_UINT64 { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_FLOAT { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } + | rpc_DOUBLE { var_type = $1; num_of_bytes = 0; var_type_name = NULL; } +; + +var_string_type: rpc_STRING rpc_NUM + { var_type = $1; num_of_bytes = $2; var_type_name = NULL; } +; + +var_user_defined_type: rpc_NAME + { var_type = rpc_USER_DEFINED; num_of_bytes = 0; var_type_name = $1; } +; + +%% + +/*---------------------------------------------------------------------------*/ +/* C additional code */ +/*---------------------------------------------------------------------------*/ +/* Including an older bison results in an error */ +/*#include "apidef.tab.h"*/ + +#include <unistd.h> +#include <assert.h> +#include <string.h> +/* + * YACC/Lex interface functions/variables + */ +extern int yydebug; /* for YACC debug */ +extern int yyparse(void); +extern FILE *yyin; +extern int yy_flex_debug; /* for FLEX debug */ +/* my own function to free the buffer flex allocates */ +extern void free_flex_buffer(void); + +#ifdef DBG_ENABLE +char rpc_log_enable; +#endif + +/**/ +static void +AddHeader(const char *filename) +{ + ApidefAddHeader(filename); +} + +static int +push_function_arg(int arg_type, int num_of_bytes, int is_pointer, + int is_vararray, int is_array_size, + const char *var_type_name, int in_out, const char *var_name) +{ + switch(arg_type) { + case rpc_CHAR: + case rpc_INT: + case rpc_SINT: + case rpc_UINT: + case rpc_INT8: + case rpc_INT16: + case rpc_INT32: + case rpc_INT64: + case rpc_UINT8: + case rpc_UINT16: + case rpc_UINT32: + case rpc_UINT64: + case rpc_FLOAT: + case rpc_DOUBLE: + case rpc_STRING: + case rpc_USER_DEFINED: + return ApidefPushFunctionArg(arg_type, num_of_bytes, is_pointer, + is_vararray, is_array_size, + var_type_name, in_out, var_name); + break; + + default: + return -1; + break; + } +} + +static void +process_function(const char *funcname) +{ + ApidefProcessFunction(funcname); +} + +static void +free_string(char *s) +{ +#ifdef DEBUG + fprintf(stderr, "freed %s\n", s); +#endif + free(s); +} + +static void +extract_id(const char *filename, char **id) +{ + char *dotapi; + char *slash; + const char *start; + + if (id == NULL) { + return; + } + dotapi = strrchr(filename, '.'); + if (dotapi == NULL) { + return; + } + if (strcmp(dotapi, ".api")) { + return; + } + + slash = strrchr(filename, '/'); + start = filename; + if (slash != NULL) { + start = slash + 1; + } + + *id = malloc((size_t)(dotapi - start + 1)); + if (*id == NULL) { + return; + } + strncpy(*id, start, (size_t)(dotapi - start)); + (*id)[dotapi - start] = '\0'; +} + +static void +usage(const char *prog) +{ + fprintf(stdout, + "How to use: %s [CPPFLAGS] ... API definition file name\n", + prog); + fprintf(stdout, "Examples1: %s XXX.api\n", prog); + fprintf(stdout, "Examples2: %s -DSOME_DEFINES XXX.api\n", prog); +} + +#define CPP_PROG "cpp" +static void free_cpp_argv(char **argv); + +static char ** +prepare_cpp_argv(int argc, char *argv[]) +{ + char **cpp_argv; + char **ret; + + cpp_argv = malloc(sizeof(char *) * (long unsigned int)(argc+1)); + if (cpp_argv == NULL) { + return NULL; + } + memset(cpp_argv, 0, sizeof(char *) * (long unsigned int)(argc+1)); + ret = cpp_argv; + + cpp_argv[0] = malloc(strlen(CPP_PROG)+1); + if (cpp_argv[0] == NULL) { + free_cpp_argv(ret); + return NULL; + } + strcpy(cpp_argv[0], CPP_PROG); + cpp_argv++; + + for( ; *argv != NULL ; argv++, cpp_argv++) { + *cpp_argv = malloc(strlen(*argv)+1); + if (*cpp_argv == NULL) { + free_cpp_argv(ret); + return NULL; + } + strcpy(*cpp_argv, *argv); + } + *cpp_argv = NULL; + return ret; +} + +static void +free_cpp_argv(char **argv) +{ + char **orig; orig = argv; + while(*argv != NULL) { + free(*argv); + argv++; + } + free(orig); +} + +/** @ingroup RPCtool + * @brief RPCtool main functions + * + * Perform the following processing. + * + * - Lexical context analysis of the API definition file(See apidef.y and apidef.l) + * - The API function definition read from the definition file is stored in the APIDef class. + * - Outputs stub and header files from function definitions stored in APIDef after a successful read + */ +int +main(int argc, char *argv[]) +{ + int start; + char **cpp_argv; + int pipefd[2]; + int pid; + int ret; + + if (argc < 2) { + usage(argv[0]); + return 1; + } + + start = 1; + yy_flex_debug = 0; + + if (!strcmp(argv[1], "-d")) { + yydebug=1; + yy_flex_debug = 1; + if (argc > 2) { + start++; + } else { + usage(argv[0]); + return 1; + } + } + +#ifdef DBG_ENABLE + /* + * If the second-to-last argument is a log specification + */ + if ( ( argc >= 2 ) && (!strcmp(argv[argc-2], "-log")) ) { + rpc_log_enable = 1; + } else { + rpc_log_enable = 0; + } +#endif + + /* + * Extract ID from last argument (API definition file name) + */ + { + char *moduleid; + moduleid = NULL; + extract_id(argv[argc-1], &moduleid); + if (moduleid == NULL) { + fprintf(stdout, "%s: The API definition file name is invalid.\n", argv[0]); + usage(argv[0]); + return 1; + } + ApidefDefineId(moduleid); + free(moduleid); + } + + /* + * Preparing options to exec CPPs + */ + cpp_argv = prepare_cpp_argv(argc, argv + start); + if (cpp_argv == NULL) { + printf("No Memory!\n"); + return 1; + } + +#define PIPE_READ 0 +#define PIPE_WRITE 1 + + if (pipe(pipefd) != 0) { + perror("pipe"); + return 1; + } + + pid = fork(); + if (pid < 0) {/* fork error */ + close(pipefd[PIPE_READ]); + close(pipefd[PIPE_WRITE]); + perror("fork"); + return 1; + } + if (pid == 0) {/* child process */ + int must_be_1; + /* + * force stdout to be pipefd[PIPE_WRITE] + */ + close(pipefd[PIPE_READ]); + close(1); + must_be_1 = dup(pipefd[PIPE_WRITE]); + assert(must_be_1 == 1); + close(pipefd[PIPE_WRITE]); + /* + * invoke C preprocessor with flags + */ + execvp(CPP_PROG, cpp_argv); + perror("execvp"); + exit(0); + } else { + /* + * parent process + */ + int must_be_0; + free_cpp_argv(cpp_argv); + + /* + * force stdin to be pipefd[PIPE_READ] + */ + close(pipefd[PIPE_WRITE]); + close(0); + must_be_0 = dup(pipefd[PIPE_READ]); + assert(must_be_0 == 0); + close(pipefd[PIPE_READ]); + } + + ret = yyparse(); + + free_flex_buffer(); + + if (ret == 0) {/* Parsed successfully */ + //ApidefListFunctions(1); + ApidefMakeStubs(); + } else {/* Parse error occurred */ + fputs("The APIs that have been analyzed so far are as follows.\n", stdout); + fputs("-----start-----\n", stdout); + ApidefListFunctions(0); + fputs("------end------\n", stdout); + fputs("Check this API definition\n", stdout); + } + ApidefFreeAllocation(); + + return ret; +} + +int +yyerror(const char *s) +{ + printf("\nError: %s\n", s); + return 0; +} + +int +yywrap() +{ + return 1; +} + +static char const *Types[] = { + "char", + "int", + "signed int", + "unsigned int", + "INT8", + "INT16", + "INT32", + "INT64", + "UINT8", + "UINT16", + "UINT32", + "UINT64", + "float", + "double", + "char *", +}; + +static const int TypeCodes[] = { + rpc_CHAR, + rpc_INT, + rpc_SINT, + rpc_UINT, + rpc_INT8, + rpc_INT16, + rpc_INT32, + rpc_INT64, + rpc_UINT8, + rpc_UINT16, + rpc_UINT32, + rpc_UINT64, + rpc_FLOAT, + rpc_DOUBLE, + rpc_STRING, +}; + +const char * +TypeCodeString(const int code) +{ + int i; + int num; + num = sizeof(TypeCodes) / sizeof(int); + + for(i = 0 ; i < num ; i++) { + if (code == TypeCodes[i]) { + return Types[i]; + } + } + return NULL; +} + +int +IsTypeCodeNumeric( const int code ) +{ + int i; + + for(i = 0 ; i < sizeof(TypeCodes) / sizeof(TypeCodes[0]) ; i++) { + if (TypeCodes[i] == rpc_FLOAT) { + break; + } + if (code == TypeCodes[i]) { + return 1; + } + } + return 0; +} |