diff options
author | Steve Bennett <steveb@workware.net.au> | 2011-01-26 10:48:58 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2011-01-26 10:48:58 +1000 |
commit | 99792bb65fca43df81844dde3acc191c56ce47e3 (patch) | |
tree | 813d728b250894105258de5b2051cc38286f3085 | |
parent | 15d4b5606abcd92748664c09aac744b207025567 (diff) | |
download | jimtcl-0.70.zip jimtcl-0.70.tar.gz jimtcl-0.70.tar.bz2 |
scan fails with strings containing nulls0.70
Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r-- | jim.c | 35 | ||||
-rw-r--r-- | tests/scan.test | 12 |
2 files changed, 33 insertions, 14 deletions
@@ -8804,12 +8804,12 @@ static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const cha * returned of -1 in case of no conversion tool place and string was * already scanned thru */ -static int ScanOneEntry(Jim_Interp *interp, const char *str, long pos, +static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen, ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr) { const char *tok; const ScanFmtPartDescr *descr = &fmtObj->descr[idx]; - size_t sLen = utf8_strlen(&str[pos], -1), scanned = 0; + size_t scanned = 0; size_t anchor = pos; int i; Jim_Obj *tmpObj = NULL; @@ -8819,18 +8819,20 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, long pos, if (descr->prefix) { /* There was a prefix given before the conversion, skip it and adjust * the string-to-be-parsed accordingly */ - for (i = 0; str[pos] && descr->prefix[i]; ++i) { + /* XXX: Should be checking strLen, not str[pos] */ + for (i = 0; pos < strLen && descr->prefix[i]; ++i) { /* If prefix require, skip WS */ if (isspace(UCHAR(descr->prefix[i]))) - while (str[pos] && isspace(UCHAR(str[pos]))) + while (pos < strLen && isspace(UCHAR(str[pos]))) ++pos; else if (descr->prefix[i] != str[pos]) break; /* Prefix do not match here, leave the loop */ else ++pos; /* Prefix matched so far, next round */ } - if (str[pos] == 0) + if (pos >= strLen) { return -1; /* All of str consumed: EOF condition */ + } else if (descr->prefix[i] != 0) return 0; /* Not whole prefix consumed, no conversion possible */ } @@ -8840,19 +8842,28 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, long pos, ++pos; /* Determine how much skipped/scanned so far */ scanned = pos - anchor; + + /* %c is a special, simple case. no width */ if (descr->type == 'n') { /* Return pseudo conversion means: how much scanned so far? */ *valObjPtr = Jim_NewIntObj(interp, anchor + scanned); } - else if (str[pos] == 0) { + else if (pos >= strLen) { /* Cannot scan anything, as str is totally consumed */ return -1; } + else if (descr->type == 'c') { + int c; + scanned += utf8_tounicode(&str[pos], &c); + *valObjPtr = Jim_NewIntObj(interp, c); + return scanned; + } else { /* Processing of conversions follows ... */ if (descr->width > 0) { /* Do not try to scan as fas as possible but only the given width. * To ensure this, we copy the part that should be scanned. */ + size_t sLen = utf8_strlen(&str[pos], strLen - pos); size_t tLen = descr->width > sLen ? sLen : descr->width; tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen); @@ -8863,12 +8874,6 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, long pos, tok = &str[pos]; } switch (descr->type) { - case 'c': { - int c; - scanned += utf8_tounicode(tok, &c); - *valObjPtr = Jim_NewIntObj(interp, c); - } - break; case 'd': case 'o': case 'x': @@ -8950,7 +8955,8 @@ Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjP { size_t i, pos; int scanned = 1; - const char *str = Jim_GetString(strObjPtr, 0); + const char *str = Jim_GetString(strObjPtr, NULL); + int strLen = Jim_Utf8Length(interp, strObjPtr); Jim_Obj *resultList = 0; Jim_Obj **resultVec = 0; int resultc; @@ -8989,12 +8995,13 @@ Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjP continue; /* As long as any conversion could be done, we will proceed */ if (scanned > 0) - scanned = ScanOneEntry(interp, str, pos, fmtObj, i, &value); + scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value); /* In case our first try results in EOF, we will leave */ if (scanned == -1 && i == 0) goto eof; /* Advance next pos-to-be-scanned for the amount scanned already */ pos += scanned; + /* value == 0 means no conversion took place so take empty string */ if (value == 0) value = Jim_NewEmptyStringObj(interp); diff --git a/tests/scan.test b/tests/scan.test index 0614d56..f936ee3 100644 --- a/tests/scan.test +++ b/tests/scan.test @@ -658,4 +658,16 @@ test scan-13.8 {Tcl_ScanObjCmd, inline XPG case lots of arguments} { list [llength $msg] [lindex $msg 99] [lindex $msg 4] [lindex $msg 199] } {200 10 20 30} +test scan-14.1 {scan with null chars} { + scan a\0c %c%c%c +} {97 0 99} + +test scan-14.2 {scan with null chars} { + scan \0\0c %c%c%c +} {0 0 99} + +test scan-14.3 {scan with null chars} { + scan ab12x\0 %cb%dx%c +} {97 12 0} + testreport |