diff --git a/.travis.yml b/.travis.yml index 8143be4..1abb951 100644 --- a/.travis.yml +++ b/.travis.yml @@ -127,7 +127,7 @@ script: -DBUILD_TESTING=on -G "${GENERATOR}" ../src - cmake --build . --config ${BUILD_TYPE} --target install - - ctest -T test -C ${BUILD_TYPE} + - CYCLONEDDS_URI='all' ctest -T test -C ${BUILD_TYPE} - if [ "${USE_SANITIZER}" != "none" ]; then CMAKE_LINKER_FLAGS="-DCMAKE_LINKER_FLAGS=-fsanitize=${USE_SANITIZER}"; CMAKE_C_FLAGS="-DCMAKE_C_FLAGS=-fsanitize=${USE_SANITIZER}"; diff --git a/appveyor.yml b/appveyor.yml index 1d1f034..0c96ec1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,13 +37,14 @@ build_script: - cd build - conan install -s arch=%ARCH% -s build_type=%CONFIGURATION% .. - cmake -DBUILD_TESTING=on -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=%CD%/install -G "%GENERATOR%" ../src - - cmake --build . --config %CONFIGURATION% --target install + - cmake --build . --config %CONFIGURATION% --target install -- /maxcpucount - cd install/share/CycloneDDS/examples/helloworld - mkdir build - cd build - cmake -DCMAKE_BUILD_TYPE=%CONFIGURATION% -G "%GENERATOR%" .. - - cmake --build . --config %CONFIGURATION% + - cmake --build . --config %CONFIGURATION% -- /maxcpucount - cd ../../../../../.. test_script: + - set "CYCLONEDDS_URI=all" - ctest --test-action test --build-config %CONFIGURATION% diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a71eb86..19b0515 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,7 +53,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "VxWorks") endif() if(${CMAKE_C_COMPILER_ID} STREQUAL "SunPro") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64 -xc99 -D__restrict=restrict") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64 -xc99 -D__restrict=restrict -D__deprecated__=") + set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -m64") endif() # Conan diff --git a/src/core/ddsc/src/dds_publisher.c b/src/core/ddsc/src/dds_publisher.c index ff920e1..689ba11 100644 --- a/src/core/ddsc/src/dds_publisher.c +++ b/src/core/ddsc/src/dds_publisher.c @@ -11,6 +11,7 @@ */ #include #include +#include "dds/ddsrt/misc.h" #include "dds__listener.h" #include "dds__qos.h" #include "dds__err.h" diff --git a/src/core/ddsc/src/dds_rhc.c b/src/core/ddsc/src/dds_rhc.c index 81b3f0c..b427df3 100644 --- a/src/core/ddsc/src/dds_rhc.c +++ b/src/core/ddsc/src/dds_rhc.c @@ -11,6 +11,7 @@ */ #include #include +#include #if HAVE_VALGRIND && ! defined (NDEBUG) #include @@ -2625,6 +2626,9 @@ int dds_rhc_takecdr #define CHECK_MAX_CONDS 64 static int rhc_check_counts_locked (struct rhc *rhc, bool check_conds, bool check_qcmask) { + if (!(config.enabled_xchecks & DDS_XCHECK_RHC)) + return 1; + const uint32_t ncheck = rhc->nconds < CHECK_MAX_CONDS ? rhc->nconds : CHECK_MAX_CONDS; unsigned n_instances = 0, n_nonempty_instances = 0; unsigned n_not_alive_disposed = 0, n_not_alive_no_writers = 0, n_new = 0; diff --git a/src/core/ddsc/src/dds_whc.c b/src/core/ddsc/src/dds_whc.c index 4e1333b..1301ef9 100644 --- a/src/core/ddsc/src/dds_whc.c +++ b/src/core/ddsc/src/dds_whc.c @@ -15,6 +15,7 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/sync.h" +#include "dds/ddsrt/misc.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_config.h" @@ -258,6 +259,7 @@ static void check_whc (const struct whc_impl *whc) assert (whc->maxseq_node == whc_findmax_procedurally (whc)); #if !defined(NDEBUG) + if (config.enabled_xchecks & DDS_XCHECK_WHC) { struct whc_intvnode *firstintv; struct whc_node *cur; diff --git a/src/core/ddsi/include/dds/ddsi/q_config.h b/src/core/ddsi/include/dds/ddsi/q_config.h index c771810..c37a40e 100644 --- a/src/core/ddsi/include/dds/ddsi/q_config.h +++ b/src/core/ddsi/include/dds/ddsi/q_config.h @@ -218,10 +218,15 @@ struct ssl_min_version { }; #endif +/* Expensive checks (compiled in when NDEBUG not defined, enabled only if flag set in xchecks) */ +#define DDS_XCHECK_WHC 1u +#define DDS_XCHECK_RHC 2u + struct config { int valid; uint32_t enabled_logcats; + uint32_t enabled_xchecks; char *servicename; char *pcap_file; diff --git a/src/core/ddsi/include/dds/ddsi/q_protocol.h b/src/core/ddsi/include/dds/ddsi/q_protocol.h index b86dc05..d0a3de2 100644 --- a/src/core/ddsi/include/dds/ddsi/q_protocol.h +++ b/src/core/ddsi/include/dds/ddsi/q_protocol.h @@ -130,8 +130,10 @@ typedef struct Header { } Header_t; #if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN #define NN_PROTOCOLID_AS_UINT32 (((uint32_t)'R' << 0) | ((uint32_t)'T' << 8) | ((uint32_t)'P' << 16) | ((uint32_t)'S' << 24)) -#else +#elif DDSRT_ENDIAN == DDSRT_BIG_ENDIAN #define NN_PROTOCOLID_AS_UINT32 (((uint32_t)'R' << 24) | ((uint32_t)'T' << 16) | ((uint32_t)'P' << 8) | ((uint32_t)'S' << 0)) +#else +#error "DDSRT_ENDIAN neither LITTLE nor BIG" #endif #define RTPS_MESSAGE_HEADER_SIZE (sizeof (Header_t)) diff --git a/src/core/ddsi/src/ddsi_ssl.c b/src/core/ddsi/src/ddsi_ssl.c index 8ebb2f0..2d85f0e 100644 --- a/src/core/ddsi/src/ddsi_ssl.c +++ b/src/core/ddsi/src/ddsi_ssl.c @@ -13,6 +13,7 @@ #include "dds/ddsi/ddsi_ssl.h" #include "dds/ddsi/q_config.h" #include "dds/ddsrt/log.h" +#include "dds/ddsrt/misc.h" #ifdef DDSI_INCLUDE_SSL diff --git a/src/core/ddsi/src/ddsi_udp.c b/src/core/ddsi/src/ddsi_udp.c index 8c2f925..2623515 100644 --- a/src/core/ddsi/src/ddsi_udp.c +++ b/src/core/ddsi/src/ddsi_udp.c @@ -14,6 +14,7 @@ #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/log.h" +#include "dds/ddsrt/misc.h" #include "dds/ddsrt/sockets.h" #include "ddsi_eth.h" #include "dds/ddsi/ddsi_tran.h" diff --git a/src/core/ddsi/src/q_addrset.c b/src/core/ddsi/src/q_addrset.c index 92ccbfa..48d9a4a 100644 --- a/src/core/ddsi/src/q_addrset.c +++ b/src/core/ddsi/src/q_addrset.c @@ -16,6 +16,7 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/log.h" #include "dds/ddsrt/string.h" +#include "dds/ddsrt/misc.h" #include "dds/util/ut_avl.h" #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_misc.h" diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c index 333d9c8..e318181 100644 --- a/src/core/ddsi/src/q_config.c +++ b/src/core/ddsi/src/q_config.c @@ -21,6 +21,7 @@ #include "dds/ddsrt/log.h" #include "dds/ddsrt/string.h" #include "dds/ddsrt/strtod.h" +#include "dds/ddsrt/misc.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" #include "dds/util/ut_avl.h" @@ -105,6 +106,14 @@ static const uint32_t logcat_codes[] = { DDS_LC_FATAL, DDS_LC_ERROR, DDS_LC_WARNING, DDS_LC_INFO, DDS_LC_CONFIG, DDS_LC_DISCOVERY, DDS_LC_DATA, DDS_LC_RADMIN, DDS_LC_TIMING, DDS_LC_TRAFFIC, DDS_LC_TOPIC, DDS_LC_TCP, DDS_LC_PLIST, DDS_LC_WHC, DDS_LC_THROTTLE, DDS_LC_RHC, DDS_LC_ALL }; +/* "trace" is special: it enables (nearly) everything */ +static const char *xcheck_names[] = { + "whc", "rhc", "all", NULL +}; +static const uint32_t xcheck_codes[] = { + DDS_XCHECK_WHC, DDS_XCHECK_RHC, ~(uint32_t)0 +}; + /* We want the tracing/verbosity settings to be fixed while parsing the configuration, so we update this variable instead. */ static unsigned enabled_logcats; @@ -131,6 +140,7 @@ DUPF(string); DU(tracingOutputFileName); DU(verbosity); DUPF(logcat); +DUPF(xcheck); DUPF(float); DUPF(int); DUPF(uint); @@ -632,6 +642,12 @@ static const struct cfgelem unsupp_cfgelems[] = { "

