diff options
Diffstat (limited to 'lstrlib.c')
-rw-r--r-- | lstrlib.c | 112 |
1 files changed, 86 insertions, 26 deletions
@@ -1090,13 +1090,31 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, | |||
1090 | 1090 | ||
1091 | 1091 | ||
1092 | /* valid flags in a format specification */ | 1092 | /* valid flags in a format specification */ |
1093 | #if !defined(L_FMTFLAGS) | 1093 | #if !defined(L_FMTFLAGSF) |
1094 | #define L_FMTFLAGS "-+ #0" | 1094 | |
1095 | /* valid flags for a, A, e, E, f, F, g, and G conversions */ | ||
1096 | #define L_FMTFLAGSF "-+#0 " | ||
1097 | |||
1098 | /* valid flags for o, x, and X conversions */ | ||
1099 | #define L_FMTFLAGSX "-#0" | ||
1100 | |||
1101 | /* valid flags for d and i conversions */ | ||
1102 | #define L_FMTFLAGSI "-+0 " | ||
1103 | |||
1104 | /* valid flags for u conversions */ | ||
1105 | #define L_FMTFLAGSU "-0" | ||
1106 | |||
1107 | /* valid flags for c, p, and s conversions */ | ||
1108 | #define L_FMTFLAGSC "-" | ||
1109 | |||
1095 | #endif | 1110 | #endif |
1096 | 1111 | ||
1097 | 1112 | ||
1098 | /* | 1113 | /* |
1099 | ** maximum size of each format specification (such as "%-099.99d") | 1114 | ** Maximum size of each format specification (such as "%-099.99d"): |
1115 | ** Initial '%', flags (up to 5), width (2), period, precision (2), | ||
1116 | ** length modifier (8), conversion specifier, and final '\0', plus some | ||
1117 | ** extra. | ||
1100 | */ | 1118 | */ |
1101 | #define MAX_FORMAT 32 | 1119 | #define MAX_FORMAT 32 |
1102 | 1120 | ||
@@ -1189,25 +1207,53 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { | |||
1189 | } | 1207 | } |
1190 | 1208 | ||
1191 | 1209 | ||
1192 | static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { | 1210 | static const char *get2digits (const char *s) { |
1193 | const char *p = strfrmt; | 1211 | if (isdigit(uchar(*s))) { |
1194 | while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++; /* skip flags */ | 1212 | s++; |
1195 | if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char)) | 1213 | if (isdigit(uchar(*s))) s++; /* (2 digits at most) */ |
1196 | luaL_error(L, "invalid format (repeated flags)"); | 1214 | } |
1197 | if (isdigit(uchar(*p))) p++; /* skip width */ | 1215 | return s; |
1198 | if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ | 1216 | } |
1199 | if (*p == '.') { | 1217 | |
1200 | p++; | 1218 | |
1201 | if (isdigit(uchar(*p))) p++; /* skip precision */ | 1219 | /* |
1202 | if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ | 1220 | ** Chech whether a conversion specification is valid. When called, |
1221 | ** first character in 'form' must be '%' and last character must | ||
1222 | ** be a valid conversion specifier. 'flags' are the accepted flags; | ||
1223 | ** 'precision' signals whether to accept a precision. | ||
1224 | */ | ||
1225 | static void checkformat (lua_State *L, const char *form, const char *flags, | ||
1226 | int precision) { | ||
1227 | const char *spec = form + 1; /* skip '%' */ | ||
1228 | spec += strspn(spec, flags); /* skip flags */ | ||
1229 | if (*spec != '0') { /* a width cannot start with '0' */ | ||
1230 | spec = get2digits(spec); /* skip width */ | ||
1231 | if (*spec == '.' && precision) { | ||
1232 | spec++; | ||
1233 | spec = get2digits(spec); /* skip precision */ | ||
1234 | } | ||
1203 | } | 1235 | } |
1204 | if (isdigit(uchar(*p))) | 1236 | if (!isalpha(uchar(*spec))) /* did not go to the end? */ |
1205 | luaL_error(L, "invalid format (width or precision too long)"); | 1237 | luaL_error(L, "invalid conversion specification: '%s'", form); |
1238 | } | ||
1239 | |||
1240 | |||
1241 | /* | ||
1242 | ** Get a conversion specification and copy it to 'form'. | ||
1243 | ** Return the address of its last character. | ||
1244 | */ | ||
1245 | static const char *getformat (lua_State *L, const char *strfrmt, | ||
1246 | char *form) { | ||
1247 | /* spans flags, width, and precision ('0' is included as a flag) */ | ||
1248 | size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789."); | ||
1249 | len++; /* adds following character (should be the specifier) */ | ||
1250 | /* still needs space for '%', '\0', plus a length modifier */ | ||
1251 | if (len >= MAX_FORMAT - 10) | ||
1252 | luaL_error(L, "invalid format (too long)"); | ||
1206 | *(form++) = '%'; | 1253 | *(form++) = '%'; |
1207 | memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); | 1254 | memcpy(form, strfrmt, len * sizeof(char)); |
1208 | form += (p - strfrmt) + 1; | 1255 | *(form + len) = '\0'; |
1209 | *form = '\0'; | 1256 | return strfrmt + len - 1; |
1210 | return p; | ||
1211 | } | 1257 | } |
1212 | 1258 | ||
1213 | 1259 | ||
@@ -1230,6 +1276,7 @@ static int str_format (lua_State *L) { | |||
1230 | size_t sfl; | 1276 | size_t sfl; |
1231 | const char *strfrmt = luaL_checklstring(L, arg, &sfl); | 1277 | const char *strfrmt = luaL_checklstring(L, arg, &sfl); |
1232 | const char *strfrmt_end = strfrmt+sfl; | 1278 | const char *strfrmt_end = strfrmt+sfl; |
1279 | const char *flags; | ||
1233 | luaL_Buffer b; | 1280 | luaL_Buffer b; |
1234 | luaL_buffinit(L, &b); | 1281 | luaL_buffinit(L, &b); |
1235 | while (strfrmt < strfrmt_end) { | 1282 | while (strfrmt < strfrmt_end) { |
@@ -1239,25 +1286,35 @@ static int str_format (lua_State *L) { | |||
1239 | luaL_addchar(&b, *strfrmt++); /* %% */ | 1286 | luaL_addchar(&b, *strfrmt++); /* %% */ |
1240 | else { /* format item */ | 1287 | else { /* format item */ |
1241 | char form[MAX_FORMAT]; /* to store the format ('%...') */ | 1288 | char form[MAX_FORMAT]; /* to store the format ('%...') */ |
1242 | int maxitem = MAX_ITEM; | 1289 | int maxitem = MAX_ITEM; /* maximum length for the result */ |
1243 | char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */ | 1290 | char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */ |
1244 | int nb = 0; /* number of bytes in added item */ | 1291 | int nb = 0; /* number of bytes in result */ |
1245 | if (++arg > top) | 1292 | if (++arg > top) |
1246 | return luaL_argerror(L, arg, "no value"); | 1293 | return luaL_argerror(L, arg, "no value"); |
1247 | strfrmt = scanformat(L, strfrmt, form); | 1294 | strfrmt = getformat(L, strfrmt, form); |
1248 | switch (*strfrmt++) { | 1295 | switch (*strfrmt++) { |
1249 | case 'c': { | 1296 | case 'c': { |
1297 | checkformat(L, form, L_FMTFLAGSC, 0); | ||
1250 | nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); | 1298 | nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); |
1251 | break; | 1299 | break; |
1252 | } | 1300 | } |
1253 | case 'd': case 'i': | 1301 | case 'd': case 'i': |
1254 | case 'o': case 'u': case 'x': case 'X': { | 1302 | flags = L_FMTFLAGSI; |
1303 | goto intcase; | ||
1304 | case 'u': | ||
1305 | flags = L_FMTFLAGSU; | ||
1306 | goto intcase; | ||
1307 | case 'o': case 'x': case 'X': | ||
1308 | flags = L_FMTFLAGSX; | ||
1309 | intcase: { | ||
1255 | lua_Integer n = luaL_checkinteger(L, arg); | 1310 | lua_Integer n = luaL_checkinteger(L, arg); |
1311 | checkformat(L, form, flags, 1); | ||
1256 | addlenmod(form, LUA_INTEGER_FRMLEN); | 1312 | addlenmod(form, LUA_INTEGER_FRMLEN); |
1257 | nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); | 1313 | nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); |
1258 | break; | 1314 | break; |
1259 | } | 1315 | } |
1260 | case 'a': case 'A': | 1316 | case 'a': case 'A': |
1317 | checkformat(L, form, L_FMTFLAGSF, 1); | ||
1261 | addlenmod(form, LUA_NUMBER_FRMLEN); | 1318 | addlenmod(form, LUA_NUMBER_FRMLEN); |
1262 | nb = lua_number2strx(L, buff, maxitem, form, | 1319 | nb = lua_number2strx(L, buff, maxitem, form, |
1263 | luaL_checknumber(L, arg)); | 1320 | luaL_checknumber(L, arg)); |
@@ -1268,12 +1325,14 @@ static int str_format (lua_State *L) { | |||
1268 | /* FALLTHROUGH */ | 1325 | /* FALLTHROUGH */ |
1269 | case 'e': case 'E': case 'g': case 'G': { | 1326 | case 'e': case 'E': case 'g': case 'G': { |
1270 | lua_Number n = luaL_checknumber(L, arg); | 1327 | lua_Number n = luaL_checknumber(L, arg); |
1328 | checkformat(L, form, L_FMTFLAGSF, 1); | ||
1271 | addlenmod(form, LUA_NUMBER_FRMLEN); | 1329 | addlenmod(form, LUA_NUMBER_FRMLEN); |
1272 | nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); | 1330 | nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); |
1273 | break; | 1331 | break; |
1274 | } | 1332 | } |
1275 | case 'p': { | 1333 | case 'p': { |
1276 | const void *p = lua_topointer(L, arg); | 1334 | const void *p = lua_topointer(L, arg); |
1335 | checkformat(L, form, L_FMTFLAGSC, 0); | ||
1277 | if (p == NULL) { /* avoid calling 'printf' with argument NULL */ | 1336 | if (p == NULL) { /* avoid calling 'printf' with argument NULL */ |
1278 | p = "(null)"; /* result */ | 1337 | p = "(null)"; /* result */ |
1279 | form[strlen(form) - 1] = 's'; /* format it as a string */ | 1338 | form[strlen(form) - 1] = 's'; /* format it as a string */ |
@@ -1294,7 +1353,8 @@ static int str_format (lua_State *L) { | |||
1294 | luaL_addvalue(&b); /* keep entire string */ | 1353 | luaL_addvalue(&b); /* keep entire string */ |
1295 | else { | 1354 | else { |
1296 | luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); | 1355 | luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); |
1297 | if (!strchr(form, '.') && l >= 100) { | 1356 | checkformat(L, form, L_FMTFLAGSC, 1); |
1357 | if (strchr(form, '.') == NULL && l >= 100) { | ||
1298 | /* no precision and string is too long to be formatted */ | 1358 | /* no precision and string is too long to be formatted */ |
1299 | luaL_addvalue(&b); /* keep entire string */ | 1359 | luaL_addvalue(&b); /* keep entire string */ |
1300 | } | 1360 | } |