From 095909158f23a1093ab452c453ebb2670b028c0d Mon Sep 17 00:00:00 2001 From: "Mark C. Miller" Date: Tue, 30 Jul 2024 09:30:19 -0700 Subject: [PATCH 1/3] add field width arg --- src/silo/silo.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/silo/silo.h.in b/src/silo/silo.h.in index 5d34ea37..91b662b9 100644 --- a/src/silo/silo.h.in +++ b/src/silo/silo.h.in @@ -2174,7 +2174,7 @@ SILO_API extern DBgroupelmap * DBGetGroupelmap(DBfile *dbfile, char cons SILO_API extern DBmrgvar * DBGetMrgvar(DBfile *dbfile, char const *name); SILO_API extern DBnamescheme * DBMakeNamescheme(char const *fmt, ...); SILO_API extern char const * DBGetName(DBnamescheme const *ns, long long natnum); -SILO_API long long DBGetIndex(char const *dbns_name_str, int field, int base); +SILO_API long long DBGetIndex(char const *dbns_name_str, int field, int width, int base); SILO_API extern char const * DBSPrintf(char const *fmt, ...); /* Multi-block objects and parallel I/O */ From f5f2d182c31dad091d88d04824292cf05eb010a0 Mon Sep 17 00:00:00 2001 From: "Mark C. Miller" Date: Tue, 30 Jul 2024 09:30:36 -0700 Subject: [PATCH 2/3] fix DBGetIndex --- src/silo/silo_ns.c | 67 +++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/src/silo/silo_ns.c b/src/silo/silo_ns.c index 56361503..f0e373a8 100644 --- a/src/silo/silo_ns.c +++ b/src/silo/silo_ns.c @@ -609,41 +609,60 @@ DBGetName(DBnamescheme const *ns, long long natnum) } PUBLIC long long -DBGetIndex(char const *dbns_name_str, int fieldSelector, int base) +DBGetIndex(char const *dbns_name_str, int fieldSelector, int minFieldWidth, int base) { int currentField = 0; char const *currentPosition = dbns_name_str; + char const *lastPosition = currentPosition + strlen(dbns_name_str); char *endPtr; - long long value = LLONG_MAX; - while (*currentPosition != '\0') + /* Note: leading zeros, which are probably quite common in fields in + nameschemes will get treated automatically as octal (base 8) if base + is not explicitly specified by caller. */ + + while (currentPosition < lastPosition) { - /* x and X and b and B allow use of hexidecimal and binary numbers as in - 0xDeadBeef and 0b101101 though the latter is non-converntional. - Note that leading zeros, which are probably quite common in fields in - nameschemes will get treated automatically as octal (base 8) if base - is not explicitly specified. */ - if (isdigit(*currentPosition) || strchr("-+xXbB", *currentPosition)) + long long mult = 1; + long long value; + + /* skip forward over chars that cannot be part of a number */ + if (!strchr("+-0123456789ABCDEFabcdefxX", *currentPosition)) { - errno = 0; - /* Found a digit, attempt to convert it to an integer value */ - value = strtoll(currentPosition, &endPtr, base); - if (errno == 0) - { - if (currentField == fieldSelector) - return value; - currentPosition = endPtr; /* moved to end of whatever was parsed by strtol */ - currentField++; - } - else - currentPosition++; - } else { - /* Skip non-digit characters */ + currentPosition++; + continue; + } + + /* walk over any sign if present */ + if (*currentPosition == '-') + { + mult = -1; currentPosition++; } + else if (*currentPosition == '+') + currentPosition++; + + /* Try to detect unconventional '0b' base-2 designator */ + if (base == 0 && (!strncmp(currentPosition,"0b0",3) || !strncmp(currentPosition,"0b1",3))) + { + currentPosition += 2; + base = 2; /* explicitly set base to 2 */ + } + + /* Attempt a conversion. A successful conversion implies its a field. */ + errno = 0; + value = strtoll(currentPosition, &endPtr, base); + if (errno == 0 && endPtr >= currentPosition + minFieldWidth) + { + if (currentField == fieldSelector) + return mult * value; + currentPosition = endPtr; + currentField++; + } + else + currentPosition++; } - return value; + return LLONG_MAX; } PUBLIC char const * From 5caa18e5de9ab64fb89de7dd67d37b36f089518d Mon Sep 17 00:00:00 2001 From: "Mark C. Miller" Date: Tue, 30 Jul 2024 09:30:59 -0700 Subject: [PATCH 3/3] fix/add DBGetIndex tests --- tests/namescheme.c | 57 +++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/tests/namescheme.c b/tests/namescheme.c index d60e2c3b..3038c3ea 100644 --- a/tests/namescheme.c +++ b/tests/namescheme.c @@ -64,6 +64,7 @@ be used for advertising or product endorsement purposes. #include #include #include +#include #define TEST_GET_NAME(NS,I,EXP) \ if (!NS) \ @@ -81,20 +82,13 @@ else } \ } -#define TEST_GET_INDEX(NS,I,IND) \ -if (!NS) \ +/* Uses a hard-coded min field width of 3 */ +#define TEST_GET_INDEX(STR, FLD, BASE, EXP) \ +if (DBGetIndex(STR, FLD, 3, BASE) != (long long) EXP) \ { \ - fprintf(stderr, "Got NULL namescheme from DBMakeNamescheme at line %d\n", __LINE__); \ + fprintf(stderr, "DBGetIndex() at line %d failed for field %d of \"%s\". Expected %lld, got %lld\n", \ + __LINE__, FLD, STR, (long long) EXP, DBGetIndex(STR,FLD,3,BASE)); \ return 1; \ -} \ -else \ -{ \ - if (DBGetIndex(NS, I) != IND) \ - { \ - fprintf(stderr, "DBGetIndex() at line %d failed for field %d of \"%s\". Expected %lld, got %lld\n",\ - __LINE__, FLD, STR, (long long) IND, DBGetIndex(STR,FLD,BASE)); \ - return 1; \ - } \ } #define TEST_STR(A,B) \ @@ -412,11 +406,11 @@ int main(int argc, char **argv) /* Test using namescheme as a simple integer mapping */ ns = DBMakeNamescheme("|chemA_%04X|n%3"); - TEST_GET_INDEX(ns, 0, 0); - TEST_GET_INDEX(ns, 1, 1); - TEST_GET_INDEX(ns, 2, 2); - TEST_GET_INDEX(ns, 3, 0); - TEST_GET_INDEX(ns, 4, 1); + TEST_GET_INDEX(DBGetName(ns, 0), 0, 0, 0); + TEST_GET_INDEX(DBGetName(ns, 1), 0, 0, 1); + TEST_GET_INDEX(DBGetName(ns, 2), 0, 0, 2); + TEST_GET_INDEX(DBGetName(ns, 3), 0, 0, 0); + TEST_GET_INDEX(DBGetName(ns, 4), 0, 0, 1); DBFreeNamescheme(ns); /* simple offset by -2 mapping */ @@ -430,10 +424,10 @@ int main(int argc, char **argv) /* Get different fields as indices from nameschemed strings */ ns = DBMakeNamescheme("|foo_%03d_%03d|n/5|n%5"); - TEST_GET_INDEX(DBGetName(ns,0), 0, 0, 0); - TEST_GET_INDEX(DBGetName(ns,0), 1, 0, 0); - TEST_GET_INDEX(DBGetName(ns,18), 0, 2, 0); - TEST_GET_INDEX(DBGetName(ns,18), 1, 3, 0); + TEST_GET_INDEX(DBGetName(ns,0), 0, 0, 0); + TEST_GET_INDEX(DBGetName(ns,0), 1, 0, 0); + TEST_GET_INDEX(DBGetName(ns,18), 0, 0, 3); + TEST_GET_INDEX(DBGetName(ns,17), 1, 0, 2); DBFreeNamescheme(ns); /* Case where index is bigger than an int */ @@ -442,13 +436,30 @@ int main(int argc, char **argv) TEST_GET_INDEX(DBGetName(ns,0x7FFFFFFFF), 0, 0, 0x7FFFFFFFF); /* make sure another `F` works */ DBFreeNamescheme(ns); + /* Test inferring base 2 (binary, leading '0b') */ + TEST_GET_INDEX("block_0b0101", 0, 0, 5); + TEST_GET_INDEX("block_0b0101_0b1100", 1, 0, 12); + + /* Test inferring base 8 (octal, leading '0') */ + TEST_GET_INDEX("slice1_035", 0, 0, 29); + + /* Test non-standard base 5 */ + TEST_GET_INDEX("VisIt_docs_section_0002_chapter_1234", 1, 5, 194); + + /* Test negative values */ + TEST_GET_INDEX("block_-0b0101", 0, 0, -5); + + /* Test some cases that could lead to error */ + TEST_GET_INDEX("block_0b0", 1, 0, LLONG_MAX); + TEST_GET_INDEX("block_+", 1, 0, LLONG_MAX); + TEST_GET_INDEX("block_0x", 1, 0, LLONG_MAX); + TEST_GET_INDEX("VisIt_docs_section_0002_chapter_1234", 5, 5, LLONG_MAX); + /* Test the convenience method, DBSPrintf */ -#if 0 snprintf(teststr, sizeof(teststr), "%s, %s", DBSPrintf("block_%d,level_%04d", 505, 17), DBSPrintf("side_%s_%cx%g", "master",'z',1.0/3)); TEST_STR(teststr, "block_505,level_0017, side_master_zx0.333333") -#endif /* Test case where fewer expressions that conversion specs */ ns = DBMakeNamescheme("|/domain_%03d/laser_beam_power_%d|n/1|");