1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
56
57
58
59
60
61
62
66
67
68
69
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
102
106
107
112
113
114
120
121
124
125
126
135
148
152
153
156
157
158
159
160
161
162
163
166
169
170
171
173
176
177
178
179
180
181
182
183
186
187
188
193
197
200
207
208
209
210
211
212
215
216
217
222
227
231
234
235
238
239
242
243
244
245
246
247
250
251
252
265
266
267
268
269
272
273
276
277
278
279
284
285
288
298
299
300
301
304
305
306
307
308
309
310
311
312
313
314
315
316
319
320
321
324
325
326
330
331
332
341
342
343
344
345
346
347
348
349
350
351
354
355
356
357
358
359
360
361
362
363
364
367
370
371
372
378
379
382
383
391
392
393
397
398
399
400
401
402
403
407
408
409
410
413
416
417
418
422
423
426
429
430
431
432
433
434
441
442
443
449
450
451
452
456
457
458
459
462
463
464
465
466
467
468
469
470
471
472
/* ... */
#include <ctype.h>
#include <string.h>
#include <jim.h>
#include "utf8.h"
#define JIM_INTEGER_SPACE 24
#define MAX_FLOAT_WIDTH 320
/* ... */
Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
{
const char *span, *format, *formatEnd, *msg;
int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
static const char * const mixedXPG =
"cannot mix \"%\" and \"%n$\" conversion specifiers";
static const char * const badIndex[2] = {
"not enough arguments for all format specifiers",
"\"%n$\" argument index out of range"
...};
int formatLen;
Jim_Obj *resultPtr;
/* ... */
char *num_buffer = NULL;
int num_buffer_size = 0;
span = format = Jim_GetString(fmtObjPtr, &formatLen);
formatEnd = format + formatLen;
resultPtr = Jim_NewEmptyStringObj(interp);
while (format != formatEnd) {
char *end;
int gotMinus, sawFlag;
int gotPrecision, useShort;
long width, precision;
int newXpg;
int ch;
int step;
int doubleType;
char pad = ' ';
char spec[2*JIM_INTEGER_SPACE + 12];
char *p;
int formatted_chars;
int formatted_bytes;
const char *formatted_buf;
step = utf8_tounicode(format, &ch);
format += step;
if (ch != '%') {
numBytes += step;
continue;
}if (ch != '%') { ... }
if (numBytes) {
Jim_AppendString(interp, resultPtr, span, numBytes);
numBytes = 0;
}if (numBytes) { ... }
/* ... */
step = utf8_tounicode(format, &ch);
if (ch == '%') {
span = format;
numBytes = step;
format += step;
continue;
}if (ch == '%') { ... }
/* ... */
newXpg = 0;
if (isdigit(ch)) {
int position = strtoul(format, &end, 10);
if (*end == '$') {
newXpg = 1;
objIndex = position - 1;
format = end + 1;
step = utf8_tounicode(format, &ch);
}if (*end == '$') { ... }
}if (isdigit(ch)) { ... }
if (newXpg) {
if (gotSequential) {
msg = mixedXPG;
goto errorMsg;
}if (gotSequential) { ... }
gotXpg = 1;
}if (newXpg) { ... } else {
if (gotXpg) {
msg = mixedXPG;
goto errorMsg;
}if (gotXpg) { ... }
gotSequential = 1;
}else { ... }
if ((objIndex < 0) || (objIndex >= objc)) {
msg = badIndex[gotXpg];
goto errorMsg;
}if ((objIndex < 0) || (objIndex >= objc)) { ... }
/* ... */
p = spec;
*p++ = '%';
gotMinus = 0;
sawFlag = 1;
do {
switch (ch) {
case '-':
gotMinus = 1;
break;case '-':
case '0':
pad = ch;
break;case '0':
case ' ':
case '+':
case '#':
break;case '#':
default:
sawFlag = 0;
continue;default
}switch (ch) { ... }
*p++ = ch;
format += step;
step = utf8_tounicode(format, &ch);
...} while (sawFlag && (p - spec <= 5));
/* ... */
width = 0;
if (isdigit(ch)) {
width = strtoul(format, &end, 10);
format = end;
step = utf8_tounicode(format, &ch);
}if (isdigit(ch)) { ... } else if (ch == '*') {
if (objIndex >= objc - 1) {
msg = badIndex[gotXpg];
goto errorMsg;
}if (objIndex >= objc - 1) { ... }
if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
goto error;
}if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) { ... }
if (width < 0) {
width = -width;
if (!gotMinus) {
*p++ = '-';
gotMinus = 1;
}if (!gotMinus) { ... }
}if (width < 0) { ... }
objIndex++;
format += step;
step = utf8_tounicode(format, &ch);
}else if (ch == '*') { ... }
/* ... */
gotPrecision = precision = 0;
if (ch == '.') {
gotPrecision = 1;
format += step;
step = utf8_tounicode(format, &ch);
}if (ch == '.') { ... }
if (isdigit(ch)) {
precision = strtoul(format, &end, 10);
format = end;
step = utf8_tounicode(format, &ch);
}if (isdigit(ch)) { ... } else if (ch == '*') {
if (objIndex >= objc - 1) {
msg = badIndex[gotXpg];
goto errorMsg;
}if (objIndex >= objc - 1) { ... }
if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
goto error;
}if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) { ... }
/* ... */
if (precision < 0) {
precision = 0;
}if (precision < 0) { ... }
objIndex++;
format += step;
step = utf8_tounicode(format, &ch);
}else if (ch == '*') { ... }
/* ... */
useShort = 0;
if (ch == 'h') {
useShort = 1;
format += step;
step = utf8_tounicode(format, &ch);
}if (ch == 'h') { ... } else if (ch == 'l') {
format += step;
step = utf8_tounicode(format, &ch);
if (ch == 'l') {
format += step;
step = utf8_tounicode(format, &ch);
}if (ch == 'l') { ... }
}else if (ch == 'l') { ... }
format += step;
span = format;
/* ... */
if (ch == 'i') {
ch = 'd';
}if (ch == 'i') { ... }
doubleType = 0;
/* ... */
switch (ch) {
case '\0':
msg = "format string ended in middle of field specifier";
goto errorMsg;case '\0':
case 's': {
formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
if (gotPrecision && (precision < formatted_chars)) {
formatted_chars = precision;
formatted_bytes = utf8_index(formatted_buf, precision);
}if (gotPrecision && (precision < formatted_chars)) { ... }
break;
...}case 's':
case 'c': {
jim_wide code;
if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
goto error;
}if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) { ... }
formatted_bytes = utf8_getchars(spec, code);
formatted_buf = spec;
formatted_chars = 1;
break;
...}case 'c':
case 'b': {
unsigned jim_wide w;
int length;
int i;
int j;
if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) {
goto error;
}if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) { ... }
length = sizeof(w) * 8;
/* ... */
if (num_buffer_size < length + 1) {
num_buffer_size = length + 1;
num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
}if (num_buffer_size < length + 1) { ... }
j = 0;
for (i = length; i > 0; ) {
i--;
if (w & ((unsigned jim_wide)1 << i)) {
num_buffer[j++] = '1';
}if (w & ((unsigned jim_wide)1 << i)) { ... }
else if (j || i == 0) {
num_buffer[j++] = '0';
}else if (j || i == 0) { ... }
}for (i = length; i > 0;) { ... }
num_buffer[j] = 0;
formatted_chars = formatted_bytes = j;
formatted_buf = num_buffer;
break;
...}
case 'b':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
doubleType = 1;
case 'G':
case 'd':
case 'u':
case 'o':
case 'x':
case 'X': {
jim_wide w;
double d;
int length;
if (width) {
p += sprintf(p, "%ld", width);
}if (width) { ... }
if (gotPrecision) {
p += sprintf(p, ".%ld", precision);
}if (gotPrecision) { ... }
if (doubleType) {
if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
goto error;
}if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) { ... }
length = MAX_FLOAT_WIDTH;
}if (doubleType) { ... }
else {
if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
goto error;
}if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) { ... }
length = JIM_INTEGER_SPACE;
if (useShort) {
if (ch == 'd') {
w = (short)w;
}if (ch == 'd') { ... }
else {
w = (unsigned short)w;
}else { ... }
}if (useShort) { ... }
*p++ = 'l';
#ifdef HAVE_LONG_LONG
if (sizeof(long long) == sizeof(jim_wide)) {
*p++ = 'l';
}if (sizeof(long long) == sizeof(jim_wide)) { ... }
/* ... */#endif
}else { ... }
*p++ = (char) ch;
*p = '\0';
if (width > 10000 || length > 10000 || precision > 10000) {
Jim_SetResultString(interp, "format too long", -1);
goto error;
}if (width > 10000 || length > 10000 || precision > 10000) { ... }
if (width > length) {
length = width;
}if (width > length) { ... }
if (gotPrecision) {
length += precision;
}if (gotPrecision) { ... }
if (num_buffer_size < length + 1) {
num_buffer_size = length + 1;
num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
}if (num_buffer_size < length + 1) { ... }
if (doubleType) {
snprintf(num_buffer, length + 1, spec, d);
}if (doubleType) { ... }
else {
formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
}else { ... }
formatted_chars = formatted_bytes = strlen(num_buffer);
formatted_buf = num_buffer;
break;
...}
case 'X':
default: {
spec[0] = ch;
spec[1] = '\0';
Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
goto error;
...}default
}switch (ch) { ... }
if (!gotMinus) {
while (formatted_chars < width) {
Jim_AppendString(interp, resultPtr, &pad, 1);
formatted_chars++;
}while (formatted_chars < width) { ... }
}if (!gotMinus) { ... }
Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
while (formatted_chars < width) {
Jim_AppendString(interp, resultPtr, &pad, 1);
formatted_chars++;
}while (formatted_chars < width) { ... }
objIndex += gotSequential;
}while (format != formatEnd) { ... }
if (numBytes) {
Jim_AppendString(interp, resultPtr, span, numBytes);
}if (numBytes) { ... }
Jim_Free(num_buffer);
return resultPtr;
errorMsg:
Jim_SetResultString(interp, msg, -1);
error:
Jim_FreeNewObj(interp, resultPtr);
Jim_Free(num_buffer);
return NULL;
}{ ... }