diff --git a/src/libCom/misc/epicsString.c b/src/libCom/misc/epicsString.c index a7ef91e5a..d6c1e3b2b 100644 --- a/src/libCom/misc/epicsString.c +++ b/src/libCom/misc/epicsString.c @@ -11,6 +11,9 @@ /* Authors: Jun-ichi Odagiri, Marty Kraimer, Eric Norum, * Mark Rivers, Andrew Johnson, Ralph Lange + * + * Routines in this file should have corresponding test code in + * libCom/test/epicsStringTest.c */ #include @@ -25,25 +28,26 @@ #include "cantProceed.h" #include "epicsString.h" -/* Deprecated: This may be insecure; use epicsStrnRawFromEscaped instead */ +/* Deprecated, use epicsStrnRawFromEscaped() instead */ int dbTranslateEscape(char *to, const char *from) { size_t big_enough = strlen(from)+1; return epicsStrnRawFromEscaped(to, big_enough, from, big_enough); } -int epicsStrnRawFromEscaped(char *to, size_t outsize, const char *from, size_t inlen) +int epicsStrnRawFromEscaped(char *to, size_t outsize, const char *from, + size_t inlen) { const char *pfrom = from; char *pto = to; char c; - int nto=0, nfrom=0; + int nto = 0, nfrom = 0; - while( (c = *pfrom++) && nto < outsize && nfrom < inlen){ + while ((c = *pfrom++) && nto < outsize && nfrom < inlen) { nfrom++; - if(c == '\\') { - if( nfrom >= inlen || *pfrom == '\0' ) break; - switch( *pfrom ){ + if (c == '\\') { + if (nfrom >= inlen || *pfrom == '\0') break; + switch (*pfrom) { case 'a': pfrom++; nfrom++; *pto++ = '\a' ; nto++; break; case 'b': pfrom++; nfrom++; *pto++ = '\b' ; nto++; break; case 'f': pfrom++; nfrom++; *pto++ = '\f' ; nto++; break; @@ -63,8 +67,8 @@ int epicsStrnRawFromEscaped(char *to, size_t outsize, const char *from, size_t i unsigned int ival; unsigned char *pchar; - for(i=0; i<3; i++) { - if((*pfrom < '0') || (*pfrom > '7')) break; + for (i=0; i<3; i++) { + if ((*pfrom < '0') || (*pfrom > '7')) break; strval[i] = *pfrom++; nfrom++; } sscanf(strval,"%o",&ival); @@ -80,8 +84,8 @@ int epicsStrnRawFromEscaped(char *to, size_t outsize, const char *from, size_t i unsigned char *pchar; pfrom++; /*skip the x*/ - for(i=0; i<2; i++) { - if(!isxdigit((int)*pfrom)) break; + for (i=0; i<2; i++) { + if (!isxdigit((int)*pfrom)) break; strval[i] = *pfrom++; nfrom++; } sscanf(strval,"%x",&ival); @@ -97,10 +101,11 @@ int epicsStrnRawFromEscaped(char *to, size_t outsize, const char *from, size_t i } } *pto = '\0'; /* NOTE that nto does not have to be incremented */ - return(nto); + return nto; } -int epicsStrnEscapedFromRaw(char *outbuf, size_t outsize, const char *inbuf, size_t inlen) +int epicsStrnEscapedFromRaw(char *outbuf, size_t outsize, const char *inbuf, + size_t inlen) { int maxout = outsize; int nout = 0; @@ -118,20 +123,19 @@ int epicsStrnEscapedFromRaw(char *outbuf, size_t outsize, const char *inbuf, siz case '\t': len = epicsSnprintf(outpos, maxout, "\\t"); break; case '\v': len = epicsSnprintf(outpos, maxout, "\\v"); break; case '\\': len = epicsSnprintf(outpos, maxout, "\\\\"); ; break; - /*? does not follow C convention because trigraphs no longer important*/ - case '\?': len = epicsSnprintf(outpos, maxout, "?"); break; case '\'': len = epicsSnprintf(outpos, maxout, "\\'"); break; case '\"': len = epicsSnprintf(outpos, maxout, "\\\""); break; default: if (isprint((int)c)) len = epicsSnprintf(outpos, maxout, "%c", c); else - len = epicsSnprintf(outpos, maxout, "\\%03o", (unsigned char)c); + len = epicsSnprintf(outpos, maxout, "\\%03o", + (unsigned char)c); break; } - if(len<0) return -1; + if (len<0) return -1; nout += len; - if(nout < outsize) { + if (nout < outsize) { maxout -= len; outpos += len; } else { @@ -147,18 +151,18 @@ size_t epicsStrnEscapedFromRawSize(const char *inbuf, size_t inlen) { size_t nout = inlen; - while (inlen--) { + while (inlen--) { char c = *inbuf++; + switch (c) { - case '\a': case '\b': case '\f': case '\n': - case '\r': case '\t': case '\v': case '\\': - case '\?': case '\'': case '\"': - inlen++; - break; - default: - if (!isprint((int)c)) - nout += 3; - break; + case '\a': case '\b': case '\f': case '\n': + case '\r': case '\t': case '\v': case '\\': + case '\'': case '\"': + nout++; + break; + default: + if (!isprint((int)c)) + nout += 3; } } return nout; @@ -166,51 +170,49 @@ size_t epicsStrnEscapedFromRawSize(const char *inbuf, size_t inlen) int epicsStrCaseCmp(const char *s1, const char *s2) { - int nexts1,nexts2; + while (1) { + int ch1 = toupper(*s1); + int ch2 = toupper(*s2); - while(1) { - /* vxWorks implementation expands argument more than once!!! */ - nexts1 = toupper(*s1); - nexts2 = toupper(*s2); - if(nexts1==0) return( (nexts2==0) ? 0 : 1 ); - if(nexts2==0) return(-1); - if(nexts1nexts2) return(1); + if (ch1 == 0) return (ch2 != 0); + if (ch2 == 0) return -1; + if (ch1 < ch2) return -1; + if (ch1 > ch2) return 1; s1++; s2++; } } -int epicsStrnCaseCmp(const char *s1, const char *s2, int n) +int epicsStrnCaseCmp(const char *s1, const char *s2, size_t len) { - size_t ind = 0; - int nexts1,nexts2; + size_t i = 0; - while(1) { - if(ind++ >= (size_t)n) break; - /* vxWorks implementation expands argument more than once!!! */ - nexts1 = toupper(*s1); - nexts2 = toupper(*s2); - if(nexts1==0) return( (nexts2==0) ? 0 : 1 ); - if(nexts2==0) return(-1); - if(nexts1nexts2) return(1); + while (i++ < len) { + int ch1 = toupper(*s1); + int ch2 = toupper(*s2); + + if (ch1 == 0) return (ch2 != 0); + if (ch2 == 0) return -1; + if (ch1 < ch2) return -1; + if (ch1 > ch2) return 1; s1++; s2++; } - return(0); + return 0; } char * epicsStrDup(const char *s) { - return strcpy(mallocMustSucceed(strlen(s)+1,"epicsStrDup"),s); + return strcpy(mallocMustSucceed(strlen(s)+1, "epicsStrDup"), s); } -int epicsStrPrintEscaped(FILE *fp, const char *s, int n) +int epicsStrPrintEscaped(FILE *fp, const char *s, size_t len) { - int nout=0; - while (n--) { + int nout = 0; + + while (len--) { char c = *s++; + switch (c) { case '\a': nout += fprintf(fp, "\\a"); break; case '\b': nout += fprintf(fp, "\\b"); break; @@ -220,13 +222,11 @@ int epicsStrPrintEscaped(FILE *fp, const char *s, int n) case '\t': nout += fprintf(fp, "\\t"); break; case '\v': nout += fprintf(fp, "\\v"); break; case '\\': nout += fprintf(fp, "\\\\"); break; - /*? does not follow C convention because trigraphs no longer important*/ - case '\?': nout += fprintf(fp, "?"); break; case '\'': nout += fprintf(fp, "\\'"); break; case '\"': nout += fprintf(fp, "\\\""); break; default: if (isprint((int)c)) - nout += fprintf(fp, "%c", c);/* putchar(c) doesn't work on vxWorks */ + nout += fprintf(fp, "%c", c); else nout += fprintf(fp, "\\%03o", (unsigned char)c); break; @@ -237,8 +237,8 @@ int epicsStrPrintEscaped(FILE *fp, const char *s, int n) int epicsStrGlobMatch(const char *str, const char *pattern) { - const char *cp=NULL, *mp=NULL; - + const char *cp = NULL, *mp = NULL; + while ((*str) && (*pattern != '*')) { if ((*pattern != *str) && (*pattern != '?')) return 0; @@ -272,9 +272,8 @@ char * epicsStrtok_r(char *s, const char *delim, char **lasts) int c, sc; char *tok; - if (s == NULL && (s = *lasts) == NULL) - return (NULL); + return NULL; /* * Skip (span) leading delimiters (s += strspn(s, delim), sort of). @@ -288,7 +287,7 @@ cont: if (c == 0) { /* no non-delimiter characters */ *lasts = NULL; - return (NULL); + return NULL; } tok = s - 1; @@ -306,7 +305,7 @@ cont: else s[-1] = 0; *lasts = s; - return (tok); + return tok; } } while (sc != 0); } @@ -337,4 +336,3 @@ unsigned int epicsMemHash(const char *str, size_t length, unsigned int seed) } return hash; } - diff --git a/src/libCom/misc/epicsString.h b/src/libCom/misc/epicsString.h index 8cf9d26a0..7b87bd8b3 100644 --- a/src/libCom/misc/epicsString.h +++ b/src/libCom/misc/epicsString.h @@ -28,17 +28,18 @@ epicsShareFunc int epicsStrnRawFromEscaped(char *outbuf, size_t outsize, const char *inbuf, size_t inlen); epicsShareFunc int epicsStrnEscapedFromRaw(char *outbuf, size_t outsize, const char *inbuf, size_t inlen); -epicsShareFunc size_t epicsStrnEscapedFromRawSize(const char *inbuf, size_t inlen); +epicsShareFunc size_t epicsStrnEscapedFromRawSize(const char *buf, size_t len); epicsShareFunc int epicsStrCaseCmp(const char *s1, const char *s2); -epicsShareFunc int epicsStrnCaseCmp(const char *s1, const char *s2, int n); +epicsShareFunc int epicsStrnCaseCmp(const char *s1, const char *s2, size_t len); epicsShareFunc char * epicsStrDup(const char *s); -epicsShareFunc int epicsStrPrintEscaped(FILE *fp, const char *s, int n); +epicsShareFunc int epicsStrPrintEscaped(FILE *fp, const char *s, size_t n); #define epicsStrSnPrintEscaped epicsStrnEscapedFromRaw epicsShareFunc int epicsStrGlobMatch(const char *str, const char *pattern); epicsShareFunc char * epicsStrtok_r(char *s, const char *delim, char **lasts); epicsShareFunc unsigned int epicsStrHash(const char *str, unsigned int seed); epicsShareFunc unsigned int epicsMemHash(const char *str, size_t length, unsigned int seed); + /* dbTranslateEscape is deprecated, use epicsStrnRawFromEscaped instead */ epicsShareFunc int dbTranslateEscape(char *s, const char *ct); diff --git a/src/libCom/test/epicsStringTest.c b/src/libCom/test/epicsStringTest.c index 46b88f7e2..ec47f02a3 100644 --- a/src/libCom/test/epicsStringTest.c +++ b/src/libCom/test/epicsStringTest.c @@ -12,6 +12,8 @@ */ #include +#include +#include #include "epicsUnitTest.h" #include "epicsString.h" @@ -22,44 +24,66 @@ void testChars(void) { char input[2] = {0, 0}; char escaped[20]; char result[20]; + size_t s, t, needed; + for (i = 255; i >= 0; --i) { input[0] = i; - epicsStrSnPrintEscaped(escaped, sizeof(escaped), input, 1); - dbTranslateEscape(result, escaped); - testOk(result[0] == input[0] && result[1] == 0, - "char 0x%2.2x -> \"%s\" -> 0x%2.2x", - input[0] & 0xff, escaped, result[0] & 0xff); + needed = epicsStrnEscapedFromRawSize(input, 1); + s = epicsStrnEscapedFromRaw(escaped, sizeof(escaped), input, 1); + t = epicsStrnRawFromEscaped(result, sizeof(result), escaped, s); + testOk(needed == s && t == 1 && + result[0] == input[0] && result[1] == 0, + "escaped char 0x%2.2x -> \"%s\" (%Zd) -> 0x%2.2x", + input[0] & 0xff, escaped, needed, result[0] & 0xff); } } MAIN(epicsStringTest) { - testPlan(0); + const char * const empty = ""; + const char * const space = " "; + const char * const A = "A"; + const char * const ABCD = "ABCD"; + const char * const ABCDE = "ABCDE"; + const char * const a = "a"; + const char * const abcd = "abcd"; + const char * const abcde = "abcde"; + char *s; + + testPlan(281); testChars(); - testOk1(epicsStrnCaseCmp("","",0)==0); - testOk1(epicsStrnCaseCmp("","",1)==0); - testOk1(epicsStrnCaseCmp(" ","",1)<0); - testOk1(epicsStrnCaseCmp(""," ",1)>0); - testOk1(epicsStrnCaseCmp("a","A",1)==0); - testOk1(epicsStrnCaseCmp("a","A",2)==0); - testOk1(epicsStrnCaseCmp("abcd","ABCD",2)==0); - testOk1(epicsStrnCaseCmp("abcd","ABCD",4)==0); - testOk1(epicsStrnCaseCmp("abcd","ABCD",1000)==0); - testOk1(epicsStrnCaseCmp("abcd","ABCDE",2)==0); - testOk1(epicsStrnCaseCmp("abcd","ABCDE",4)==0); - testOk1(epicsStrnCaseCmp("abcd","ABCDE",1000)>0); - testOk1(epicsStrnCaseCmp("abcde","ABCD",2)==0); - testOk1(epicsStrnCaseCmp("abcde","ABCD",4)==0); - testOk1(epicsStrnCaseCmp("abcde","ABCD",1000)<0); + testOk1(epicsStrnCaseCmp(empty, "", 0) == 0); + testOk1(epicsStrnCaseCmp(empty, "", 1) == 0); + testOk1(epicsStrnCaseCmp(space, empty, 1) < 0); + testOk1(epicsStrnCaseCmp(empty, space, 1) > 0); + testOk1(epicsStrnCaseCmp(a, A, 1) == 0); + testOk1(epicsStrnCaseCmp(a, A, 2) == 0); + testOk1(epicsStrnCaseCmp(abcd, ABCD, 2) == 0); + testOk1(epicsStrnCaseCmp(abcd, ABCD, 4) == 0); + testOk1(epicsStrnCaseCmp(abcd, ABCD, 1000) == 0); + testOk1(epicsStrnCaseCmp(abcd, ABCDE, 2) == 0); + testOk1(epicsStrnCaseCmp(abcd, ABCDE, 4) == 0); + testOk1(epicsStrnCaseCmp(abcd, ABCDE, 1000)> 0); + testOk1(epicsStrnCaseCmp(abcde, ABCD, 2) == 0); + testOk1(epicsStrnCaseCmp(abcde, ABCD, 4) == 0); + testOk1(epicsStrnCaseCmp(abcde, ABCD, 1000) < 0); - testOk1(epicsStrCaseCmp("","")==0); - testOk1(epicsStrCaseCmp("a","A")==0); - testOk1(epicsStrCaseCmp("abcd","ABCD")==0); - testOk1(epicsStrCaseCmp("abcd","ABCDE")!=0); - testOk1(epicsStrCaseCmp("abcde","ABCD")!=0); - testOk1(epicsStrCaseCmp("abcde","ABCDF")!=0); + testOk1(epicsStrCaseCmp(empty, "") == 0); + testOk1(epicsStrCaseCmp(a, A) == 0); + testOk1(epicsStrCaseCmp(abcd, ABCD) == 0); + testOk1(epicsStrCaseCmp(abcd, ABCDE) != 0); + testOk1(epicsStrCaseCmp(abcde, ABCD) != 0); + testOk1(epicsStrCaseCmp(abcde, "ABCDF") != 0); + + s = epicsStrDup(abcd); + testOk(strcmp(s, abcd) == 0 && s != abcd, "epicsStrDup"); + free(s); + + testOk1(epicsStrHash(abcd, 0) != epicsStrHash("bacd", 0)); + testOk1(epicsStrHash(abcd, 0) == epicsMemHash(abcde, 4, 0)); + testOk1(epicsStrHash(abcd, 0) != epicsMemHash("abcd\0", 5, 0)); return testDone(); }