Fossil SCM

Fix error-handling in parsing of binary/octal/hex integers for th1. Add test-cases for it.

jan.nijtmans 2014-04-04 10:20 trunk merge
Commit 99901fbf7951a5424bb1a2aa9fdfbc31779d2d6b
+57 -26
--- src/th.c
+++ src/th.c
@@ -128,10 +128,11 @@
128128
*/
129129
static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
130130
static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
131131
static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
132132
static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
133
+static int thNextInteger (Th_Interp*, const char *z, int n, int *pN);
133134
static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
134135
135136
/*
136137
** Given that the input string (z, n) contains a language construct of
137138
** the relevant type (a command enclosed in [], an escape sequence
@@ -1866,10 +1867,46 @@
18661867
{"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
18671868
{"|", OP_BITWISE_OR, 10, ARG_INTEGER},
18681869
18691870
{0,0,0,0}
18701871
};
1872
+
1873
+/*
1874
+** The first part of the string (zInput,nInput) contains an integer.
1875
+** Set *pnVarname to the number of bytes in the numeric string.
1876
+*/
1877
+static int thNextInteger(
1878
+ Th_Interp *interp,
1879
+ const char *zInput,
1880
+ int nInput,
1881
+ int *pnLiteral
1882
+){
1883
+ int i = 0;
1884
+ int seenDot = 0;
1885
+ int (*isdigit)(char) = th_isdigit;
1886
+ if( nInput>2 ){
1887
+ if( zInput[1]=='x' || zInput[1]=='X' ){
1888
+ i=2;
1889
+ isdigit = th_ishexdig;
1890
+ }else if( zInput[1]=='o' || zInput[1]=='O' ){
1891
+ i=2;
1892
+ }else if( zInput[1]=='b' || zInput[1]=='B' ){
1893
+ i=2;
1894
+ }else{
1895
+ *pnLiteral = 0;
1896
+ return TH_OK;
1897
+ }
1898
+ }
1899
+ for(; i<nInput; i++){
1900
+ char c = zInput[i];
1901
+ if( !isdigit(c) ){
1902
+ break;
1903
+ }
1904
+ }
1905
+ *pnLiteral = i;
1906
+ return TH_OK;
1907
+}
18711908
18721909
/*
18731910
** The first part of the string (zInput,nInput) contains a number.
18741911
** Set *pnVarname to the number of bytes in the numeric string.
18751912
*/
@@ -1879,28 +1916,13 @@
18791916
int nInput,
18801917
int *pnLiteral
18811918
){
18821919
int i = 0;
18831920
int seenDot = 0;
1884
- int (*isdigit)(char) = th_isdigit;
1885
- if( nInput>2 ){
1886
- if( zInput[0]=='0' && (zInput[1]=='x' || zInput[1]=='X') ){
1887
- i=2;
1888
- isdigit = th_ishexdig;
1889
- }
1890
- if( zInput[0]=='0' && (zInput[1]=='o' || zInput[1]=='O') ){
1891
- i=2;
1892
- isdigit = th_isoctdig;
1893
- }
1894
- if( zInput[0]=='0' && (zInput[1]=='b' || zInput[1]=='B') ){
1895
- i=2;
1896
- isdigit = th_isbindig;
1897
- }
1898
- }
18991921
for(; i<nInput; i++){
19001922
char c = zInput[i];
1901
- if( (seenDot || c!='.') && !isdigit(c) ) break;
1923
+ if( (seenDot || c!='.') && !th_isdigit(c) ) break;
19021924
if( c=='.' ) seenDot = 1;
19031925
}
19041926
*pnLiteral = i;
19051927
return TH_OK;
19061928
}
@@ -2170,12 +2192,18 @@
21702192
}else{
21712193
Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
21722194
const char *z = &zExpr[i];
21732195
21742196
switch (c) {
2175
- case '0': case '1': case '2': case '3': case '4':
2176
- case '5': case '6': case '7': case '8': case '9':
2197
+ case '0':
2198
+ if( (i+2<nExpr) && th_isalpha(zExpr[i+1]) ){
2199
+ thNextInteger(interp, z, nExpr-i, &pNew->nValue);
2200
+ if(pNew->nValue) break;
2201
+ }
2202
+ /* fall through */
2203
+ case '1': case '2': case '3': case '4': case '5':
2204
+ case '6': case '7': case '8': case '9':
21772205
thNextNumber(interp, z, nExpr-i, &pNew->nValue);
21782206
break;
21792207
21802208
case '$':
21812209
thNextVarname(interp, z, nExpr-i, &pNew->nValue);
@@ -2471,10 +2499,13 @@
24712499
return (aCharProp[(unsigned char)c] & 0x11);
24722500
}
24732501
int th_isalnum(char c){
24742502
return (aCharProp[(unsigned char)c] & 0x0A);
24752503
}
2504
+int th_isalpha(char c){
2505
+ return (aCharProp[(unsigned char)c] & 0x08);
2506
+}
24762507
int th_ishexdig(char c){
24772508
return (aCharProp[(unsigned char)c] & 0x20);
24782509
}
24792510
int th_isoctdig(char c){
24802511
return ((c|7) == '7');
@@ -2626,23 +2657,23 @@
26262657
isdigit = th_isbindig;
26272658
}
26282659
}
26292660
}
26302661
for(; i<n; i++){
2631
- int shift;
2632
- if( !isdigit(z[i]) ){
2662
+ char c = z[i];
2663
+ if( !isdigit(c) ){
26332664
Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
26342665
return TH_ERROR;
26352666
}
2636
- if( z[i]>='a' ){
2637
- shift = 'a' - 10;
2638
- }else if( z[i]>='A' ){
2639
- shift = 'A' - 10;
2667
+ if( c>='a' ){
2668
+ c -= 'a'-10;
2669
+ }else if( c>='A' ){
2670
+ c -= 'A'-10;
26402671
}else{
2641
- shift = '0';
2672
+ c -= '0';
26422673
}
2643
- iOut = iOut * base + (z[i] - shift);
2674
+ iOut = iOut * base + c;
26442675
}
26452676
26462677
if( n>0 && z[0]=='-' ){
26472678
iOut *= -1;
26482679
}
26492680
--- src/th.c
+++ src/th.c
@@ -128,10 +128,11 @@
128 */
129 static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
130 static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
131 static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
132 static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
 
133 static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
134
135 /*
136 ** Given that the input string (z, n) contains a language construct of
137 ** the relevant type (a command enclosed in [], an escape sequence
@@ -1866,10 +1867,46 @@
1866 {"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
1867 {"|", OP_BITWISE_OR, 10, ARG_INTEGER},
1868
1869 {0,0,0,0}
1870 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1871
1872 /*
1873 ** The first part of the string (zInput,nInput) contains a number.
1874 ** Set *pnVarname to the number of bytes in the numeric string.
1875 */
@@ -1879,28 +1916,13 @@
1879 int nInput,
1880 int *pnLiteral
1881 ){
1882 int i = 0;
1883 int seenDot = 0;
1884 int (*isdigit)(char) = th_isdigit;
1885 if( nInput>2 ){
1886 if( zInput[0]=='0' && (zInput[1]=='x' || zInput[1]=='X') ){
1887 i=2;
1888 isdigit = th_ishexdig;
1889 }
1890 if( zInput[0]=='0' && (zInput[1]=='o' || zInput[1]=='O') ){
1891 i=2;
1892 isdigit = th_isoctdig;
1893 }
1894 if( zInput[0]=='0' && (zInput[1]=='b' || zInput[1]=='B') ){
1895 i=2;
1896 isdigit = th_isbindig;
1897 }
1898 }
1899 for(; i<nInput; i++){
1900 char c = zInput[i];
1901 if( (seenDot || c!='.') && !isdigit(c) ) break;
1902 if( c=='.' ) seenDot = 1;
1903 }
1904 *pnLiteral = i;
1905 return TH_OK;
1906 }
@@ -2170,12 +2192,18 @@
2170 }else{
2171 Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
2172 const char *z = &zExpr[i];
2173
2174 switch (c) {
2175 case '0': case '1': case '2': case '3': case '4':
2176 case '5': case '6': case '7': case '8': case '9':
 
 
 
 
 
 
2177 thNextNumber(interp, z, nExpr-i, &pNew->nValue);
2178 break;
2179
2180 case '$':
2181 thNextVarname(interp, z, nExpr-i, &pNew->nValue);
@@ -2471,10 +2499,13 @@
2471 return (aCharProp[(unsigned char)c] & 0x11);
2472 }
2473 int th_isalnum(char c){
2474 return (aCharProp[(unsigned char)c] & 0x0A);
2475 }
 
 
 
2476 int th_ishexdig(char c){
2477 return (aCharProp[(unsigned char)c] & 0x20);
2478 }
2479 int th_isoctdig(char c){
2480 return ((c|7) == '7');
@@ -2626,23 +2657,23 @@
2626 isdigit = th_isbindig;
2627 }
2628 }
2629 }
2630 for(; i<n; i++){
2631 int shift;
2632 if( !isdigit(z[i]) ){
2633 Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
2634 return TH_ERROR;
2635 }
2636 if( z[i]>='a' ){
2637 shift = 'a' - 10;
2638 }else if( z[i]>='A' ){
2639 shift = 'A' - 10;
2640 }else{
2641 shift = '0';
2642 }
2643 iOut = iOut * base + (z[i] - shift);
2644 }
2645
2646 if( n>0 && z[0]=='-' ){
2647 iOut *= -1;
2648 }
2649
--- src/th.c
+++ src/th.c
@@ -128,10 +128,11 @@
128 */
129 static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
130 static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
131 static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
132 static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
133 static int thNextInteger (Th_Interp*, const char *z, int n, int *pN);
134 static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
135
136 /*
137 ** Given that the input string (z, n) contains a language construct of
138 ** the relevant type (a command enclosed in [], an escape sequence
@@ -1866,10 +1867,46 @@
1867 {"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
1868 {"|", OP_BITWISE_OR, 10, ARG_INTEGER},
1869
1870 {0,0,0,0}
1871 };
1872
1873 /*
1874 ** The first part of the string (zInput,nInput) contains an integer.
1875 ** Set *pnVarname to the number of bytes in the numeric string.
1876 */
1877 static int thNextInteger(
1878 Th_Interp *interp,
1879 const char *zInput,
1880 int nInput,
1881 int *pnLiteral
1882 ){
1883 int i = 0;
1884 int seenDot = 0;
1885 int (*isdigit)(char) = th_isdigit;
1886 if( nInput>2 ){
1887 if( zInput[1]=='x' || zInput[1]=='X' ){
1888 i=2;
1889 isdigit = th_ishexdig;
1890 }else if( zInput[1]=='o' || zInput[1]=='O' ){
1891 i=2;
1892 }else if( zInput[1]=='b' || zInput[1]=='B' ){
1893 i=2;
1894 }else{
1895 *pnLiteral = 0;
1896 return TH_OK;
1897 }
1898 }
1899 for(; i<nInput; i++){
1900 char c = zInput[i];
1901 if( !isdigit(c) ){
1902 break;
1903 }
1904 }
1905 *pnLiteral = i;
1906 return TH_OK;
1907 }
1908
1909 /*
1910 ** The first part of the string (zInput,nInput) contains a number.
1911 ** Set *pnVarname to the number of bytes in the numeric string.
1912 */
@@ -1879,28 +1916,13 @@
1916 int nInput,
1917 int *pnLiteral
1918 ){
1919 int i = 0;
1920 int seenDot = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1921 for(; i<nInput; i++){
1922 char c = zInput[i];
1923 if( (seenDot || c!='.') && !th_isdigit(c) ) break;
1924 if( c=='.' ) seenDot = 1;
1925 }
1926 *pnLiteral = i;
1927 return TH_OK;
1928 }
@@ -2170,12 +2192,18 @@
2192 }else{
2193 Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
2194 const char *z = &zExpr[i];
2195
2196 switch (c) {
2197 case '0':
2198 if( (i+2<nExpr) && th_isalpha(zExpr[i+1]) ){
2199 thNextInteger(interp, z, nExpr-i, &pNew->nValue);
2200 if(pNew->nValue) break;
2201 }
2202 /* fall through */
2203 case '1': case '2': case '3': case '4': case '5':
2204 case '6': case '7': case '8': case '9':
2205 thNextNumber(interp, z, nExpr-i, &pNew->nValue);
2206 break;
2207
2208 case '$':
2209 thNextVarname(interp, z, nExpr-i, &pNew->nValue);
@@ -2471,10 +2499,13 @@
2499 return (aCharProp[(unsigned char)c] & 0x11);
2500 }
2501 int th_isalnum(char c){
2502 return (aCharProp[(unsigned char)c] & 0x0A);
2503 }
2504 int th_isalpha(char c){
2505 return (aCharProp[(unsigned char)c] & 0x08);
2506 }
2507 int th_ishexdig(char c){
2508 return (aCharProp[(unsigned char)c] & 0x20);
2509 }
2510 int th_isoctdig(char c){
2511 return ((c|7) == '7');
@@ -2626,23 +2657,23 @@
2657 isdigit = th_isbindig;
2658 }
2659 }
2660 }
2661 for(; i<n; i++){
2662 char c = z[i];
2663 if( !isdigit(c) ){
2664 Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
2665 return TH_ERROR;
2666 }
2667 if( c>='a' ){
2668 c -= 'a'-10;
2669 }else if( c>='A' ){
2670 c -= 'A'-10;
2671 }else{
2672 c -= '0';
2673 }
2674 iOut = iOut * base + c;
2675 }
2676
2677 if( n>0 && z[0]=='-' ){
2678 iOut *= -1;
2679 }
2680
+57 -26
--- src/th.c
+++ src/th.c
@@ -128,10 +128,11 @@
128128
*/
129129
static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
130130
static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
131131
static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
132132
static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
133
+static int thNextInteger (Th_Interp*, const char *z, int n, int *pN);
133134
static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
134135
135136
/*
136137
** Given that the input string (z, n) contains a language construct of
137138
** the relevant type (a command enclosed in [], an escape sequence
@@ -1866,10 +1867,46 @@
18661867
{"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
18671868
{"|", OP_BITWISE_OR, 10, ARG_INTEGER},
18681869
18691870
{0,0,0,0}
18701871
};
1872
+
1873
+/*
1874
+** The first part of the string (zInput,nInput) contains an integer.
1875
+** Set *pnVarname to the number of bytes in the numeric string.
1876
+*/
1877
+static int thNextInteger(
1878
+ Th_Interp *interp,
1879
+ const char *zInput,
1880
+ int nInput,
1881
+ int *pnLiteral
1882
+){
1883
+ int i = 0;
1884
+ int seenDot = 0;
1885
+ int (*isdigit)(char) = th_isdigit;
1886
+ if( nInput>2 ){
1887
+ if( zInput[1]=='x' || zInput[1]=='X' ){
1888
+ i=2;
1889
+ isdigit = th_ishexdig;
1890
+ }else if( zInput[1]=='o' || zInput[1]=='O' ){
1891
+ i=2;
1892
+ }else if( zInput[1]=='b' || zInput[1]=='B' ){
1893
+ i=2;
1894
+ }else{
1895
+ *pnLiteral = 0;
1896
+ return TH_OK;
1897
+ }
1898
+ }
1899
+ for(; i<nInput; i++){
1900
+ char c = zInput[i];
1901
+ if( !isdigit(c) ){
1902
+ break;
1903
+ }
1904
+ }
1905
+ *pnLiteral = i;
1906
+ return TH_OK;
1907
+}
18711908
18721909
/*
18731910
** The first part of the string (zInput,nInput) contains a number.
18741911
** Set *pnVarname to the number of bytes in the numeric string.
18751912
*/
@@ -1879,28 +1916,13 @@
18791916
int nInput,
18801917
int *pnLiteral
18811918
){
18821919
int i = 0;
18831920
int seenDot = 0;
1884
- int (*isdigit)(char) = th_isdigit;
1885
- if( nInput>2 ){
1886
- if( zInput[0]=='0' && (zInput[1]=='x' || zInput[1]=='X') ){
1887
- i=2;
1888
- isdigit = th_ishexdig;
1889
- }
1890
- if( zInput[0]=='0' && (zInput[1]=='o' || zInput[1]=='O') ){
1891
- i=2;
1892
- isdigit = th_isoctdig;
1893
- }
1894
- if( zInput[0]=='0' && (zInput[1]=='b' || zInput[1]=='B') ){
1895
- i=2;
1896
- isdigit = th_isbindig;
1897
- }
1898
- }
18991921
for(; i<nInput; i++){
19001922
char c = zInput[i];
1901
- if( (seenDot || c!='.') && !isdigit(c) ) break;
1923
+ if( (seenDot || c!='.') && !th_isdigit(c) ) break;
19021924
if( c=='.' ) seenDot = 1;
19031925
}
19041926
*pnLiteral = i;
19051927
return TH_OK;
19061928
}
@@ -2170,12 +2192,18 @@
21702192
}else{
21712193
Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
21722194
const char *z = &zExpr[i];
21732195
21742196
switch (c) {
2175
- case '0': case '1': case '2': case '3': case '4':
2176
- case '5': case '6': case '7': case '8': case '9':
2197
+ case '0':
2198
+ if( (i+2<nExpr) && th_isalpha(zExpr[i+1]) ){
2199
+ thNextInteger(interp, z, nExpr-i, &pNew->nValue);
2200
+ if(pNew->nValue) break;
2201
+ }
2202
+ /* fall through */
2203
+ case '1': case '2': case '3': case '4': case '5':
2204
+ case '6': case '7': case '8': case '9':
21772205
thNextNumber(interp, z, nExpr-i, &pNew->nValue);
21782206
break;
21792207
21802208
case '$':
21812209
thNextVarname(interp, z, nExpr-i, &pNew->nValue);
@@ -2471,10 +2499,13 @@
24712499
return (aCharProp[(unsigned char)c] & 0x11);
24722500
}
24732501
int th_isalnum(char c){
24742502
return (aCharProp[(unsigned char)c] & 0x0A);
24752503
}
2504
+int th_isalpha(char c){
2505
+ return (aCharProp[(unsigned char)c] & 0x08);
2506
+}
24762507
int th_ishexdig(char c){
24772508
return (aCharProp[(unsigned char)c] & 0x20);
24782509
}
24792510
int th_isoctdig(char c){
24802511
return ((c|7) == '7');
@@ -2626,23 +2657,23 @@
26262657
isdigit = th_isbindig;
26272658
}
26282659
}
26292660
}
26302661
for(; i<n; i++){
2631
- int shift;
2632
- if( !isdigit(z[i]) ){
2662
+ char c = z[i];
2663
+ if( !isdigit(c) ){
26332664
Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
26342665
return TH_ERROR;
26352666
}
2636
- if( z[i]>='a' ){
2637
- shift = 'a' - 10;
2638
- }else if( z[i]>='A' ){
2639
- shift = 'A' - 10;
2667
+ if( c>='a' ){
2668
+ c -= 'a'-10;
2669
+ }else if( c>='A' ){
2670
+ c -= 'A'-10;
26402671
}else{
2641
- shift = '0';
2672
+ c -= '0';
26422673
}
2643
- iOut = iOut * base + (z[i] - shift);
2674
+ iOut = iOut * base + c;
26442675
}
26452676
26462677
if( n>0 && z[0]=='-' ){
26472678
iOut *= -1;
26482679
}
26492680
--- src/th.c
+++ src/th.c
@@ -128,10 +128,11 @@
128 */
129 static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
130 static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
131 static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
132 static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
 
133 static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
134
135 /*
136 ** Given that the input string (z, n) contains a language construct of
137 ** the relevant type (a command enclosed in [], an escape sequence
@@ -1866,10 +1867,46 @@
1866 {"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
1867 {"|", OP_BITWISE_OR, 10, ARG_INTEGER},
1868
1869 {0,0,0,0}
1870 };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1871
1872 /*
1873 ** The first part of the string (zInput,nInput) contains a number.
1874 ** Set *pnVarname to the number of bytes in the numeric string.
1875 */
@@ -1879,28 +1916,13 @@
1879 int nInput,
1880 int *pnLiteral
1881 ){
1882 int i = 0;
1883 int seenDot = 0;
1884 int (*isdigit)(char) = th_isdigit;
1885 if( nInput>2 ){
1886 if( zInput[0]=='0' && (zInput[1]=='x' || zInput[1]=='X') ){
1887 i=2;
1888 isdigit = th_ishexdig;
1889 }
1890 if( zInput[0]=='0' && (zInput[1]=='o' || zInput[1]=='O') ){
1891 i=2;
1892 isdigit = th_isoctdig;
1893 }
1894 if( zInput[0]=='0' && (zInput[1]=='b' || zInput[1]=='B') ){
1895 i=2;
1896 isdigit = th_isbindig;
1897 }
1898 }
1899 for(; i<nInput; i++){
1900 char c = zInput[i];
1901 if( (seenDot || c!='.') && !isdigit(c) ) break;
1902 if( c=='.' ) seenDot = 1;
1903 }
1904 *pnLiteral = i;
1905 return TH_OK;
1906 }
@@ -2170,12 +2192,18 @@
2170 }else{
2171 Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
2172 const char *z = &zExpr[i];
2173
2174 switch (c) {
2175 case '0': case '1': case '2': case '3': case '4':
2176 case '5': case '6': case '7': case '8': case '9':
 
 
 
 
 
 
2177 thNextNumber(interp, z, nExpr-i, &pNew->nValue);
2178 break;
2179
2180 case '$':
2181 thNextVarname(interp, z, nExpr-i, &pNew->nValue);
@@ -2471,10 +2499,13 @@
2471 return (aCharProp[(unsigned char)c] & 0x11);
2472 }
2473 int th_isalnum(char c){
2474 return (aCharProp[(unsigned char)c] & 0x0A);
2475 }
 
 
 
2476 int th_ishexdig(char c){
2477 return (aCharProp[(unsigned char)c] & 0x20);
2478 }
2479 int th_isoctdig(char c){
2480 return ((c|7) == '7');
@@ -2626,23 +2657,23 @@
2626 isdigit = th_isbindig;
2627 }
2628 }
2629 }
2630 for(; i<n; i++){
2631 int shift;
2632 if( !isdigit(z[i]) ){
2633 Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
2634 return TH_ERROR;
2635 }
2636 if( z[i]>='a' ){
2637 shift = 'a' - 10;
2638 }else if( z[i]>='A' ){
2639 shift = 'A' - 10;
2640 }else{
2641 shift = '0';
2642 }
2643 iOut = iOut * base + (z[i] - shift);
2644 }
2645
2646 if( n>0 && z[0]=='-' ){
2647 iOut *= -1;
2648 }
2649
--- src/th.c
+++ src/th.c
@@ -128,10 +128,11 @@
128 */
129 static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
130 static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
131 static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
132 static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
133 static int thNextInteger (Th_Interp*, const char *z, int n, int *pN);
134 static int thNextSpace (Th_Interp*, const char *z, int n, int *pN);
135
136 /*
137 ** Given that the input string (z, n) contains a language construct of
138 ** the relevant type (a command enclosed in [], an escape sequence
@@ -1866,10 +1867,46 @@
1867 {"^", OP_BITWISE_XOR, 9, ARG_INTEGER},
1868 {"|", OP_BITWISE_OR, 10, ARG_INTEGER},
1869
1870 {0,0,0,0}
1871 };
1872
1873 /*
1874 ** The first part of the string (zInput,nInput) contains an integer.
1875 ** Set *pnVarname to the number of bytes in the numeric string.
1876 */
1877 static int thNextInteger(
1878 Th_Interp *interp,
1879 const char *zInput,
1880 int nInput,
1881 int *pnLiteral
1882 ){
1883 int i = 0;
1884 int seenDot = 0;
1885 int (*isdigit)(char) = th_isdigit;
1886 if( nInput>2 ){
1887 if( zInput[1]=='x' || zInput[1]=='X' ){
1888 i=2;
1889 isdigit = th_ishexdig;
1890 }else if( zInput[1]=='o' || zInput[1]=='O' ){
1891 i=2;
1892 }else if( zInput[1]=='b' || zInput[1]=='B' ){
1893 i=2;
1894 }else{
1895 *pnLiteral = 0;
1896 return TH_OK;
1897 }
1898 }
1899 for(; i<nInput; i++){
1900 char c = zInput[i];
1901 if( !isdigit(c) ){
1902 break;
1903 }
1904 }
1905 *pnLiteral = i;
1906 return TH_OK;
1907 }
1908
1909 /*
1910 ** The first part of the string (zInput,nInput) contains a number.
1911 ** Set *pnVarname to the number of bytes in the numeric string.
1912 */
@@ -1879,28 +1916,13 @@
1916 int nInput,
1917 int *pnLiteral
1918 ){
1919 int i = 0;
1920 int seenDot = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1921 for(; i<nInput; i++){
1922 char c = zInput[i];
1923 if( (seenDot || c!='.') && !th_isdigit(c) ) break;
1924 if( c=='.' ) seenDot = 1;
1925 }
1926 *pnLiteral = i;
1927 return TH_OK;
1928 }
@@ -2170,12 +2192,18 @@
2192 }else{
2193 Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
2194 const char *z = &zExpr[i];
2195
2196 switch (c) {
2197 case '0':
2198 if( (i+2<nExpr) && th_isalpha(zExpr[i+1]) ){
2199 thNextInteger(interp, z, nExpr-i, &pNew->nValue);
2200 if(pNew->nValue) break;
2201 }
2202 /* fall through */
2203 case '1': case '2': case '3': case '4': case '5':
2204 case '6': case '7': case '8': case '9':
2205 thNextNumber(interp, z, nExpr-i, &pNew->nValue);
2206 break;
2207
2208 case '$':
2209 thNextVarname(interp, z, nExpr-i, &pNew->nValue);
@@ -2471,10 +2499,13 @@
2499 return (aCharProp[(unsigned char)c] & 0x11);
2500 }
2501 int th_isalnum(char c){
2502 return (aCharProp[(unsigned char)c] & 0x0A);
2503 }
2504 int th_isalpha(char c){
2505 return (aCharProp[(unsigned char)c] & 0x08);
2506 }
2507 int th_ishexdig(char c){
2508 return (aCharProp[(unsigned char)c] & 0x20);
2509 }
2510 int th_isoctdig(char c){
2511 return ((c|7) == '7');
@@ -2626,23 +2657,23 @@
2657 isdigit = th_isbindig;
2658 }
2659 }
2660 }
2661 for(; i<n; i++){
2662 char c = z[i];
2663 if( !isdigit(c) ){
2664 Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
2665 return TH_ERROR;
2666 }
2667 if( c>='a' ){
2668 c -= 'a'-10;
2669 }else if( c>='A' ){
2670 c -= 'A'-10;
2671 }else{
2672 c -= '0';
2673 }
2674 iOut = iOut * base + c;
2675 }
2676
2677 if( n>0 && z[0]=='-' ){
2678 iOut *= -1;
2679 }
2680
+1
--- src/th.h
+++ src/th.h
@@ -145,10 +145,11 @@
145145
*/
146146
int th_strlen(const char *);
147147
int th_isdigit(char);
148148
int th_isspace(char);
149149
int th_isalnum(char);
150
+int th_isalpha(char);
150151
int th_isspecial(char);
151152
int th_ishexdig(char);
152153
int th_isoctdig(char);
153154
int th_isbindig(char);
154155
char *th_strdup(Th_Interp *interp, const char *z, int n);
155156
--- src/th.h
+++ src/th.h
@@ -145,10 +145,11 @@
145 */
146 int th_strlen(const char *);
147 int th_isdigit(char);
148 int th_isspace(char);
149 int th_isalnum(char);
 
