diff --git a/Testing/unit/hg/CMakeLists.txt b/Testing/unit/hg/CMakeLists.txt index 7201394b..166b2e3d 100644 --- a/Testing/unit/hg/CMakeLists.txt +++ b/Testing/unit/hg/CMakeLists.txt @@ -27,16 +27,30 @@ endif() function(build_mercury_test test_name) if(${CMAKE_VERSION} VERSION_GREATER 3.12) add_executable(hg_test_${test_name} test_${test_name}.c) - target_link_libraries(hg_test_${test_name} mercury_unit) + target_link_libraries(hg_test_${test_name} mercury_unit ${ARGN}) else() add_executable(hg_test_${test_name} test_${test_name}.c mercury_unit.c mercury_rpc_cb.c) - target_link_libraries(hg_test_${test_name} mercury_test_common) + target_link_libraries(hg_test_${test_name} mercury_test_common ${ARGN}) endif() if(MERCURY_ENABLE_COVERAGE) set_coverage_flags(hg_test_${test_name}) endif() endfunction() +# add ${test_xname} lib target using hg_rpcgen on file ${test_xname}.x +function(build_mercury_rpcgen_procs test_xname) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${test_xname}.h + ${CMAKE_CURRENT_BINARY_DIR}/${test_xname}_proc.c + COMMAND ${CMAKE_BINARY_DIR}/bin/hg_rpcgen + ${CMAKE_CURRENT_SOURCE_DIR}/${test_xname}.x + DEPENDS ${test_xname}.x) + add_library(${test_xname} ${test_xname}_proc.c) + target_link_libraries(${test_xname} mercury) + target_include_directories(${test_xname} + PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) +endfunction() + macro(add_mercury_test test_name comm protocol busy parallel self scalable ignore_server_err) # Set full test name @@ -222,9 +236,13 @@ build_mercury_test(bulk) build_mercury_test(lookup) build_mercury_test(proc) +build_mercury_rpcgen_procs(test_hg_rpcgen) +build_mercury_test(hg_rpcgen test_hg_rpcgen) + build_mercury_test(kill) add_mercury_test_standalone(proc) +add_mercury_test_standalone(hg_rpcgen) add_mercury_test_comm_all(rpc) add_mercury_test_comm_all(bulk) diff --git a/Testing/unit/hg/mercury_rpc_cb.c b/Testing/unit/hg/mercury_rpc_cb.c index ba4538d1..5ede877e 100644 --- a/Testing/unit/hg/mercury_rpc_cb.c +++ b/Testing/unit/hg/mercury_rpc_cb.c @@ -188,13 +188,11 @@ HG_TEST_RPC_CB(hg_test_rpc_open, handle) hg_size_t payload_size = HG_Get_input_payload_size(handle); #ifdef HG_HAS_XDR size_t expected_string_payload_size = /* note xdr rounding rules */ - sizeof(uint64_t) + /* length */ - RNDUP(strlen(HG_TEST_RPC_PATH) + 1) + /* string data, inc \0 at end */ - RNDUP(sizeof(uint8_t)) + /* is_const */ - RNDUP(sizeof(uint8_t)); /* is_owned */ + sizeof(uint32_t) + /* length */ + RNDUP(strlen(HG_TEST_RPC_PATH)); /* string data (no \0) */ #else size_t expected_string_payload_size = - strlen(HG_TEST_RPC_PATH) + sizeof(uint64_t) + 3; + sizeof(uint32_t) + strlen(HG_TEST_RPC_PATH); /* len + data */ #endif HG_TEST_CHECK_ERROR( diff --git a/Testing/unit/hg/test_hg_rpcgen.c b/Testing/unit/hg/test_hg_rpcgen.c new file mode 100644 index 00000000..5fd84a61 --- /dev/null +++ b/Testing/unit/hg/test_hg_rpcgen.c @@ -0,0 +1,628 @@ +/* + * test_hg_rpcgen.c test hg_rpcgen/hg_proc integration + * 29-Nov-2024 chuck@ece.cmu.edu + */ + +#include +#include +#include +#include + +#include "mercury_unit.h" +#include "mercury_proc_extra.h" +#include "test_hg_rpcgen.h" + +/* proc ops: HG_ENCODE, HG_DECODE, HG_FREE */ + +/* encode/decode a uint32_t directly, w/o hg_rpcgen code */ +static void +test0(hg_proc_t prc) +{ + hg_return_t ret; + char buf[BUFSIZ]; + uint32_t in0, in, out; + + HG_TEST("u32 direct"); + + in0 = 0xcafec001; + in = in0; + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE)"); + + ret = hg_proc_uint32_t(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc encode"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush"); + + in = out = 0; + ret = hg_proc_reset(prc, buf, hg_proc_get_size_used(prc), HG_DECODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (DECODE)"); + + ret = hg_proc_uint32_t(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc decode"); + + HG_TEST_CHECK_ERROR(out != in0, done, ret, HG_OTHER_ERROR, "data mismatch"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_FREE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (FREE)"); + + ret = hg_proc_uint32_t(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc free"); + + HG_PASSED(); + +done: + if (ret != HG_SUCCESS) + HG_FAILED(); + + return; +} + +/* encode/decode a fixed buffer directly, w/o hgrpcgen code */ +static void +test1(hg_proc_t prc) +{ + hg_return_t ret; + char buf[BUFSIZ]; + char in0[64], in[64], out[64]; +#define TEST1_MSG "0xcafec001 is on!" + + HG_TEST("fixed buf direct"); + + snprintf(in0, sizeof(in0), TEST1_MSG); + snprintf(in, sizeof(in), "%s", in0); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE)"); + + ret = hg_proc_bytes(prc, in, sizeof(TEST1_MSG)); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc encode"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush"); + + memset(in, 0, sizeof(in)); + memset(out, 0, sizeof(out)); + + ret = hg_proc_reset(prc, buf, hg_proc_get_size_used(prc), HG_DECODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (DECODE)"); + + ret = hg_proc_bytes(prc, out, sizeof(TEST1_MSG)); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc decode"); + + HG_TEST_CHECK_ERROR(strcmp(in0, out) != 0, done, ret, + HG_OTHER_ERROR, "data mismatch"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_FREE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (FREE)"); + + ret = hg_proc_bytes(prc, out, sizeof(TEST1_MSG)); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc free"); + + HG_PASSED(); + +done: + if (ret != HG_SUCCESS) + HG_FAILED(); + + return; +} + +/* encode/decode a 'rgbcount' struct using generated output */ +static void +test2(hg_proc_t prc) +{ + hg_return_t ret; + char buf[BUFSIZ]; + rgbcount in0, in, out; + + HG_TEST("hg_rpcgen struct"); + + in0.rval = GREEN; + in0.pcount = 54321; + in0.valid = HG_TRUE; + in = in0; /* struct copy */ + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE)"); + + ret = hg_proc_rgbcount(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc encode"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush"); + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + + ret = hg_proc_reset(prc, buf, hg_proc_get_size_used(prc), HG_DECODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (DECODE)"); + + ret = hg_proc_rgbcount(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc decode"); + + HG_TEST_CHECK_ERROR(out.rval != in0.rval || out.pcount != in0.pcount || + out.valid != HG_TRUE, done, ret, HG_OTHER_ERROR, "data mismatch"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_FREE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (FREE)"); + + ret = hg_proc_rgbcount(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc free"); + + HG_PASSED(); + +done: + if (ret != HG_SUCCESS) + HG_FAILED(); + + return; +} + +/* encode/decode opaque items */ +static void +test3(hg_proc_t prc) +{ + hg_return_t ret; + char buf[BUFSIZ], scratch[BUFSIZ]; + otype1 o1; + otype2 o2; + otype3 o3; + optest in0, in, out; + + HG_TEST("hg_rpcgen opaque"); + + /* first test encode (not bothering about checking the data) */ + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE)"); + + ret = hg_proc_otype1(prc, &o1); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode otype1"); + + o2.otype2_len = 10; + o2.otype2_val = scratch; + ret = hg_proc_otype2(prc, &o2); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode otype2"); + + o3.otype3_len = 100; + o3.otype3_val = scratch; + ret = hg_proc_otype3(prc, &o3); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode otype3"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush"); + + /* try again, but overflow max len */ + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE2)"); + + o2.otype2_len = 21; /* over maxsize limit */ + o2.otype2_val = scratch; + ret = hg_proc_otype2(prc, &o2); + HG_TEST_CHECK_ERROR(ret != HG_OVERFLOW, done, ret, HG_OTHER_ERROR, + "failed overflow check"); + + /* now switch to optest structure - make up some test data */ + snprintf(in0.ofield1, sizeof(in0.ofield1), "%s", "hi!"); + snprintf(in0.ofield4, sizeof(in0.ofield4), "%s", "there"); + in0.ofield2.ofield2_len = 0; + in0.ofield2.ofield2_val = NULL; + in0.ofield5.otype2_len = 0; + in0.ofield5.otype2_val = NULL; + in0.ofield3.ofield3_len = sizeof(TEST1_MSG); + in0.ofield3.ofield3_val = TEST1_MSG; +#define TEST3_MSG "more testing" + in0.ofield6.otype3_len = sizeof(TEST3_MSG); + in0.ofield6.otype3_val = TEST3_MSG; + in = in0; /* struct copy */ + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE3)"); + + ret = hg_proc_optest(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode optest"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush2"); + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + + ret = hg_proc_reset(prc, buf, hg_proc_get_size_used(prc), HG_DECODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (DECODE)"); + + ret = hg_proc_optest(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "decode optest"); + + HG_TEST_CHECK_ERROR(strcmp(in0.ofield1, out.ofield1) || + strcmp(in0.ofield4, out.ofield4) || out.ofield2.ofield2_len || + out.ofield2.ofield2_val || out.ofield5.otype2_len || + out.ofield5.otype2_val || + out.ofield3.ofield3_len != sizeof(TEST1_MSG) || + strcmp(out.ofield3.ofield3_val, TEST1_MSG) || + out.ofield6.otype3_len != sizeof(TEST3_MSG) || + strcmp(out.ofield6.otype3_val, TEST3_MSG), + done, ret, HG_OTHER_ERROR, "data mismatch"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_FREE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (FREE)"); + + ret = hg_proc_optest(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "free optest"); + + HG_PASSED(); + +done: + if (ret != HG_SUCCESS) + HG_FAILED(); + + return; +} + +/* encode/decode strings */ +void test4(hg_proc_t prc) { + hg_return_t ret; + char buf[BUFSIZ]; + stype1 s1; + stype2 s2; + stringtest in0, in, out; + + HG_TEST("hg_rpcgen string"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE)"); + + s1 = TEST1_MSG; + ret = hg_proc_stype1(prc, &s1); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode stype1"); + + s2 = "more"; + ret = hg_proc_stype2(prc, &s2); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode stype2"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE2)"); + + s2 = TEST1_MSG; /* over limit */ + ret = hg_proc_stype2(prc, &s2); + HG_TEST_CHECK_ERROR(ret != HG_OVERFLOW, done, ret, HG_OTHER_ERROR, + "failed overflow check"); + + /* fields cannot be null (or we'll crash in strlen()) */ + in0.field1 = "first string"; + in0.field2 = "short"; + in0.field3 = "f3"; + in0.field4 = "closing soon!"; + in = in0; /* struct copy */ + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE3)"); + + ret = hg_proc_stringtest(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode stringtest"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush"); + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + + ret = hg_proc_reset(prc, buf, hg_proc_get_size_used(prc), HG_DECODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (DECODE)"); + + ret = hg_proc_stringtest(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "decode stringtest"); + + HG_TEST_CHECK_ERROR(strcmp(out.field1, in0.field1) || + strcmp(out.field2, in0.field2) || strcmp(out.field3, in0.field3) || + strcmp(out.field4, in0.field4), done, ret, + HG_OTHER_ERROR, "data mismatch"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_FREE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (FREE)"); + + ret = hg_proc_stringtest(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (FREE)"); + + HG_PASSED(); + +done: + if (ret != HG_SUCCESS) + HG_FAILED(); + + return; +} + +/* encode/decode various data types */ +static void +test5(hg_proc_t prc) +{ + hg_return_t ret; + char buf[BUFSIZ]; + size_t lcv; + uint32_t scratch[BUFSIZ]; + uint32_t tmpval; + typedstr in0, in, out; + + HG_TEST("hg_rpcgen types"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE)"); + + for (lcv = 0 ; lcv < sizeof(in0.f1)/sizeof(in0.f1[0]) ; lcv++) { + in0.f1[lcv] = lcv+10; + scratch[lcv] = lcv+100; + } + in0.f2.type2_len = sizeof(in0.f1)/sizeof(in0.f1[0]); + in0.f2.type2_val = scratch; + in0.f3.type3_len = 0; + in0.f3.type3_val = NULL; + in0.f4 = 4000; + tmpval = 5000; + in0.f5 = &tmpval; + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + + in = in0; /* struct copy */ + + ret = hg_proc_typedstr(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode typedstr"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush"); + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + + ret = hg_proc_reset(prc, buf, hg_proc_get_size_used(prc), HG_DECODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (DECODE)"); + + ret = hg_proc_typedstr(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "decode typedstr"); + + for (lcv = 0 ; lcv < sizeof(in0.f1)/sizeof(in0.f1[0]) ; lcv++) { + HG_TEST_CHECK_ERROR(in0.f1[lcv] != out.f1[lcv], done, ret, + HG_OTHER_ERROR, "f1 data mismatch"); + } + HG_TEST_CHECK_ERROR(in0.f2.type2_len != out.f2.type2_len, done, ret, + HG_OTHER_ERROR, "f2 data len mismatch"); + for (lcv = 0 ; lcv < out.f2.type2_len ; lcv++) { + HG_TEST_CHECK_ERROR(in0.f2.type2_val[lcv] != out.f2.type2_val[lcv], + done, ret, HG_OTHER_ERROR, "f2 data mismatch"); + } + HG_TEST_CHECK_ERROR(out.f3.type3_len || out.f3.type3_val || + out.f4 != in0.f4, done, ret, HG_OTHER_ERROR, "f3 mismatch"); + HG_TEST_CHECK_ERROR(*in0.f5 != *out.f5 || in.f5 == out.f5, + done, ret, HG_OTHER_ERROR, "f3 mismatch"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_FREE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (FREE)"); + + ret = hg_proc_typedstr(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "free typedstr"); + + HG_PASSED(); + +done: + if (ret != HG_SUCCESS) + HG_FAILED(); + + return; +} + +/* encode/decode various data types */ +static void +test6(hg_proc_t prc) +{ + hg_return_t ret; + char buf[BUFSIZ]; + utest in, out0, out1, out2, out3, out4; + + HG_TEST("hg_rpcgen struct+union"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE)"); + + in.type = 0; + in.utest_u.b.base_id = 10; + snprintf(in.utest_u.b.base_name, sizeof(in.utest_u.b.base_name), "type0"); + + ret = hg_proc_utest(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode utest t0"); + + in.type = 1; + in.utest_u.c.baseinfo.base_id = 11; + snprintf(in.utest_u.c.baseinfo.base_name, + sizeof(in.utest_u.c.baseinfo.base_name), "type1"); + in.utest_u.c.counter = 0xcafec001; + + ret = hg_proc_utest(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode utest t1"); + + in.type = 2; + ret = hg_proc_utest(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode utest t2"); + + in.type = 3; + ret = hg_proc_utest(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode utest t3"); + + in.type = 4; + in.utest_u.data = 0xfeedcafe; + + ret = hg_proc_utest(prc, &in); + HG_TEST_CHECK_HG_ERROR(done, ret, "encode utest t4"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush"); + + memset(&in, 0, sizeof(in)); + memset(&out0, 0, sizeof(out0)); + memset(&out1, 0, sizeof(out1)); + memset(&out2, 0, sizeof(out2)); + memset(&out3, 0, sizeof(out3)); + memset(&out4, 0, sizeof(out4)); + + ret = hg_proc_reset(prc, buf, hg_proc_get_size_used(prc), HG_DECODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (DECODE)"); + + ret = hg_proc_utest(prc, &out0); + HG_TEST_CHECK_HG_ERROR(done, ret, "decode utest t0"); + + HG_TEST_CHECK_ERROR(out0.type != 0 || out0.utest_u.b.base_id != 10 || + strcmp("type0", out0.utest_u.b.base_name), done, ret, + HG_OTHER_ERROR, "out0 mismatch"); + + ret = hg_proc_utest(prc, &out1); + HG_TEST_CHECK_HG_ERROR(done, ret, "decode utest t1"); + + HG_TEST_CHECK_ERROR(out1.type != 1 || + out1.utest_u.c.baseinfo.base_id != 11 || + strcmp(out1.utest_u.c.baseinfo.base_name, "type1") || + out1.utest_u.c.counter != 0xcafec001, + done, ret, HG_OTHER_ERROR, "out1 mismatch"); + + ret = hg_proc_utest(prc, &out2); + HG_TEST_CHECK_HG_ERROR(done, ret, "decode utest t2"); + + HG_TEST_CHECK_ERROR(out2.type != 2, done, ret, HG_OTHER_ERROR, + "out2 mismatch"); + + ret = hg_proc_utest(prc, &out3); + HG_TEST_CHECK_HG_ERROR(done, ret, "decode utest t3"); + + HG_TEST_CHECK_ERROR(out3.type != 3, done, ret, HG_OTHER_ERROR, + "out3 mismatch"); + + ret = hg_proc_utest(prc, &out4); + HG_TEST_CHECK_HG_ERROR(done, ret, "decode utest t4"); + + HG_TEST_CHECK_ERROR(out4.type != 4 || out4.utest_u.data != 0xfeedcafe, + done, ret, HG_OTHER_ERROR, "out4 mismatch"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_FREE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (FREE)"); + + ret = hg_proc_utest(prc, &out0); + HG_TEST_CHECK_HG_ERROR(done, ret, "free utest t0"); + ret = hg_proc_utest(prc, &out1); + HG_TEST_CHECK_HG_ERROR(done, ret, "free utest t1"); + ret = hg_proc_utest(prc, &out2); + HG_TEST_CHECK_HG_ERROR(done, ret, "free utest t2"); + ret = hg_proc_utest(prc, &out3); + HG_TEST_CHECK_HG_ERROR(done, ret, "free utest t3"); + ret = hg_proc_utest(prc, &out4); + HG_TEST_CHECK_HG_ERROR(done, ret, "free utest t4"); + + HG_PASSED(); + +done: + if (ret != HG_SUCCESS) + HG_FAILED(); + + return; +} + +/* encode/decode linked list */ +void test7(hg_proc_t prc) { + hg_return_t ret; + char buf[BUFSIZ]; + i32list il[4], out, *p; + int lcv; + + HG_TEST("hg_rpcgen linked list"); + + for (lcv = 0 ; lcv < 4 ; lcv++) { + il[lcv].ival = lcv+1; + if (lcv < 3) + il[lcv].next = &il[lcv+1]; + } + il[3].next = NULL; + out.ival = 0; + out.next = NULL; + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_ENCODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (ENCODE)"); + + ret = hg_proc_i32list(prc, il); + HG_TEST_CHECK_HG_ERROR(done, ret, "i32list encode"); + + ret = hg_proc_flush(prc); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc flush"); + + ret = hg_proc_reset(prc, buf, hg_proc_get_size_used(prc), HG_DECODE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (DECODE)"); + + ret = hg_proc_i32list(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "i32list decode"); + + for (lcv = 0, p = &out ; lcv < 4 ; lcv++, p = p->next) { + HG_TEST_CHECK_ERROR(il[lcv].ival != p->ival, done, ret, + HG_OTHER_ERROR, "data mismatch"); + } + HG_TEST_CHECK_ERROR(p != NULL, done, ret, HG_OTHER_ERROR, "null mismatch"); + + ret = hg_proc_reset(prc, buf, sizeof(buf), HG_FREE); + HG_TEST_CHECK_HG_ERROR(done, ret, "proc_reset (FREE)"); + + ret = hg_proc_i32list(prc, &out); + HG_TEST_CHECK_HG_ERROR(done, ret, "i32list free"); + + HG_PASSED(); + +done: + if (ret != HG_SUCCESS) + HG_FAILED(); + + return; +} + +int +main(void) +{ + hg_return_t hg_ret; + int ret = EXIT_SUCCESS; + hg_class_t *hgclass; + hg_proc_t prc; /* a pointer */ + + /* + * XXX: + * hg_proc_create() will fail without a non-NULL class pointer + * even though we do not need an hg_class_t for any of our tests. + * create a fake non-NULL class pointer to work around this... + */ + hgclass = (hg_class_t *) 1; /* will crash test program if used */ + + /* create proc test */ + HG_TEST("create proc"); + hg_ret = hg_proc_create(hgclass, HG_CRC32, &prc); + HG_TEST_CHECK_ERROR(hg_ret != HG_SUCCESS, done, ret, + EXIT_FAILURE, "create proc test failed"); + HG_PASSED(); + + test0(prc); + test1(prc); + test2(prc); + test3(prc); + test4(prc); + test5(prc); + test6(prc); + test7(prc); + + /* dispose of proc test */ + HG_TEST("dispose of proc"); + hg_ret = hg_proc_free(prc); + HG_TEST_CHECK_ERROR(hg_ret != HG_SUCCESS, done, ret, + EXIT_FAILURE, "dispose of proc test failed"); + HG_PASSED(); + +done: + if (ret != EXIT_SUCCESS) + HG_FAILED(); + + return ret; +} diff --git a/Testing/unit/hg/test_hg_rpcgen.x b/Testing/unit/hg/test_hg_rpcgen.x new file mode 100644 index 00000000..0f831e97 --- /dev/null +++ b/Testing/unit/hg/test_hg_rpcgen.x @@ -0,0 +1,305 @@ +/* + * test_hg_rpcgen.x document/test hg_rpcgen .x input files + * 29-Nov-2024 chuck@ece.cmu.edu + */ + +/* + * this file gets run through the C pre-processor with -DHG_RPC_HDR + * when generating *.h files and -DHG_RPC_PROC when generating *_proc.c + * files. we use the same parser as rpcgen, but ignore 'program' + * statements. lines that start with '%' are directly passed through + * to the output stream without being parsed. + */ + +/* there are 5 basic statement types: const, enum, typedef, struct, union */ + +const MAXSIZE = 512; /* becomes a C #define in the .h file */ + +/* + * an enum becomes a C enum definition (with a typedef) in the .h file. + * we also generate a hg_proc_cb_t proc function suitable for registering + * with mercury RPCs. the prototype for the proc function is generated + * in the .h file and the actual function is generated in the .c file. + * + * note that in C an enum can handle 'int' sized values, but the compiler + * can choose a smaller type if the values fit. in sunrpc enum_t is + * typedef'd to "int" which maps to int32_t on modern platforms. + * + * XXX: hg_rpcgen currently directly generates enums as int32_t rather + * than defining and using an 'enum_t' type. + */ +enum rgb { + RED = 1, + GREEN = 2, + BLUE = 3 +}; + +/* + * typdefs are passed through to the .h file. we also generate + * a hg_proc_cb_t proc function for the new type we are defining. + */ +typedef uint32_t counter32; /* becomes a C typedef (w/proc fn) */ + +/* + * predefined mercury types: int8_t, uint8_t, int16_t, uint16_t, + * int32_t, uint32_t, int64_t, uint64_t. + * + * vectors: a fixed length C array defined with the length in '[]' + * - 'int32_t stats[8]' + * + * arrays: a variable length array defined with the max length in '<>' + * - 'int32_t numlist<10>' 0 to 10 int32_t + * - 'uint32_t blocklist<>' list of uint32_t with no size limit + * note: internally arrays are stored as a length and a pointer to + * a dynamically allocated C array (as seen in the .h output + * of hg_rpcgen). + * + * special types: + * - 'bool' is converted to hg_bool_t (a uint8_t) + * - 'opaque' is a byte array (fixed vector or variable length array) + * - 'string' is a null terminated C string (variable length array only) + * - pointers are allowed (including pointers set to NULL, but not + * pointers to pointers or void* pointers) + * + * note: hg_rpcgen itself does not detect undefined types. instead + * it lets the compiler detect this. + */ + +/* + * structs are converted to C structures and hg_proc_cb_t proc functions. + * C structure definitions are adjusted for variable length arrays. + * structures can be nested. + */ +struct rgbcount { + rgb rval; + counter32 pcount; + bool valid; /* converted to hg_bool_t */ +}; + +/* + * unions have an int type and are converted to a C structure + * with an embedded C union in it. note the union syntax here + * is different from C. also note that only one variable decl + * is allowed per case (if you need more, define a struct first + * and then use it in the union). + */ +union name_number_or_nothing switch (uint32_t type) { + case 0: opaque name[MAXSIZE]; + case 1: uint32_t number; + case 2: /* fall throughs are ok, goes to next case */ + case 3: void; /* no additional fields */ +}; + +/* sample typedefs */ + +/* + * do multiple types of typedef and then use them in a structure. + */ +typedef uint32_t type1[10]; /* a vector (REL_VECTOR) */ +typedef uint32_t type2<20>; /* a var length array (REL_ARRAY) */ +typedef uint32_t type3<>; /* var length w/o max */ +typedef uint32_t type4; /* an alias (REL_ALIAS) */ +typedef uint32_t *type5; /* a pointer (REL_POINTER) */ + +struct typedstr { + type1 f1; + type2 f2; + type3 f3; + type4 f4; + type5 f5; +}; + +/* + * typedef in a struct with a pointer + */ +typedef struct typedstr *tspointer; + +struct tdlist { + typedstr tdata; + tspointer *next; +}; + +/* + * we track structs we've defined and use their typedef type + * rather than 'struct type' ... + */ +struct known { /* will create 'known' typedef for this struct */ + uint32_t f6; +}; + +#ifdef HG_RPC_PROC +%/* make dummy function for unknown outside of hg_rpcgen so test compiles */ +%hg_return_t hg_proc_unknown(hg_proc_t p, void *v) { return HG_SUCCESS; } +#endif /* HG_RPC_PROC */ + +typedef struct known type6; /* emit: 'typedef known type6' */ +typedef known type7; /* emit: 'typedef known type7' */ +typedef struct unknown type8; /* emit: 'typedef struct unknown type8' */ + +/* sample opaque */ + +/* + * 'opaque' must be an array (fixed [] or variable <>). + * internally it becomes a char* with a length. opaque + * can be in typedefs, structs, or unions. unions share + * the same code generator as structs, so we just test + * typedef and struct here. + */ + +typedef opaque otype1[10]; /* fixed size, 10 bytes */ +typedef opaque otype2<20>; /* variable size, up to 20 bytes */ +typedef opaque otype3<>; /* variable size, no max */ + +struct optest { + opaque ofield1[30]; /* fixed size in a struct */ + opaque ofield2<40>; /* variable sized in a struct */ + opaque ofield3<>; /* variable sized in a struct (no max) */ + /* define some fields using the typedefs */ + otype1 ofield4; + otype2 ofield5; + otype3 ofield6; +#if 0 + /* + * opaque cannot be pointers or aliases. the parser + * will reject the two opaque lines below... + */ + opaque *broke1; /* NO! */ + opaque broke2; /* NO! */ +#endif +}; + +/* sample strings */ + +/* + * strings: null terminated C strings. we can determine string length + * using strlen(). strings must be defined as variable length arrays + * ("<>") and are converted to 'char *' in our output. the underlying + * char* for a string cannot be NULL. + */ + +/* + * typedef strings + */ +typedef string stype1<>; /* typedef char *stype1 */ +typedef string stype2<10>; /* typedef char *stype2 */ + +/* + * strings inside of structs using typedefs or directly defined + */ +struct stringtest { + stype1 field1; /* use above typedef */ + stype2 field2; /* use above typedef */ + string field3<>; /* string w/o max length */ + string field4<20>; /* string with max length */ +#if 0 + /* + * strings cannot be pointers, vectors, or aliases. the parser + * will reject the three string lines below... + */ + string *broke1; /* NO! */ + string broke2[30]; /* NO! */ + string broke3; /* NO! */ +#endif +}; + +/* sample struct/union */ + +/* + * structures have 4 types of fields: alias, vector, pointer, array. + * vectors are fixed sized C arrays, arrays are variable size. + */ +struct fourtypes { + uint32_t alias_type; + uint32_t vec_type[20]; /* vectors are fixed size */ + uint32_t *ptr_type; + uint32_t array_type<>; /* array becomes _len, _val structure */ +}; + +/* + * structs can nest + */ +struct base { + uint32_t base_id; + opaque base_name[16]; +}; + +/* nest 'base' inside of counter */ +struct counter { + base baseinfo; + uint32_t counter; +}; + +/* you can nest a dynamically allocated base structure with a pointer */ +struct counterp { + base *baseinfop; /* points to a base or NULL */ + uint32_t counter; +}; + +/* you can make vectors/arrays of structures */ +struct bases { + base basevector[10]; /* fixed length vector */ + base basearray<>; /* variable length */ +}; + +/* + * structures can have pointers to themselves (e.g. for a simple linked + * list or basic tree). (more complicated structures may require writing + * helper functions directly in C.) + */ +struct i32list { + uint32_t ival; + i32list *next; +}; + +/* + * unions have a switch with an int type and cases. each case + * is allowed to have a single type, fall through, or have an + * empty structure (denoted by 'void'). + */ +union utest switch (uint8_t type) { + case 0: base b; + case 1: counter c; + case 2: /* fall through */ + case 3: void; /* no data */ + default: uint32_t data; /* if type does not match a case */ +}; + +#if 0 +/* + * this will fail, as type is not an int. the type has to be + * something that works with a C switch statement. +union utest2 switch (float type) { /* NO! */ + case 0: void; +} +#endif + +/* code generation cases */ + +/* + * here are all the code generation cases in a single structure. + */ +struct codgencases { + /* POINTER (any type) */ + int64_t *p1; /* pointer case: becomes hg_proc_pointer() call */ + + /* VECTOR (fixed length C array) */ +#if 0 + string vr1[11]; /* vector case 1: C string -- parser does not allow! */ +#endif + opaque vr2[12]; /* vector case 2: unstructed opaque blob, fixed length */ + /* uses hg_proc_bytes() with given size */ + int64_t vr3[9]; /* vector case 3: neither string nor opaque */ + /* uses hg_proc_vector() on this */ + + /* ARRAY (variable length) */ + string ar1<20>; /* array case 1: C string, becomes char* */ + /* use hg_proc_string() for coding (uses strlen) */ + opaque ar2<30>; /* array case 2: unstructured blob, becomes (char*,len) */ + /* use hg_proc_varbytes() to store len, char*data */ + int64_t ar3<40>; /* array case 3: neither string nor opaque */ + /* uses hg_proc_array() and proc for element type */ + + /* ALIAS */ + bool av1; /* alias case 1: bool - gets converted to hg_bool_t */ + int64_t av2; /* alias case 2: !bool */ +}; diff --git a/Testing/unit/hg/test_overflow.h b/Testing/unit/hg/test_overflow.h index 69a57bbc..2059e565 100644 --- a/Testing/unit/hg/test_overflow.h +++ b/Testing/unit/hg/test_overflow.h @@ -9,7 +9,7 @@ #define TEST_OVERFLOW_H #include "mercury_macros.h" -#include "mercury_proc_string.h" +#include "mercury_proc_extra.h" #ifdef HG_HAS_BOOST diff --git a/Testing/unit/hg/test_proc.c b/Testing/unit/hg/test_proc.c index b1bdec7e..67b9efe1 100644 --- a/Testing/unit/hg/test_proc.c +++ b/Testing/unit/hg/test_proc.c @@ -209,7 +209,7 @@ static hg_return_t hg_test_proc_string(void) { hg_return_t ret; - hg_test_proc_string_t in = {"Hello"}, out = {"NULL"}; + hg_test_proc_string_t in = {"Hello"}, out = {NULL}; ret = hg_test_proc_generic(hg_proc_hg_test_proc_string_t, &in, &out); HG_TEST_CHECK_HG_ERROR(done, ret, "hg_test_proc_generic() failed"); diff --git a/Testing/unit/hg/test_rpc.c b/Testing/unit/hg/test_rpc.c index 49a52a87..10ceb3f8 100644 --- a/Testing/unit/hg/test_rpc.c +++ b/Testing/unit/hg/test_rpc.c @@ -178,13 +178,11 @@ hg_test_rpc_input(hg_handle_t handle, hg_addr_t addr, hg_id_t rpc_id, hg_size_t payload_size; #ifdef HG_HAS_XDR size_t expected_string_payload_size = /* note xdr rounding rules */ - sizeof(uint64_t) + /* length */ - RNDUP(strlen(HG_TEST_RPC_PATH) + 1) + /* string data, inc \0 at end */ - RNDUP(sizeof(uint8_t)) + /* is_const */ - RNDUP(sizeof(uint8_t)); /* is_owned */ + sizeof(uint32_t) + /* length */ + RNDUP(strlen(HG_TEST_RPC_PATH)); /* string data, no \0 */ #else size_t expected_string_payload_size = - strlen(HG_TEST_RPC_PATH) + sizeof(uint64_t) + 3; + sizeof(uint32_t) + strlen(HG_TEST_RPC_PATH); #endif unsigned int flag; int rc; @@ -349,9 +347,11 @@ hg_test_rpc_output_overflow_cb(const struct hg_cb_info *callback_info) # endif hg_return_t ret = callback_info->ret; hg_size_t payload_size = HG_Get_output_payload_size(handle); - size_t expected_string_payload_size = - HG_Class_get_output_eager_size(HG_Get_info(handle)->hg_class) * 2 + 3 + - 2 * sizeof(uint64_t); + /* payload is an encoded overflow_out_t */ + /* to support xdr: RNDUP() the string length (eager output size * 2) */ + size_t expected_string_payload_size = sizeof(uint32_t) + /* length */ + HG_Class_get_output_eager_size(HG_Get_info(handle)->hg_class) * 2 + + sizeof(uint64_t); /* overflow_out_t.string_len */ HG_TEST_CHECK_HG_ERROR(done, ret, "Error in HG callback (%s)", HG_Error_to_string(callback_info->ret)); diff --git a/Testing/unit/hg/test_rpc.h b/Testing/unit/hg/test_rpc.h index c722843e..b304b24d 100644 --- a/Testing/unit/hg/test_rpc.h +++ b/Testing/unit/hg/test_rpc.h @@ -9,7 +9,7 @@ #define TEST_RPC_H #include "mercury_macros.h" -#include "mercury_proc_string.h" +#include "mercury_proc_extra.h" #include #include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a052f85..a46c16aa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -135,8 +135,9 @@ set(MERCURY_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/mercury_header.c ${CMAKE_CURRENT_SOURCE_DIR}/mercury_proc.c ${CMAKE_CURRENT_SOURCE_DIR}/mercury_proc_bulk.c - ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_proc_string.c - ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_string_object.c + ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_proc_rpcgen.c + ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_proc_rpcgen_array.c + ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_proc_rpcgen_ref.c ) #------------------------------------------------------------------------------ @@ -154,8 +155,7 @@ set(MERCURY_PUBLIC_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/mercury_proc_bulk.h ${CMAKE_CURRENT_SOURCE_DIR}/mercury_proc.h ${CMAKE_CURRENT_SOURCE_DIR}/mercury_types.h - ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_proc_string.h - ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_string_object.h + ${CMAKE_CURRENT_SOURCE_DIR}/proc_extra/mercury_proc_extra.h ) #------------------------------------------------------------------------------ diff --git a/src/proc_extra/mercury_proc_extra.h b/src/proc_extra/mercury_proc_extra.h new file mode 100644 index 00000000..60eb1328 --- /dev/null +++ b/src/proc_extra/mercury_proc_extra.h @@ -0,0 +1,189 @@ +/** + * Copyright (c) 2013-2022 UChicago Argonne, LLC and The HDF Group. + * Copyright (c) 2022-2023 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MERCURY_PROC_EXTRA_H +#define MERCURY_PROC_EXTRA_H + +#include "mercury_proc.h" + +/*************************************/ +/* Public Type and Struct Definition */ +/*************************************/ + +/* legacy string types for backward compat */ +typedef const char *hg_const_string_t; +typedef char *hg_string_t; + +/*****************/ +/* Public Macros */ +/*****************/ + +/*********************/ +/* Public Prototypes */ +/*********************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * helper functions for hg_rpcgen. + * + * note: memory allocated by the HG_DECODE op in the following + * functions can be freed using the HG_FREE op. + */ + +/** + * Variable length counted bytes (xdr_bytes). Decode will allocate + * and return memory in *cpp (if it is NULL). + * + * \param proc [IN/OUT] abstract processor object + * \param cpp [IN/OUT] *cpp points to the bytes + * \param sizep [IN/OUT] *sizep is the count + * \param maxsize [IN] largest number of bytes we allow + * + * \return HG_SUCCESS or corresponding HG error code + */ +HG_PUBLIC hg_return_t +hg_proc_varbytes(hg_proc_t proc, char **cpp, uint32_t *sizep, uint32_t maxsize); + +/** + * NULL terminated C strings (xdr_string). Length can be determined + * with strlen(). Decode will allocate and return memory in *cpp + * (if it is NULL). + * + * \param proc [IN/OUT] abstract processor object + * \param cpp [IN/OUT] *cpp points to the string + * \param maxsize [IN] largest size of string we allow + * + * \return HG_SUCCESS or corresponding HG error code + */ +HG_PUBLIC hg_return_t +hg_proc_string(hg_proc_t proc, char **cpp, uint32_t maxsize); + +/** + * A variable length array of elements (xdr_array). Decode will + * allocate the array memory if *addrp is NULL. + * + * \param proc [IN/OUT] abstract processor object + * \param addrp [IN/OUT] pointer to the variable length array + * \param sizep [IN/OUT] *sizep is the number of array elements + * \param maxsize [IN] max number of elements allowed in array + * \param elsize [IN] size of a single element in bytes + * \param elproc [IN] proc fn to handle an array element + * + * \return HG_SUCCESS or corresponding HG error code + */ +HG_PUBLIC hg_return_t +hg_proc_array(hg_proc_t proc, char **addrp, uint32_t *sizep, + uint32_t maxsize, uint32_t elsize, hg_proc_cb_t elproc); + +/** + * A fixed length array of elements (xdr_vector). + * + * \param proc [IN/OUT] abstract processor object + * \param basep [IN] base address of vector array + * \param nelem [IN] number of elements in the array + * \param elemsize [IN] size of one element + * \param xelem [IN] proc fn to handle a vector array element + * + * \return HG_SUCCESS or corresponding HG error code + */ +HG_PUBLIC hg_return_t +hg_proc_vector(hg_proc_t proc, char *basep, uint32_t nelem, uint32_t elemsize, + hg_proc_cb_t xelem); + +/** + * Pointer indirection (xdr_reference). can be used to help encode/decode + * basic structs with pointers. Decode will allocate the memory we + * indirect to (if *pp is NULL). + * + * \param proc [IN/OUT] abstract processor object + * \param pp [IN/OUT] *pp reference that points to our data + * \param size [IN] size of the data we reference + * \param pr [IN] proc fn to handle the reference + * + * \return HG_SUCCESS or corresponding HG error code + */ +HG_PUBLIC hg_return_t +hg_proc_reference(hg_proc_t proc, char **pp, uint32_t size, hg_proc_cb_t pr); + +/** + * A pointer, the pointer is allowed to be NULL (xdr_pointer). coded + * as a union (NULL pointer or data structure). uses hg_proc_reference() + * if pointer is non-NULL, so decode will allocate memory if needed. + * + * \param proc [IN/OUT] abstract processor object + * \param objpp [IN/OUT] *objpp is the pointer + * \param obj_size [IN] size of object we point to + * \param xobj [IN] proc fn to handle the pointer + * + * \return HG_SUCCESS or corresponding HG error code + */ +HG_PUBLIC hg_return_t +hg_proc_pointer(hg_proc_t proc, char **objpp, uint32_t obj_size, + hg_proc_cb_t xobj); + +/* + * legacy hg_proc_hg_const_string_t() and hg_proc_hg_string_t() + * string functions. these now use rpcgen's hg_proc_string() as + * a backend. On decode we assume that the string pointer may be + * uninitialized, so we set it to NULL to ensure that hg_proc_string() + * calls malloc to allocate string memory (so callers cannot provide + * their own buffer -- we always malloc). + */ + +/** + * Generic processing routine. + * + * \param proc [IN/OUT] abstract processor object + * \param data [IN/OUT] pointer to data + * + * \return HG_SUCCESS or corresponding HG error code + */ +static HG_INLINE hg_return_t +hg_proc_hg_const_string_t(hg_proc_t proc, void *data); + +/** + * Generic processing routine. + * + * \param proc [IN/OUT] abstract processor object + * \param data [IN/OUT] pointer to data + * + * \return HG_SUCCESS or corresponding HG error code + */ +static HG_INLINE hg_return_t +hg_proc_hg_string_t(hg_proc_t proc, void *data); + +/************************************/ +/* Local Type and Struct Definition */ +/************************************/ + +/*---------------------------------------------------------------------------*/ +static HG_INLINE hg_return_t +hg_proc_hg_const_string_t(hg_proc_t proc, void *data) +{ + if (hg_proc_get_op(proc) == HG_DECODE) { + *( (char **) data ) = NULL; + } + return hg_proc_string(proc, (char **)data, UINT32_MAX); +} + +/*---------------------------------------------------------------------------*/ +static HG_INLINE hg_return_t +hg_proc_hg_string_t(hg_proc_t proc, void *data) +{ + if (hg_proc_get_op(proc) == HG_DECODE) { + *( (char **) data ) = NULL; + } + return hg_proc_string(proc, (char **)data, UINT32_MAX); +} + +#ifdef __cplusplus +} +#endif +#endif /* MERCURY_PROC_EXTRA_H */ diff --git a/src/proc_extra/mercury_proc_rpcgen.c b/src/proc_extra/mercury_proc_rpcgen.c new file mode 100644 index 00000000..287bcb1c --- /dev/null +++ b/src/proc_extra/mercury_proc_rpcgen.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * xdr.c, Generic XDR routines implementation. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + * + * These are the "generic" xdr routines used to serialize and de-serialize + * most common data items. See xdr.h for more info on the interface to + * xdr. + */ + +#include +#include +#include "mercury_proc_extra.h" + +/* + * counted bytes + * *cpp is a pointer to the bytes, *sizep is the count. + * If *cpp is NULL maxsize bytes are allocated + */ +hg_return_t +hg_proc_varbytes(hg_proc_t proc, char **cpp, uint32_t *sizep, uint32_t maxsize) +{ + char *sp; /* sp is the actual string pointer */ + uint32_t nodesize; + hg_return_t ret; + hg_bool_t allocated = HG_FALSE; + + sp = *cpp; + + /* + * first deal with the length since bytes are counted + */ + if ((ret = hg_proc_uint32_t(proc, sizep)) != HG_SUCCESS) { + return (ret); + } + nodesize = *sizep; + if ((nodesize > maxsize) && (hg_proc_get_op(proc) != HG_FREE)) { + return(HG_OVERFLOW); + } + + /* + * now deal with the actual bytes + */ + switch (hg_proc_get_op(proc)) { + case HG_DECODE: + if (nodesize == 0) { + return (HG_SUCCESS); + } + if (sp == NULL) { + *cpp = sp = malloc(nodesize); + allocated = HG_TRUE; + } + if (sp == NULL) { + warn("%s: out of memory", __func__); + return (HG_NOMEM); + } + /* FALLTHROUGH */ + + case HG_ENCODE: + ret = hg_proc_bytes(proc, sp, nodesize); + if ((hg_proc_get_op(proc) == HG_DECODE) && + (ret != HG_SUCCESS)) { + if (allocated == HG_TRUE) { + free(sp); + *cpp = NULL; + } + } + return (ret); + + case HG_FREE: + if (sp != NULL) { + free(sp); + *cpp = NULL; + } + return (HG_SUCCESS); + } + /* NOTREACHED */ + return (HG_OVERFLOW); +} + +/* + * null terminated ASCII strings + * we deal with "C strings" - arrays of bytes that are + * terminated by a NULL character. The parameter cpp references a + * pointer to storage; If the pointer is null, then the necessary + * storage is allocated. The last parameter is the max allowed length + * of the string as specified by a protocol. + */ +hg_return_t +hg_proc_string(hg_proc_t proc, char **cpp, uint32_t maxsize) +{ + char *sp; /* sp is the actual string pointer */ + uint32_t size = 0; /* XXX: GCC */ + uint32_t nodesize; + size_t len; + hg_return_t ret; + hg_bool_t allocated = HG_FALSE; + + sp = *cpp; + + /* + * first deal with the length since strings are counted-strings + */ + switch (hg_proc_get_op(proc)) { + case HG_FREE: + if (sp == NULL) { + return(HG_SUCCESS); /* already free */ + } + /* FALLTHROUGH */ + case HG_ENCODE: + len = strlen(sp); + size = (uint32_t)len; + break; + case HG_DECODE: + break; + } + if ((ret = hg_proc_uint32_t(proc, &size)) != HG_SUCCESS) { + return (ret); + } + if (size > maxsize) { + return (HG_OVERFLOW); + } + + nodesize = size + 1; + + /* + * now deal with the actual bytes + */ + switch (hg_proc_get_op(proc)) { + + case HG_DECODE: + if (nodesize == 0) { + return (HG_SUCCESS); + } + if (sp == NULL) { + *cpp = sp = malloc(nodesize); + allocated = HG_TRUE; + } + if (sp == NULL) { + warn("%s: out of memory", __func__); + return (HG_NOMEM); + } + sp[size] = 0; + /* FALLTHROUGH */ + + case HG_ENCODE: + ret = hg_proc_bytes(proc, sp, size); + if ((hg_proc_get_op(proc) == HG_DECODE) && + (ret != HG_SUCCESS)) { + if (allocated == HG_TRUE) { + free(sp); + *cpp = NULL; + } + } + return (ret); + + case HG_FREE: + free(sp); + *cpp = NULL; + return (HG_SUCCESS); + } + /* NOTREACHED */ + return (HG_OVERFLOW); +} diff --git a/src/proc_extra/mercury_proc_rpcgen_array.c b/src/proc_extra/mercury_proc_rpcgen_array.c new file mode 100644 index 00000000..b2e5d739 --- /dev/null +++ b/src/proc_extra/mercury_proc_rpcgen_array.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * xdr_array.c, Generic XDR routines implementation. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * arrays. See xdr.h for more info on the interface to xdr. + */ + +#include +#include +#include "mercury_proc_extra.h" + +/* + * handle an array of arbitrary elements + * *addrp is a pointer to the array, *sizep is the number of elements. + * If addrp is NULL (*sizep * elsize) bytes are allocated. + * elsize is the size (in bytes) of each element, and elproc is the + * procedure to call to handle each element of the array. + */ +hg_return_t +hg_proc_array(hg_proc_t proc, char **addrp, uint32_t *sizep, + uint32_t maxsize, uint32_t elsize, hg_proc_cb_t elproc) +{ + uint32_t i; + char *target = *addrp; + uint32_t c; /* the actual element count */ + hg_return_t stat = HG_SUCCESS; + uint32_t nodesize; + hg_return_t ret; + + /* like strings, arrays are really counted arrays */ + if ((ret = hg_proc_uint32_t(proc, sizep)) != HG_SUCCESS) + return (HG_FALSE); + + c = *sizep; + if ((c > maxsize || UINT32_MAX/elsize < c) && + (hg_proc_get_op(proc) != HG_FREE)) + return (HG_FALSE); + nodesize = c * elsize; + + /* + * if we are deserializing, we may need to allocate an array. + * We also save time by checking for a null array if we are freeing. + */ + if (target == NULL) + switch (hg_proc_get_op(proc)) { + case HG_DECODE: + if (c == 0) + return (HG_SUCCESS); + *addrp = target = malloc(nodesize); + if (target == NULL) { + warn("%s: out of memory", __func__); + return (HG_NOMEM); + } + memset(target, 0, nodesize); + break; + + case HG_FREE: + return (HG_SUCCESS); + + case HG_ENCODE: + break; + } + + /* + * now we process each element of array + */ + for (i = 0; (i < c) && stat == HG_SUCCESS ; i++) { + stat = (*elproc)(proc, target); + target += elsize; + } + + /* + * the array may need freeing + */ + if (hg_proc_get_op(proc) == HG_FREE) { + free(*addrp); + *addrp = NULL; + } + return (stat); +} + +/* + * process a fixed length array. Unlike variable-length arrays, + * the storage of fixed length arrays is static and unfreeable. + * > basep: base of the array + * > size: size of the array + * > elemsize: size of each element + * > xelem: routine to process each element + */ +hg_return_t +hg_proc_vector(hg_proc_t proc, char *basep, uint32_t nelem, uint32_t elemsize, + hg_proc_cb_t xelem) +{ + uint32_t i; + char *elptr; + hg_return_t ret; + + elptr = basep; + for (i = 0; i < nelem; i++) { + if ((ret = (*xelem)(proc, elptr)) != HG_SUCCESS) { + return(ret); + } + elptr += elemsize; + } + return(HG_SUCCESS); +} diff --git a/src/proc_extra/mercury_proc_rpcgen_ref.c b/src/proc_extra/mercury_proc_rpcgen_ref.c new file mode 100644 index 00000000..12780608 --- /dev/null +++ b/src/proc_extra/mercury_proc_rpcgen_ref.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * xdr_reference.c, Generic XDR routines implementation. + * + * Copyright (C) 1987, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * "pointers". See xdr.h for more info on the interface to xdr. + */ + +#include +#include +#include "mercury_proc_extra.h" + +/* + * an indirect pointer + * this is for recursively translating a structure that is + * referenced by a pointer inside the structure that is currently being + * translated. pp references a pointer to storage. If *pp is null + * the necessary storage is allocated. + * size is the sizeof the referenced structure. + * proc is the routine to handle the referenced structure. + */ +hg_return_t +hg_proc_reference(hg_proc_t proc, char **pp, uint32_t size, hg_proc_cb_t pr) +{ + char *loc = *pp; + hg_return_t stat; + + if (loc == NULL) + switch (hg_proc_get_op(proc)) { + case HG_FREE: + return (HG_SUCCESS); + + case HG_DECODE: + *pp = loc = malloc(size); + if (loc == NULL) { + warn("%s: out of memory", __func__); + return (HG_NOMEM); + } + memset(loc, 0, size); + break; + + case HG_ENCODE: + break; + } + + stat = (*pr)(proc, loc); + + if (hg_proc_get_op(proc) == HG_FREE) { + free(loc); + *pp = NULL; + } + return (stat); +} + + +/* + * handle a pointer to a possibly recursive data structure. This + * differs with reference in that it can serialize/deserialize + * trees correctly. + * + * What's sent is actually a union: + * + * union object_pointer switch (boolean b) { + * case TRUE: object_data data; + * case FALSE: void nothing; + * } + * + * > objpp: Pointer to the pointer to the object. + * > obj_size: size of the object. + * > xobj: routine to code an object. + * + */ +hg_return_t +hg_proc_pointer(hg_proc_t proc, char **objpp, uint32_t obj_size, + hg_proc_cb_t xobj) +{ + hg_return_t ret; + hg_bool_t more_data; + + more_data = (*objpp != NULL) ? HG_TRUE : HG_FALSE; + if ((ret = hg_proc_hg_bool_t(proc, &more_data)) != HG_SUCCESS) { + return (ret); + } + if (more_data == HG_FALSE) { + *objpp = NULL; + return (HG_SUCCESS); + } + return (hg_proc_reference(proc,objpp,obj_size,xobj)); +} diff --git a/src/proc_extra/mercury_proc_string.c b/src/proc_extra/mercury_proc_string.c deleted file mode 100644 index 12fa6906..00000000 --- a/src/proc_extra/mercury_proc_string.c +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2013-2022 UChicago Argonne, LLC and The HDF Group. - * Copyright (c) 2022-2023 Intel Corporation. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "mercury_proc_string.h" - -#include - -/****************/ -/* Local Macros */ -/****************/ - -/************************************/ -/* Local Type and Struct Definition */ -/************************************/ - -/********************/ -/* Local Prototypes */ -/********************/ - -/*******************/ -/* Local Variables */ -/*******************/ - -/*---------------------------------------------------------------------------*/ -hg_return_t -hg_proc_hg_string_object_t(hg_proc_t proc, void *string) -{ - uint64_t string_len = 0; - hg_return_t ret = HG_SUCCESS; - hg_string_object_t *strobj = (hg_string_object_t *) string; - - switch (hg_proc_get_op(proc)) { - case HG_ENCODE: - string_len = (strobj->data) ? strlen(strobj->data) + 1 : 0; - ret = hg_proc_uint64_t(proc, &string_len); - if (ret != HG_SUCCESS) - goto done; - if (string_len) { - ret = hg_proc_bytes(proc, strobj->data, string_len); - if (ret != HG_SUCCESS) - goto done; - ret = hg_proc_uint8_t(proc, (uint8_t *) &strobj->is_const); - if (ret != HG_SUCCESS) - goto done; - ret = hg_proc_uint8_t(proc, (uint8_t *) &strobj->is_owned); - if (ret != HG_SUCCESS) - goto done; - } - break; - case HG_DECODE: - ret = hg_proc_uint64_t(proc, &string_len); - if (ret != HG_SUCCESS) - goto done; - if (string_len) { - strobj->data = (char *) malloc(string_len); - if (strobj->data == NULL) { - ret = HG_NOMEM; - goto done; - } - ret = hg_proc_bytes(proc, strobj->data, string_len); - if (ret != HG_SUCCESS) { - free(strobj->data); - strobj->data = NULL; - goto done; - } - ret = hg_proc_uint8_t(proc, (uint8_t *) &strobj->is_const); - if (ret != HG_SUCCESS) { - free(strobj->data); - strobj->data = NULL; - goto done; - } - ret = hg_proc_uint8_t(proc, (uint8_t *) &strobj->is_owned); - if (ret != HG_SUCCESS) { - free(strobj->data); - strobj->data = NULL; - goto done; - } - } else - strobj->data = NULL; - break; - case HG_FREE: - ret = hg_string_object_free(strobj); - if (ret != HG_SUCCESS) - goto done; - break; - default: - break; - } - -done: - return ret; -} diff --git a/src/proc_extra/mercury_proc_string.h b/src/proc_extra/mercury_proc_string.h deleted file mode 100644 index 65d883f5..00000000 --- a/src/proc_extra/mercury_proc_string.h +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (c) 2013-2022 UChicago Argonne, LLC and The HDF Group. - * Copyright (c) 2022-2023 Intel Corporation. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef MERCURY_PROC_STRING_H -#define MERCURY_PROC_STRING_H - -#include "mercury_proc.h" -#include "mercury_string_object.h" - -/*************************************/ -/* Public Type and Struct Definition */ -/*************************************/ - -typedef const char *hg_const_string_t; -typedef char *hg_string_t; - -/*****************/ -/* Public Macros */ -/*****************/ - -/*********************/ -/* Public Prototypes */ -/*********************/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Generic processing routine. - * - * \param proc [IN/OUT] abstract processor object - * \param data [IN/OUT] pointer to data - * - * \return HG_SUCCESS or corresponding HG error code - */ -static HG_INLINE hg_return_t -hg_proc_hg_const_string_t(hg_proc_t proc, void *data); - -/** - * Generic processing routine. - * - * \param proc [IN/OUT] abstract processor object - * \param data [IN/OUT] pointer to data - * - * \return HG_SUCCESS or corresponding HG error code - */ -static HG_INLINE hg_return_t -hg_proc_hg_string_t(hg_proc_t proc, void *data); - -/** - * Generic processing routine. - * - * \param proc [IN/OUT] abstract processor object - * \param string [IN/OUT] pointer to string - * - * \return HG_SUCCESS or corresponding HG error code - */ -HG_PUBLIC hg_return_t -hg_proc_hg_string_object_t(hg_proc_t proc, void *string); - -/************************************/ -/* Local Type and Struct Definition */ -/************************************/ - -/*---------------------------------------------------------------------------*/ -static HG_INLINE hg_return_t -hg_proc_hg_const_string_t(hg_proc_t proc, void *data) -{ - hg_string_object_t string; - hg_const_string_t *strdata = (hg_const_string_t *) data; - hg_return_t ret = HG_SUCCESS; - - switch (hg_proc_get_op(proc)) { - case HG_ENCODE: - hg_string_object_init_const_char(&string, *strdata, 0); - ret = hg_proc_hg_string_object_t(proc, &string); - if (ret != HG_SUCCESS) - goto done; - hg_string_object_free(&string); - break; - case HG_DECODE: - ret = hg_proc_hg_string_object_t(proc, &string); - if (ret != HG_SUCCESS) - goto done; - *strdata = hg_string_object_swap(&string, 0); - hg_string_object_free(&string); - break; - case HG_FREE: - hg_string_object_init_const_char(&string, *strdata, 1); - ret = hg_proc_hg_string_object_t(proc, &string); - if (ret != HG_SUCCESS) - goto done; - break; - default: - break; - } - -done: - return ret; -} - -/*---------------------------------------------------------------------------*/ -static HG_INLINE hg_return_t -hg_proc_hg_string_t(hg_proc_t proc, void *data) -{ - hg_string_object_t string; - hg_string_t *strdata = (hg_string_t *) data; - hg_return_t ret = HG_SUCCESS; - - switch (hg_proc_get_op(proc)) { - case HG_ENCODE: - hg_string_object_init_char(&string, *strdata, 0); - ret = hg_proc_hg_string_object_t(proc, &string); - if (ret != HG_SUCCESS) - goto done; - hg_string_object_free(&string); - break; - case HG_DECODE: - ret = hg_proc_hg_string_object_t(proc, &string); - if (ret != HG_SUCCESS) - goto done; - *strdata = hg_string_object_swap(&string, 0); - hg_string_object_free(&string); - break; - case HG_FREE: - hg_string_object_init_char(&string, *strdata, 1); - ret = hg_proc_hg_string_object_t(proc, &string); - if (ret != HG_SUCCESS) - goto done; - break; - default: - break; - } - -done: - return ret; -} - -#ifdef __cplusplus -} -#endif - -#endif /* MERCURY_PROC_STRING_H */ diff --git a/src/proc_extra/mercury_string_object.c b/src/proc_extra/mercury_string_object.c deleted file mode 100644 index fdddf1a7..00000000 --- a/src/proc_extra/mercury_string_object.c +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Copyright (c) 2013-2022 UChicago Argonne, LLC and The HDF Group. - * Copyright (c) 2022-2023 Intel Corporation. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "mercury_string_object.h" -#include "mercury_error.h" - -#include -#include - -/****************/ -/* Local Macros */ -/****************/ - -#ifdef _WIN32 -# undef strdup -# define strdup _strdup -#endif - -/************************************/ -/* Local Type and Struct Definition */ -/************************************/ - -/********************/ -/* Local Prototypes */ -/********************/ - -/*******************/ -/* Local Variables */ -/*******************/ - -/*---------------------------------------------------------------------------*/ -hg_return_t -hg_string_object_init(hg_string_object_t *string) -{ - hg_return_t ret = HG_SUCCESS; - - string->data = NULL; - string->is_owned = 0; - string->is_const = 0; - - return ret; -} - -/*---------------------------------------------------------------------------*/ -hg_return_t -hg_string_object_init_char( - hg_string_object_t *string, char *s, uint8_t is_owned) -{ - hg_return_t ret = HG_SUCCESS; - - string->data = s; - string->is_owned = is_owned; - string->is_const = 0; - - return ret; -} - -/*---------------------------------------------------------------------------*/ -hg_return_t -hg_string_object_init_const_char( - hg_string_object_t *string, const char *s, uint8_t is_owned) -{ - union { - char *p; - const char *const_p; - } safe_string = {.const_p = s}; - hg_return_t ret = HG_SUCCESS; - - string->data = safe_string.p; - string->is_owned = is_owned; - string->is_const = 1; - - return ret; -} - -/*---------------------------------------------------------------------------*/ -hg_return_t -hg_string_object_free(hg_string_object_t *string) -{ - hg_return_t ret = HG_SUCCESS; - - if (string->is_owned) { - free(string->data); - string->data = NULL; - } - - return ret; -} - -/*---------------------------------------------------------------------------*/ -hg_return_t -hg_string_object_dup(hg_string_object_t string, hg_string_object_t *new_string) -{ - hg_return_t ret = HG_SUCCESS; - - new_string->data = strdup(string.data); - HG_CHECK_ERROR(new_string->data == NULL, done, ret, HG_NOMEM, - "Could not dup string data"); - new_string->is_owned = 1; - new_string->is_const = 0; - -done: - return ret; -} - -/*---------------------------------------------------------------------------*/ -char * -hg_string_object_swap(hg_string_object_t *string, char *s) -{ - char *old = string->data; - - string->data = s; - string->is_const = 0; - string->is_owned = 0; - - return old; -} diff --git a/src/proc_extra/mercury_string_object.h b/src/proc_extra/mercury_string_object.h deleted file mode 100644 index 841c3353..00000000 --- a/src/proc_extra/mercury_string_object.h +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (c) 2013-2022 UChicago Argonne, LLC and The HDF Group. - * Copyright (c) 2022-2023 Intel Corporation. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef MERCURY_STRING_OBJECT_H -#define MERCURY_STRING_OBJECT_H - -#include "mercury_types.h" - -/*************************************/ -/* Public Type and Struct Definition */ -/*************************************/ - -typedef struct hg_string_object { - char *data; - bool is_const; - bool is_owned; -} hg_string_object_t; - -/*****************/ -/* Public Macros */ -/*****************/ - -/*********************/ -/* Public Prototypes */ -/*********************/ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Initialize a string object. - * - * \param string [OUT] pointer to string structure - * - * \return HG_SUCCESS or corresponding HG error code - */ -HG_PUBLIC hg_return_t -hg_string_object_init(hg_string_object_t *string); - -/** - * Initialize a string object from the string pointed to by s. - * - * \param string [OUT] pointer to string structure - * \param s [IN] pointer to string - * \param is_owned [IN] boolean - * - * \return HG_SUCCESS or corresponding HG error code - */ -HG_PUBLIC hg_return_t -hg_string_object_init_char( - hg_string_object_t *string, char *s, uint8_t is_owned); - -/** - * Initialize a string object from the const string pointed to by s. - * - * \param string [OUT] pointer to string structure - * \param s [IN] pointer to string - * \param is_owned [IN] boolean - * - * \return HG_SUCCESS or corresponding HG error code - */ -HG_PUBLIC hg_return_t -hg_string_object_init_const_char( - hg_string_object_t *string, const char *s, uint8_t is_owned); - -/** - * Free a string object. - * - * \param string [IN/OUT] pointer to string structure - * - * \return HG_SUCCESS or corresponding HG error code - */ -HG_PUBLIC hg_return_t -hg_string_object_free(hg_string_object_t *string); - -/** - * Duplicate a string object. - * - * \param string [IN] pointer to string structure - * \param new_string [OUT] pointer to string structure - * - * \return HG_SUCCESS or corresponding HG error code - */ -HG_PUBLIC hg_return_t -hg_string_object_dup(hg_string_object_t string, hg_string_object_t *new_string); - -/** - * Exchange the content of the string structure by the content of s. - * - * \param string [IN/OUT] pointer to string structure - * - * \return Pointer to string contained by string before the swap - */ -HG_PUBLIC char * -hg_string_object_swap(hg_string_object_t *string, char *s); - -#ifdef __cplusplus -} -#endif - -#endif /* MERCURY_STRING_OBJECT_H */ diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt index 60d1f257..66b3c4f6 100644 --- a/util/CMakeLists.txt +++ b/util/CMakeLists.txt @@ -1,50 +1,5 @@ -#------------------------------------------------------------------------------ -# Include source and build directories -#------------------------------------------------------------------------------ -set(MERCURY_BUILD_INCLUDE_DEPENDENCIES - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR} -) - #----------------------------------------------------------------------------- -# External dependencies +# Util subdirs #----------------------------------------------------------------------------- -find_package(json-c CONFIG) -if(json-c_FOUND) - set(MERCURY_INFO_INT_LIB_DEPENDENCIES - ${MERCURY_INFO_INT_LIB_DEPENDENCIES} - json-c::json-c - ) - set(HG_INFO_HAS_JSON 1) -endif() - -#------------------------------------------------------------------------------ -# Configure module header files -#------------------------------------------------------------------------------ -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/config.h -) - -#----------------------------------------------------------------------------- -# Create executable -#----------------------------------------------------------------------------- -add_executable(hg_info info.c getopt.c) -target_include_directories(hg_info - PRIVATE "$" -) -target_link_libraries(hg_info PRIVATE mercury - ${MERCURY_INFO_INT_LIB_DEPENDENCIES}) -mercury_set_exe_options(hg_info MERCURY) -if(MERCURY_ENABLE_COVERAGE) - set_coverage_flags(hg_info) -endif() - -#----------------------------------------------------------------------------- -# Add Target(s) to CMake Install -#----------------------------------------------------------------------------- -install( - TARGETS - hg_info - RUNTIME DESTINATION ${MERCURY_INSTALL_BIN_DIR} -) \ No newline at end of file +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/hg_info) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/hg_rpcgen) diff --git a/util/hg_info/CMakeLists.txt b/util/hg_info/CMakeLists.txt new file mode 100644 index 00000000..60d1f257 --- /dev/null +++ b/util/hg_info/CMakeLists.txt @@ -0,0 +1,50 @@ +#------------------------------------------------------------------------------ +# Include source and build directories +#------------------------------------------------------------------------------ +set(MERCURY_BUILD_INCLUDE_DEPENDENCIES + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +#----------------------------------------------------------------------------- +# External dependencies +#----------------------------------------------------------------------------- +find_package(json-c CONFIG) +if(json-c_FOUND) + set(MERCURY_INFO_INT_LIB_DEPENDENCIES + ${MERCURY_INFO_INT_LIB_DEPENDENCIES} + json-c::json-c + ) + set(HG_INFO_HAS_JSON 1) +endif() + +#------------------------------------------------------------------------------ +# Configure module header files +#------------------------------------------------------------------------------ +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h +) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +add_executable(hg_info info.c getopt.c) +target_include_directories(hg_info + PRIVATE "$" +) +target_link_libraries(hg_info PRIVATE mercury + ${MERCURY_INFO_INT_LIB_DEPENDENCIES}) +mercury_set_exe_options(hg_info MERCURY) +if(MERCURY_ENABLE_COVERAGE) + set_coverage_flags(hg_info) +endif() + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install +#----------------------------------------------------------------------------- +install( + TARGETS + hg_info + RUNTIME DESTINATION ${MERCURY_INSTALL_BIN_DIR} +) \ No newline at end of file diff --git a/util/config.h.in b/util/hg_info/config.h.in similarity index 100% rename from util/config.h.in rename to util/hg_info/config.h.in diff --git a/util/getopt.c b/util/hg_info/getopt.c similarity index 100% rename from util/getopt.c rename to util/hg_info/getopt.c diff --git a/util/getopt.h b/util/hg_info/getopt.h similarity index 100% rename from util/getopt.h rename to util/hg_info/getopt.h diff --git a/util/info.c b/util/hg_info/info.c similarity index 100% rename from util/info.c rename to util/hg_info/info.c diff --git a/util/hg_rpcgen/CMakeLists.txt b/util/hg_rpcgen/CMakeLists.txt new file mode 100644 index 00000000..ae362263 --- /dev/null +++ b/util/hg_rpcgen/CMakeLists.txt @@ -0,0 +1,26 @@ +#------------------------------------------------------------------------------ +# Include source and build directories +#------------------------------------------------------------------------------ +set(MERCURY_BUILD_INCLUDE_DEPENDENCIES + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +#----------------------------------------------------------------------------- +# Create executable +#----------------------------------------------------------------------------- +add_executable(hg_rpcgen rpc_hg_cout.c rpc_hg_hout.c rpc_hg_main.c + rpc_parse.c rpc_scan.c rpc_util.c) +mercury_set_exe_options(hg_rpcgen MERCURY) +if(MERCURY_ENABLE_COVERAGE) + set_coverage_flags(hg_rpcgen) +endif() + +#----------------------------------------------------------------------------- +# Add Target(s) to CMake Install +#----------------------------------------------------------------------------- +install( + TARGETS + hg_rpcgen + RUNTIME DESTINATION ${MERCURY_INSTALL_BIN_DIR} +) diff --git a/util/hg_rpcgen/rpc_hg_cout.c b/util/hg_rpcgen/rpc_hg_cout.c new file mode 100644 index 00000000..48b3d693 --- /dev/null +++ b/util/hg_rpcgen/rpc_hg_cout.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_cout.c, XDR routine outputter for the RPC protocol compiler + */ +#include +#include +#include +#include +#include +#include "rpc_scan.h" +#include "rpc_parse.h" +#include "rpc_util.h" + +static int findtype(definition *, const char *); +static int undefined(const char *); +static void print_generic_header(const char *, int); +static void print_header(definition *); +static void print_trailer(void); +static void print_ifopen(int, const char *); +static void print_ifarg(const char *); +static void print_ifsizeof(const char *, const char *); +static void print_ifclose(int); +static void print_ifstat(int, const char *, const char *, relation, + const char *, const char *, const char *); +static void emit_enum(definition *); +static void emit_union(definition *); +static void emit_struct(definition *); +static void emit_typedef(definition *); +static void print_stat(int, declaration *); + +/* + * Emit the C-routine for the given definition + */ +void +emit(definition *def) +{ + bas_type *bas; + if (def->def_kind == DEF_CONST) { + return; + } + if (def->def_kind == DEF_PROGRAM) { + return; + } + if (def->def_kind == DEF_TYPEDEF) { + /* now we need to handle declarations like struct typedef foo + * foo; since we dont want this to be expanded into 2 calls to + * xdr_foo */ + + if (strcmp(def->def.ty.old_type.str, def->def_name.str) == 0) + return; + }; + + /* check for reserved/predefined type */ + bas = find_type(def->def_name.str); + if (bas) { + if (bas->length == 0) + error("Type '%s' is reserved (used in " + "mercury_proc.h).", def->def_name.str); + error("Type '%s' already defined by mercury.", + def->def_name.str); + } + + print_header(def); + + switch (def->def_kind) { + case DEF_UNION: + emit_union(def); + break; + case DEF_ENUM: + emit_enum(def); + break; + case DEF_STRUCT: + emit_struct(def); + break; + case DEF_TYPEDEF: + emit_typedef(def); + break; + case DEF_PROGRAM: + case DEF_CONST: + errx(1, "Internal error at %s:%d: Case %d not handled", + __FILE__, __LINE__, def->def_kind); + break; + } + print_trailer(); +} + +/* callback compare function for FINDVAL */ +static int +findtype(definition *def, const char *type) +{ + + if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST) { + return (0); + } else { + return (streq(def->def_name.str, type)); + } +} + +static int +undefined(const char *type) +{ + definition *def; + + def = (definition *) FINDVAL(defined, type, findtype); + + + return (def == NULL); +} + +static void +print_generic_header(const char *procname, int pointerp) +{ + f_print(fout, "\n"); + f_print(fout, "hg_return_t\n"); + f_print(fout, "hg_proc_%s(", procname); + f_print(fout, "hg_proc_t proc, void *proc_data)\n{\n"); + f_print(fout, "\t%s ", procname); + if (pointerp) + f_print(fout, "*"); + f_print(fout, "objp = (%s%s) proc_data;\n", procname, + (pointerp) ? " *" : ""); + f_print(fout, "\thg_return_t ret;\n"); +} + +static void +print_header(definition *def) +{ + print_generic_header(def->def_name.str, + 1 || /* XXX: hg_rpcgen currently always uses a pointer */ + def->def_kind != DEF_TYPEDEF || + !isvectordef(def->def.ty.old_type.str, def->def.ty.rel)); +} + +static void +print_trailer(void) +{ + f_print(fout, "\treturn (HG_SUCCESS);\n"); + f_print(fout, "}\n"); +} + + +static void +print_ifopen(int indent, const char *name) +{ + tabify(fout, indent); + f_print(fout, "if ((ret = hg_proc_%s(proc", name); +} + +static void +print_ifarg(const char *arg) +{ + f_print(fout, ", %s", arg); +} + +static void +print_ifsizeof(const char *prefix, const char *type) +{ + if (streq(type, "bool")) { + f_print(fout, ", (unsigned int)sizeof(uint8_t), %s", + "hg_proc_uint8_t"); + } else { + f_print(fout, ", (unsigned int)sizeof("); + if (undefined(type) && prefix) { + f_print(fout, "%s ", prefix); + } + f_print(fout, "%s), hg_proc_%s", type, type); + } +} + +static void +print_ifclose(int indent) +{ + f_print(fout, ")) != HG_SUCCESS)\n"); + tabify(fout, indent); + f_print(fout, "\treturn (ret);\n"); +} + +static void +print_ifstat(int indent, const char *prefix, const char *type, relation rel, + const char *amax, const char *objname, const char *name) +{ + const char *alt = NULL; + + switch (rel) { + case REL_POINTER: + print_ifopen(indent, "pointer"); + print_ifarg("(char **)(void *)"); + f_print(fout, "%s", objname); + print_ifsizeof(prefix, type); + break; + case REL_VECTOR: + if (streq(type, "string")) { + alt = "string"; + /* + * this case should not be possible as the parser + * only allows REL_ARRAY strings (so error() it). + */ + error("Unexpected REL_VECTOR string"); + } else if (streq(type, "opaque")) { + /* hg_proc_bytes() corresponds to xdr_opaque() */ + alt = "bytes"; /* XXX was 'opaque' in xdr */ + } + if (alt) { + print_ifopen(indent, alt); + print_ifarg(objname); + } else { + print_ifopen(indent, "vector"); + print_ifarg("(char *)(void *)"); + f_print(fout, "%s", objname); + } + print_ifarg(amax); + if (!alt) { + print_ifsizeof(prefix, type); + } + break; + case REL_ARRAY: + if (streq(type, "string")) { + alt = "string"; + } else if (streq(type, "opaque")) { + /* hg_proc_varbytes() corresponds to xdr_bytes() */ + alt = "varbytes"; /* XXX was 'bytes' in xdr */ + } + if (streq(type, "string")) { + print_ifopen(indent, alt); + print_ifarg(objname); + } else { + if (alt) { + print_ifopen(indent, alt); + } else { + print_ifopen(indent, "array"); + } + print_ifarg("(char **)(void *)"); + if (*objname == '&') { + f_print(fout, "%s.%s_val, (uint32_t *)%s.%s_len", + objname, name, objname, name); + } else { + f_print(fout, "&%s->%s_val, (uint32_t *)&%s->%s_len", + objname, name, objname, name); + } + } + print_ifarg(amax); + if (!alt) { + print_ifsizeof(prefix, type); + } + break; + case REL_ALIAS: + if (streq(type, "bool")) { + alt = "uint8_t"; + } + if (alt) { + print_ifopen(indent, alt); + } else { + print_ifopen(indent, type); + } + print_ifarg(objname); + break; + } + print_ifclose(indent); +} +/* ARGSUSED */ +static void +emit_enum(definition *def) +{ + tabify(fout, 1); + f_print(fout, "{\n"); + tabify(fout, 2); + f_print(fout, "int32_t et = (int32_t)*objp;\n"); + print_ifopen(2, "int32_t"); + print_ifarg("&et"); + print_ifclose(2); + tabify(fout, 2); + f_print(fout, "*objp = (%s)et;\n", def->def_name.str); + tabify(fout, 1); + f_print(fout, "}\n"); +} + +static void +emit_union(definition *def) +{ + declaration *dflt; + case_list *cl; + declaration *cs; + char *object; + static const char vecformat[] = "objp->%s_u.%s"; + static const char format[] = "&objp->%s_u.%s"; + + f_print(fout, "\n"); + print_stat(1, &def->def.un.enum_decl); + f_print(fout, "\tswitch (objp->%s) {\n", + def->def.un.enum_decl.name.str); + for (cl = def->def.un.cases; cl != NULL; cl = cl->next) { + f_print(fout, "\tcase %s:\n", cl->case_name.str); + if (cl->contflag == 1) /* a continued case statement */ + continue; + cs = &cl->case_decl; + if (!streq(cs->type.str, "void")) { + object = alloc(strlen(def->def_name.str) + strlen(format) + + strlen(cs->name.str) + 1); + if (isvectordef(cs->type.str, cs->rel)) { + s_print(object, vecformat, def->def_name.str, + cs->name.str); + } else { + s_print(object, format, def->def_name.str, + cs->name.str); + } + print_ifstat(2, cs->prefix.str, cs->type.str, cs->rel, + cs->array_max.str, object, cs->name.str); + free(object); + } + f_print(fout, "\t\tbreak;\n"); + } + dflt = def->def.un.default_decl; + f_print(fout, "\tdefault:\n"); + if (dflt != NULL) { + if (!streq(dflt->type.str, "void")) { + object = alloc(strlen(def->def_name.str) + strlen(format) + + strlen(dflt->name.str) + 1); + if (isvectordef(dflt->type.str, dflt->rel)) { + s_print(object, vecformat, def->def_name.str, + dflt->name.str); + } else { + s_print(object, format, def->def_name.str, + dflt->name.str); + } + print_ifstat(2, dflt->prefix.str, dflt->type.str, dflt->rel, + dflt->array_max.str, object, dflt->name.str); + free(object); + } + f_print(fout, "\t\tbreak;\n"); + } else { + f_print(fout, "\t\treturn (ret);\n"); + } + + f_print(fout, "\t}\n"); +} + +static void +emit_struct(definition *def) +{ + decl_list *dl; + + f_print(fout, "\n"); + for (dl = def->def.st.decls; dl != NULL; dl = dl->next) + print_stat(1, &dl->decl); + return; +} + +static void +emit_typedef(definition *def) +{ + const char *prefix = def->def.ty.old_prefix.str; + const char *type = def->def.ty.old_type.str; + const char *amax = def->def.ty.array_max.str; + relation rel = def->def.ty.rel; + + f_print(fout, "\n"); + print_ifstat(1, prefix, type, rel, amax, "objp", def->def_name.str); +} + +static void +print_stat(int indent, declaration *dec) +{ + const char *prefix = dec->prefix.str; + const char *type = dec->type.str; + const char *amax = dec->array_max.str; + relation rel = dec->rel; + char name[256]; + + if (isvectordef(type, rel)) { + s_print(name, "objp->%s", dec->name.str); + } else { + s_print(name, "&objp->%s", dec->name.str); + } + print_ifstat(indent, prefix, type, rel, amax, name, dec->name.str); +} diff --git a/util/hg_rpcgen/rpc_hg_hout.c b/util/hg_rpcgen/rpc_hg_hout.c new file mode 100644 index 00000000..b6e95aa5 --- /dev/null +++ b/util/hg_rpcgen/rpc_hg_hout.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_hout.c, Header file outputter for the RPC protocol compiler + */ +#include +#include +#include +#include "rpc_scan.h" +#include "rpc_parse.h" +#include "rpc_util.h" + +static void pconstdef(definition *); +static void pstructdef(definition *); +static void puniondef(definition *); +static void pdeclaration(const char *, declaration *, int, const char *); +static void pdefine(const char *, const char *); +static void penumdef(definition *); +static void ptypedef(definition *); +static int undefined2(const char *, const char *); +static void cplusplusstart(void); +static void cplusplusend(void); + +/* + * Print the C-version of an xdr definition + */ +void +print_datadef(definition *def) +{ + + if (def->def_kind != DEF_CONST && def->def_kind != DEF_PROGRAM) { + f_print(fout, "\n"); + } + switch (def->def_kind) { + case DEF_STRUCT: + pstructdef(def); + break; + case DEF_UNION: + puniondef(def); + break; + case DEF_ENUM: + penumdef(def); + break; + case DEF_TYPEDEF: + ptypedef(def); + case DEF_PROGRAM: + /* handle data only */ + break; + case DEF_CONST: + pconstdef(def); + break; + } +} + +void +print_funcdef(definition *def, int *did) +{ + bas_type *bas; + switch (def->def_kind) { + case DEF_PROGRAM: + case DEF_CONST: + break; + case DEF_TYPEDEF: + case DEF_ENUM: + case DEF_UNION: + case DEF_STRUCT: + if (!*did) { + f_print(fout, "\n"); + cplusplusstart(); + *did = 1; + } + + /* check for reserved/predefined type */ + bas = find_type(def->def_name.str); + if (bas) { + if (bas->length == 0) + error("Type '%s' is reserved (used in " + "mercury_proc.h).", def->def_name.str); + error("Type '%s' already defined by mercury.", + def->def_name.str); + } + + /* hg_proc funtion's second arg is always a void* */ + f_print(fout, "hg_return_t hg_proc_%s(hg_proc_t proc, " + "void *%s);\n", def->def_name.str, + def->def_name.str); + break; + } +} + +void +print_funcend(int did) { + if (did) { + cplusplusend(); + } +} + +static void +pconstdef(definition *def) +{ + pdefine(def->def_name.str, def->def.co.str); +} + +static void +pstructdef(definition *def) +{ + decl_list *l; + const char *name = def->def_name.str; + + f_print(fout, "struct %s {\n", name); + for (l = def->def.st.decls; l != NULL; l = l->next) { + pdeclaration(name, &l->decl, 1, ";\n"); + } + f_print(fout, "};\n"); + f_print(fout, "typedef struct %s %s;\n", name, name); +} + +static void +puniondef(definition *def) +{ + case_list *l; + const char *name = def->def_name.str; + declaration *decl; + + f_print(fout, "struct %s {\n", name); + decl = &def->def.un.enum_decl; + if (streq(decl->type.str, "bool")) { + f_print(fout, "\tuint8_t %s;\n", decl->name.str); + } else { + f_print(fout, "\t%s %s;\n", decl->type.str, decl->name.str); + } + f_print(fout, "\tunion {\n"); + for (l = def->def.un.cases; l != NULL; l = l->next) { + if (l->contflag == 0) + pdeclaration(name, &l->case_decl, 2, ";\n"); + } + decl = def->def.un.default_decl; + if (decl && !streq(decl->type.str, "void")) { + pdeclaration(name, decl, 2, ";\n"); + } + f_print(fout, "\t} %s_u;\n", name); + f_print(fout, "};\n"); + f_print(fout, "typedef struct %s %s;\n", name, name); +} + +static void +pdefine(const char *name, const char *num) +{ + f_print(fout, "#define %s %s\n", name, num); +} + +static void +cplusplusstart(void) +{ + if (BSDflag) + f_print(fout, "__BEGIN_DECLS\n"); + else + f_print(fout, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"); +} + +static void +cplusplusend(void) +{ + if (BSDflag) + f_print(fout, "__END_DECLS\n"); + else + f_print(fout, "#ifdef __cplusplus\n};\n#endif\n"); +} + +static void +penumdef(definition *def) +{ + const char *name = def->def_name.str; + enumval_list *l; + const char *last = NULL; + int count = 0; + const char *first = ""; + + f_print(fout, "enum %s {\n", name); + for (l = def->def.en.vals; l != NULL; l = l->next) { + f_print(fout, "%s\t%s", first, l->name.str); + if (l->assignment.str) { + f_print(fout, " = %s", l->assignment.str); + last = l->assignment.str; + count = 1; + } else { + if (last == NULL) { + f_print(fout, " = %d", count++); + } else { + f_print(fout, " = %s + %d", last, count++); + } + } + first = ",\n"; + } + f_print(fout, "\n};\n"); + f_print(fout, "typedef enum %s %s;\n", name, name); +} + +static void +ptypedef(definition *def) +{ + const char *name = def->def_name.str; + const char *old = def->def.ty.old_type.str; + char prefix[8]; /* enough to contain "struct ", including NUL */ + relation rel = def->def.ty.rel; + + /* example: 'typedef struct foo *foolist' => name=foolist, old=foo */ + if (!streq(name, old)) { + /* adjust special case base types */ + if (streq(old, "string")) { /* string => char* */ + old = "char"; + rel = REL_POINTER; + } else if (streq(old, "opaque")) { /* opaque => char */ + old = "char"; + } else if (streq(old, "bool")) { /* bool => bool_t */ + old = "uint8_t"; + } + /* if we did not define 'old' and it has a prefix, use it */ + /* allows us to use struct's typedef'd name if we made it */ + if (undefined2(old, name) && def->def.ty.old_prefix.str) { + s_print(prefix, "%s ", def->def.ty.old_prefix.str); + } else { + prefix[0] = 0; + } + f_print(fout, "typedef "); + switch (rel) { + case REL_ARRAY: + f_print(fout, "struct {\n"); + f_print(fout, "\tuint32_t %s_len;\n", name); + f_print(fout, "\t%s%s *%s_val;\n", prefix, old, name); + f_print(fout, "} %s", name); + break; + case REL_POINTER: + f_print(fout, "%s%s *%s", prefix, old, name); + break; + case REL_VECTOR: + f_print(fout, "%s%s %s[%s]", prefix, old, name, + def->def.ty.array_max.str); + break; + case REL_ALIAS: + f_print(fout, "%s%s %s", prefix, old, name); + break; + } + f_print(fout, ";\n"); + } +} + +static void +pdeclaration(const char *name, declaration *dec, int tab, + const char *separator) +{ + char buf[8]; /* enough to hold "struct ", include NUL */ + const char *prefix; + const char *type; + + if (streq(dec->type.str, "void")) { + return; + } + tabify(fout, tab); + /* struct that has itself in it (e.g. a pointer) */ + if (streq(dec->type.str, name) && !dec->prefix.str) { + f_print(fout, "struct "); + } + if (streq(dec->type.str, "string")) { + f_print(fout, "char *%s", dec->name.str); + } else { + prefix = ""; + if (streq(dec->type.str, "bool")) { + type = "uint8_t"; + } else if (streq(dec->type.str, "opaque")) { + type = "char"; + } else { + if (dec->prefix.str) { + s_print(buf, "%s ", dec->prefix.str); + prefix = buf; + } + type = dec->type.str; + } + switch (dec->rel) { + case REL_ALIAS: + f_print(fout, "%s%s %s", prefix, type, dec->name.str); + break; + case REL_VECTOR: + f_print(fout, "%s%s %s[%s]", prefix, type, + dec->name.str, dec->array_max.str); + break; + case REL_POINTER: + f_print(fout, "%s%s *%s", prefix, type, dec->name.str); + break; + case REL_ARRAY: + f_print(fout, "struct {\n"); + tabify(fout, tab); + f_print(fout, "\tuint32_t %s_len;\n", dec->name.str); + tabify(fout, tab); + f_print(fout, "\t%s%s *%s_val;\n", prefix, type, dec->name.str); + tabify(fout, tab); + f_print(fout, "} %s", dec->name.str); + break; + } + } + f_print(fout, "%s", separator); /* normally ";\n" */ +} + +/* look at defns from start of file until we hit 'stop' */ +/* ret 1 if 'type' was not defined in above range, o.w. ret 0 */ +static int +undefined2(const char *type, const char *stop) +{ + list *l; + definition *def; + + for (l = defined; l != NULL; l = l->next) { + def = (definition *) l->val; + if (def->def_kind != DEF_PROGRAM) { + if (streq(def->def_name.str, stop)) { + return (1); + } else if (streq(def->def_name.str, type)) { + return (0); + } + } + } + return (1); +} diff --git a/util/hg_rpcgen/rpc_hg_main.c b/util/hg_rpcgen/rpc_hg_main.c new file mode 100644 index 00000000..fed6d0e8 --- /dev/null +++ b/util/hg_rpcgen/rpc_hg_main.c @@ -0,0 +1,633 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_main.c, Top level of the RPC protocol compiler. + */ + +#define HG_RPCGEN_VERSION "199506"/* This program's version (year & month) */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rpc_scan.h" +#include "rpc_parse.h" +#include "rpc_util.h" + +#define EXTEND 1 /* alias for TRUE */ +#define DONT_EXTEND 0 /* alias for FALSE */ + +struct commandline { + int cflag; /* code/decode C routines */ + int hflag; /* header file */ + char *infile; /* input module name */ + char *outfile; /* output module name */ +}; + +static char *cmdname; + +static char *CPP; +static char CPPFLAGS[] = "-C"; +static char pathbuf[MAXPATHLEN + 1]; + +#define ARGLISTLEN 20 +#define FIXEDARGS 2 + +static char *arglist[ARGLISTLEN]; +static int argcount = FIXEDARGS; + + +int BSDflag; /* use BSD cplusplus guard macros */ +int docleanup = 1; /* cause atexit to remove files */ + +/* + * removed xdr_inline() related code. base mercury fns already + * inline data movement for basic types into memcpy ops, plus + * mercury may be config'd to do checksum code (not relevant in xdr). + */ + +static char *extendfile(const char *, const char *); +static void open_output(const char *, const char *); +static void add_warning(void); +static void clear_args(void); +static void open_input(char *, char *); +static void c_output(char *, char *, int, const char *); +static void initialize_base_types(void); +static char *generate_guard(const char *); +static void h_output(char *, char *, int, const char *); +static void addarg(char *); +static void putarg(int, char *); +static void checkfiles(const char *, const char *); +static int parseargs(int, char *[], struct commandline *); +static void usage(void); + +int +main(int argc, char *argv[]) +{ + struct commandline cmd; + + if ((CPP = getenv("HG_RPCGEN_CPP")) == NULL) { + CPP = "/usr/bin/cpp"; + if (access(CPP, X_OK)) + CPP = "/usr/bin/clang-cpp"; + } + + (void) memset((char *) &cmd, 0, sizeof(struct commandline)); + clear_args(); + atexit(crash); + if (!parseargs(argc, argv, &cmd)) + usage(); + + if (cmd.cflag || cmd.hflag) { + checkfiles(cmd.infile, cmd.outfile); + } else + checkfiles(cmd.infile, NULL); + + if (cmd.cflag) { + c_output(cmd.infile, "-DHG_RPC_PROC", DONT_EXTEND, cmd.outfile); + } else if (cmd.hflag) { + h_output(cmd.infile, "-DHG_RPC_HDR", DONT_EXTEND, cmd.outfile); + } else { + c_output(cmd.infile, "-DHG_RPC_PROC", EXTEND, "_proc.c"); + reinitialize(); + h_output(cmd.infile, "-DHG_RPC_HDR", EXTEND, ".h"); + } + docleanup = 0; + exit(0); + /* NOTREACHED */ +} +/* + * add extension to filename + */ +static char * +extendfile(const char *path, const char *ext) +{ + const char *file; + char *res; + const char *p; + + if ((file = strrchr(path, '/')) == NULL) + file = path; + else + file++; + + res = alloc(strlen(file) + strlen(ext) + 1); + if (res == NULL) { + err(EXIT_FAILURE, "Out of memory"); + } + p = strrchr(file, '.'); + if (p == NULL) { + p = file + strlen(file); + } + (void) strcpy(res, file); + (void) strcpy(res + (p - file), ext); + return (res); +} +/* + * Open output file with given extension + */ +static void +open_output(const char *infile, const char *outfile) +{ + + if (outfile == NULL) { + fout = stdout; + return; + } + if (infile != NULL && streq(outfile, infile)) { + errx(EXIT_FAILURE, "Output would overwrite `%s'", infile); + } + fout = fopen(outfile, "w"); + if (fout == NULL) { + err(EXIT_FAILURE, "Can't open `%s'", outfile); + } + record_open(outfile); + +} + +static void +add_warning(void) +{ + f_print(fout, "/*\n"); + f_print(fout, " * Please do not edit this file.\n"); + f_print(fout, " * It was generated using hg_rpcgen.\n"); + f_print(fout, " */\n\n"); +} + +/* clear list of arguments */ +static void +clear_args(void) +{ + int i; + for (i = FIXEDARGS; i < ARGLISTLEN; i++) + arglist[i] = NULL; + argcount = FIXEDARGS; +} + +/* + * Open input file with given define for C-preprocessor + */ +static void +open_input(char *infile, char *define) +{ + int pd[2]; + + baseinfilename = (infile == NULL) ? "" : infile; + if (pipe(pd) < 0) + err(EXIT_FAILURE, "pipe"); + switch (fork()) { + case 0: + putarg(0, CPP); + putarg(1, CPPFLAGS); + addarg(define); + if (infile) + addarg(infile); + addarg(NULL); + (void) close(1); + (void) dup2(pd[1], 1); + (void) close(pd[0]); + execvp(arglist[0], arglist); + err(EXIT_FAILURE, "$HG_RPCGEN_CPP: %s", CPP); + case -1: + err(EXIT_FAILURE, "fork"); + } + (void) close(pd[1]); + fin = fdopen(pd[0], "r"); + if (fin == NULL) { + err(EXIT_FAILURE, "Can't open `%s'", baseinfilename); + } +} + +/* + * Compile into a PROC routine output file + */ + +static void +c_output(char *infile, char *define, int extend, const char *outfile) +{ + definition *def; + char *include; + const char *outfilename; + long tell; + + initialize_base_types(); + open_input(infile, define); + outfilename = extend ? extendfile(infile, outfile) : outfile; + open_output(infile, outfilename); + add_warning(); + if (infile && (include = extendfile(infile, ".h"))) { + f_print(fout, "#include \"%s\"\n", include); + free(include); + /* .h file already contains mercury includes */ + } else + f_print(fout, "#include \n"); + tell = ftell(fout); + while ((def = get_definition()) != NULL) { + emit(def); + } + if (extend && tell == ftell(fout)) { + (void) unlink(outfilename); + } +} + + +static void +initialize_base_types(void) +{ + + /* add all the starting basic types - from mercury_proc.h */ + add_type(1, "hg_int8_t"); + add_type(1, "hg_uint8_t"); + add_type(1, "hg_int16_t"); + add_type(1, "hg_uint16_t"); + add_type(1, "hg_int32_t"); + add_type(1, "hg_uint32_t"); + add_type(1, "hg_int64_t"); + add_type(1, "hg_uint64_t"); + add_type(1, "bytes"); + + /* add aliases established with preprocessor defines */ + add_type(1, "int8_t"); + add_type(1, "uint8_t"); + add_type(1, "int16_t"); + add_type(1, "uint16_t"); + add_type(1, "int32_t"); + add_type(1, "uint32_t"); + add_type(1, "int64_t"); + add_type(1, "uint64_t"); + add_type(1, "hg_bool_t"); /* maps to hg_uint8_t */ + add_type(1, "hg_ptr_t"); /* maps to hg_uint64_t */ + add_type(1, "hg_size_t"); /* maps to hg_uint64_t */ + add_type(1, "hg_id_t"); /* maps to hg_uint32_t */ + + /* + * add other hg_proc_* names used by mercury_proc.h as + * reserved words (we overload setting 'len' to zero + * to mark reserved words). + */ + add_type(0, "memcpy"); /* defined to hg_proc_bytes */ + add_type(0, "raw"); /* also defined to hg_proc_bytes */ + + add_type(0, "array"); + add_type(0, "checksum_get"); + add_type(0, "checksum_update"); + add_type(0, "checksum_verify"); + add_type(0, "create"); + add_type(0, "create_set"); + add_type(0, "flush"); + add_type(0, "free"); + add_type(0, "get_class"); + add_type(0, "get_extra_buf"); + add_type(0, "get_extra_size"); + add_type(0, "get_flags"); + add_type(0, "get_handle"); + add_type(0, "get_op"); + add_type(0, "get_size"); + add_type(0, "get_size_left"); + add_type(0, "get_size_used"); + add_type(0, "get_xdr_ptr"); + add_type(0, "hg_bulk_t"); + add_type(0, "hg_const_string_t"); + add_type(0, "hg_string_t"); + add_type(0, "pointer"); + add_type(0, "reference"); + add_type(0, "reset"); + add_type(0, "restore_ptr"); + add_type(0, "save_ptr"); + add_type(0, "set_extra_buf_is_mine"); + add_type(0, "set_handle"); + add_type(0, "set_flags"); + add_type(0, "set_size"); + /* add_type(0, "string"); */ /* caught elsewhere */ + add_type(0, "varbytes"); + add_type(0, "vector"); +} + +static char * +generate_guard(const char *pathname) +{ + const char *filename; + char *guard, *tmp, *tmp2, *extdot; + + filename = strrchr(pathname, '/'); /* find last component */ + filename = ((filename == 0) ? pathname : filename + 1); + guard = strdup(filename); + if (guard == NULL) { + err(EXIT_FAILURE, "strdup"); + } + extdot = strrchr(guard, '.'); + + /* + * Convert to valid C symbol name and make it upper case. + * Map non alphanumerical characters to '_'. + * + * Leave extension as it is. It will be handled in extendfile(). + */ + for (tmp = guard; *tmp; tmp++) { + if (islower((unsigned char)*tmp)) + *tmp = toupper((unsigned char)*tmp); + else if (isupper((unsigned char)*tmp)) + continue; + else if (isdigit((unsigned char)*tmp)) + continue; + else if (*tmp == '_') + continue; + else if (tmp == extdot) + break; + else + *tmp = '_'; + } + + /* + * Can't have a '_' or '.' at the front of a symbol name, because it + * will end up as "__". + * + * Prefix it with "HG_RPCGEN_". + */ + if (guard[0] == '_' || guard[0] == '.') { + size_t sz = (strlen(guard) + 1) + (sizeof("HG_RPCGEN_") - 1); + tmp2 = malloc(sz); + if (!tmp2) { + errx(EXIT_FAILURE, "malloc"); + } + snprintf(tmp2, sz, "HG_RPCGEN_%s", guard); + free(guard); + guard = tmp2; + } + + /* Replace the file extension */ + tmp2 = extendfile(guard, "_H_HG_RPCGEN"); + free(guard); + guard = tmp2; + + return (guard); +} + +/* + * Compile into an XDR header file + */ +static void +h_output(char *infile, char *define, int extend, const char *outfile) +{ + definition *def; + const char *outfilename; + long tell; + char *guard; + list *l; + int did; + + initialize_base_types(); + open_input(infile, define); + outfilename = extend ? extendfile(infile, outfile) : outfile; + open_output(infile, outfilename); + add_warning(); + if (outfilename || infile) + guard = generate_guard(outfilename ? outfilename : infile); + else { + guard = strdup("STDIN_"); + if (guard == NULL) { + err(EXIT_FAILURE, "strdup"); + } + } + + f_print(fout, "#ifndef _%s\n#define _%s\n\n", guard, + guard); + + f_print(fout, "#define HG_RPCGEN_VERSION\t%s\n\n", HG_RPCGEN_VERSION); + f_print(fout, "#include \n\n"); + + tell = ftell(fout); + /* print data definitions */ + while ((def = get_definition()) != NULL) { + print_datadef(def); + } + + /* print function declarations. Do this after data definitions + * because they might be used as arguments for functions */ + did = 0; + for (l = defined; l != NULL; l = l->next) { + print_funcdef(l->val, &did); + } + print_funcend(did); + + if (extend && tell == ftell(fout)) { + (void) unlink(outfilename); + } + f_print(fout, "\n#endif /* !_%s */\n", guard); + + free(guard); +} + +/* + * Add another argument to the arg list + */ +static void +addarg(char *cp) +{ + if (argcount >= ARGLISTLEN) { + errx(EXIT_FAILURE, "Internal error: too many defines"); + /* NOTREACHED */ + } + arglist[argcount++] = cp; + +} + +static void +putarg(int pwhere, char *cp) +{ + if (pwhere >= ARGLISTLEN) { + errx(EXIT_FAILURE, "Internal error: arglist coding error"); + /* NOTREACHED */ + } + arglist[pwhere] = cp; + +} +/* + * if input file is stdin and an output file is specified then complain + * if the file already exists. Otherwise the file may get overwritten + * If input file does not exist, exit with an error + */ + +static void +checkfiles(const char *infile, const char *outfile) +{ + + struct stat buf; + + if (infile) /* infile ! = NULL */ + if (stat(infile, &buf) < 0) { + err(EXIT_FAILURE, "Can't stat `%s'", infile); + }; + if (outfile && 0 == 1 /* XXX disable */) { + if (stat(outfile, &buf) < 0) + return; /* file does not exist */ + else { + errx(EXIT_FAILURE, + "`%s' already exists and would be overwritten", + outfile); + } + } +} +/* + * Parse command line arguments + */ +static int +parseargs(int argc, char *argv[], struct commandline *cmd) +{ + int i; + int j; + int c; + char flag[1 << CHAR_BIT]; + int nflags; + + cmdname = argv[0]; + cmd->infile = cmd->outfile = NULL; + if (argc < 2) { + return (0); + } + flag['c'] = 0; + flag['h'] = 0; + flag['o'] = 0; + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + if (cmd->infile) { + f_print(stderr, "Cannot specify more than one input file!\n"); + + return (0); + } + cmd->infile = argv[i]; + } else { + for (j = 1; argv[i][j] != 0; j++) { + c = argv[i][j]; + switch (c) { + case 'B': + BSDflag = 1; + break; + case 'c': + case 'h': + case 't': + if (flag[c]) { + return (0); + } + flag[c] = 1; + break; + case 'o': + if (argv[i][j - 1] != '-' || + argv[i][j + 1] != 0) { + return (0); + } + flag[c] = 1; + if (++i == argc) { + return (0); + } + if (cmd->outfile) { + return (0); + } + cmd->outfile = argv[i]; + goto nextarg; + case 'D': + if (argv[i][j - 1] != '-') { + return (0); + } + (void) addarg(argv[i]); + goto nextarg; + case 'Y': + if (++i == argc) { + return (0); + } + (void) strncpy(pathbuf, argv[i], + sizeof(pathbuf)-1); + (void) strncat(pathbuf, "/cpp", + sizeof(pathbuf)-1); + CPP = pathbuf; + goto nextarg; + + case 'v': + printf("version 1.0\n"); + exit(0); + + default: + return (0); + } + } + nextarg: + ; + } + } + + cmd->cflag = flag['c']; + cmd->hflag = flag['h']; + + /* check no conflicts with file generation flags */ + nflags = cmd->cflag + cmd->hflag; + + if (nflags == 0) { + if (cmd->outfile != NULL || cmd->infile == NULL) { + return (0); + } + } else + if (nflags > 1) { + f_print(stderr, "Cannot have more than one file generation flag!\n"); + return (0); + } + return (1); +} + +static void +usage(void) +{ + f_print(stderr, "usage:\n"); + f_print(stderr, "\t%s [flags] infile\n", cmdname); + f_print(stderr, "\t%s [flags] [-c | -h] [-o outfile] [input]\n", + cmdname); + f_print(stderr, "\n"); + f_print(stderr, "First version generates all file from input file.\n"); + f_print(stderr, "Second version generates specified type of file\n"); + f_print(stderr, "from input (default input=stdin, output=stdout)\n\n"); + f_print(stderr, "Available output formats:\n"); + f_print(stderr, "-c\t\tgenerate code/decode proc routines\n"); + f_print(stderr, "-h\t\tgenerate header file\n"); + f_print(stderr, "\nflags:\n"); + f_print(stderr, "-B\t\tuse BSD c++ guard macros in header files\n"); + f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n"); + f_print(stderr, "-v\t\tdisplay hg_rpcgen version number\n"); + f_print(stderr, "-Y path\t\tdirectory name to find C preprocessor (cpp)\n"); + f_print(stderr, "\n"); + f_print(stderr, "$HG_RPCGEN_CPP directly sets path to C preprocessor\n"); + exit(1); +} diff --git a/util/hg_rpcgen/rpc_parse.c b/util/hg_rpcgen/rpc_parse.c new file mode 100644 index 00000000..a2b3f84d --- /dev/null +++ b/util/hg_rpcgen/rpc_parse.c @@ -0,0 +1,710 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_parse.c, Parser for the RPC protocol compiler + * Copyright (C) 1987 Sun Microsystems, Inc. + */ +#include +#include +#include +#include "rpc_scan.h" +#include "rpc_parse.h" +#include "rpc_util.h" + +#define ARGNAME "arg" + +static void isdefined(definition *); +static void def_struct(definition *); +static void def_program(definition *); +static void def_enum(definition *); +static void def_const(definition *); +static void def_union(definition *); +static void check_type_name(const char *, int); +static void def_typedef(definition *); +static void get_declaration(declaration *, defkind); +static void get_prog_declaration(declaration *, defkind, int); +static void get_type(token *, token *, defkind); +static void unsigned_dec(token *); + +static void +free_declaration(declaration *d) +{ + free_token_str(&d->prefix); + free_token_str(&d->type); + free_token_str(&d->name); + free_token_str(&d->array_max); +} + +static void +free_proc_list(proc_list *procs) +{ + proc_list *pl, *plnxt; + decl_list *dl, *dlnxt; + for (pl = procs ; pl ; pl = plnxt) { + plnxt = pl->next; + free_token_str(&pl->proc_name); + free_token_str(&pl->proc_num); + free_token_str(&pl->args.argname); + for (dl = pl->args.decls ; dl ; dl = dlnxt) { + dlnxt = dl->next; + free_declaration(&dl->decl); + free(dl); + } + free_token_str(&pl->res_type); + free_token_str(&pl->res_prefix); + free(pl); + } +} + +/* + * free list of definitions + */ +void +free_definitions(list **dlistp) { + list *dl = *dlistp; + list *nxt; + definition *d; + decl_list *dcl, *dclnxt; + case_list *cl, *clnxt; + enumval_list *el, *elnxt; + version_list *vl, *vlnxt; + + *dlistp = NULL; + + for ( ; dl != NULL ; dl = nxt) { + d = dl->val; + nxt = dl->next; + free(dl); + + switch (d->def_kind) { + case DEF_CONST: + free_token_str(&d->def.co); + break; + case DEF_STRUCT: + for (dcl = d->def.st.decls ; dcl ; dcl = dclnxt) { + dclnxt = dcl->next; + free_declaration(&dcl->decl); + free(dcl); + } + break; + case DEF_UNION: + free_declaration(&d->def.un.enum_decl); + for (cl = d->def.un.cases ; cl ; cl = clnxt) { + clnxt = cl->next; + free_token_str(&cl->case_name); + free_declaration(&cl->case_decl); + free(cl); + } + if (d->def.un.default_decl) { + free_declaration(d->def.un.default_decl); + free(d->def.un.default_decl); + } + break; + case DEF_ENUM: + for ( el = d->def.en.vals ; el != NULL ; el = elnxt) { + elnxt = el->next; + free_token_str(&el->name); + free_token_str(&el->assignment); + free(el); + } + break; + case DEF_TYPEDEF: + free_token_str(&d->def.ty.old_prefix); + free_token_str(&d->def.ty.old_type); + free_token_str(&d->def.ty.array_max); + break; + case DEF_PROGRAM: + free_token_str(&d->def.pr.prog_num); + for (vl = d->def.pr.versions ; vl ; vl = vlnxt) { + vlnxt = vl->next; + free_token_str(&vl->vers_name); + free_token_str(&vl->vers_num); + free_proc_list(vl->procs); + free(vl); + } + break; + default: + break; + } + free_token_str(&d->def_name); + free(d); + } +} + +/* + * return the next definition you see + */ +definition * +get_definition(void) +{ + definition *defp; + token tok; + + defp = ALLOC(definition); + get_token(&tok); + switch (tok.kind) { + case TOK_STRUCT: + def_struct(defp); + break; + case TOK_UNION: + def_union(defp); + break; + case TOK_TYPEDEF: + def_typedef(defp); + break; + case TOK_ENUM: + def_enum(defp); + break; + case TOK_PROGRAM: + def_program(defp); + break; + case TOK_CONST: + def_const(defp); + break; + case TOK_EOF: + free(defp); + return (NULL); + default: + error("Expected definition keyword"); + } + scan(TOK_SEMICOLON, &tok); + isdefined(defp); + return (defp); +} + +static void +isdefined(definition *defp) +{ + STOREVAL(&defined, defp); +} + +static void +def_struct(definition *defp) +{ + token tok; + declaration dec; + decl_list *decls; + decl_list **tailp; + + defp->def_kind = DEF_STRUCT; + + scan(TOK_IDENT, &defp->def_name); + scan(TOK_LBRACE, &tok); + tailp = &defp->def.st.decls; + do { + get_declaration(&dec, DEF_STRUCT); + decls = ALLOC(decl_list); + decls->decl = dec; + *tailp = decls; + tailp = &decls->next; + scan(TOK_SEMICOLON, &tok); + peek(&tok); + } while (tok.kind != TOK_RBRACE); + get_token(&tok); + *tailp = NULL; +} + +static void +def_program(definition *defp) +{ + token tok; + declaration dec; + decl_list *decls; + decl_list **tailp; + version_list *vlist; + version_list **vtailp; + proc_list *plist; + proc_list **ptailp; + int num_args; + int isvoid = 0; /* whether first argument is void */ + defp->def_kind = DEF_PROGRAM; + scan(TOK_IDENT, &defp->def_name); + scan(TOK_LBRACE, &tok); + vtailp = &defp->def.pr.versions; + tailp = &defp->def.st.decls; + scan(TOK_VERSION, &tok); + do { + vlist = ALLOC(version_list); + scan(TOK_IDENT, &vlist->vers_name); + scan(TOK_LBRACE, &tok); + ptailp = &vlist->procs; + do { + /* get result type */ + plist = ALLOC(proc_list); + get_type(&plist->res_prefix, &plist->res_type, + DEF_PROGRAM); + if (streq(plist->res_type.str, "opaque")) { + error("Illegal result type"); + } + scan(TOK_IDENT, &plist->proc_name); + scan(TOK_LPAREN, &tok); + /* get args - first one */ + num_args = 1; + isvoid = 0; + /* type of DEF_PROGRAM in the first + * get_prog_declaration and DEF_STRUCT in the next + * allows void as argument if it is the only argument */ + get_prog_declaration(&dec, DEF_PROGRAM, num_args); + if (streq(dec.type.str, "void")) + isvoid = 1; + decls = ALLOC(decl_list); + plist->args.decls = decls; + decls->decl = dec; + tailp = &decls->next; + /* get args */ + while (peekscan(TOK_COMMA, &tok)) { + num_args++; + get_prog_declaration(&dec, DEF_STRUCT, + num_args); + decls = ALLOC(decl_list); + decls->decl = dec; + *tailp = decls; + if (streq(dec.type.str, "void")) + isvoid = 1; + tailp = &decls->next; + } + /* multiple arguments are only allowed in new style */ + if (num_args > 1) { + error("Only one argument is allowed"); + } + if (isvoid && num_args > 1) { + error("Illegal use of void in program definition"); + } + *tailp = NULL; + scan(TOK_RPAREN, &tok); + scan(TOK_EQUAL, &tok); + scan_num(&plist->proc_num); + scan(TOK_SEMICOLON, &tok); + plist->arg_num = num_args; + *ptailp = plist; + ptailp = &plist->next; + peek(&tok); + } while (tok.kind != TOK_RBRACE); + *ptailp = NULL; + *vtailp = vlist; + vtailp = &vlist->next; + scan(TOK_RBRACE, &tok); + scan(TOK_EQUAL, &tok); + scan_num(&vlist->vers_num); + /* make the argument structure name for each arg */ + for (plist = vlist->procs; plist != NULL; + plist = plist->next) { + plist->args.argname.kind = TOK_IDENT; + plist->args.argname.str = make_argname(plist->proc_name.str, + vlist->vers_num.str); + } + scan(TOK_SEMICOLON, &tok); + scan2(TOK_VERSION, TOK_RBRACE, &tok); + } while (tok.kind == TOK_VERSION); + scan(TOK_EQUAL, &tok); + scan_num(&defp->def.pr.prog_num); + *vtailp = NULL; +} + + +static void +def_enum(definition *defp) +{ + token tok; + enumval_list *elist; + enumval_list **tailp; + + defp->def_kind = DEF_ENUM; + scan(TOK_IDENT, &defp->def_name); + scan(TOK_LBRACE, &tok); + tailp = &defp->def.en.vals; + do { + scan(TOK_IDENT, &tok); + elist = ALLOC(enumval_list); + elist->name = tok; + init_token(&elist->assignment); + scan3(TOK_COMMA, TOK_RBRACE, TOK_EQUAL, &tok); + if (tok.kind == TOK_EQUAL) { + scan_num(&elist->assignment); + scan2(TOK_COMMA, TOK_RBRACE, &tok); + } + *tailp = elist; + tailp = &elist->next; + } while (tok.kind != TOK_RBRACE); + *tailp = NULL; +} + +static void +def_const(definition *defp) +{ + token tok; + + defp->def_kind = DEF_CONST; + scan(TOK_IDENT, &defp->def_name); + scan(TOK_EQUAL, &tok); + scan2(TOK_IDENT, TOK_STRCONST, &defp->def.co); +} + +static void +def_union(definition *defp) +{ + token tok; + declaration dec; + case_list *cases; + case_list **tailp; + + defp->def_kind = DEF_UNION; + scan(TOK_IDENT, &defp->def_name); + scan(TOK_SWITCH, &tok); + scan(TOK_LPAREN, &tok); + get_declaration(&dec, DEF_UNION); + defp->def.un.enum_decl = dec; + tailp = &defp->def.un.cases; + scan(TOK_RPAREN, &tok); + scan(TOK_LBRACE, &tok); + scan(TOK_CASE, &tok); + while (tok.kind == TOK_CASE) { + scan2(TOK_IDENT, TOK_CHARCONST, &tok); + cases = ALLOC(case_list); + cases->case_name = tok; + scan(TOK_COLON, &tok); + /* now peek at next token */ + if (peekscan(TOK_CASE, &tok)) { + + do { + scan2(TOK_IDENT, TOK_CHARCONST, &tok); + cases->contflag = 1; /* continued case + * statement */ + *tailp = cases; + tailp = &cases->next; + cases = ALLOC(case_list); + cases->case_name = tok; + scan(TOK_COLON, &tok); + + } while (peekscan(TOK_CASE, &tok)); + } + get_declaration(&dec, DEF_UNION); + cases->case_decl = dec; + cases->contflag = 0; /* no continued case statement */ + *tailp = cases; + tailp = &cases->next; + scan(TOK_SEMICOLON, &tok); + + scan3(TOK_CASE, TOK_DEFAULT, TOK_RBRACE, &tok); + } + *tailp = NULL; + if (tok.kind == TOK_DEFAULT) { + scan(TOK_COLON, &tok); + get_declaration(&dec, DEF_UNION); + defp->def.un.default_decl = ALLOC(declaration); + *defp->def.un.default_decl = dec; + scan(TOK_SEMICOLON, &tok); + scan(TOK_RBRACE, &tok); + } else { + defp->def.un.default_decl = NULL; + } +} + +static const char *const reserved_words[] = { + "array", + "bytes", + "destroy", + "free", + "getpos", + "inline", + "pointer", + "reference", + "setpos", + "sizeof", + "union", + "vector", + NULL +}; + +static const char *const reserved_types[] = { + "opaque", + "string", + NULL +}; +/* check that the given name is not one that would eventually result in + xdr routines that would conflict with internal XDR routines. */ +static void +check_type_name(const char *name, int new_type) +{ + int i; + + for (i = 0; reserved_words[i] != NULL; i++) { + if (strcmp(name, reserved_words[i]) == 0) { + error("Illegal (reserved) name '%s' in type definition", name); + } + } + if (new_type) { + for (i = 0; reserved_types[i] != NULL; i++) { + if (strcmp(name, reserved_types[i]) == 0) { + error("Illegal (reserved) name '%s' in type definition", name); + } + } + } +} + +static void +def_typedef(definition *defp) +{ + declaration dec; + + defp->def_kind = DEF_TYPEDEF; + get_declaration(&dec, DEF_TYPEDEF); + defp->def_name = dec.name; + check_type_name(dec.name.str, 1); + defp->def.ty.old_prefix = dec.prefix; + defp->def.ty.old_type = dec.type; + defp->def.ty.rel = dec.rel; + defp->def.ty.array_max = dec.array_max; +} + +static void +get_declaration(declaration *dec, defkind dkind) +{ + token tok; + + /* make sure we fully init dec first */ + get_type(&dec->prefix, &dec->type, dkind); + init_token(&dec->name); + dec->rel = REL_ALIAS; + init_token(&dec->array_max); + + if (streq(dec->type.str, "void")) { + return; + } + check_type_name(dec->type.str, 0); + + scan2(TOK_STAR, TOK_IDENT, &tok); + if (tok.kind == TOK_STAR) { + dec->rel = REL_POINTER; + scan(TOK_IDENT, &tok); + } + dec->name = tok; + if (peekscan(TOK_LBRACKET, &tok)) { + if (dec->rel == REL_POINTER) { + error("No array-of-pointer declarations -- use typedef"); + } + dec->rel = REL_VECTOR; + scan_num(&dec->array_max); + scan(TOK_RBRACKET, &tok); + } else + if (peekscan(TOK_LANGLE, &tok)) { + if (dec->rel == REL_POINTER) { + error("No array-of-pointer declarations -- use typedef"); + } + dec->rel = REL_ARRAY; + if (peekscan(TOK_RANGLE, &tok)) { + dec->array_max.kind = TOK_STRSTATIC; + dec->array_max.str = "(unsigned int)~0"; + /* unspecified size, use * max */ + } else { + scan_num(&dec->array_max); + scan(TOK_RANGLE, &tok); + } + } + if (streq(dec->type.str, "opaque")) { + if (dec->rel != REL_ARRAY && dec->rel != REL_VECTOR) { + error("Array declaration expected"); + } + } else + if (streq(dec->type.str, "string")) { + if (dec->rel != REL_ARRAY) { + error("Variable-length array declaration expected"); + } + } +} + +static void +get_prog_declaration(declaration *dec, defkind dkind, int num /* arg number */) +{ + token tok; + char name[255]; /* argument name */ + + if (dkind == DEF_PROGRAM) { + peek(&tok); + if (tok.kind == TOK_RPAREN) { /* no arguments */ + dec->rel = REL_ALIAS; + dec->type.kind = TOK_VOID; + dec->type.str = "void"; + init_token(&dec->prefix); + init_token(&dec->name); + return; + } + } + get_type(&dec->prefix, &dec->type, dkind); + dec->rel = REL_ALIAS; + if (!peekscan(TOK_IDENT, &dec->name)) { /* ok to use dec->name here */ + /* peekscan failed, must generate new dec->name */ + sprintf(name, "%s%d", ARGNAME, num); /* default name of + * argument */ + dec->name.kind = TOK_IDENT; + dec->name.str = strdup(name); + if (!dec->name.str) + error("strdup failed\n"); + } + + if (streq(dec->type.str, "void")) { + return; + } + if (streq(dec->type.str, "opaque")) { + error("Opaque -- illegal argument type"); + } + if (peekscan(TOK_STAR, &tok)) { + if (streq(dec->type.str, "string")) { + error("Pointer to string not allowed in program arguments\n"); + } + dec->rel = REL_POINTER; + if (peekscan(TOK_IDENT, &tok)) { + dec->name = tok; /* opt name of argument */ + } + } + if (peekscan(TOK_LANGLE, &tok)) { + if (!streq(dec->type.str, "string")) { + error("Arrays cannot be declared as arguments to procedures -- use typedef"); + } + dec->rel = REL_ARRAY; + if (peekscan(TOK_RANGLE, &tok)) { + dec->array_max.kind = TOK_STRSTATIC; + dec->array_max.str = "(unsigned int)~0"; + /* unspecified size, use max */ + } else { + scan_num(&dec->array_max); + scan(TOK_RANGLE, &tok); + } + } + if (streq(dec->type.str, "string")) { + if (dec->rel != REL_ARRAY) { /* .x specifies just string as + * type of argument - make it + * string<> */ + dec->rel = REL_ARRAY; + dec->array_max.kind = TOK_STRSTATIC; + dec->array_max.str = "(unsigned int)~0"; + /* unspecified size, use max */ + } + } +} + + + +static void +get_type(token *prefixp, token *typep, defkind dkind) +{ + token tok; + + init_token(prefixp); + get_token(&tok); + switch (tok.kind) { + case TOK_IDENT: + *typep = tok; + break; + case TOK_STRUCT: + case TOK_ENUM: + case TOK_UNION: + *prefixp = tok; + scan(TOK_IDENT, typep); + break; + case TOK_UNSIGNED: + unsigned_dec(typep); + break; + case TOK_SHORT: + *typep = tok; + (void) peekscan(TOK_INT, &tok); + break; + case TOK_LONG: + *typep = tok; + (void) peekscan(TOK_INT, &tok); + break; + case TOK_HYPER: + *typep = tok; + (void) peekscan(TOK_INT, &tok); + break; + case TOK_VOID: + if (dkind != DEF_UNION && dkind != DEF_PROGRAM) { + error("Void is allowed only inside union and program definitions with one argument"); + } + *typep = tok; + break; + case TOK_STRING: + case TOK_OPAQUE: + case TOK_CHAR: + case TOK_INT: + case TOK_FLOAT: + case TOK_DOUBLE: + case TOK_BOOL: + case TOK_QUAD: + *typep = tok; + break; + default: + error("Type specifier expected"); + } +} + +static void +unsigned_dec(token *typep) +{ + token tok; + + peek(&tok); + switch (tok.kind) { + case TOK_CHAR: + get_token(&tok); + *typep = tok; + typep->str = "u_char"; + break; + case TOK_SHORT: + get_token(&tok); + *typep = tok; + typep->str = "u_short"; + (void) peekscan(TOK_INT, &tok); + break; + case TOK_LONG: + get_token(&tok); + *typep = tok; + typep->str = "u_long"; + (void) peekscan(TOK_INT, &tok); + break; + case TOK_HYPER: + get_token(&tok); + *typep = tok; + typep->str = "u_longlong_t"; + (void) peekscan(TOK_INT, &tok); + break; + case TOK_INT: + get_token(&tok); + *typep = tok; + typep->str = "u_int"; + break; + default: + typep->kind = TOK_INT; + typep->str = "u_int"; + break; + } +} diff --git a/util/hg_rpcgen/rpc_parse.h b/util/hg_rpcgen/rpc_parse.h new file mode 100644 index 00000000..20c5c89c --- /dev/null +++ b/util/hg_rpcgen/rpc_parse.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_parse.h, Definitions for the RPCL parser + */ + +enum defkind { + DEF_CONST, + DEF_STRUCT, + DEF_UNION, + DEF_ENUM, + DEF_TYPEDEF, + DEF_PROGRAM +}; +typedef enum defkind defkind; + +typedef token const_def; + +enum relation { + REL_VECTOR, /* fixed length array */ + REL_ARRAY, /* variable length array */ + REL_POINTER, /* pointer */ + REL_ALIAS, /* simple */ +}; +typedef enum relation relation; + +struct typedef_def { + token old_prefix; + token old_type; + relation rel; + token array_max; +}; +typedef struct typedef_def typedef_def; + +struct enumval_list { + token name; + token assignment; + struct enumval_list *next; +}; +typedef struct enumval_list enumval_list; + +struct enum_def { + enumval_list *vals; +}; +typedef struct enum_def enum_def; + +struct declaration { + token prefix; + token type; + token name; + relation rel; + token array_max; +}; +typedef struct declaration declaration; + +struct decl_list { + declaration decl; + struct decl_list *next; +}; +typedef struct decl_list decl_list; + +struct struct_def { + decl_list *decls; +}; +typedef struct struct_def struct_def; + +struct case_list { + token case_name; + int contflag; + declaration case_decl; + struct case_list *next; +}; +typedef struct case_list case_list; + +struct union_def { + declaration enum_decl; + case_list *cases; + declaration *default_decl; +}; +typedef struct union_def union_def; + +struct arg_list { + token argname; /* name of struct for arg */ + decl_list *decls; +}; + +typedef struct arg_list arg_list; + +struct proc_list { + token proc_name; + token proc_num; + arg_list args; + int arg_num; + token res_type; + token res_prefix; + struct proc_list *next; +}; +typedef struct proc_list proc_list; + +struct version_list { + token vers_name; + token vers_num; + proc_list *procs; + struct version_list *next; +}; +typedef struct version_list version_list; + +struct program_def { + token prog_num; + version_list *versions; +}; +typedef struct program_def program_def; + +struct definition { + token def_name; + defkind def_kind; + union { + const_def co; + struct_def st; + union_def un; + enum_def en; + typedef_def ty; + program_def pr; + } def; +}; +typedef struct definition definition; + +struct list { + definition *val; + struct list *next; +}; +typedef struct list list; + +definition *get_definition(void); +void free_definitions(list **); + +struct bas_type +{ + const char *name; + int length; + struct bas_type *next; +}; + +typedef struct bas_type bas_type; diff --git a/util/hg_rpcgen/rpc_scan.c b/util/hg_rpcgen/rpc_scan.c new file mode 100644 index 00000000..365edc93 --- /dev/null +++ b/util/hg_rpcgen/rpc_scan.c @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_scan.c, Scanner for the RPC protocol compiler + * Copyright (C) 1987, Sun Microsystems, Inc. + */ +#include +#include +#include +#include +#include "rpc_scan.h" +#include "rpc_parse.h" +#include "rpc_util.h" + +#define startcomment(where) (where[0] == '/' && where[1] == '*') +#define endcomment(where) (where[-1] == '*' && where[0] == '/') + +static void unget_token(token *); +static void findstrconst(char **, const char **); +static void findchrconst(char **, const char **); +static void findconst(char **, const char **); +static void findkind(char **, token *); +static int cppline(const char *); +static int directive(const char *); +static void printdirective(const char *); +static void docppline(char *, int *, char **); + +static int pushed = 0; /* is a token pushed */ +static token lasttok; /* last token, if pushed */ + +/* + * scan expecting 1 given token + */ +void +scan(tok_kind expect, token *tokp) +{ + get_token(tokp); + if (tokp->kind != expect) { + expected1(expect); + } +} +/* + * scan expecting any of the 2 given tokens + */ +void +scan2(tok_kind expect1, tok_kind expect2, token *tokp) +{ + get_token(tokp); + if (tokp->kind != expect1 && tokp->kind != expect2) { + expected2(expect1, expect2); + } +} +/* + * scan expecting any of the 3 given token + */ +void +scan3(tok_kind expect1, tok_kind expect2, tok_kind expect3, token *tokp) +{ + get_token(tokp); + if (tokp->kind != expect1 && tokp->kind != expect2 + && tokp->kind != expect3) { + expected3(expect1, expect2, expect3); + } +} +/* + * scan expecting a constant, possibly symbolic + */ +void +scan_num(token *tokp) +{ + get_token(tokp); + switch (tokp->kind) { + case TOK_IDENT: + break; + default: + error("Expected constant or identifier"); + } +} +/* + * Peek at the next token + */ +void +peek(token *tokp) +{ + get_token(tokp); + unget_token(tokp); +} +/* + * Peek at the next token and scan it if it matches what you expect + */ +int +peekscan(tok_kind expect, token *tokp) +{ + peek(tokp); + if (tokp->kind == expect) { + get_token(tokp); + return (1); + } + return (0); +} +/* + * Init token to undefined state with a NULL string value. + * Token may later be loaded with different value. + */ +void +init_token(token *tokp) +{ + tokp->kind = TOK_UNDEFINED; + tokp->str = NULL; +} +/* + * free token string -- if it was malloced. + */ +void +free_token_str(token *tokp) +{ + /* only certain kinds of tokens have malloced strings ... */ + if (tokp->kind == TOK_IDENT || tokp->kind == TOK_CHARCONST || + tokp->kind == TOK_STRCONST) { + if (tokp->str) + free((void *)tokp->str); + init_token(tokp); /* to be safe */ + } +} +/* + * Get the next token, printing out any directive that are encountered. + */ +void +get_token(token *tokp) +{ + int commenting; + + if (pushed) { + pushed = 0; + *tokp = lasttok; + return; + } + commenting = 0; + for (;;) { + if (*where == 0) { + for (;;) { + if (!fgets(curline, MAXLINESIZE, fin)) { + tokp->kind = TOK_EOF; + *where = 0; + return; + } + linenum++; + if (commenting) { + break; + } else + if (cppline(curline)) { + docppline(curline, &linenum, + &infilename); + } else + if (directive(curline)) { + printdirective(curline); + } else { + break; + } + } + where = curline; + } else + if (isspace((unsigned char)*where)) { + while (isspace((unsigned char)*where)) { + where++; /* eat */ + } + } else + if (commenting) { + for (where++; *where; where++) { + if (endcomment(where)) { + where++; + commenting--; + break; + } + } + } else + if (startcomment(where)) { + where += 2; + commenting++; + } else { + break; + } + } + + /* + * 'where' is not whitespace, comment or directive Must be a token! + */ + switch (*where) { + case ':': + tokp->kind = TOK_COLON; + where++; + break; + case ';': + tokp->kind = TOK_SEMICOLON; + where++; + break; + case ',': + tokp->kind = TOK_COMMA; + where++; + break; + case '=': + tokp->kind = TOK_EQUAL; + where++; + break; + case '*': + tokp->kind = TOK_STAR; + where++; + break; + case '[': + tokp->kind = TOK_LBRACKET; + where++; + break; + case ']': + tokp->kind = TOK_RBRACKET; + where++; + break; + case '{': + tokp->kind = TOK_LBRACE; + where++; + break; + case '}': + tokp->kind = TOK_RBRACE; + where++; + break; + case '(': + tokp->kind = TOK_LPAREN; + where++; + break; + case ')': + tokp->kind = TOK_RPAREN; + where++; + break; + case '<': + tokp->kind = TOK_LANGLE; + where++; + break; + case '>': + tokp->kind = TOK_RANGLE; + where++; + break; + + case '"': + tokp->kind = TOK_STRCONST; + findstrconst(&where, &tokp->str); + break; + case '\'': + tokp->kind = TOK_CHARCONST; + findchrconst(&where, &tokp->str); + break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + tokp->kind = TOK_IDENT; + findconst(&where, &tokp->str); + break; + + default: + if (!(isalpha((unsigned char)*where) || *where == '_')) { + if (isprint((unsigned char)*where)) { + error("Illegal character '%c' in file", *where); + } else { + error("Illegal character %d in file", *where); + } + } + findkind(&where, tokp); + break; + } +} + +static void +unget_token(token *tokp) +{ + lasttok = *tokp; + pushed = 1; +} + +static void +findstrconst(char **str, const char **val) +{ + char *p; + int size; + char *tmp; + + p = *str; + do { + p++; + } while (*p && *p != '"'); + if (*p == 0) { + error("Unterminated string constant"); + } + p++; + size = p - *str; + tmp = alloc(size + 1); + (void) strncpy(tmp, *str, size); + tmp[size] = 0; + *val = tmp; + *str = p; +} + +static void +findchrconst(char **str, const char **val) +{ + char *p; + int size; + char *tmp; + + p = *str; + do { + p++; + } while (*p && *p != '\''); + if (*p == 0) { + error("Unterminated string constant"); + } + p++; + size = p - *str; + if (size != 3) { + error("Empty character"); + } + tmp = alloc(size + 1); + (void) strncpy(tmp, *str, size); + tmp[size] = 0; + *val = tmp; + *str = p; +} + +static void +findconst(char **str, const char **val) +{ + char *p; + int size; + char *tmp; + + p = *str; + if (*p == '0' && *(p + 1) == 'x') { + p++; + do { + p++; + } while (isxdigit((unsigned char)*p)); + } else { + do { + p++; + } while (isdigit((unsigned char)*p)); + } + size = p - *str; + tmp = alloc(size + 1); + (void) strncpy(tmp, *str, size); + tmp[size] = 0; + *val = tmp; + *str = p; +} + +static const token symbols[] = { + {TOK_CONST, "const"}, + {TOK_UNION, "union"}, + {TOK_SWITCH, "switch"}, + {TOK_CASE, "case"}, + {TOK_DEFAULT, "default"}, + {TOK_STRUCT, "struct"}, + {TOK_TYPEDEF, "typedef"}, + {TOK_ENUM, "enum"}, + {TOK_OPAQUE, "opaque"}, + {TOK_BOOL, "bool"}, + {TOK_VOID, "void"}, + {TOK_CHAR, "char"}, + {TOK_INT, "int"}, + {TOK_UNSIGNED, "unsigned"}, + {TOK_SHORT, "short"}, + {TOK_LONG, "long"}, + {TOK_HYPER, "hyper"}, + {TOK_FLOAT, "float"}, + {TOK_DOUBLE, "double"}, + {TOK_QUAD, "quadruple"}, + {TOK_STRING, "string"}, + {TOK_PROGRAM, "program"}, + {TOK_VERSION, "version"}, + {TOK_EOF, "??????"}, +}; + +static void +findkind(char **mark, token *tokp) +{ + int len; + const token *s; + char *str; + char *tmp; + + str = *mark; + for (s = symbols; s->kind != TOK_EOF; s++) { + len = strlen(s->str); + if (strncmp(str, s->str, len) == 0) { + if (!isalnum((unsigned char)str[len]) && + str[len] != '_') { + tokp->kind = s->kind; + tokp->str = s->str; + *mark = str + len; + return; + } + } + } + tokp->kind = TOK_IDENT; + for (len = 0; isalnum((unsigned char)str[len]) || + str[len] == '_'; len++); + tmp = alloc(len + 1); + (void) strncpy(tmp, str, len); + tmp[len] = 0; + tokp->str = tmp; + *mark = str + len; +} + +static int +cppline(const char *line) +{ + return (line == curline && *line == '#'); +} + +static int +directive(const char *line) +{ + return (line == curline && *line == '%'); +} + +static void +printdirective(const char *line) +{ + f_print(fout, "%s", line + 1); +} + +static void +docppline(char *line, int *lineno, char **fname) +{ + char *file; + int num; + char *p; + + line++; + while (isspace((unsigned char)*line)) { + line++; + } + num = atoi(line); + while (isdigit((unsigned char)*line)) { + line++; + } + while (isspace((unsigned char)*line)) { + line++; + } + if (*line != '"') { + error("Preprocessor error"); + } + line++; + p = file = alloc(strlen(line) + 1); + while (*line && *line != '"') { + *p++ = *line++; + } + if (*line == 0) { + error("Preprocessor error"); + } + *p = 0; + if (*fname != NULL) { /* free previous malloc */ + free(*fname); + *fname = NULL; + } + if (*file == 0) { + free(file); + } else { + *fname = file; + } + *lineno = num - 1; +} diff --git a/util/hg_rpcgen/rpc_scan.h b/util/hg_rpcgen/rpc_scan.h new file mode 100644 index 00000000..36ce1101 --- /dev/null +++ b/util/hg_rpcgen/rpc_scan.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_scan.h, Definitions for the RPCL scanner + */ + +/* + * kinds of tokens + */ +enum tok_kind { + TOK_IDENT, /* malloced ident string */ + TOK_CHARCONST, /* malloced char const */ + TOK_STRCONST, /* malloced string const */ + TOK_UNDEFINED, + TOK_STRSTATIC, /* static string, not malloced */ + TOK_LPAREN, + TOK_RPAREN, + TOK_LBRACE, + TOK_RBRACE, + TOK_LBRACKET, + TOK_RBRACKET, + TOK_LANGLE, + TOK_RANGLE, + TOK_STAR, + TOK_COMMA, + TOK_EQUAL, + TOK_COLON, + TOK_SEMICOLON, + TOK_CONST, + TOK_STRUCT, + TOK_UNION, + TOK_SWITCH, + TOK_CASE, + TOK_DEFAULT, + TOK_ENUM, + TOK_TYPEDEF, + TOK_INT, + TOK_SHORT, + TOK_LONG, + TOK_HYPER, + TOK_UNSIGNED, + TOK_FLOAT, + TOK_DOUBLE, + TOK_QUAD, + TOK_OPAQUE, + TOK_CHAR, + TOK_STRING, + TOK_BOOL, + TOK_VOID, + TOK_PROGRAM, + TOK_VERSION, + TOK_EOF +}; +typedef enum tok_kind tok_kind; + +/* + * a token + */ +struct token { + tok_kind kind; + const char *str; +}; +typedef struct token token; + + +/* + * routine interface + */ +void scan(tok_kind, token *); +void scan2(tok_kind, tok_kind, token *); +void scan3(tok_kind, tok_kind, tok_kind, token *); +void scan_num(token *); +void peek(token *); +int peekscan(tok_kind, token *); +void init_token(token *); +void free_token_str(token *); +void get_token(token *); diff --git a/util/hg_rpcgen/rpc_util.c b/util/hg_rpcgen/rpc_util.c new file mode 100644 index 00000000..79a6ca9c --- /dev/null +++ b/util/hg_rpcgen/rpc_util.c @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_util.c, Utility routines for the RPC protocol compiler + */ +#include +#include +#include +#include +#include +#include +#include +#include "rpc_scan.h" +#include "rpc_parse.h" +#include "rpc_util.h" + +#define ARGEXT "argument" + +static void printwhere(void); + +char curline[MAXLINESIZE]; /* current read line */ +char *where = curline; /* current point in line */ +int linenum = 0; /* current line number */ + +char *baseinfilename = NULL; /* input filename from argv */ +char *infilename = NULL; /* input filename (malloc'd) */ + +#define NFILES 7 +static const char *outfiles[NFILES]; /* output file names */ +int nfiles; + +FILE *fout; /* file pointer of current output */ +FILE *fin; /* file pointer of current input */ + +list *defined; /* list of defined things */ + +static const char *toktostr(tok_kind); +static void printbuf(void); +static void printwhere(void); +static int findit(definition *, const char *); +static const char *fixit(const char *, const char *); +static int typedefed(definition *, const char *); + +/* + * Reinitialize the world + */ +void +reinitialize(void) +{ + memset(curline, 0, MAXLINESIZE); + where = curline; + if (infilename) { + free(infilename); + infilename = NULL; + } + linenum = 0; + free_definitions(&defined); +} +/* + * string equality + */ +int +streq(const char *a, const char *b) +{ + return (strcmp(a, b) == 0); +} +/* + * find a value in a list + */ +definition * +findval(list *lst, const char *val, int (*cmp)(definition *, const char *)) +{ + + for (; lst != NULL; lst = lst->next) { + if ((*cmp) (lst->val, val)) { + return (lst->val); + } + } + return (NULL); +} +/* + * store a value in a list + */ +void +storeval(list **lstp, definition *val) +{ + list **l; + list *lst; + + + for (l = lstp; *l != NULL; l = (list **) & (*l)->next); + lst = ALLOC(list); + lst->val = val; + lst->next = NULL; + *l = lst; +} + +static int +findit(definition *def, const char *type) +{ + return (streq(def->def_name.str, type)); +} + +static const char * +fixit(const char *type, const char *orig) +{ + definition *def; + + def = (definition *) FINDVAL(defined, type, findit); + if (def == NULL || def->def_kind != DEF_TYPEDEF) { + return (orig); + } + switch (def->def.ty.rel) { + case REL_VECTOR: + return (def->def.ty.old_type.str); + case REL_ALIAS: + return (fixit(def->def.ty.old_type.str, orig)); + default: + return (orig); + } +} + +const char * +fixtype(const char *type) +{ + return (fixit(type, type)); +} + +void +ptype(const char *prefix, const char *type, int follow) +{ + if (prefix != NULL) { + if (streq(prefix, "enum")) { + f_print(fout, "enum "); + } else { + f_print(fout, "struct "); + } + } + if (streq(type, "bool")) { + f_print(fout, "bool_t "); + } else + if (streq(type, "string")) { + f_print(fout, "char *"); + } else { + f_print(fout, "%s ", follow ? fixtype(type) : type); + } +} + +static int +typedefed(definition *def, const char *type) +{ + if (def->def_kind != DEF_TYPEDEF || def->def.ty.old_prefix.str != NULL) { + return (0); + } else { + return (streq(def->def_name.str, type)); + } +} + +int +isvectordef(const char *type, relation rel) +{ + definition *def; + + for (;;) { + switch (rel) { + case REL_VECTOR: + return (!streq(type, "string")); + case REL_ARRAY: + return (0); + case REL_POINTER: + return (0); + case REL_ALIAS: + def = (definition *) FINDVAL(defined, type, typedefed); + if (def == NULL) { + return (0); + } + type = def->def.ty.old_type.str; + rel = def->def.ty.rel; + } + } +} + +char * +locase(const char *str) +{ + char c; + static char buf[100]; + char *p = buf; + + while ((c = *str++) != '\0') { + *p++ = (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c; + } + *p = 0; + return (buf); +} + +void +pvname_svc(const char *pname, const char *vnum) +{ + f_print(fout, "%s_%s_svc", locase(pname), vnum); +} + +void +pvname(const char *pname, const char *vnum) +{ + f_print(fout, "%s_%s", locase(pname), vnum); +} +/* + * print a useful (?) error message, and then die + */ +xprintfattr(1, 2) void +error(const char *msg, ...) +{ + va_list ap; + + printwhere(); + fprintf(stderr, "%s:%d: ", (infilename) ? infilename : baseinfilename, + linenum); + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + fprintf(stderr, "\n"); + errx(EXIT_FAILURE, "Cannot recover from this error"); +} +/* + * Something went wrong, unlink any files that we may have created and then + * die. + */ +void +crash(void) +{ + int i; + + if (!docleanup) + return; + + for (i = 0; i < nfiles; i++) { + (void) unlink(outfiles[i]); + } +} + +void +record_open(const char *file) +{ + if (nfiles < NFILES) { + outfiles[nfiles++] = file; + } else { + errx(EXIT_FAILURE, "Too many files!"); + } +} + +/* + * error, token encountered was not the expected one + */ +void +expected1(tok_kind exp1) +{ + error("Expected '%s'", toktostr(exp1)); +} +/* + * error, token encountered was not one of two expected ones + */ +void +expected2(tok_kind exp1, tok_kind exp2) +{ + error("Expected '%s' or '%s'", + toktostr(exp1), + toktostr(exp2)); +} +/* + * error, token encountered was not one of 3 expected ones + */ +void +expected3(tok_kind exp1, tok_kind exp2, tok_kind exp3) +{ + error("Expected '%s', '%s', or '%s'", + toktostr(exp1), + toktostr(exp2), + toktostr(exp3)); +} + +void +tabify(FILE *f, int tab) +{ + while (tab--) { + (void) fputc('\t', f); + } +} + + +static token tokstrings[] = { + {TOK_IDENT, "identifier"}, + {TOK_CONST, "const"}, + {TOK_RPAREN, ")"}, + {TOK_LPAREN, "("}, + {TOK_RBRACE, "}"}, + {TOK_LBRACE, "{"}, + {TOK_LBRACKET, "["}, + {TOK_RBRACKET, "]"}, + {TOK_STAR, "*"}, + {TOK_COMMA, ","}, + {TOK_EQUAL, "="}, + {TOK_COLON, ":"}, + {TOK_SEMICOLON, ";"}, + {TOK_UNION, "union"}, + {TOK_STRUCT, "struct"}, + {TOK_SWITCH, "switch"}, + {TOK_CASE, "case"}, + {TOK_DEFAULT, "default"}, + {TOK_ENUM, "enum"}, + {TOK_TYPEDEF, "typedef"}, + {TOK_INT, "int"}, + {TOK_SHORT, "short"}, + {TOK_LONG, "long"}, + {TOK_UNSIGNED, "unsigned"}, + {TOK_DOUBLE, "double"}, + {TOK_FLOAT, "float"}, + {TOK_CHAR, "char"}, + {TOK_STRING, "string"}, + {TOK_OPAQUE, "opaque"}, + {TOK_BOOL, "bool"}, + {TOK_VOID, "void"}, + {TOK_PROGRAM, "program"}, + {TOK_VERSION, "version"}, + {TOK_EOF, "??????"} +}; + +static const char * +toktostr(tok_kind kind) +{ + token *sp; + + for (sp = tokstrings; sp->kind != TOK_EOF && sp->kind != kind; sp++); + return (sp->str); +} + +static void +printbuf(void) +{ + char c; + int i; + int cnt; + +#define TABSIZE 4 + + for (i = 0; (c = curline[i]) != '\0'; i++) { + if (c == '\t') { + cnt = 8 - (i % TABSIZE); + c = ' '; + } else { + cnt = 1; + } + while (cnt--) { + (void) fputc(c, stderr); + } + } +} + +static void +printwhere(void) +{ + int i; + char c; + int cnt; + + printbuf(); + for (i = 0; i < where - curline; i++) { + c = curline[i]; + if (c == '\t') { + cnt = 8 - (i % TABSIZE); + } else { + cnt = 1; + } + while (cnt--) { + (void) fputc('^', stderr); + } + } + (void) fputc('\n', stderr); +} + +char * +make_argname(const char *pname, const char *vname) +{ + char *name; + size_t len; + + len = strlen(pname) + strlen(vname) + strlen(ARGEXT) + 3; + name = malloc(len); + if (!name) { + err(EXIT_FAILURE, "malloc"); + } + snprintf(name, len, "%s_%s_%s", locase(pname), vname, ARGEXT); + return (name); +} + +bas_type *typ_list_h; +bas_type *typ_list_t; + +void +add_type(int len, const char *type) +{ + bas_type *ptr; + + if ((ptr = malloc(sizeof(bas_type))) == NULL) { + err(EXIT_FAILURE, "malloc"); + } + ptr->name = type; + ptr->length = len; + ptr->next = NULL; + if (typ_list_t == NULL) { + typ_list_t = ptr; + typ_list_h = ptr; + } else { + typ_list_t->next = ptr; + typ_list_t = ptr; + } +} + +bas_type * +find_type(const char *type) +{ + bas_type *ptr; + + ptr = typ_list_h; + + + while (ptr != NULL) { + if (strcmp(ptr->name, type) == 0) + return (ptr); + else + ptr = ptr->next; + } + return (NULL); +} diff --git a/util/hg_rpcgen/rpc_util.h b/util/hg_rpcgen/rpc_util.h new file mode 100644 index 00000000..b98b88f6 --- /dev/null +++ b/util/hg_rpcgen/rpc_util.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2010, Oracle America, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * * Neither the name of the "Oracle America, Inc." nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * rpc_util.h, Useful definitions for the RPC protocol compiler + */ + +/* quick hack for printf formatting checks on most platforms+noreturn */ +#if defined(__GNUC__) && (__GNUC__ > 2) +#define xnoreturn() __attribute__((__noreturn__)) +#define xprintfattr(fmtarg, firstvararg) \ + __attribute__((__format__ (__printf__, fmtarg, firstvararg))) +#define xscanfattr(fmtarg, firstvararg) \ + __attribute__((__format__ (__scanf__, fmtarg, firstvararg))) +#else +#define xnoreturn() +#define xprintfattr(fmtarg, firstvararg) +#define xscanfattr(fmtarg, firstvararg) +#endif + +#define alloc(size) ((char *)malloc((size_t)(size))) +#define ALLOC(object) ((object *)malloc(sizeof(object))) + +#define s_print (void) sprintf +#define f_print (void) fprintf + +/* + * Global variables + */ +#define MAXLINESIZE 1024 +extern char curline[MAXLINESIZE]; +extern char *where; +extern int linenum; +extern int docleanup; + +extern char *baseinfilename; +extern char *infilename; +extern FILE *fout; +extern FILE *fin; + +extern list *defined; + +/* + * All the option flags + */ +extern int BSDflag; + +/* + * rpc_util routines + */ + +#define STOREVAL(list,item) \ + storeval(list,item) + +#define FINDVAL(list,item,finder) \ + findval(list, item, finder) + +void reinitialize(void); +int streq(const char *, const char *); +definition *findval(list *, const char *, + int (*)(definition *, const char *)); +void storeval(list **, definition *); +const char *fixtype(const char *); +void ptype(const char *, const char *, int); +int isvectordef(const char *, relation); +char *locase(const char *); +void pvname_svc(const char *, const char *); +void pvname(const char *, const char *); +xnoreturn() xprintfattr(1, 2) void error(const char *, ...); +void crash(void); +void record_open(const char *); +void expected1(tok_kind) xnoreturn(); +void expected2(tok_kind, tok_kind) xnoreturn(); +void expected3(tok_kind, tok_kind, tok_kind) xnoreturn(); +void tabify(FILE *, int); +char *make_argname(const char *, const char *); +void add_type(int, const char *); +bas_type *find_type(const char *); + +/* + * rpc_cout routines + */ +void emit(definition *); + +/* + * rpc_hout routines + */ + +void print_datadef(definition *); +void print_funcdef(definition *, int *); +void print_funcend(int);