Testing options.

" }, { GROUP("Watermarks", unsupp_watermarks_cfgelems), "

Watermarks for flow-control.

" }, +{ LEAF("EnableExpensiveChecks"), 1, "", ABSOFF(enabled_xchecks), 0, uf_xcheck, 0, pf_xcheck, + "

This element enables expensive checks in builds with assertions enabled and is ignored otherwise. Recognised categories are:

\n\ +
  • whc: writer history cache checking
  • \n\ +
  • rhc: reader history cache checking
  • \n\ +

    In addition, there is the keyword all that enables all checks.

    " }, + END_MARKER }; @@ -1348,24 +1364,33 @@ static void pf_boolean_default (struct cfgst *cfgst, void *parent, struct cfgele } #endif -static int uf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value) +static int do_uint32_bitset(struct cfgst *cfgst, uint32_t *cats, const char **names, const uint32_t *codes, const char *value) { - static const char **vs = logcat_names; - static const uint32_t *lc = logcat_codes; char *copy = ddsrt_strdup(value), *cursor = copy, *tok; while ( (tok = ddsrt_strsep(&cursor, ",")) != NULL ) { - int idx = list_index(vs, tok); + int idx = list_index(names, tok); if ( idx < 0 ) { int ret = cfg_error(cfgst, "'%s' in '%s' undefined", tok, value); ddsrt_free(copy); return ret; } - enabled_logcats |= lc[idx]; + *cats |= codes[idx]; } ddsrt_free(copy); return 1; } +static int uf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value) +{ + return do_uint32_bitset (cfgst, &enabled_logcats, logcat_names, logcat_codes, value); +} + +static int uf_xcheck(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) +{ + uint32_t *elem = cfg_address(cfgst, parent, cfgelem); + return do_uint32_bitset (cfgst, elem, xcheck_names, xcheck_codes, value); +} + static int uf_verbosity(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int first), const char *value) { static const char *vs[] = { @@ -2333,45 +2358,76 @@ static void pf_standards_conformance(struct cfgst *cfgst, void *parent, struct c cfg_log(cfgst, "%s%s", str, is_default ? " [def]" : ""); } -static void pf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int is_default)) +static unsigned uint32_popcnt (uint32_t x) +{ + unsigned n = 0; + while (x != 0) + { + n += ((x & 1u) != 0); + x >>= 1; + } + return n; +} + +static void do_print_uint32_bitset (struct cfgst *cfgst, uint32_t mask, size_t ncodes, const char **names, const uint32_t *codes, const char *suffix) { - uint32_t remaining = config.enabled_logcats; char res[256] = "", *resp = res; const char *prefix = ""; - size_t i; #ifndef NDEBUG { - size_t max; - for ( i = 0, max = 0; i < sizeof(logcat_codes) / sizeof(*logcat_codes); i++ ) - max += 1 + strlen(logcat_names[i]); + size_t max = 0; + for (size_t i = 0; i < ncodes; i++ ) + max += 1 + strlen(names[i]); max += 11; /* ,0x%x */ max += 1; /* \0 */ assert(max <= sizeof(res)); } #endif - /* TRACE enables ALLCATS, all the others just one */ - if ( (remaining & DDS_LC_ALL) == DDS_LC_ALL ) { - resp += snprintf(resp, 256, "%strace", prefix); - remaining &= ~DDS_LC_ALL; - prefix = ","; - } - for ( i = 0; i < sizeof(logcat_codes) / sizeof(*logcat_codes); i++ ) { - if ( remaining & logcat_codes[i] ) { - resp += snprintf(resp, 256, "%s%s", prefix, logcat_names[i]); - remaining &= ~logcat_codes[i]; + while (mask) { + size_t i_best = 0; + unsigned pc_best = 0; + for (size_t i = 0; i < ncodes; i++) { + uint32_t m = mask & codes[i]; + if (m == codes[i]) { + unsigned pc = uint32_popcnt (m); + if (pc > pc_best) { + i_best = i; + pc_best = pc; + } + } + } + if (pc_best != 0) { + resp += snprintf(resp, 256, "%s%s", prefix, names[i_best]); + mask &= ~codes[i_best]; prefix = ","; + } else { + resp += snprintf (resp, 256, "%s0x%x", prefix, (unsigned) mask); + mask = 0; } } - if ( remaining ) { - resp += snprintf(resp, 256, "%s0x%x", prefix, (unsigned) remaining); - } - assert(resp <= res + sizeof(res)); - /* can't do default indicator: user may have specified Verbosity, in - which case EnableCategory is at default, but for these two - settings, I don't mind. */ - cfg_log(cfgst, "%s", res); + assert (resp <= res + sizeof(res)); + cfg_log (cfgst, "%s%s", res, suffix); } +static void pf_logcat(struct cfgst *cfgst, UNUSED_ARG(void *parent), UNUSED_ARG(struct cfgelem const * const cfgelem), UNUSED_ARG(int is_default)) +{ + /* can't do default indicator: user may have specified Verbosity, in + which case EnableCategory is at default, but for these two + settings, I don't mind. */ + do_print_uint32_bitset (cfgst, config.enabled_logcats, sizeof(logcat_codes) / sizeof(*logcat_codes), logcat_names, logcat_codes, ""); +} + +static void pf_xcheck(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, int is_default) +{ + const uint32_t *p = cfg_address(cfgst, parent, cfgelem); +#ifndef NDEBUG + const char *suffix = is_default ? " [def]" : ""; +#else + const char *suffix = " [ignored]"; + (void)is_default; +#endif + do_print_uint32_bitset (cfgst, *p, sizeof(xcheck_codes) / sizeof(*xcheck_codes), xcheck_names, xcheck_codes, suffix); +} static void print_configitems(struct cfgst *cfgst, void *parent, int isattr, struct cfgelem const * const cfgelem, int unchecked) { @@ -2772,51 +2828,69 @@ struct cfgst * config_init (const char *configfile) cfgst->error = 0; /* configfile == NULL will get you the default configuration */ - if ( configfile ) { - char *copy = ddsrt_strdup(configfile), *cursor = copy, *tok; - while ( (tok = ddsrt_strsep(&cursor, ",")) != NULL ) { - struct ut_xmlpCallbacks cb; + if (configfile) { + char *copy = ddsrt_strdup(configfile), *cursor = copy; + struct ut_xmlpCallbacks cb; + + cb.attr = proc_attr; + cb.elem_close = proc_elem_close; + cb.elem_data = proc_elem_data; + cb.elem_open = proc_elem_open; + cb.error = proc_error; + + while (ok && cursor && cursor[0]) { struct ut_xmlpState *qx; FILE *fp; - - DDSRT_WARNING_MSVC_OFF(4996); - if ( (fp = fopen(tok, "r")) == NULL ) { - if ( strncmp(tok, "file://", 7) != 0 || (fp = fopen(tok + 7, "r")) == NULL ) { - DDS_ERROR("can't open configuration file %s\n", tok); - ddsrt_free(copy); - ddsrt_free(cfgst); - return NULL; + char *tok; + tok = cursor; + if (tok[0] == '<') { + /* Read XML directly from input string */ + qx = ut_xmlpNewString (tok, cfgst, &cb); + ut_xmlpSetRequireEOF (qx, 0); + fp = NULL; + } else { + char *comma; + if ((comma = strchr (cursor, ',')) == NULL) { + cursor = NULL; + } else { + *comma = 0; + cursor = comma + 1; } - } - DDSRT_WARNING_MSVC_ON(4996); - - cb.attr = proc_attr; - cb.elem_close = proc_elem_close; - cb.elem_data = proc_elem_data; - cb.elem_open = proc_elem_open; - cb.error = proc_error; - - if ( (qx = ut_xmlpNewFile(fp, cfgst, &cb)) == NULL ) { - fclose(fp); - ddsrt_free(copy); - ddsrt_free(cfgst); - return NULL; + DDSRT_WARNING_MSVC_OFF(4996); + if ((fp = fopen(tok, "r")) == NULL) { + if (strncmp(tok, "file://", 7) != 0 || (fp = fopen(tok + 7, "r")) == NULL) { + DDS_ERROR("can't open configuration file %s\n", tok); + ddsrt_free(copy); + ddsrt_free(cfgst); + return NULL; + } + } + DDSRT_WARNING_MSVC_ON(4996); + qx = ut_xmlpNewFile(fp, cfgst, &cb); } cfgst_push(cfgst, 0, &root_cfgelem, &config); ok = (ut_xmlpParse(qx) >= 0) && !cfgst->error; /* Pop until stack empty: error handling is rather brutal */ assert(!ok || cfgst->path_depth == 1); - while ( cfgst->path_depth > 0 ) + while (cfgst->path_depth > 0) { cfgst_pop(cfgst); + } + if (fp) { + fclose(fp); + } else if (ok) { + cursor = tok + ut_xmlpGetBufpos (qx); + } ut_xmlpFree(qx); - fclose(fp); + while (cursor && cursor[0] == ',') { + cursor++; + } } ddsrt_free(copy); } /* Set defaults for everything not set that we have a default value - for, signal errors for things unset but without a default. */ + for, signal errors for things unset but without a default. */ { int ok1 = set_defaults(cfgst, cfgst->cfg, 0, root_cfgelems, 0); ok = ok && ok1; diff --git a/src/core/ddsi/src/q_debmon.c b/src/core/ddsi/src/q_debmon.c index 15a2fc9..eb83d81 100644 --- a/src/core/ddsi/src/q_debmon.c +++ b/src/core/ddsi/src/q_debmon.c @@ -16,6 +16,7 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsrt/log.h" #include "dds/ddsrt/sync.h" +#include "dds/ddsrt/misc.h" #include "dds/util/ut_avl.h" diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c index 9e20649..39e15c2 100644 --- a/src/core/ddsi/src/q_entity.c +++ b/src/core/ddsi/src/q_entity.c @@ -18,6 +18,7 @@ #include "dds/ddsrt/sockets.h" #include "dds/ddsrt/string.h" #include "dds/ddsrt/sync.h" +#include "dds/ddsrt/misc.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_config.h" diff --git a/src/core/ddsi/src/q_ephash.c b/src/core/ddsi/src/q_ephash.c index 9413be2..f287aae 100644 --- a/src/core/ddsi/src/q_ephash.c +++ b/src/core/ddsi/src/q_ephash.c @@ -13,6 +13,8 @@ #include #include "dds/ddsrt/heap.h" +#include "dds/ddsrt/misc.h" + #include "dds/util/ut_hopscotch.h" #include "dds/ddsi/q_ephash.h" #include "dds/ddsi/q_config.h" diff --git a/src/core/ddsi/src/q_freelist.c b/src/core/ddsi/src/q_freelist.c index c5259a4..78e2a77 100644 --- a/src/core/ddsi/src/q_freelist.c +++ b/src/core/ddsi/src/q_freelist.c @@ -12,6 +12,7 @@ #include #include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/misc.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/sync.h" #include "dds/ddsrt/threads.h" diff --git a/src/core/ddsi/src/q_nwif.c b/src/core/ddsi/src/q_nwif.c index d72cb32..d6a7109 100644 --- a/src/core/ddsi/src/q_nwif.c +++ b/src/core/ddsi/src/q_nwif.c @@ -544,9 +544,7 @@ int find_own_ip (const char *requested_address) quality = q; } - /* FIXME: HACK HACK */ - //ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].loc, &tmpip, gv.m_factory->m_kind); - if (ifa->addr->sa_family == AF_INET || ifa->addr->sa_family == AF_INET6) + if (ifa->addr->sa_family == AF_INET && ifa->netmask) { ddsi_ipaddr_to_loc(&gv.interfaces[gv.n_interfaces].netmask, ifa->netmask, gv.m_factory->m_kind); } diff --git a/src/core/ddsi/src/q_thread.c b/src/core/ddsi/src/q_thread.c index 0254062..cadbb6e 100644 --- a/src/core/ddsi/src/q_thread.c +++ b/src/core/ddsi/src/q_thread.c @@ -19,6 +19,7 @@ #include "dds/ddsrt/string.h" #include "dds/ddsrt/sync.h" #include "dds/ddsrt/threads.h" +#include "dds/ddsrt/misc.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_servicelease.h" diff --git a/src/core/ddsi/src/sysdeps.c b/src/core/ddsi/src/sysdeps.c index 251b781..e362823 100644 --- a/src/core/ddsi/src/sysdeps.c +++ b/src/core/ddsi/src/sysdeps.c @@ -13,6 +13,7 @@ #include #include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/misc.h" #include "dds/ddsi/q_error.h" #include "dds/ddsi/q_log.h" diff --git a/src/ddsrt/include/dds/ddsrt/attributes.h b/src/ddsrt/include/dds/ddsrt/attributes.h index 4850777..c91584d 100644 --- a/src/ddsrt/include/dds/ddsrt/attributes.h +++ b/src/ddsrt/include/dds/ddsrt/attributes.h @@ -24,6 +24,10 @@ # define ddsrt_clang (0) #endif +#ifdef __SUNPRO_C +# define __attribute__(x) +#endif + #if defined(__has_attribute) # define ddsrt_has_attribute(params) __has_attribute(params) #elif ddsrt_gnuc diff --git a/src/ddsrt/include/dds/ddsrt/endian.h b/src/ddsrt/include/dds/ddsrt/endian.h index a6a2358..a046b09 100644 --- a/src/ddsrt/include/dds/ddsrt/endian.h +++ b/src/ddsrt/include/dds/ddsrt/endian.h @@ -32,6 +32,13 @@ extern "C" { # elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define DDSRT_ENDIAN DDSRT_LITTLE_ENDIAN # endif +# elif defined(__sun) +# include +# if defined(_BIG_ENDIAN) +# define DDSRT_ENDIAN DDSRT_BIG_ENDIAN +# elif defined(_LITTLE_ENDIAN) +# define DDSRT_ENDIAN DDSRT_LITTLE_ENDIAN +# endif # endif #endif /* _WIN32 */ diff --git a/src/ddsrt/src/sockets/posix/socket.c b/src/ddsrt/src/sockets/posix/socket.c index 67d805e..35b80d8 100644 --- a/src/ddsrt/src/sockets/posix/socket.c +++ b/src/ddsrt/src/sockets/posix/socket.c @@ -23,6 +23,9 @@ #endif /* __VXWORKS__ */ #include #include +#ifdef __sun +#include +#endif #ifdef __APPLE__ #include diff --git a/src/examples/helloworld/publisher.c b/src/examples/helloworld/publisher.c index 9b7527b..eeb2d54 100644 --- a/src/examples/helloworld/publisher.c +++ b/src/examples/helloworld/publisher.c @@ -31,6 +31,7 @@ int main (int argc, char ** argv) DDS_FATAL("dds_create_write: %s\n", dds_strretcode(-writer)); printf("=== [Publisher] Waiting for a reader to be discovered ...\n"); + fflush (stdout); rc = dds_set_status_mask(writer, DDS_PUBLICATION_MATCHED_STATUS); if (rc != DDS_RETCODE_OK) @@ -52,6 +53,7 @@ int main (int argc, char ** argv) printf ("=== [Publisher] Writing : "); printf ("Message (%d, %s)\n", msg.userID, msg.message); + fflush (stdout); rc = dds_write (writer, &msg); if (rc != DDS_RETCODE_OK) diff --git a/src/examples/helloworld/subscriber.c b/src/examples/helloworld/subscriber.c index bf4c0f4..f35f80a 100644 --- a/src/examples/helloworld/subscriber.c +++ b/src/examples/helloworld/subscriber.c @@ -40,6 +40,7 @@ int main (int argc, char ** argv) dds_delete_qos(qos); printf ("\n=== [Subscriber] Waiting for a sample ...\n"); + fflush (stdout); /* Initialize sample buffer, by pointing the void pointer within * the buffer array to a valid sample memory location. */ @@ -61,6 +62,7 @@ int main (int argc, char ** argv) msg = (HelloWorldData_Msg*) samples[0]; printf ("=== [Subscriber] Received : "); printf ("Message (%d, %s)\n", msg->userID, msg->message); + fflush (stdout); break; } else diff --git a/src/examples/roundtrip/ping.c b/src/examples/roundtrip/ping.c index 32ca63c..9b09c3a 100644 --- a/src/examples/roundtrip/ping.c +++ b/src/examples/roundtrip/ping.c @@ -193,6 +193,7 @@ static void data_available(dds_entity_t rd, void *arg) readAccess.count, exampleGetMedianFromTimeStats (&readAccess), readAccess.min); + fflush (stdout); exampleResetTimeStats (&roundTrip); exampleResetTimeStats (&writeAccess); @@ -282,11 +283,10 @@ int main (int argc, char *argv[]) } prepare_dds(&writer, &reader, &readCond, listener); - setvbuf(stdout, NULL, _IONBF, 0); - if (argc - argidx == 1 && strcmp (argv[argidx], "quit") == 0) { printf ("Sending termination request.\n"); + fflush (stdout); /* pong uses a waitset which is triggered by instance disposal, and quits when it fires. */ dds_sleepfor (DDS_SECS (1)); @@ -325,6 +325,7 @@ int main (int argc, char *argv[]) if (invalidargs || (argc - argidx == 1 && (strcmp (argv[argidx], "-h") == 0 || strcmp (argv[argidx], "--help") == 0))) usage(); printf ("# payloadSize: %" PRIu32 " | numSamples: %" PRIu64 " | timeOut: %" PRIi64 "\n\n", payloadSize, numSamples, timeOut); + fflush (stdout); pub_data.payload._length = payloadSize; pub_data.payload._buffer = payloadSize ? dds_alloc (payloadSize) : NULL; @@ -337,6 +338,7 @@ int main (int argc, char *argv[]) startTime = dds_time (); printf ("# Waiting for startup jitter to stabilise\n"); + fflush (stdout); /* Write a sample that pong can send back */ while (!dds_triggered (waitSet) && difference < DDS_SECS(5)) { @@ -358,11 +360,10 @@ int main (int argc, char *argv[]) { warmUp = false; printf("# Warm up complete.\n\n"); - printf("# Latency measurements (in us)\n"); printf("# Latency [us] Write-access time [us] Read-access time [us]\n"); printf("# Seconds Count median min 99%% max Count median min Count median min\n"); - + fflush (stdout); } exampleResetTimeStats (&roundTrip); @@ -375,7 +376,7 @@ int main (int argc, char *argv[]) if (status < 0) DDS_FATAL("dds_write_ts: %s\n", dds_strretcode(-status)); postWriteTime = dds_time (); - for (i = 0; !dds_triggered (waitSet) && (!numSamples || i < numSamples); i++) + for (i = 0; !dds_triggered (waitSet) && (!numSamples || i < numSamples) && !(timeOut && elapsed >= timeOut); i++) { status = dds_waitset_wait (waitSet, wsresults, wsresultsize, waitTimeout); if (status < 0) @@ -403,6 +404,7 @@ int main (int argc, char *argv[]) exampleGetMedianFromTimeStats (&readAccessOverall), readAccessOverall.min ); + fflush (stdout); } done: diff --git a/src/examples/throughput/publisher.c b/src/examples/throughput/publisher.c index 69cbc09..8fd49d7 100644 --- a/src/examples/throughput/publisher.c +++ b/src/examples/throughput/publisher.c @@ -47,10 +47,6 @@ int main (int argc, char **argv) dds_return_t rc; ThroughputModule_DataType sample; -#if !defined(_WIN32) - setvbuf (stdout, NULL, _IOLBF, 0); -#endif - if (parse_args(argc, argv, &payloadSize, &burstInterval, &burstSize, &timeOut, &partitionName) == EXIT_FAILURE) { return EXIT_FAILURE; } @@ -60,6 +56,7 @@ int main (int argc, char **argv) /* Wait until have a reader */ if (wait_for_reader(writer, participant) == 0) { printf ("=== [Publisher] Did not discover a reader.\n"); + fflush (stdout); rc = dds_delete (participant); if (rc < 0) DDS_FATAL("dds_delete: %s\n", dds_strretcode(-rc)); @@ -131,6 +128,7 @@ static int parse_args( printf ("payloadSize: %u bytes burstInterval: %u ms burstSize: %u timeOut: %u seconds partitionName: %s\n", *payloadSize, *burstInterval, *burstSize, *timeOut, *partitionName); + fflush (stdout); return result; } @@ -182,6 +180,7 @@ static dds_entity_t prepare_dds(dds_entity_t *writer, const char *partitionName) static dds_return_t wait_for_reader(dds_entity_t writer, dds_entity_t participant) { printf ("\n=== [Publisher] Waiting for a reader ...\n"); + fflush (stdout); dds_return_t rc; dds_entity_t waitset; @@ -224,6 +223,7 @@ static void start_writing( unsigned int burstCount = 0; printf ("=== [Publisher] Writing samples...\n"); + fflush (stdout); while (!done && !timedOut) { @@ -277,14 +277,8 @@ static void start_writing( } dds_write_flush (writer); - if (done) - { - printf ("=== [Publisher] Terminated, %llu samples written.\n", (unsigned long long) sample->count); - } - else - { - printf ("=== [Publisher] Timed out, %llu samples written.\n", (unsigned long long) sample->count); - } + printf ("=== [Publisher] %s, %llu samples written.\n", done ? "Terminated" : "Timed out", (unsigned long long) sample->count); + fflush (stdout); } } diff --git a/src/examples/throughput/subscriber.c b/src/examples/throughput/subscriber.c index f57fed7..92560b6 100644 --- a/src/examples/throughput/subscriber.c +++ b/src/examples/throughput/subscriber.c @@ -75,20 +75,18 @@ int main (int argc, char **argv) dds_entity_t participant; dds_entity_t reader; -#if !defined(_WIN32) - setvbuf (stdout, NULL, _IOLBF, 0); -#endif - if (parse_args(argc, argv, &maxCycles, &partitionName) == EXIT_FAILURE) { return EXIT_FAILURE; } printf ("Cycles: %llu | PollingDelay: %ld | Partition: %s\n", maxCycles, pollingDelay, partitionName); + fflush (stdout); participant = prepare_dds(&reader, partitionName); printf ("=== [Subscriber] Waiting for samples...\n"); + fflush (stdout); /* Process samples until Ctrl-C is pressed or until maxCycles */ /* has been reached (0 = infinite) */ @@ -280,6 +278,7 @@ static void process_samples(dds_entity_t reader, unsigned long long maxCycles) deltaTime, payloadSize, total_samples, total_bytes, outOfOrder, (deltaTime != 0.0) ? ((double)(total_samples - prev_samples) / deltaTime) : 0, (deltaTime != 0.0) ? ((double)((total_bytes - prev_bytes) / BYTES_PER_SEC_TO_MEGABITS_PER_SEC) / deltaTime) : 0); + fflush (stdout); cycles++; prev_time = time_now; prev_bytes = total_bytes; @@ -300,6 +299,7 @@ static void process_samples(dds_entity_t reader, unsigned long long maxCycles) printf ("Out of order: %llu samples\n", outOfOrder); printf ("Average transfer rate: %.2lf samples/s, ", (double)total_samples / deltaTime); printf ("%.2lf Mbit/s\n", (double)(total_bytes / BYTES_PER_SEC_TO_MEGABITS_PER_SEC) / deltaTime); + fflush (stdout); } static dds_entity_t prepare_dds(dds_entity_t *reader, const char *partitionName) diff --git a/src/tools/pubsub/pubsub.c b/src/tools/pubsub/pubsub.c index 187a2de..cf7cde2 100644 --- a/src/tools/pubsub/pubsub.c +++ b/src/tools/pubsub/pubsub.c @@ -62,6 +62,7 @@ enum readermode { MODE_PRINT, MODE_CHECK, MODE_ZEROLOAD, MODE_DUMP, MODE_NONE }; #define PM_STATE 512u static volatile sig_atomic_t termflag = 0; +static int flushflag = 0; static int pid; static dds_entity_t termcond; static unsigned nkeyvals = 1; @@ -885,6 +886,9 @@ static void print_K(dds_time_t *tstart, dds_time_t tnow, dds_entity_t rd, const } else printf ("get_key_value: error (%s)\n", dds_err_str(result)); } + if (flushflag) { + fflush (stdout); + } ddsrt_mutex_unlock(&output_mutex); } @@ -935,6 +939,9 @@ static void print_seq_OU(dds_time_t *tstart, dds_time_t tnow, dds_entity_t rd __ } else { printf ("NA\n"); } + if (flushflag) { + fflush (stdout); + } ddsrt_mutex_unlock(&output_mutex); } } @@ -967,10 +974,16 @@ static void rd_on_liveliness_changed(dds_entity_t rd __attribute__ ((unused)), c status.alive_count, status.alive_count_change, status.not_alive_count, status.not_alive_count_change, status.last_publication_handle); + if (flushflag) { + fflush (stdout); + } } static void rd_on_sample_lost(dds_entity_t rd __attribute__ ((unused)), const dds_sample_lost_status_t status, void* arg __attribute__ ((unused))) { printf ("[sample-lost: total=(%"PRIu32" change %"PRId32")]\n", status.total_count, status.total_count_change); + if (flushflag) { + fflush (stdout); + } } static void rd_on_sample_rejected(dds_entity_t rd __attribute__ ((unused)), const dds_sample_rejected_status_t status, void* arg __attribute__ ((unused))) { @@ -985,6 +998,9 @@ static void rd_on_sample_rejected(dds_entity_t rd __attribute__ ((unused)), cons status.total_count, status.total_count_change, reasonstr, status.last_instance_handle); + if (flushflag) { + fflush (stdout); + } } static void rd_on_subscription_matched(dds_entity_t rd __attribute__((unused)), const dds_subscription_matched_status_t status, void* arg __attribute__((unused))) { @@ -992,12 +1008,18 @@ static void rd_on_subscription_matched(dds_entity_t rd __attribute__((unused)), status.total_count, status.total_count_change, status.current_count, status.current_count_change, status.last_publication_handle); + if (flushflag) { + fflush (stdout); + } } static void rd_on_requested_deadline_missed(dds_entity_t rd __attribute__((unused)), const dds_requested_deadline_missed_status_t status, void* arg __attribute__ ((unused))) { printf ("[requested-deadline-missed: total=(%"PRIu32" change %"PRId32") handle=%"PRIu64"]\n", status.total_count, status.total_count_change, status.last_instance_handle); + if (flushflag) { + fflush (stdout); + } } static const char *policystr(uint32_t id) { @@ -1048,21 +1070,33 @@ static const char *policystr(uint32_t id) { static void rd_on_requested_incompatible_qos(dds_entity_t rd __attribute__((unused)), const dds_requested_incompatible_qos_status_t status, void* arg __attribute__((unused))) { printf ("[requested-incompatible-qos: total=(%"PRIu32" change %"PRId32") last_policy=%s]\n", status.total_count, status.total_count_change, policystr(status.last_policy_id)); + if (flushflag) { + fflush (stdout); + } } static void wr_on_offered_incompatible_qos(dds_entity_t wr __attribute__((unused)), const dds_offered_incompatible_qos_status_t status, void* arg __attribute__((unused))) { printf ("[offered-incompatible-qos: total=(%"PRIu32" change %"PRId32") last_policy=%s]\n", status.total_count, status.total_count_change, policystr(status.last_policy_id)); + if (flushflag) { + fflush (stdout); + } } static void wr_on_liveliness_lost(dds_entity_t wr __attribute__((unused)), const dds_liveliness_lost_status_t status, void* arg __attribute__ ((unused))) { printf ("[liveliness-lost: total=(%"PRIu32" change %"PRId32")]\n", status.total_count, status.total_count_change); + if (flushflag) { + fflush (stdout); + } } static void wr_on_offered_deadline_missed(dds_entity_t wr __attribute__((unused)), const dds_offered_deadline_missed_status_t status, void* arg __attribute__((unused))) { printf ("[offered-deadline-missed: total=(%"PRIu32" change %"PRId32") handle=%"PRIu64"]\n", status.total_count, status.total_count_change, status.last_instance_handle); + if (flushflag) { + fflush (stdout); + } } static void wr_on_publication_matched(dds_entity_t wr __attribute__((unused)), const dds_publication_matched_status_t status, void* arg __attribute__((unused))) { @@ -1070,6 +1104,9 @@ static void wr_on_publication_matched(dds_entity_t wr __attribute__((unused)), c status.total_count, status.total_count_change, status.current_count, status.current_count_change, status.last_subscription_handle); + if (flushflag) { + fflush (stdout); + } } static int register_instance_wrapper(dds_entity_t wr, const void *d, const dds_time_t tstamp) { @@ -1105,6 +1142,9 @@ static void non_data_operation(char command, dds_entity_t wr) { switch (command) { case 'Y': printf ("Dispose all: not supported\n"); + if (flushflag) { + fflush (stdout); + } // TODO Implement application side tracking of alive instances for use with a 'dispose all' function // if ((result = DDS_Topic_dispose_all_data(DDS_DataWriter_get_topic(wr))) != DDS_RETCODE_OK) // error ("DDS_Topic_dispose_all: error %d\n", (int) result); @@ -1207,6 +1247,9 @@ static void pub_do_auto(const struct writerspec *spec) { while (!termflag && tprev < tstop) { if ((result = dds_write(spec->wr, &d)) != DDS_RETCODE_OK) { printf ("write: error %d (%s)\n", (int) result, dds_err_str(result)); + if (flushflag) { + fflush (stdout); + } if (result != DDS_RETCODE_TIMEOUT) break; } else { @@ -1232,6 +1275,9 @@ static void pub_do_auto(const struct writerspec *spec) { while (!termflag && tprev < tstop) { if ((result = dds_write(spec->wr, &d)) != DDS_RETCODE_OK) { printf ("write: error %d (%s)\n", (int) result, dds_err_str(result)); + if (flushflag) { + fflush (stdout); + } if (result != DDS_RETCODE_TIMEOUT) break; } @@ -1265,6 +1311,9 @@ static void pub_do_auto(const struct writerspec *spec) { hist_print(hist, tlast - tfirst, 0); hist_free(hist); printf ("total writes: %" PRId64 " (%e/s)\n", ntot, (double)ntot * 1e9 / (double)(tlast - tfirst0)); + if (flushflag) { + fflush (stdout); + } if (spec->topicsel == KS) { dds_free(d.ks.baggage._buffer); } @@ -1319,6 +1368,9 @@ static char *pub_do_nonarb(const struct writerspec *spec, uint32_t *seq) { tstamp = (tstamp_spec.t % T_SECOND) + ((int) (tstamp_spec.t / T_SECOND) * DDS_NSECS_IN_SEC); if ((result = fn(spec->wr, &d, tstamp)) != DDS_RETCODE_OK) { printf ("%s %d: error %d (%s)\n", get_write_operstr(command), k, (int) result, dds_err_str(result)); + if (flushflag) { + fflush (stdout); + } if (!accept_error(command, result)) exit(1); } @@ -1326,6 +1378,9 @@ static char *pub_do_nonarb(const struct writerspec *spec, uint32_t *seq) { dds_write_flush(spec->wr); if (spec->dupwr && (result = fn(spec->dupwr, &d, tstamp)) != DDS_RETCODE_OK) { printf ("%s %d(dup): error %d (%s)\n", get_write_operstr(command), k, (int) result, dds_err_str(result)); + if (flushflag) { + fflush (stdout); + } if (!accept_error(command, result)) exit(1); } @@ -1337,11 +1392,17 @@ static char *pub_do_nonarb(const struct writerspec *spec, uint32_t *seq) { break; } case 'z': - if (spec->topicsel != KS) + if (spec->topicsel != KS) { printf ("payload size cannot be set for selected type\n"); - else if (k < 12 && k != 0) + if (flushflag) { + fflush (stdout); + } + } else if (k < 12 && k != 0) { printf ("invalid payload size: %d\n", k); - else { + if (flushflag) { + fflush (stdout); + } + } else { uint32_t baggagesize = (k != 0) ? (uint32_t) (k - 12) : 0; if (d.ks.baggage._buffer) dds_free (d.ks.baggage._buffer); @@ -1354,9 +1415,12 @@ static char *pub_do_nonarb(const struct writerspec *spec, uint32_t *seq) { set_pub_partition(spec->pub, arg); break; case 's': - if (k < 0) + if (k < 0) { printf ("invalid sleep duration: %ds\n", k); - else { + if (flushflag) { + fflush (stdout); + } + } else { dds_sleepfor(DDS_SECS(k)); } break; @@ -1524,6 +1588,9 @@ static uint32_t pubthread(void *vwrspecs) { cand = cursor; else { printf ("%s: ambiguous writer specification\n", nextspec); + if (flushflag) { + fflush (stdout); + } break; } } @@ -1531,6 +1598,9 @@ static uint32_t pubthread(void *vwrspecs) { } while (cursor != endm); if (cand == NULL) { printf ("%s: no matching writer specification\n", nextspec); + if (flushflag) { + fflush (stdout); + } } else if (cursor != endm) { /* ambiguous case */ cursor = endm; } else { @@ -1699,6 +1769,9 @@ static uint32_t subthread(void *vspec) { rc = dds_waitset_wait(ws, xs, nxs, DDS_INFINITY); if (rc < DDS_RETCODE_OK) { printf ("wait: error %d\n", (int) rc); + if (flushflag) { + fflush (stdout); + } break; } else if (rc == DDS_RETCODE_OK) { continue; @@ -1727,6 +1800,9 @@ static uint32_t subthread(void *vspec) { status.current_count, status.current_count_change, status.last_publication_handle); + if (flushflag) { + fflush (stdout); + } } } @@ -1767,8 +1843,14 @@ static uint32_t subthread(void *vspec) { ; /* expected */ } else if (spec->mode == MODE_CHECK || spec->mode == MODE_DUMP || spec->polling) { printf ("%s: %d (%s) on %s\n", (!spec->use_take && spec->mode == MODE_DUMP) ? "read" : "take", (int) nread, dds_err_str(nread), spec->polling ? "poll" : "stcond"); + if (flushflag) { + fflush (stdout); + } } else { printf ("%s: %d (%s) on rdcond%s\n", spec->use_take ? "take" : "read", (int) nread, dds_err_str(nread), (cond == rdcondA) ? "A" : (cond == rdcondD) ? "D" : "?"); + if (flushflag) { + fflush (stdout); + } } continue; } @@ -1825,6 +1907,9 @@ static uint32_t subthread(void *vspec) { const double rate_Mbps = (double)(nreceived_bytes - last_nreceived_bytes) * 8 / 1e6; printf ("%"PRId64".%03"PRId64" ntot %lld nseq %lld ndelta %lld rate %.2f Mb/s\n", tdelta_s, tdelta_ms, nreceived, out_of_seq, ndelta, rate_Mbps); + if (flushflag) { + fflush (stdout); + } last_nreceived = nreceived; last_nreceived_bytes = nreceived_bytes; tprint = tnow; @@ -1854,10 +1939,14 @@ static uint32_t subthread(void *vspec) { dds_return_t nread; nread = dds_take_mask(rd, mseq, iseq, spec->read_maxsamples, spec->read_maxsamples, DDS_ANY_STATE); if (nread == 0) { - if (!once_mode) + if (!once_mode) { printf ("-- final take: data reader empty --\n"); - else + if (flushflag) { + fflush (stdout); + } + } else { exitcode = 1; + } } else if (nread < DDS_RETCODE_OK) { if (!once_mode) { error_report(rc, "-- final take --\n"); @@ -1888,8 +1977,12 @@ static uint32_t subthread(void *vspec) { } dds_free(iseq); dds_free(mseq); - if (spec->mode == MODE_CHECK) + if (spec->mode == MODE_CHECK) { printf ("received: %lld, out of seq: %lld\n", nreceived, out_of_seq); + if (flushflag) { + fflush (stdout); + } + } fini_eseq_admin(&eseq_admin); } @@ -1950,6 +2043,9 @@ static uint32_t autotermthread(void *varg __attribute__((unused))) { if ((rc = dds_waitset_wait(ws, wsresults, wsresultsize, timeout)) < DDS_RETCODE_OK) { printf ("wait: error %s\n", dds_err_str(rc)); + if (flushflag) { + fflush (stdout); + } break; } tnow = dds_time(); @@ -2020,8 +2116,12 @@ static dds_entity_t find_topic(dds_entity_t dpFindTopic, const char *name, const // } // TODO Note: the implementation for dds_topic_find blocks infinitely if the topic does not exist in the domain - if (!(tp = dds_find_topic(dpFindTopic, name))) + if (!(tp = dds_find_topic(dpFindTopic, name))) { printf ("topic %s not found\n", name); + if (flushflag) { + fflush (stdout); + } + } // if (!isbuiltin) { // char *tn = DDS_Topic_get_type_name(tp); @@ -2240,7 +2340,7 @@ int main(int argc, char *argv[]) { wait_for_matching_reader_arg = optarg + pos; break; case 'F': - setvbuf(stdout, (char *) NULL, _IOLBF, 0); + flushflag = 1; break; case 'K': addspec(SPEC_TOPICSEL, &spec_sofar, &specidx, &spec, want_reader); @@ -2629,6 +2729,9 @@ int main(int argc, char *argv[]) { if (want_writer && wait_for_matching_reader_arg) { printf("Wait for matching reader: unsupported\n"); + if (flushflag) { + fflush (stdout); + } // TODO Reimplement wait_for_matching_reader functionality via wait on status subscription matched // struct qos *q = NULL; // uint64_t tnow = dds_time(); diff --git a/src/util/include/dds/util/ut_xmlparser.h b/src/util/include/dds/util/ut_xmlparser.h index 2b9c7be..b7d5076 100644 --- a/src/util/include/dds/util/ut_xmlparser.h +++ b/src/util/include/dds/util/ut_xmlparser.h @@ -38,6 +38,8 @@ extern "C" { DDS_EXPORT struct ut_xmlpState *ut_xmlpNewFile (FILE *fp, void *varg, const struct ut_xmlpCallbacks *cb); DDS_EXPORT struct ut_xmlpState *ut_xmlpNewString (const char *string, void *varg, const struct ut_xmlpCallbacks *cb); + DDS_EXPORT void ut_xmlpSetRequireEOF (struct ut_xmlpState *st, int require_eof); + DDS_EXPORT size_t ut_xmlpGetBufpos (const struct ut_xmlpState *st); DDS_EXPORT void ut_xmlpFree (struct ut_xmlpState *st); DDS_EXPORT int ut_xmlpParse (struct ut_xmlpState *st); diff --git a/src/util/src/ut_xmlparser.c b/src/util/src/ut_xmlparser.c index 92f8676..2d31a54 100644 --- a/src/util/src/ut_xmlparser.c +++ b/src/util/src/ut_xmlparser.c @@ -49,6 +49,7 @@ struct ut_xmlpState { size_t tpescp; /* still escape sequences in tpescp .. tpp */ int nest; /* current nesting level */ void *varg; /* user argument to callback functions */ + int require_eof; /* if false, junk may follow top-level closing tag */ struct ut_xmlpCallbacks cb; /* user-supplied callbacks (or stubs) */ }; @@ -107,6 +108,7 @@ static void ut_xmlpNewCommon (struct ut_xmlpState *st) st->peekpayload = NULL; st->nest = 0; st->error = 0; + st->require_eof = 1; } static void ut_xmlpNewSetCB (struct ut_xmlpState *st, void *varg, const struct ut_xmlpCallbacks *cb) @@ -146,6 +148,16 @@ struct ut_xmlpState *ut_xmlpNewString (const char *string, void *varg, const str return st; } +void ut_xmlpSetRequireEOF (struct ut_xmlpState *st, int require_eof) +{ + st->require_eof = require_eof; +} + +size_t ut_xmlpGetBufpos (const struct ut_xmlpState *st) +{ + return st->cbufp; +} + void ut_xmlpFree (struct ut_xmlpState *st) { if (st->fp != NULL) { @@ -697,7 +709,7 @@ int ut_xmlpParse (struct ut_xmlpState *st) return 0; } else { int ret = parse_element (st, 0); - if (ret < 0 || next_token (st, NULL) == TOK_EOF) { + if (ret < 0|| !st->require_eof || next_token (st, NULL) == TOK_EOF ) { return ret; } else { return -1;