150 int th_isspecial(char);
151 int th_ishexdig(char);
152 int th_isoctdig(char);
153 int th_isbindig(char);
154 char *th_strdup(Th_Interp *interp, const char *z, int n);
155
--- src/th.h
+++ src/th.h
@@ -145,10 +145,11 @@
145 */
146 int th_strlen(const char *);
147 int th_isdigit(char);
148 int th_isspace(char);
149 int th_isalnum(char);
150 int th_isalpha(char);
151 int th_isspecial(char);
152 int th_ishexdig(char);
153 int th_isoctdig(char);
154 int th_isbindig(char);
155 char *th_strdup(Th_Interp *interp, const char *z, int n);
156
--- test/th1.test
+++ test/th1.test
@@ -412,5 +412,60 @@
412412
413413
###############################################################################
414414
415415
fossil test-th-eval "expr ~(+1)"
416416
test th1-expr-23 {$RESULT eq {-2}}
417
+
418
+###############################################################################
419
+
420
+fossil test-th-eval "expr 0+0b11"
421
+test th1-expr-24 {$RESULT eq 3}
422
+
423
+###############################################################################
424
+
425
+fossil test-th-eval "expr 0+0o15"
426
+test th1-expr-25 {$RESULT eq 13}
427
+
428
+###############################################################################
429
+
430
+fossil test-th-eval "expr 0+0x15"
431
+test th1-expr-26 {$RESULT eq 21}
432
+
433
+###############################################################################
434
+
435
+fossil test-th-eval "expr 0+0b2"
436
+test th1-expr-27 {$RESULT eq {TH_ERROR: expected number, got: "0b2"}}
437
+
438
+###############################################################################
439
+
440
+fossil test-th-eval "expr 0+0o8"
441
+test th1-expr-28 {$RESULT eq {TH_ERROR: expected number, got: "0o8"}}
442
+
443
+###############################################################################
444
+
445
+fossil test-th-eval "expr 0+0xg"
446
+test th1-expr-29 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0xg"}}
447
+
448
+###############################################################################
449
+
450
+fossil test-th-eval "expr 0+0b1."
451
+test th1-expr-30 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0b1."}}
452
+
453
+###############################################################################
454
+
455
+fossil test-th-eval "expr 0+0o1."
456
+test th1-expr-31 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0o1."}}
457
+
458
+###############################################################################
459
+
460
+fossil test-th-eval "expr 0+0x1."
461
+test th1-expr-32 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0x1."}}
462
+
463
+###############################################################################
464
+
465
+fossil test-th-eval "expr 0ne5"
466
+test th1-expr-33 {$RESULT eq {1}}
467
+
468
+###############################################################################
469
+
470
+fossil test-th-eval "expr 0b1+5"
471
+test th1-expr-34 {$RESULT eq {6}}
417472
--- test/th1.test
+++ test/th1.test
@@ -412,5 +412,60 @@
412
413 ###############################################################################
414
415 fossil test-th-eval "expr ~(+1)"
416 test th1-expr-23 {$RESULT eq {-2}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
417
--- test/th1.test
+++ test/th1.test
@@ -412,5 +412,60 @@
412
413 ###############################################################################
414
415 fossil test-th-eval "expr ~(+1)"
416 test th1-expr-23 {$RESULT eq {-2}}
417
418 ###############################################################################
419
420 fossil test-th-eval "expr 0+0b11"
421 test th1-expr-24 {$RESULT eq 3}
422
423 ###############################################################################
424
425 fossil test-th-eval "expr 0+0o15"
426 test th1-expr-25 {$RESULT eq 13}
427
428 ###############################################################################
429
430 fossil test-th-eval "expr 0+0x15"
431 test th1-expr-26 {$RESULT eq 21}
432
433 ###############################################################################
434
435 fossil test-th-eval "expr 0+0b2"
436 test th1-expr-27 {$RESULT eq {TH_ERROR: expected number, got: "0b2"}}
437
438 ###############################################################################
439
440 fossil test-th-eval "expr 0+0o8"
441 test th1-expr-28 {$RESULT eq {TH_ERROR: expected number, got: "0o8"}}
442
443 ###############################################################################
444
445 fossil test-th-eval "expr 0+0xg"
446 test th1-expr-29 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0xg"}}
447
448 ###############################################################################
449
450 fossil test-th-eval "expr 0+0b1."
451 test th1-expr-30 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0b1."}}
452
453 ###############################################################################
454
455 fossil test-th-eval "expr 0+0o1."
456 test th1-expr-31 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0o1."}}
457
458 ###############################################################################
459
460 fossil test-th-eval "expr 0+0x1."
461 test th1-expr-32 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0x1."}}
462
463 ###############################################################################
464
465 fossil test-th-eval "expr 0ne5"
466 test th1-expr-33 {$RESULT eq {1}}
467
468 ###############################################################################
469
470 fossil test-th-eval "expr 0b1+5"
471 test th1-expr-34 {$RESULT eq {6}}
472
--- test/th1.test
+++ test/th1.test
@@ -412,5 +412,60 @@
412412
413413
###############################################################################
414414
415415
fossil test-th-eval "expr ~(+1)"
416416
test th1-expr-23 {$RESULT eq {-2}}
417
+
418
+###############################################################################
419
+
420
+fossil test-th-eval "expr 0+0b11"
421
+test th1-expr-24 {$RESULT eq 3}
422
+
423
+###############################################################################
424
+
425
+fossil test-th-eval "expr 0+0o15"
426
+test th1-expr-25 {$RESULT eq 13}
427
+
428
+###############################################################################
429
+
430
+fossil test-th-eval "expr 0+0x15"
431
+test th1-expr-26 {$RESULT eq 21}
432
+
433
+###############################################################################
434
+
435
+fossil test-th-eval "expr 0+0b2"
436
+test th1-expr-27 {$RESULT eq {TH_ERROR: expected number, got: "0b2"}}
437
+
438
+###############################################################################
439
+
440
+fossil test-th-eval "expr 0+0o8"
441
+test th1-expr-28 {$RESULT eq {TH_ERROR: expected number, got: "0o8"}}
442
+
443
+###############################################################################
444
+
445
+fossil test-th-eval "expr 0+0xg"
446
+test th1-expr-29 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0xg"}}
447
+
448
+###############################################################################
449
+
450
+fossil test-th-eval "expr 0+0b1."
451
+test th1-expr-30 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0b1."}}
452
+
453
+###############################################################################
454
+
455
+fossil test-th-eval "expr 0+0o1."
456
+test th1-expr-31 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0o1."}}
457
+
458
+###############################################################################
459
+
460
+fossil test-th-eval "expr 0+0x1."
461
+test th1-expr-32 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0x1."}}
462
+
463
+###############################################################################
464
+
465
+fossil test-th-eval "expr 0ne5"
466
+test th1-expr-33 {$RESULT eq {1}}
467
+
468
+###############################################################################
469
+
470
+fossil test-th-eval "expr 0b1+5"
471
+test th1-expr-34 {$RESULT eq {6}}
417472
--- test/th1.test
+++ test/th1.test
@@ -412,5 +412,60 @@
412
413 ###############################################################################
414
415 fossil test-th-eval "expr ~(+1)"
416 test th1-expr-23 {$RESULT eq {-2}}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
417
--- test/th1.test
+++ test/th1.test
@@ -412,5 +412,60 @@
412
413 ###############################################################################
414
415 fossil test-th-eval "expr ~(+1)"
416 test th1-expr-23 {$RESULT eq {-2}}
417
418 ###############################################################################
419
420 fossil test-th-eval "expr 0+0b11"
421 test th1-expr-24 {$RESULT eq 3}
422
423 ###############################################################################
424
425 fossil test-th-eval "expr 0+0o15"
426 test th1-expr-25 {$RESULT eq 13}
427
428 ###############################################################################
429
430 fossil test-th-eval "expr 0+0x15"
431 test th1-expr-26 {$RESULT eq 21}
432
433 ###############################################################################
434
435 fossil test-th-eval "expr 0+0b2"
436 test th1-expr-27 {$RESULT eq {TH_ERROR: expected number, got: "0b2"}}
437
438 ###############################################################################
439
440 fossil test-th-eval "expr 0+0o8"
441 test th1-expr-28 {$RESULT eq {TH_ERROR: expected number, got: "0o8"}}
442
443 ###############################################################################
444
445 fossil test-th-eval "expr 0+0xg"
446 test th1-expr-29 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0xg"}}
447
448 ###############################################################################
449
450 fossil test-th-eval "expr 0+0b1."
451 test th1-expr-30 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0b1."}}
452
453 ###############################################################################
454
455 fossil test-th-eval "expr 0+0o1."
456 test th1-expr-31 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0o1."}}
457
458 ###############################################################################
459
460 fossil test-th-eval "expr 0+0x1."
461 test th1-expr-32 {$RESULT eq {TH_ERROR: syntax error in expression: "0+0x1."}}
462
463 ###############################################################################
464
465 fossil test-th-eval "expr 0ne5"
466 test th1-expr-33 {$RESULT eq {1}}
467
468 ###############################################################################
469
470 fossil test-th-eval "expr 0b1+5"
471 test th1-expr-34 {$RESULT eq {6}}
472

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button