| | @@ -37,10 +37,11 @@ |
| 37 | 37 | #define TCL_PLATFORM_OS "unknown" |
| 38 | 38 | #define TCL_PLATFORM_PLATFORM "unix" |
| 39 | 39 | #define TCL_PLATFORM_PATH_SEPARATOR ":" |
| 40 | 40 | #define HAVE_VFORK |
| 41 | 41 | #define HAVE_WAITPID |
| 42 | +#define HAVE_ISATTY |
| 42 | 43 | #define HAVE_SYS_TIME_H |
| 43 | 44 | #define HAVE_DIRENT_H |
| 44 | 45 | #define HAVE_UNISTD_H |
| 45 | 46 | #endif |
| 46 | 47 | #ifndef JIM_WIN32COMPAT_H |
| | @@ -532,10 +533,11 @@ |
| 532 | 533 | structure. */ |
| 533 | 534 | int local; |
| 534 | 535 | Jim_Obj *liveList; |
| 535 | 536 | Jim_Obj *freeList; |
| 536 | 537 | Jim_Obj *currentScriptObj; |
| 538 | + Jim_Obj *nullScriptObj; |
| 537 | 539 | Jim_Obj *emptyObj; |
| 538 | 540 | Jim_Obj *trueObj; |
| 539 | 541 | Jim_Obj *falseObj; |
| 540 | 542 | unsigned long referenceNextId; |
| 541 | 543 | struct Jim_HashTable references; |
| | @@ -1078,13 +1080,108 @@ |
| 1078 | 1080 | "\n" |
| 1079 | 1081 | "\n" |
| 1080 | 1082 | "\n" |
| 1081 | 1083 | "\n" |
| 1082 | 1084 | "\n" |
| 1085 | +"\n" |
| 1083 | 1086 | "\n" |
| 1084 | 1087 | "package require readdir\n" |
| 1085 | 1088 | "\n" |
| 1089 | +"\n" |
| 1090 | +"proc glob.globdir {dir pattern} {\n" |
| 1091 | +" set result {}\n" |
| 1092 | +" set files [readdir $dir]\n" |
| 1093 | +" lappend files . ..\n" |
| 1094 | +"\n" |
| 1095 | +" foreach name $files {\n" |
| 1096 | +" if {[string match $pattern $name]} {\n" |
| 1097 | +"\n" |
| 1098 | +" if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n" |
| 1099 | +" continue\n" |
| 1100 | +" }\n" |
| 1101 | +" lappend result $name\n" |
| 1102 | +" }\n" |
| 1103 | +" }\n" |
| 1104 | +"\n" |
| 1105 | +" return $result\n" |
| 1106 | +"}\n" |
| 1107 | +"\n" |
| 1108 | +"\n" |
| 1109 | +"\n" |
| 1110 | +"\n" |
| 1111 | +"proc glob.explode {pattern} {\n" |
| 1112 | +" set oldexp {}\n" |
| 1113 | +" set newexp {\"\"}\n" |
| 1114 | +"\n" |
| 1115 | +" while 1 {\n" |
| 1116 | +" set oldexp $newexp\n" |
| 1117 | +" set newexp {}\n" |
| 1118 | +" set ob [string first \\{ $pattern]\n" |
| 1119 | +" set cb [string first \\} $pattern]\n" |
| 1120 | +"\n" |
| 1121 | +" if {$ob < $cb && $ob != -1} {\n" |
| 1122 | +" set mid [string range $pattern 0 $ob-1]\n" |
| 1123 | +" set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n" |
| 1124 | +" if {$pattern eq \"\"} {\n" |
| 1125 | +" error \"unmatched open brace in glob pattern\"\n" |
| 1126 | +" }\n" |
| 1127 | +" set pattern [string range $pattern 1 end]\n" |
| 1128 | +"\n" |
| 1129 | +" foreach subs $subexp {\n" |
| 1130 | +" foreach sub [split $subs ,] {\n" |
| 1131 | +" foreach old $oldexp {\n" |
| 1132 | +" lappend newexp $old$mid$sub\n" |
| 1133 | +" }\n" |
| 1134 | +" }\n" |
| 1135 | +" }\n" |
| 1136 | +" } elseif {$cb != -1} {\n" |
| 1137 | +" set suf [string range $pattern 0 $cb-1]\n" |
| 1138 | +" set rest [string range $pattern $cb end]\n" |
| 1139 | +" break\n" |
| 1140 | +" } else {\n" |
| 1141 | +" set suf $pattern\n" |
| 1142 | +" set rest \"\"\n" |
| 1143 | +" break\n" |
| 1144 | +" }\n" |
| 1145 | +" }\n" |
| 1146 | +"\n" |
| 1147 | +" foreach old $oldexp {\n" |
| 1148 | +" lappend newexp $old$suf\n" |
| 1149 | +" }\n" |
| 1150 | +" linsert $newexp 0 $rest\n" |
| 1151 | +"}\n" |
| 1152 | +"\n" |
| 1153 | +"\n" |
| 1154 | +"\n" |
| 1155 | +"proc glob.glob {base pattern} {\n" |
| 1156 | +" set dir [file dirname $pattern]\n" |
| 1157 | +" if {$pattern eq $dir || $pattern eq \"\"} {\n" |
| 1158 | +" return [list [file join $base $dir] $pattern]\n" |
| 1159 | +" } elseif {$pattern eq [file tail $pattern]} {\n" |
| 1160 | +" set dir \"\"\n" |
| 1161 | +" }\n" |
| 1162 | +"\n" |
| 1163 | +"\n" |
| 1164 | +" set dirlist [glob.glob $base $dir]\n" |
| 1165 | +" set pattern [file tail $pattern]\n" |
| 1166 | +"\n" |
| 1167 | +"\n" |
| 1168 | +" set result {}\n" |
| 1169 | +" foreach {realdir dir} $dirlist {\n" |
| 1170 | +" if {![file isdir $realdir]} {\n" |
| 1171 | +" continue\n" |
| 1172 | +" }\n" |
| 1173 | +" if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n" |
| 1174 | +" append dir /\n" |
| 1175 | +" }\n" |
| 1176 | +" foreach name [glob.globdir $realdir $pattern] {\n" |
| 1177 | +" lappend result [file join $realdir $name] $dir$name\n" |
| 1178 | +" }\n" |
| 1179 | +" }\n" |
| 1180 | +" return $result\n" |
| 1181 | +"}\n" |
| 1182 | +"\n" |
| 1086 | 1183 | "\n" |
| 1087 | 1184 | "\n" |
| 1088 | 1185 | "\n" |
| 1089 | 1186 | "\n" |
| 1090 | 1187 | "\n" |
| | @@ -1093,114 +1190,75 @@ |
| 1093 | 1190 | "\n" |
| 1094 | 1191 | "\n" |
| 1095 | 1192 | "\n" |
| 1096 | 1193 | "\n" |
| 1097 | 1194 | "proc glob {args} {\n" |
| 1098 | | -"\n" |
| 1099 | | -"\n" |
| 1100 | | -"\n" |
| 1101 | | -"\n" |
| 1102 | | -" local proc glob.readdir_pattern {dir pattern} {\n" |
| 1103 | | -" set result {}\n" |
| 1104 | | -"\n" |
| 1105 | | -"\n" |
| 1106 | | -" if {$pattern in {. ..}} {\n" |
| 1107 | | -" return $pattern\n" |
| 1108 | | -" }\n" |
| 1109 | | -"\n" |
| 1110 | | -"\n" |
| 1111 | | -" if {[string match {*[[*?]*} $pattern]} {\n" |
| 1112 | | -"\n" |
| 1113 | | -" set files [readdir -nocomplain $dir]\n" |
| 1114 | | -" } elseif {[file isdir $dir] && [file exists $dir/$pattern]} {\n" |
| 1115 | | -" set files [list $pattern]\n" |
| 1116 | | -" } else {\n" |
| 1117 | | -" set files \"\"\n" |
| 1118 | | -" }\n" |
| 1119 | | -"\n" |
| 1120 | | -" foreach name $files {\n" |
| 1121 | | -" if {[string match $pattern $name]} {\n" |
| 1122 | | -"\n" |
| 1123 | | -" if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n" |
| 1124 | | -" continue\n" |
| 1125 | | -" }\n" |
| 1195 | +" set nocomplain 0\n" |
| 1196 | +" set base \"\"\n" |
| 1197 | +"\n" |
| 1198 | +" set n 0\n" |
| 1199 | +" foreach arg $args {\n" |
| 1200 | +" if {[info exists param]} {\n" |
| 1201 | +" set $param $arg\n" |
| 1202 | +" unset param\n" |
| 1203 | +" incr n\n" |
| 1204 | +" continue\n" |
| 1205 | +" }\n" |
| 1206 | +" switch -glob -- $arg {\n" |
| 1207 | +" -d* {\n" |
| 1208 | +" set switch $arg\n" |
| 1209 | +" set param base\n" |
| 1210 | +" }\n" |
| 1211 | +" -n* {\n" |
| 1212 | +" set nocomplain 1\n" |
| 1213 | +" }\n" |
| 1214 | +" -t* {\n" |
| 1215 | +"\n" |
| 1216 | +" }\n" |
| 1217 | +"\n" |
| 1218 | +" -* {\n" |
| 1219 | +" return -code error \"bad option \\\"$switch\\\": must be -directory, -nocomplain, -tails, or --\"\n" |
| 1220 | +" }\n" |
| 1221 | +" -- {\n" |
| 1222 | +" incr n\n" |
| 1223 | +" break\n" |
| 1224 | +" }\n" |
| 1225 | +" * {\n" |
| 1226 | +" break\n" |
| 1227 | +" }\n" |
| 1228 | +" }\n" |
| 1229 | +" incr n\n" |
| 1230 | +" }\n" |
| 1231 | +" if {[info exists param]} {\n" |
| 1232 | +" return -code error \"missing argument to \\\"$switch\\\"\"\n" |
| 1233 | +" }\n" |
| 1234 | +" if {[llength $args] <= $n} {\n" |
| 1235 | +" return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n" |
| 1236 | +" }\n" |
| 1237 | +"\n" |
| 1238 | +" set args [lrange $args $n end]\n" |
| 1239 | +"\n" |
| 1240 | +" set result {}\n" |
| 1241 | +" foreach pattern $args {\n" |
| 1242 | +" set pattern [string map {\n" |
| 1243 | +" \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n" |
| 1244 | +" } $pattern]\n" |
| 1245 | +" set patexps [lassign [glob.explode $pattern] rest]\n" |
| 1246 | +" if {$rest ne \"\"} {\n" |
| 1247 | +" return -code error \"unmatched close brace in glob pattern\"\n" |
| 1248 | +" }\n" |
| 1249 | +" foreach patexp $patexps {\n" |
| 1250 | +" set patexp [string map {\n" |
| 1251 | +" \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n" |
| 1252 | +" } $patexp]\n" |
| 1253 | +" foreach {realname name} [glob.glob $base $patexp] {\n" |
| 1126 | 1254 | " lappend result $name\n" |
| 1127 | 1255 | " }\n" |
| 1128 | 1256 | " }\n" |
| 1129 | | -"\n" |
| 1130 | | -" return $result\n" |
| 1131 | | -" }\n" |
| 1132 | | -"\n" |
| 1133 | | -"\n" |
| 1134 | | -"\n" |
| 1135 | | -"\n" |
| 1136 | | -"\n" |
| 1137 | | -" proc glob.expandbraces {pattern} {\n" |
| 1138 | | -"\n" |
| 1139 | | -"\n" |
| 1140 | | -" if {[set fb [string first \"\\{\" $pattern]] < 0} {\n" |
| 1141 | | -" return [list $pattern]\n" |
| 1142 | | -" }\n" |
| 1143 | | -" if {[set nb [string first \"\\}\" $pattern $fb]] < 0} {\n" |
| 1144 | | -" return [list $pattern]\n" |
| 1145 | | -" }\n" |
| 1146 | | -" set before [string range $pattern 0 $fb-1]\n" |
| 1147 | | -" set braced [string range $pattern $fb+1 $nb-1]\n" |
| 1148 | | -" set after [string range $pattern $nb+1 end]\n" |
| 1149 | | -"\n" |
| 1150 | | -" lmap part [split $braced ,] {\n" |
| 1151 | | -" set pat $before$part$after\n" |
| 1152 | | -" }\n" |
| 1153 | | -" }\n" |
| 1154 | | -"\n" |
| 1155 | | -"\n" |
| 1156 | | -" proc glob.glob {pattern} {\n" |
| 1157 | | -" set dir [file dirname $pattern]\n" |
| 1158 | | -" if {$dir eq $pattern} {\n" |
| 1159 | | -"\n" |
| 1160 | | -" return [list $dir]\n" |
| 1161 | | -" }\n" |
| 1162 | | -"\n" |
| 1163 | | -"\n" |
| 1164 | | -" set dirlist [glob.glob $dir]\n" |
| 1165 | | -" set pattern [file tail $pattern]\n" |
| 1166 | | -"\n" |
| 1167 | | -"\n" |
| 1168 | | -" set result {}\n" |
| 1169 | | -" foreach dir $dirlist {\n" |
| 1170 | | -" set globdir $dir\n" |
| 1171 | | -" if {[string match \"*/\" $dir]} {\n" |
| 1172 | | -" set sep \"\"\n" |
| 1173 | | -" } elseif {$dir eq \".\"} {\n" |
| 1174 | | -" set globdir \"\"\n" |
| 1175 | | -" set sep \"\"\n" |
| 1176 | | -" } else {\n" |
| 1177 | | -" set sep /\n" |
| 1178 | | -" }\n" |
| 1179 | | -" foreach pat [glob.expandbraces $pattern] {\n" |
| 1180 | | -" foreach name [glob.readdir_pattern $dir $pat] {\n" |
| 1181 | | -" lappend result $globdir$sep$name\n" |
| 1182 | | -" }\n" |
| 1183 | | -" }\n" |
| 1184 | | -" }\n" |
| 1185 | | -" return $result\n" |
| 1186 | | -" }\n" |
| 1187 | | -"\n" |
| 1188 | | -"\n" |
| 1189 | | -" set nocomplain 0\n" |
| 1190 | | -"\n" |
| 1191 | | -" if {[lindex $args 0] eq \"-nocomplain\"} {\n" |
| 1192 | | -" set nocomplain 1\n" |
| 1193 | | -" set args [lrange $args 1 end]\n" |
| 1194 | | -" }\n" |
| 1195 | | -"\n" |
| 1196 | | -" set result {}\n" |
| 1197 | | -" foreach pattern $args {\n" |
| 1198 | | -" lappend result {*}[glob.glob $pattern]\n" |
| 1199 | | -" }\n" |
| 1200 | | -"\n" |
| 1201 | | -" if {$nocomplain == 0 && [llength $result] == 0} {\n" |
| 1257 | +" }\n" |
| 1258 | +"\n" |
| 1259 | +" if {!$nocomplain && [llength $result] == 0} {\n" |
| 1202 | 1260 | " return -code error \"no files matched glob patterns\"\n" |
| 1203 | 1261 | " }\n" |
| 1204 | 1262 | "\n" |
| 1205 | 1263 | " return $result\n" |
| 1206 | 1264 | "}\n" |
| | @@ -1628,10 +1686,11 @@ |
| 1628 | 1686 | " file delete $path\n" |
| 1629 | 1687 | "}\n" |
| 1630 | 1688 | ); |
| 1631 | 1689 | } |
| 1632 | 1690 | |
| 1691 | + |
| 1633 | 1692 | |
| 1634 | 1693 | #include <stdio.h> |
| 1635 | 1694 | #include <string.h> |
| 1636 | 1695 | #include <errno.h> |
| 1637 | 1696 | #include <fcntl.h> |
| | @@ -1651,10 +1710,17 @@ |
| 1651 | 1710 | #endif |
| 1652 | 1711 | |
| 1653 | 1712 | |
| 1654 | 1713 | #define AIO_CMD_LEN 32 |
| 1655 | 1714 | #define AIO_BUF_LEN 256 |
| 1715 | + |
| 1716 | +#ifndef HAVE_FTELLO |
| 1717 | + #define ftello ftell |
| 1718 | +#endif |
| 1719 | +#ifndef HAVE_FSEEKO |
| 1720 | + #define fseeko fseek |
| 1721 | +#endif |
| 1656 | 1722 | |
| 1657 | 1723 | #define AIO_KEEPOPEN 1 |
| 1658 | 1724 | |
| 1659 | 1725 | #if defined(JIM_IPV6) |
| 1660 | 1726 | #define IPV6 1 |
| | @@ -1935,10 +2001,22 @@ |
| 1935 | 2001 | } |
| 1936 | 2002 | JimAioSetError(interp, af->filename); |
| 1937 | 2003 | return JIM_ERR; |
| 1938 | 2004 | } |
| 1939 | 2005 | |
| 2006 | +static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
| 2007 | +{ |
| 2008 | +#ifdef HAVE_ISATTY |
| 2009 | + AioFile *af = Jim_CmdPrivData(interp); |
| 2010 | + Jim_SetResultInt(interp, isatty(fileno(af->fp))); |
| 2011 | +#else |
| 2012 | + Jim_SetResultInt(interp, 0); |
| 2013 | +#endif |
| 2014 | + |
| 2015 | + return JIM_OK; |
| 2016 | +} |
| 2017 | + |
| 1940 | 2018 | |
| 1941 | 2019 | static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
| 1942 | 2020 | { |
| 1943 | 2021 | AioFile *af = Jim_CmdPrivData(interp); |
| 1944 | 2022 | |
| | @@ -1965,11 +2043,11 @@ |
| 1965 | 2043 | |
| 1966 | 2044 | static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
| 1967 | 2045 | { |
| 1968 | 2046 | AioFile *af = Jim_CmdPrivData(interp); |
| 1969 | 2047 | int orig = SEEK_SET; |
| 1970 | | - long offset; |
| 2048 | + jim_wide offset; |
| 1971 | 2049 | |
| 1972 | 2050 | if (argc == 2) { |
| 1973 | 2051 | if (Jim_CompareStringImmediate(interp, argv[1], "start")) |
| 1974 | 2052 | orig = SEEK_SET; |
| 1975 | 2053 | else if (Jim_CompareStringImmediate(interp, argv[1], "current")) |
| | @@ -1978,14 +2056,14 @@ |
| 1978 | 2056 | orig = SEEK_END; |
| 1979 | 2057 | else { |
| 1980 | 2058 | return -1; |
| 1981 | 2059 | } |
| 1982 | 2060 | } |
| 1983 | | - if (Jim_GetLong(interp, argv[0], &offset) != JIM_OK) { |
| 2061 | + if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) { |
| 1984 | 2062 | return JIM_ERR; |
| 1985 | 2063 | } |
| 1986 | | - if (fseek(af->fp, offset, orig) == -1) { |
| 2064 | + if (fseeko(af->fp, offset, orig) == -1) { |
| 1987 | 2065 | JimAioSetError(interp, af->filename); |
| 1988 | 2066 | return JIM_ERR; |
| 1989 | 2067 | } |
| 1990 | 2068 | return JIM_OK; |
| 1991 | 2069 | } |
| | @@ -1992,11 +2070,11 @@ |
| 1992 | 2070 | |
| 1993 | 2071 | static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
| 1994 | 2072 | { |
| 1995 | 2073 | AioFile *af = Jim_CmdPrivData(interp); |
| 1996 | 2074 | |
| 1997 | | - Jim_SetResultInt(interp, ftell(af->fp)); |
| 2075 | + Jim_SetResultInt(interp, ftello(af->fp)); |
| 1998 | 2076 | return JIM_OK; |
| 1999 | 2077 | } |
| 2000 | 2078 | |
| 2001 | 2079 | static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
| 2002 | 2080 | { |
| | @@ -2167,10 +2245,17 @@ |
| 2167 | 2245 | "?-nonewline? str", |
| 2168 | 2246 | aio_cmd_puts, |
| 2169 | 2247 | 1, |
| 2170 | 2248 | 2, |
| 2171 | 2249 | |
| 2250 | + }, |
| 2251 | + { "isatty", |
| 2252 | + NULL, |
| 2253 | + aio_cmd_isatty, |
| 2254 | + 0, |
| 2255 | + 0, |
| 2256 | + |
| 2172 | 2257 | }, |
| 2173 | 2258 | { "flush", |
| 2174 | 2259 | NULL, |
| 2175 | 2260 | aio_cmd_flush, |
| 2176 | 2261 | 0, |
| | @@ -3048,11 +3133,13 @@ |
| 3048 | 3133 | static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
| 3049 | 3134 | { |
| 3050 | 3135 | const char *path = Jim_String(argv[0]); |
| 3051 | 3136 | const char *p = strrchr(path, '/'); |
| 3052 | 3137 | |
| 3053 | | - if (!p) { |
| 3138 | + if (!p && path[0] == '.' && path[1] == '.' && path[2] == '\0') { |
| 3139 | + Jim_SetResultString(interp, "..", -1); |
| 3140 | + } else if (!p) { |
| 3054 | 3141 | Jim_SetResultString(interp, ".", -1); |
| 3055 | 3142 | } |
| 3056 | 3143 | else if (p == path) { |
| 3057 | 3144 | Jim_SetResultString(interp, "/", -1); |
| 3058 | 3145 | } |
| | @@ -3116,16 +3203,17 @@ |
| 3116 | 3203 | const char *path = Jim_String(argv[0]); |
| 3117 | 3204 | char *newname = Jim_Alloc(MAXPATHLEN + 1); |
| 3118 | 3205 | |
| 3119 | 3206 | if (realpath(path, newname)) { |
| 3120 | 3207 | Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1)); |
| 3208 | + return JIM_OK; |
| 3121 | 3209 | } |
| 3122 | 3210 | else { |
| 3123 | 3211 | Jim_Free(newname); |
| 3124 | | - Jim_SetResult(interp, argv[0]); |
| 3212 | + Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno)); |
| 3213 | + return JIM_ERR; |
| 3125 | 3214 | } |
| 3126 | | - return JIM_OK; |
| 3127 | 3215 | #else |
| 3128 | 3216 | Jim_SetResultString(interp, "Not implemented", -1); |
| 3129 | 3217 | return JIM_ERR; |
| 3130 | 3218 | #endif |
| 3131 | 3219 | } |
| | @@ -4934,11 +5022,11 @@ |
| 4934 | 5022 | return env; |
| 4935 | 5023 | } |
| 4936 | 5024 | |
| 4937 | 5025 | static void JimRestoreEnv(char **env) |
| 4938 | 5026 | { |
| 4939 | | - JimFreeEnv(env, NULL); |
| 5027 | + JimFreeEnv(env, Jim_GetEnviron()); |
| 4940 | 5028 | } |
| 4941 | 5029 | |
| 4942 | 5030 | static Jim_Obj * |
| 4943 | 5031 | JimWinBuildCommandLine(Jim_Interp *interp, char **argv) |
| 4944 | 5032 | { |
| | @@ -5869,16 +5957,103 @@ |
| 5869 | 5957 | endptr++; |
| 5870 | 5958 | } |
| 5871 | 5959 | } |
| 5872 | 5960 | return JIM_OK; |
| 5873 | 5961 | } |
| 5962 | + |
| 5963 | +static int JimNumberBase(const char *str, int *base, int *sign) |
| 5964 | +{ |
| 5965 | + int i = 0; |
| 5966 | + |
| 5967 | + *base = 10; |
| 5968 | + |
| 5969 | + while (isspace(UCHAR(str[i]))) { |
| 5970 | + i++; |
| 5971 | + } |
| 5972 | + |
| 5973 | + if (str[i] == '-') { |
| 5974 | + *sign = -1; |
| 5975 | + i++; |
| 5976 | + } |
| 5977 | + else { |
| 5978 | + if (str[i] == '+') { |
| 5979 | + i++; |
| 5980 | + } |
| 5981 | + *sign = 1; |
| 5982 | + } |
| 5983 | + |
| 5984 | + if (str[i] != '0') { |
| 5985 | + |
| 5986 | + return 0; |
| 5987 | + } |
| 5988 | + |
| 5989 | + |
| 5990 | + switch (str[i + 1]) { |
| 5991 | + case 'x': case 'X': *base = 16; break; |
| 5992 | + case 'o': case 'O': *base = 8; break; |
| 5993 | + case 'b': case 'B': *base = 2; break; |
| 5994 | + default: return 0; |
| 5995 | + } |
| 5996 | + i += 2; |
| 5997 | + |
| 5998 | + if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) { |
| 5999 | + |
| 6000 | + return i; |
| 6001 | + } |
| 6002 | + |
| 6003 | + return 10; |
| 6004 | +} |
| 6005 | + |
| 6006 | +static long jim_strtol(const char *str, char **endptr) |
| 6007 | +{ |
| 6008 | + int sign; |
| 6009 | + int base; |
| 6010 | + int i = JimNumberBase(str, &base, &sign); |
| 6011 | + |
| 6012 | + if (base != 10) { |
| 6013 | + long value = strtol(str + i, endptr, base); |
| 6014 | + if (endptr == NULL || *endptr != str + i) { |
| 6015 | + return value * sign; |
| 6016 | + } |
| 6017 | + } |
| 6018 | + |
| 6019 | + |
| 6020 | + return strtol(str, endptr, 10); |
| 6021 | +} |
| 6022 | + |
| 6023 | + |
| 6024 | +static jim_wide jim_strtoull(const char *str, char **endptr) |
| 6025 | +{ |
| 6026 | +#ifdef HAVE_LONG_LONG |
| 6027 | + int sign; |
| 6028 | + int base; |
| 6029 | + int i = JimNumberBase(str, &base, &sign); |
| 6030 | + |
| 6031 | + if (base != 10) { |
| 6032 | + jim_wide value = strtoull(str + i, endptr, base); |
| 6033 | + if (endptr == NULL || *endptr != str + i) { |
| 6034 | + return value * sign; |
| 6035 | + } |
| 6036 | + } |
| 6037 | + |
| 6038 | + |
| 6039 | + return strtoull(str, endptr, 10); |
| 6040 | +#else |
| 6041 | + return (unsigned long)jim_strtol(str, endptr); |
| 6042 | +#endif |
| 6043 | +} |
| 5874 | 6044 | |
| 5875 | 6045 | int Jim_StringToWide(const char *str, jim_wide * widePtr, int base) |
| 5876 | 6046 | { |
| 5877 | 6047 | char *endptr; |
| 5878 | 6048 | |
| 5879 | | - *widePtr = strtoull(str, &endptr, base); |
| 6049 | + if (base) { |
| 6050 | + *widePtr = strtoull(str, &endptr, base); |
| 6051 | + } |
| 6052 | + else { |
| 6053 | + *widePtr = jim_strtoull(str, &endptr); |
| 6054 | + } |
| 5880 | 6055 | |
| 5881 | 6056 | return JimCheckConversion(str, endptr); |
| 5882 | 6057 | } |
| 5883 | 6058 | |
| 5884 | 6059 | int Jim_DoubleToString(char *buf, double doubleValue) |
| | @@ -7390,27 +7565,10 @@ |
| 7390 | 7565 | Jim_Free(objPtr->bytes); |
| 7391 | 7566 | } |
| 7392 | 7567 | objPtr->bytes = NULL; |
| 7393 | 7568 | } |
| 7394 | 7569 | |
| 7395 | | -#define Jim_SetStringRep(o, b, l) \ |
| 7396 | | - do { (o)->bytes = b; (o)->length = l; } while (0) |
| 7397 | | - |
| 7398 | | -void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length) |
| 7399 | | -{ |
| 7400 | | - if (length == 0) { |
| 7401 | | - objPtr->bytes = JimEmptyStringRep; |
| 7402 | | - objPtr->length = 0; |
| 7403 | | - } |
| 7404 | | - else { |
| 7405 | | - objPtr->bytes = Jim_Alloc(length + 1); |
| 7406 | | - objPtr->length = length; |
| 7407 | | - memcpy(objPtr->bytes, bytes, length); |
| 7408 | | - objPtr->bytes[length] = '\0'; |
| 7409 | | - } |
| 7410 | | -} |
| 7411 | | - |
| 7412 | 7570 | |
| 7413 | 7571 | Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr) |
| 7414 | 7572 | { |
| 7415 | 7573 | Jim_Obj *dupPtr; |
| 7416 | 7574 | |
| | @@ -7417,12 +7575,22 @@ |
| 7417 | 7575 | dupPtr = Jim_NewObj(interp); |
| 7418 | 7576 | if (objPtr->bytes == NULL) { |
| 7419 | 7577 | |
| 7420 | 7578 | dupPtr->bytes = NULL; |
| 7421 | 7579 | } |
| 7580 | + else if (objPtr->length == 0) { |
| 7581 | + |
| 7582 | + dupPtr->bytes = JimEmptyStringRep; |
| 7583 | + dupPtr->length = 0; |
| 7584 | + dupPtr->typePtr = NULL; |
| 7585 | + return dupPtr; |
| 7586 | + } |
| 7422 | 7587 | else { |
| 7423 | | - Jim_InitStringRep(dupPtr, objPtr->bytes, objPtr->length); |
| 7588 | + dupPtr->bytes = Jim_Alloc(objPtr->length + 1); |
| 7589 | + dupPtr->length = objPtr->length; |
| 7590 | + |
| 7591 | + memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1); |
| 7424 | 7592 | } |
| 7425 | 7593 | |
| 7426 | 7594 | |
| 7427 | 7595 | dupPtr->typePtr = objPtr->typePtr; |
| 7428 | 7596 | if (objPtr->typePtr != NULL) { |
| | @@ -7596,13 +7764,12 @@ |
| 7596 | 7764 | |
| 7597 | 7765 | Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len) |
| 7598 | 7766 | { |
| 7599 | 7767 | Jim_Obj *objPtr = Jim_NewObj(interp); |
| 7600 | 7768 | |
| 7601 | | - if (len == -1) |
| 7602 | | - len = strlen(s); |
| 7603 | | - Jim_SetStringRep(objPtr, s, len); |
| 7769 | + objPtr->bytes = s; |
| 7770 | + objPtr->length = len == -1 ? strlen(s) : len; |
| 7604 | 7771 | objPtr->typePtr = NULL; |
| 7605 | 7772 | return objPtr; |
| 7606 | 7773 | } |
| 7607 | 7774 | |
| 7608 | 7775 | static void StringAppendString(Jim_Obj *objPtr, const char *str, int len) |
| | @@ -7818,11 +7985,11 @@ |
| 7818 | 7985 | |
| 7819 | 7986 | if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) { |
| 7820 | 7987 | return NULL; |
| 7821 | 7988 | } |
| 7822 | 7989 | |
| 7823 | | - if (last <= first) { |
| 7990 | + if (last < first) { |
| 7824 | 7991 | return strObjPtr; |
| 7825 | 7992 | } |
| 7826 | 7993 | |
| 7827 | 7994 | str = Jim_String(strObjPtr); |
| 7828 | 7995 | |
| | @@ -8169,19 +8336,19 @@ |
| 8169 | 8336 | Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj); |
| 8170 | 8337 | } |
| 8171 | 8338 | |
| 8172 | 8339 | void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) |
| 8173 | 8340 | { |
| 8174 | | - dupPtr->internalRep = srcPtr->internalRep; |
| 8341 | + dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue; |
| 8175 | 8342 | Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj); |
| 8176 | 8343 | } |
| 8177 | 8344 | |
| 8178 | 8345 | static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, |
| 8179 | 8346 | Jim_Obj *fileNameObj, int lineNumber) |
| 8180 | 8347 | { |
| 8181 | 8348 | JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object")); |
| 8182 | | - JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typePtr != NULL")); |
| 8349 | + JimPanic((objPtr->typePtr == &sourceObjType, "JimSetSourceInfo called with non-source object")); |
| 8183 | 8350 | Jim_IncrRefCount(fileNameObj); |
| 8184 | 8351 | objPtr->internalRep.sourceValue.fileNameObj = fileNameObj; |
| 8185 | 8352 | objPtr->internalRep.sourceValue.lineNumber = lineNumber; |
| 8186 | 8353 | objPtr->typePtr = &sourceObjType; |
| 8187 | 8354 | } |
| | @@ -8557,13 +8724,16 @@ |
| 8557 | 8724 | return JIM_OK; |
| 8558 | 8725 | } |
| 8559 | 8726 | |
| 8560 | 8727 | ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr) |
| 8561 | 8728 | { |
| 8562 | | - struct ScriptObj *script = Jim_GetIntRepPtr(objPtr); |
| 8729 | + if (objPtr == interp->emptyObj) { |
| 8730 | + |
| 8731 | + objPtr = interp->nullScriptObj; |
| 8732 | + } |
| 8563 | 8733 | |
| 8564 | | - if (objPtr->typePtr != &scriptObjType || script->substFlags) { |
| 8734 | + if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) { |
| 8565 | 8735 | SetScriptFromAny(interp, objPtr, NULL); |
| 8566 | 8736 | } |
| 8567 | 8737 | return (ScriptObj *) Jim_GetIntRepPtr(objPtr); |
| 8568 | 8738 | } |
| 8569 | 8739 | |
| | @@ -10045,16 +10215,18 @@ |
| 10045 | 10215 | i->result = i->emptyObj; |
| 10046 | 10216 | i->stackTrace = Jim_NewListObj(i, NULL, 0); |
| 10047 | 10217 | i->unknown = Jim_NewStringObj(i, "unknown", -1); |
| 10048 | 10218 | i->errorProc = i->emptyObj; |
| 10049 | 10219 | i->currentScriptObj = Jim_NewEmptyStringObj(i); |
| 10220 | + i->nullScriptObj = Jim_NewEmptyStringObj(i); |
| 10050 | 10221 | Jim_IncrRefCount(i->emptyObj); |
| 10051 | 10222 | Jim_IncrRefCount(i->errorFileNameObj); |
| 10052 | 10223 | Jim_IncrRefCount(i->result); |
| 10053 | 10224 | Jim_IncrRefCount(i->stackTrace); |
| 10054 | 10225 | Jim_IncrRefCount(i->unknown); |
| 10055 | 10226 | Jim_IncrRefCount(i->currentScriptObj); |
| 10227 | + Jim_IncrRefCount(i->nullScriptObj); |
| 10056 | 10228 | Jim_IncrRefCount(i->errorProc); |
| 10057 | 10229 | Jim_IncrRefCount(i->trueObj); |
| 10058 | 10230 | Jim_IncrRefCount(i->falseObj); |
| 10059 | 10231 | |
| 10060 | 10232 | |
| | @@ -10084,10 +10256,11 @@ |
| 10084 | 10256 | Jim_DecrRefCount(i, i->stackTrace); |
| 10085 | 10257 | Jim_DecrRefCount(i, i->errorProc); |
| 10086 | 10258 | Jim_DecrRefCount(i, i->unknown); |
| 10087 | 10259 | Jim_DecrRefCount(i, i->errorFileNameObj); |
| 10088 | 10260 | Jim_DecrRefCount(i, i->currentScriptObj); |
| 10261 | + Jim_DecrRefCount(i, i->nullScriptObj); |
| 10089 | 10262 | Jim_FreeHashTable(&i->commands); |
| 10090 | 10263 | #ifdef JIM_REFERENCES |
| 10091 | 10264 | Jim_FreeHashTable(&i->references); |
| 10092 | 10265 | #endif |
| 10093 | 10266 | Jim_FreeHashTable(&i->packages); |
| | @@ -10159,11 +10332,11 @@ |
| 10159 | 10332 | if (levelObjPtr) { |
| 10160 | 10333 | str = Jim_String(levelObjPtr); |
| 10161 | 10334 | if (str[0] == '#') { |
| 10162 | 10335 | char *endptr; |
| 10163 | 10336 | |
| 10164 | | - level = strtol(str + 1, &endptr, 0); |
| 10337 | + level = jim_strtol(str + 1, &endptr); |
| 10165 | 10338 | if (str[1] == '\0' || endptr[0] != '\0') { |
| 10166 | 10339 | level = -1; |
| 10167 | 10340 | } |
| 10168 | 10341 | } |
| 10169 | 10342 | else { |
| | @@ -10822,13 +10995,11 @@ |
| 10822 | 10995 | |
| 10823 | 10996 | if (objPtr->typePtr == &listObjType) { |
| 10824 | 10997 | return JIM_OK; |
| 10825 | 10998 | } |
| 10826 | 10999 | |
| 10827 | | -#if 0 |
| 10828 | | - |
| 10829 | | - if (Jim_IsDict(objPtr)) { |
| 11000 | + if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) { |
| 10830 | 11001 | Jim_Obj **listObjPtrPtr; |
| 10831 | 11002 | int len; |
| 10832 | 11003 | int i; |
| 10833 | 11004 | |
| 10834 | 11005 | Jim_DictPairs(interp, objPtr, &listObjPtrPtr, &len); |
| | @@ -10843,11 +11014,10 @@ |
| 10843 | 11014 | objPtr->internalRep.listValue.maxLen = len; |
| 10844 | 11015 | objPtr->internalRep.listValue.ele = listObjPtrPtr; |
| 10845 | 11016 | |
| 10846 | 11017 | return JIM_OK; |
| 10847 | 11018 | } |
| 10848 | | -#endif |
| 10849 | 11019 | |
| 10850 | 11020 | |
| 10851 | 11021 | if (objPtr->typePtr == &sourceObjType) { |
| 10852 | 11022 | fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; |
| 10853 | 11023 | linenr = objPtr->internalRep.sourceValue.lineNumber; |
| | @@ -10866,20 +11036,22 @@ |
| 10866 | 11036 | objPtr->internalRep.listValue.len = 0; |
| 10867 | 11037 | objPtr->internalRep.listValue.maxLen = 0; |
| 10868 | 11038 | objPtr->internalRep.listValue.ele = NULL; |
| 10869 | 11039 | |
| 10870 | 11040 | |
| 10871 | | - JimParserInit(&parser, str, strLen, linenr); |
| 10872 | | - while (!parser.eof) { |
| 10873 | | - Jim_Obj *elementPtr; |
| 10874 | | - |
| 10875 | | - JimParseList(&parser); |
| 10876 | | - if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) |
| 10877 | | - continue; |
| 10878 | | - elementPtr = JimParserGetTokenObj(interp, &parser); |
| 10879 | | - JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline); |
| 10880 | | - ListAppendElement(objPtr, elementPtr); |
| 11041 | + if (strLen) { |
| 11042 | + JimParserInit(&parser, str, strLen, linenr); |
| 11043 | + while (!parser.eof) { |
| 11044 | + Jim_Obj *elementPtr; |
| 11045 | + |
| 11046 | + JimParseList(&parser); |
| 11047 | + if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) |
| 11048 | + continue; |
| 11049 | + elementPtr = JimParserGetTokenObj(interp, &parser); |
| 11050 | + JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline); |
| 11051 | + ListAppendElement(objPtr, elementPtr); |
| 11052 | + } |
| 10881 | 11053 | } |
| 10882 | 11054 | Jim_DecrRefCount(interp, fileNameObj); |
| 10883 | 11055 | return JIM_OK; |
| 10884 | 11056 | } |
| 10885 | 11057 | |
| | @@ -11682,11 +11854,11 @@ |
| 11682 | 11854 | end = 1; |
| 11683 | 11855 | str += 3; |
| 11684 | 11856 | idx = 0; |
| 11685 | 11857 | } |
| 11686 | 11858 | else { |
| 11687 | | - idx = strtol(str, &endptr, 0); |
| 11859 | + idx = jim_strtol(str, &endptr); |
| 11688 | 11860 | |
| 11689 | 11861 | if (endptr == str) { |
| 11690 | 11862 | goto badindex; |
| 11691 | 11863 | } |
| 11692 | 11864 | str = endptr; |
| | @@ -11694,11 +11866,11 @@ |
| 11694 | 11866 | |
| 11695 | 11867 | |
| 11696 | 11868 | if (*str == '+' || *str == '-') { |
| 11697 | 11869 | int sign = (*str == '+' ? 1 : -1); |
| 11698 | 11870 | |
| 11699 | | - idx += sign * strtol(++str, &endptr, 0); |
| 11871 | + idx += sign * jim_strtol(++str, &endptr); |
| 11700 | 11872 | if (str == endptr || *endptr) { |
| 11701 | 11873 | goto badindex; |
| 11702 | 11874 | } |
| 11703 | 11875 | str = endptr; |
| 11704 | 11876 | } |
| | @@ -12769,32 +12941,57 @@ |
| 12769 | 12941 | } |
| 12770 | 12942 | |
| 12771 | 12943 | static int JimParseExprNumber(struct JimParserCtx *pc) |
| 12772 | 12944 | { |
| 12773 | 12945 | int allowdot = 1; |
| 12774 | | - int allowhex = 0; |
| 12946 | + int base = 10; |
| 12775 | 12947 | |
| 12776 | 12948 | |
| 12777 | 12949 | pc->tt = JIM_TT_EXPR_INT; |
| 12778 | 12950 | pc->tstart = pc->p; |
| 12779 | 12951 | pc->tline = pc->linenr; |
| 12952 | + |
| 12953 | + |
| 12954 | + if (pc->p[0] == '0') { |
| 12955 | + switch (pc->p[1]) { |
| 12956 | + case 'x': |
| 12957 | + case 'X': |
| 12958 | + base = 16; |
| 12959 | + allowdot = 0; |
| 12960 | + pc->p += 2; |
| 12961 | + pc->len -= 2; |
| 12962 | + break; |
| 12963 | + case 'o': |
| 12964 | + case 'O': |
| 12965 | + base = 8; |
| 12966 | + allowdot = 0; |
| 12967 | + pc->p += 2; |
| 12968 | + pc->len -= 2; |
| 12969 | + break; |
| 12970 | + case 'b': |
| 12971 | + case 'B': |
| 12972 | + base = 2; |
| 12973 | + allowdot = 0; |
| 12974 | + pc->p += 2; |
| 12975 | + pc->len -= 2; |
| 12976 | + break; |
| 12977 | + } |
| 12978 | + } |
| 12979 | + |
| 12780 | 12980 | while (isdigit(UCHAR(*pc->p)) |
| 12781 | | - || (allowhex && isxdigit(UCHAR(*pc->p))) |
| 12981 | + || (base == 16 && isxdigit(UCHAR(*pc->p))) |
| 12982 | + || (base == 8 && *pc->p >= '0' && *pc->p <= '7') |
| 12983 | + || (base == 2 && (*pc->p == '0' || *pc->p == '1')) |
| 12782 | 12984 | || (allowdot && *pc->p == '.') |
| 12783 | | - || (pc->p - pc->tstart == 1 && *pc->tstart == '0' && (*pc->p == 'x' || *pc->p == 'X')) |
| 12784 | 12985 | ) { |
| 12785 | | - if ((*pc->p == 'x') || (*pc->p == 'X')) { |
| 12786 | | - allowhex = 1; |
| 12787 | | - allowdot = 0; |
| 12788 | | - } |
| 12789 | 12986 | if (*pc->p == '.') { |
| 12790 | 12987 | allowdot = 0; |
| 12791 | 12988 | pc->tt = JIM_TT_EXPR_DOUBLE; |
| 12792 | 12989 | } |
| 12793 | 12990 | pc->p++; |
| 12794 | 12991 | pc->len--; |
| 12795 | | - if (!allowhex && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+' |
| 12992 | + if (base == 10 && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+' |
| 12796 | 12993 | || isdigit(UCHAR(pc->p[1])))) { |
| 12797 | 12994 | pc->p += 2; |
| 12798 | 12995 | pc->len -= 2; |
| 12799 | 12996 | pc->tt = JIM_TT_EXPR_DOUBLE; |
| 12800 | 12997 | } |
| | @@ -13183,29 +13380,39 @@ |
| 13183 | 13380 | case JIM_TT_ESC: |
| 13184 | 13381 | case JIM_TT_VAR: |
| 13185 | 13382 | case JIM_TT_DICTSUGAR: |
| 13186 | 13383 | case JIM_TT_EXPRSUGAR: |
| 13187 | 13384 | case JIM_TT_CMD: |
| 13188 | | - token->objPtr = Jim_NewStringObj(interp, t->token, t->len); |
| 13189 | 13385 | token->type = t->type; |
| 13386 | +strexpr: |
| 13387 | + token->objPtr = Jim_NewStringObj(interp, t->token, t->len); |
| 13190 | 13388 | if (t->type == JIM_TT_CMD) { |
| 13191 | 13389 | |
| 13192 | 13390 | JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line); |
| 13193 | 13391 | } |
| 13194 | 13392 | expr->len++; |
| 13195 | 13393 | break; |
| 13196 | 13394 | |
| 13197 | 13395 | case JIM_TT_EXPR_INT: |
| 13198 | | - token->objPtr = Jim_NewIntObj(interp, strtoull(t->token, NULL, 0)); |
| 13199 | | - token->type = t->type; |
| 13200 | | - expr->len++; |
| 13201 | | - break; |
| 13202 | | - |
| 13203 | 13396 | case JIM_TT_EXPR_DOUBLE: |
| 13204 | | - token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, NULL)); |
| 13205 | | - token->type = t->type; |
| 13206 | | - expr->len++; |
| 13397 | + { |
| 13398 | + char *endptr; |
| 13399 | + if (t->type == JIM_TT_EXPR_INT) { |
| 13400 | + token->objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr)); |
| 13401 | + } |
| 13402 | + else { |
| 13403 | + token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr)); |
| 13404 | + } |
| 13405 | + if (endptr != t->token + t->len) { |
| 13406 | + |
| 13407 | + Jim_FreeNewObj(interp, token->objPtr); |
| 13408 | + token->type = JIM_TT_STR; |
| 13409 | + goto strexpr; |
| 13410 | + } |
| 13411 | + token->type = t->type; |
| 13412 | + expr->len++; |
| 13413 | + } |
| 13207 | 13414 | break; |
| 13208 | 13415 | |
| 13209 | 13416 | case JIM_TT_SUBEXPR_START: |
| 13210 | 13417 | Jim_StackPush(&stack, t); |
| 13211 | 13418 | prevtt = JIM_TT_NONE; |
| | @@ -13984,13 +14191,15 @@ |
| 13984 | 14191 | |
| 13985 | 14192 | int base = descr->type == 'o' ? 8 |
| 13986 | 14193 | : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10; |
| 13987 | 14194 | |
| 13988 | 14195 | |
| 13989 | | - w = strtoull(tok, &endp, base); |
| 13990 | | - if (endp == tok && base == 0) { |
| 13991 | | - w = strtoull(tok, &endp, 10); |
| 14196 | + if (base == 0) { |
| 14197 | + w = jim_strtoull(tok, &endp); |
| 14198 | + } |
| 14199 | + else { |
| 14200 | + w = strtoull(tok, &endp, base); |
| 13992 | 14201 | } |
| 13993 | 14202 | |
| 13994 | 14203 | if (endp != tok) { |
| 13995 | 14204 | |
| 13996 | 14205 | *valObjPtr = Jim_NewIntObj(interp, w); |
| | @@ -14817,10 +15026,15 @@ |
| 14817 | 15026 | (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) { |
| 14818 | 15027 | JimSetProcWrongArgs(interp, argv[0], cmd); |
| 14819 | 15028 | return JIM_ERR; |
| 14820 | 15029 | } |
| 14821 | 15030 | |
| 15031 | + if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) { |
| 15032 | + |
| 15033 | + return JIM_OK; |
| 15034 | + } |
| 15035 | + |
| 14822 | 15036 | |
| 14823 | 15037 | if (interp->framePtr->level == interp->maxCallFrameDepth) { |
| 14824 | 15038 | Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); |
| 14825 | 15039 | return JIM_ERR; |
| 14826 | 15040 | } |
| | @@ -15079,78 +15293,49 @@ |
| 15079 | 15293 | Jim_DecrRefCount(interp, scriptObjPtr); |
| 15080 | 15294 | |
| 15081 | 15295 | return retcode; |
| 15082 | 15296 | } |
| 15083 | 15297 | |
| 15084 | | -static int JimParseSubstStr(struct JimParserCtx *pc) |
| 15298 | +static void JimParseSubst(struct JimParserCtx *pc, int flags) |
| 15085 | 15299 | { |
| 15086 | 15300 | pc->tstart = pc->p; |
| 15087 | 15301 | pc->tline = pc->linenr; |
| 15088 | | - while (pc->len && *pc->p != '$' && *pc->p != '[') { |
| 15302 | + |
| 15303 | + if (pc->len == 0) { |
| 15304 | + pc->tend = pc->p; |
| 15305 | + pc->tt = JIM_TT_EOL; |
| 15306 | + pc->eof = 1; |
| 15307 | + return; |
| 15308 | + } |
| 15309 | + if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { |
| 15310 | + JimParseCmd(pc); |
| 15311 | + return; |
| 15312 | + } |
| 15313 | + if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { |
| 15314 | + if (JimParseVar(pc) == JIM_OK) { |
| 15315 | + return; |
| 15316 | + } |
| 15317 | + |
| 15318 | + pc->tstart = pc->p; |
| 15319 | + flags |= JIM_SUBST_NOVAR; |
| 15320 | + } |
| 15321 | + while (pc->len) { |
| 15322 | + if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { |
| 15323 | + break; |
| 15324 | + } |
| 15325 | + if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { |
| 15326 | + break; |
| 15327 | + } |
| 15089 | 15328 | if (*pc->p == '\\' && pc->len > 1) { |
| 15090 | 15329 | pc->p++; |
| 15091 | 15330 | pc->len--; |
| 15092 | 15331 | } |
| 15093 | 15332 | pc->p++; |
| 15094 | 15333 | pc->len--; |
| 15095 | 15334 | } |
| 15096 | 15335 | pc->tend = pc->p - 1; |
| 15097 | | - pc->tt = JIM_TT_ESC; |
| 15098 | | - return JIM_OK; |
| 15099 | | -} |
| 15100 | | - |
| 15101 | | -static int JimParseSubst(struct JimParserCtx *pc, int flags) |
| 15102 | | -{ |
| 15103 | | - int retval; |
| 15104 | | - |
| 15105 | | - if (pc->len == 0) { |
| 15106 | | - pc->tstart = pc->tend = pc->p; |
| 15107 | | - pc->tline = pc->linenr; |
| 15108 | | - pc->tt = JIM_TT_EOL; |
| 15109 | | - pc->eof = 1; |
| 15110 | | - return JIM_OK; |
| 15111 | | - } |
| 15112 | | - switch (*pc->p) { |
| 15113 | | - case '[': |
| 15114 | | - retval = JimParseCmd(pc); |
| 15115 | | - if (flags & JIM_SUBST_NOCMD) { |
| 15116 | | - pc->tstart--; |
| 15117 | | - pc->tend++; |
| 15118 | | - pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC; |
| 15119 | | - } |
| 15120 | | - return retval; |
| 15121 | | - break; |
| 15122 | | - case '$': |
| 15123 | | - if (JimParseVar(pc) == JIM_ERR) { |
| 15124 | | - pc->tstart = pc->tend = pc->p++; |
| 15125 | | - pc->len--; |
| 15126 | | - pc->tline = pc->linenr; |
| 15127 | | - pc->tt = JIM_TT_STR; |
| 15128 | | - } |
| 15129 | | - else { |
| 15130 | | - if (flags & JIM_SUBST_NOVAR) { |
| 15131 | | - pc->tstart--; |
| 15132 | | - if (flags & JIM_SUBST_NOESC) |
| 15133 | | - pc->tt = JIM_TT_STR; |
| 15134 | | - else |
| 15135 | | - pc->tt = JIM_TT_ESC; |
| 15136 | | - if (*pc->tstart == '{') { |
| 15137 | | - pc->tstart--; |
| 15138 | | - if (*(pc->tend + 1)) |
| 15139 | | - pc->tend++; |
| 15140 | | - } |
| 15141 | | - } |
| 15142 | | - } |
| 15143 | | - break; |
| 15144 | | - default: |
| 15145 | | - retval = JimParseSubstStr(pc); |
| 15146 | | - if (flags & JIM_SUBST_NOESC) |
| 15147 | | - pc->tt = JIM_TT_STR; |
| 15148 | | - return retval; |
| 15149 | | - break; |
| 15150 | | - } |
| 15151 | | - return JIM_OK; |
| 15336 | + pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC; |
| 15152 | 15337 | } |
| 15153 | 15338 | |
| 15154 | 15339 | |
| 15155 | 15340 | static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags) |
| 15156 | 15341 | { |
| | @@ -17173,10 +17358,13 @@ |
| 17173 | 17358 | OPT_TRIM, OPT_TRIMLEFT, OPT_TRIMRIGHT, OPT_TOLOWER, OPT_TOUPPER, OPT_TOTITLE |
| 17174 | 17359 | }; |
| 17175 | 17360 | static const char * const nocase_options[] = { |
| 17176 | 17361 | "-nocase", NULL |
| 17177 | 17362 | }; |
| 17363 | + static const char * const nocase_length_options[] = { |
| 17364 | + "-nocase", "-length", NULL |
| 17365 | + }; |
| 17178 | 17366 | |
| 17179 | 17367 | if (argc < 2) { |
| 17180 | 17368 | Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?"); |
| 17181 | 17369 | return JIM_ERR; |
| 17182 | 17370 | } |
| | @@ -17200,27 +17388,58 @@ |
| 17200 | 17388 | Jim_SetResultInt(interp, len); |
| 17201 | 17389 | return JIM_OK; |
| 17202 | 17390 | |
| 17203 | 17391 | case OPT_COMPARE: |
| 17204 | 17392 | case OPT_EQUAL: |
| 17205 | | - if (argc != 4 && |
| 17206 | | - (argc != 5 || |
| 17207 | | - Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL, |
| 17208 | | - JIM_ENUM_ABBREV) != JIM_OK)) { |
| 17209 | | - Jim_WrongNumArgs(interp, 2, argv, "?-nocase? string1 string2"); |
| 17210 | | - return JIM_ERR; |
| 17211 | | - } |
| 17212 | | - if (opt_case == 0) { |
| 17213 | | - argv++; |
| 17214 | | - } |
| 17215 | | - if (option == OPT_COMPARE || !opt_case) { |
| 17216 | | - Jim_SetResultInt(interp, Jim_StringCompareObj(interp, argv[2], argv[3], !opt_case)); |
| 17217 | | - } |
| 17218 | | - else { |
| 17219 | | - Jim_SetResultBool(interp, Jim_StringEqObj(argv[2], argv[3])); |
| 17220 | | - } |
| 17221 | | - return JIM_OK; |
| 17393 | + { |
| 17394 | + |
| 17395 | + long opt_length = -1; |
| 17396 | + int n = argc - 4; |
| 17397 | + int i = 2; |
| 17398 | + while (n > 0) { |
| 17399 | + int subopt; |
| 17400 | + if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL, |
| 17401 | + JIM_ENUM_ABBREV) != JIM_OK) { |
| 17402 | +badcompareargs: |
| 17403 | + Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2"); |
| 17404 | + return JIM_ERR; |
| 17405 | + } |
| 17406 | + if (subopt == 0) { |
| 17407 | + |
| 17408 | + opt_case = 0; |
| 17409 | + n--; |
| 17410 | + } |
| 17411 | + else { |
| 17412 | + |
| 17413 | + if (n < 2) { |
| 17414 | + goto badcompareargs; |
| 17415 | + } |
| 17416 | + if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) { |
| 17417 | + return JIM_ERR; |
| 17418 | + } |
| 17419 | + n -= 2; |
| 17420 | + } |
| 17421 | + } |
| 17422 | + if (n) { |
| 17423 | + goto badcompareargs; |
| 17424 | + } |
| 17425 | + argv += argc - 2; |
| 17426 | + if (opt_length < 0 && option != OPT_COMPARE && opt_case) { |
| 17427 | + |
| 17428 | + Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1])); |
| 17429 | + } |
| 17430 | + else { |
| 17431 | + if (opt_length >= 0) { |
| 17432 | + n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case); |
| 17433 | + } |
| 17434 | + else { |
| 17435 | + n = Jim_StringCompareObj(interp, argv[0], argv[1], !opt_case); |
| 17436 | + } |
| 17437 | + Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0); |
| 17438 | + } |
| 17439 | + return JIM_OK; |
| 17440 | + } |
| 17222 | 17441 | |
| 17223 | 17442 | case OPT_MATCH: |
| 17224 | 17443 | if (argc != 4 && |
| 17225 | 17444 | (argc != 5 || |
| 17226 | 17445 | Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL, |
| | @@ -17281,11 +17500,11 @@ |
| 17281 | 17500 | |
| 17282 | 17501 | case OPT_REPLACE:{ |
| 17283 | 17502 | Jim_Obj *objPtr; |
| 17284 | 17503 | |
| 17285 | 17504 | if (argc != 5 && argc != 6) { |
| 17286 | | - Jim_WrongNumArgs(interp, 2, argv, "string first last ?newstring?"); |
| 17505 | + Jim_WrongNumArgs(interp, 2, argv, "string first last ?string?"); |
| 17287 | 17506 | return JIM_ERR; |
| 17288 | 17507 | } |
| 17289 | 17508 | objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL); |
| 17290 | 17509 | if (objPtr == NULL) { |
| 17291 | 17510 | return JIM_ERR; |
| | @@ -17739,13 +17958,13 @@ |
| 17739 | 17958 | |
| 17740 | 17959 | listObjPtr = Jim_NewListObj(interp, NULL, 0); |
| 17741 | 17960 | |
| 17742 | 17961 | htiter = Jim_GetHashTableIterator(&interp->references); |
| 17743 | 17962 | while ((he = Jim_NextHashEntry(htiter)) != NULL) { |
| 17744 | | - char buf[JIM_REFERENCE_SPACE]; |
| 17963 | + char buf[JIM_REFERENCE_SPACE + 1]; |
| 17745 | 17964 | Jim_Reference *refPtr = he->u.val; |
| 17746 | | - const jim_wide *refId = he->key; |
| 17965 | + const unsigned long *refId = he->key; |
| 17747 | 17966 | |
| 17748 | 17967 | JimFormatReference(buf, refPtr, *refId); |
| 17749 | 17968 | Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1)); |
| 17750 | 17969 | } |
| 17751 | 17970 | Jim_FreeHashTableIterator(htiter); |
| | @@ -17988,11 +18207,10 @@ |
| 17988 | 18207 | static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) |
| 17989 | 18208 | { |
| 17990 | 18209 | int cmd; |
| 17991 | 18210 | Jim_Obj *objPtr; |
| 17992 | 18211 | int mode = 0; |
| 17993 | | - int nons = 0; |
| 17994 | 18212 | |
| 17995 | 18213 | static const char * const commands[] = { |
| 17996 | 18214 | "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals", |
| 17997 | 18215 | "vars", "version", "patchlevel", "complete", "args", "hostname", |
| 17998 | 18216 | "script", "source", "stacktrace", "nameofexecutable", "returncodes", |
| | @@ -18003,20 +18221,25 @@ |
| 18003 | 18221 | INFO_FRAME, INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS, |
| 18004 | 18222 | INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE, |
| 18005 | 18223 | INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS |
| 18006 | 18224 | }; |
| 18007 | 18225 | |
| 18008 | | - if (argc < 2) { |
| 18009 | | - Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?"); |
| 18010 | | - return JIM_ERR; |
| 18011 | | - } |
| 18226 | +#ifdef jim_ext_namespace |
| 18227 | + int nons = 0; |
| 18228 | + |
| 18012 | 18229 | if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) { |
| 18013 | 18230 | |
| 18014 | 18231 | argc--; |
| 18015 | 18232 | argv++; |
| 18016 | 18233 | nons = 1; |
| 18017 | 18234 | } |
| 18235 | +#endif |
| 18236 | + |
| 18237 | + if (argc < 2) { |
| 18238 | + Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?"); |
| 18239 | + return JIM_ERR; |
| 18240 | + } |
| 18018 | 18241 | if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV) |
| 18019 | 18242 | != JIM_OK) { |
| 18020 | 18243 | return JIM_ERR; |
| 18021 | 18244 | } |
| 18022 | 18245 | |
| 18023 | 18246 | |