Skip to content

Commit f6907f3

Browse files
committed
2.8.17ce4: Fully implemented ce_vsprintf according to standards
1 parent 82971e3 commit f6907f3

2 files changed

Lines changed: 233 additions & 37 deletions

File tree

src/sqlite-ce/os.c

Lines changed: 229 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@
3939
int ce_vsprintf(char *buf, const char *fmt, va_list ap) {
4040
char *p = buf;
4141
const char *f = fmt;
42-
char tmp[32];
43-
int precision;
42+
char tmp[64];
43+
int flag_minus, flag_plus, flag_space, flag_hash, flag_zero;
44+
int width, precision, is_long;
4445

4546
while (*f) {
4647
if (*f != '%') {
@@ -49,22 +50,39 @@ int ce_vsprintf(char *buf, const char *fmt, va_list ap) {
4950
}
5051
f++; /* skip '%' */
5152

52-
/* Handle flags and width (simplified - just skip them) */
53-
while (*f == '-' || *f == '+' || *f == ' ' || *f == '#' || *f == '0') f++;
54-
/* Handle * width specifier - consume the argument */
53+
/* Parse flags */
54+
flag_minus = flag_plus = flag_space = flag_hash = flag_zero = 0;
55+
while (1) {
56+
if (*f == '-') { flag_minus = 1; f++; }
57+
else if (*f == '+') { flag_plus = 1; f++; }
58+
else if (*f == ' ') { flag_space = 1; f++; }
59+
else if (*f == '#') { flag_hash = 1; f++; }
60+
else if (*f == '0') { flag_zero = 1; f++; }
61+
else break;
62+
}
63+
if (flag_minus) flag_zero = 0; /* - overrides 0 */
64+
if (flag_plus) flag_space = 0; /* + overrides space */
65+
66+
/* Parse width */
67+
width = 0;
5568
if (*f == '*') {
56-
(void)va_arg(ap, int);
69+
width = va_arg(ap, int);
70+
if (width < 0) { flag_minus = 1; width = -width; }
5771
f++;
5872
} else {
59-
while (*f >= '0' && *f <= '9') f++;
73+
while (*f >= '0' && *f <= '9') {
74+
width = width * 10 + (*f - '0');
75+
f++;
76+
}
6077
}
6178

6279
/* Parse precision */
63-
precision = -1; /* -1 means use default */
80+
precision = -1;
6481
if (*f == '.') {
6582
f++;
6683
if (*f == '*') {
6784
precision = va_arg(ap, int);
85+
if (precision < 0) precision = -1;
6886
f++;
6987
} else {
7088
precision = 0;
@@ -75,83 +93,245 @@ int ce_vsprintf(char *buf, const char *fmt, va_list ap) {
7593
}
7694
}
7795

78-
/* Handle length modifiers */
79-
if (*f == 'l') f++;
80-
if (*f == 'l') f++; /* ll */
96+
/* Parse length modifier */
97+
is_long = 0;
98+
if (*f == 'l') { is_long = 1; f++; }
99+
if (*f == 'l') { f++; } /* ll treated as l on 32-bit */
81100

101+
/* Format specifier */
82102
switch (*f) {
83103
case 'd': case 'i': {
84-
int val = va_arg(ap, int);
104+
long val = is_long ? va_arg(ap, long) : (long)va_arg(ap, int);
85105
int neg = 0;
86106
char *t = tmp + sizeof(tmp) - 1;
87-
unsigned int uval;
107+
unsigned long uval;
108+
int len, pad;
109+
char sign = 0;
110+
88111
*t = '\0';
89-
if (val < 0) { neg = 1; uval = (unsigned int)(-(val + 1)) + 1; }
90-
else { uval = (unsigned int)val; }
112+
if (val < 0) { neg = 1; uval = (unsigned long)(-(val + 1)) + 1; }
113+
else { uval = (unsigned long)val; }
91114
if (uval == 0) *--t = '0';
92115
while (uval > 0) { *--t = '0' + (uval % 10); uval /= 10; }
93-
if (neg) *--t = '-';
116+
117+
/* Apply precision (minimum digits) */
118+
len = (int)((tmp + sizeof(tmp) - 1) - t);
119+
if (precision > 0) {
120+
while (len < precision) { *--t = '0'; len++; }
121+
}
122+
123+
/* Determine sign character */
124+
if (neg) sign = '-';
125+
else if (flag_plus) sign = '+';
126+
else if (flag_space) sign = ' ';
127+
128+
len = (int)((tmp + sizeof(tmp) - 1) - t);
129+
if (sign) len++;
130+
pad = (width > len) ? width - len : 0;
131+
132+
if (!flag_minus && !flag_zero) while (pad-- > 0) *p++ = ' ';
133+
if (sign) *p++ = sign;
134+
if (!flag_minus && flag_zero) while (pad-- > 0) *p++ = '0';
94135
while (*t) *p++ = *t++;
136+
if (flag_minus) while (pad-- > 0) *p++ = ' ';
95137
break;
96138
}
97139
case 'u': {
98-
unsigned val = va_arg(ap, unsigned);
140+
unsigned long val = is_long ? va_arg(ap, unsigned long) : (unsigned long)va_arg(ap, unsigned);
99141
char *t = tmp + sizeof(tmp) - 1;
142+
int len, pad;
143+
100144
*t = '\0';
101145
if (val == 0) *--t = '0';
102146
while (val > 0) { *--t = '0' + (val % 10); val /= 10; }
147+
148+
if (precision > 0) {
149+
len = (int)((tmp + sizeof(tmp) - 1) - t);
150+
while (len < precision) { *--t = '0'; len++; }
151+
}
152+
153+
len = (int)((tmp + sizeof(tmp) - 1) - t);
154+
pad = (width > len) ? width - len : 0;
155+
156+
if (!flag_minus && !flag_zero) while (pad-- > 0) *p++ = ' ';
157+
if (!flag_minus && flag_zero) while (pad-- > 0) *p++ = '0';
103158
while (*t) *p++ = *t++;
159+
if (flag_minus) while (pad-- > 0) *p++ = ' ';
160+
break;
161+
}
162+
case 'o': {
163+
unsigned long val = is_long ? va_arg(ap, unsigned long) : (unsigned long)va_arg(ap, unsigned);
164+
char *t = tmp + sizeof(tmp) - 1;
165+
int len, pad, need_prefix;
166+
167+
*t = '\0';
168+
need_prefix = (flag_hash && val != 0);
169+
if (val == 0) *--t = '0';
170+
while (val > 0) { *--t = '0' + (val & 7); val >>= 3; }
171+
172+
if (precision > 0) {
173+
len = (int)((tmp + sizeof(tmp) - 1) - t);
174+
while (len < precision) { *--t = '0'; len++; }
175+
}
176+
if (need_prefix && *t != '0') *--t = '0';
177+
178+
len = (int)((tmp + sizeof(tmp) - 1) - t);
179+
pad = (width > len) ? width - len : 0;
180+
181+
if (!flag_minus && !flag_zero) while (pad-- > 0) *p++ = ' ';
182+
if (!flag_minus && flag_zero) while (pad-- > 0) *p++ = '0';
183+
while (*t) *p++ = *t++;
184+
if (flag_minus) while (pad-- > 0) *p++ = ' ';
104185
break;
105186
}
106187
case 'x': case 'X': {
107-
unsigned val = va_arg(ap, unsigned);
188+
unsigned long val = is_long ? va_arg(ap, unsigned long) : (unsigned long)va_arg(ap, unsigned);
108189
char *t = tmp + sizeof(tmp) - 1;
109190
const char *hex = (*f == 'X') ? "0123456789ABCDEF" : "0123456789abcdef";
191+
int len, pad, need_prefix;
192+
110193
*t = '\0';
194+
need_prefix = (flag_hash && val != 0);
111195
if (val == 0) *--t = '0';
112196
while (val > 0) { *--t = hex[val & 0xF]; val >>= 4; }
197+
198+
if (precision > 0) {
199+
len = (int)((tmp + sizeof(tmp) - 1) - t);
200+
while (len < precision) { *--t = '0'; len++; }
201+
}
202+
203+
len = (int)((tmp + sizeof(tmp) - 1) - t);
204+
if (need_prefix) len += 2;
205+
pad = (width > len) ? width - len : 0;
206+
207+
if (!flag_minus && !flag_zero) while (pad-- > 0) *p++ = ' ';
208+
if (need_prefix) { *p++ = '0'; *p++ = (*f == 'X') ? 'X' : 'x'; }
209+
if (!flag_minus && flag_zero) while (pad-- > 0) *p++ = '0';
113210
while (*t) *p++ = *t++;
211+
if (flag_minus) while (pad-- > 0) *p++ = ' ';
114212
break;
115213
}
116214
case 'p': {
117215
unsigned long val = (unsigned long)va_arg(ap, void*);
118216
char *t = tmp + sizeof(tmp) - 1;
217+
int len, pad;
218+
119219
*t = '\0';
120220
if (val == 0) *--t = '0';
121221
while (val > 0) { *--t = "0123456789abcdef"[val & 0xF]; val >>= 4; }
122-
*--t = 'x'; *--t = '0';
222+
223+
len = (int)((tmp + sizeof(tmp) - 1) - t) + 2;
224+
pad = (width > len) ? width - len : 0;
225+
226+
if (!flag_minus) while (pad-- > 0) *p++ = ' ';
227+
*p++ = '0'; *p++ = 'x';
123228
while (*t) *p++ = *t++;
229+
if (flag_minus) while (pad-- > 0) *p++ = ' ';
124230
break;
125231
}
126232
case 's': {
127233
const char *s = va_arg(ap, const char*);
128-
int len;
234+
int len = 0, pad;
235+
const char *t;
236+
129237
if (!s) s = "(null)";
130-
if (precision >= 0) {
131-
/* Copy at most 'precision' characters */
132-
for (len = 0; len < precision && s[len]; len++)
133-
*p++ = s[len];
134-
} else {
135-
while (*s) *p++ = *s++;
136-
}
238+
t = s;
239+
while (*t) { len++; t++; }
240+
if (precision >= 0 && len > precision) len = precision;
241+
pad = (width > len) ? width - len : 0;
242+
243+
if (!flag_minus) while (pad-- > 0) *p++ = ' ';
244+
while (len-- > 0) *p++ = *s++;
245+
if (flag_minus) while (pad-- > 0) *p++ = ' ';
137246
break;
138247
}
139248
case 'c': {
140249
char c = (char)va_arg(ap, int);
250+
int pad = (width > 1) ? width - 1 : 0;
251+
252+
if (!flag_minus) while (pad-- > 0) *p++ = ' ';
141253
*p++ = c;
254+
if (flag_minus) while (pad-- > 0) *p++ = ' ';
142255
break;
143256
}
144257
case '%':
145258
*p++ = '%';
146259
break;
260+
case 'e': case 'E': {
261+
double val = va_arg(ap, double);
262+
int neg = 0, exp = 0, i;
263+
int prec = (precision < 0) ? 6 : precision;
264+
char *t;
265+
double rounder;
266+
int len, pad;
267+
char sign = 0;
268+
char expchar = *f;
269+
270+
if (val < 0) { neg = 1; val = -val; }
271+
272+
/* Normalize to 1.xxx * 10^exp */
273+
if (val != 0) {
274+
while (val >= 10) { val /= 10; exp++; }
275+
while (val < 1) { val *= 10; exp--; }
276+
}
277+
278+
/* Apply rounding */
279+
rounder = 0.5;
280+
for (i = 0; i < prec; i++) rounder *= 0.1;
281+
val += rounder;
282+
if (val >= 10) { val /= 10; exp++; }
283+
284+
/* Build number in tmp */
285+
t = tmp;
286+
if (neg) sign = '-';
287+
else if (flag_plus) sign = '+';
288+
else if (flag_space) sign = ' ';
289+
290+
/* Integer part (single digit) */
291+
*t++ = '0' + (int)val;
292+
val -= (int)val;
293+
294+
/* Fractional part */
295+
if (prec > 0 || flag_hash) {
296+
*t++ = '.';
297+
for (i = 0; i < prec; i++) {
298+
val *= 10;
299+
*t++ = '0' + (int)val;
300+
val -= (int)val;
301+
}
302+
}
303+
304+
/* Exponent */
305+
*t++ = expchar;
306+
*t++ = (exp < 0) ? '-' : '+';
307+
if (exp < 0) exp = -exp;
308+
if (exp < 10) *t++ = '0';
309+
if (exp >= 100) { *t++ = '0' + (exp / 100); exp %= 100; }
310+
if (exp >= 10) { *t++ = '0' + (exp / 10); exp %= 10; }
311+
*t++ = '0' + exp;
312+
*t = '\0';
313+
314+
len = (int)(t - tmp);
315+
if (sign) len++;
316+
pad = (width > len) ? width - len : 0;
317+
318+
if (!flag_minus && !flag_zero) while (pad-- > 0) *p++ = ' ';
319+
if (sign) *p++ = sign;
320+
if (!flag_minus && flag_zero) while (pad-- > 0) *p++ = '0';
321+
t = tmp;
322+
while (*t) *p++ = *t++;
323+
if (flag_minus) while (pad-- > 0) *p++ = ' ';
324+
break;
325+
}
147326
case 'g': case 'f': {
148327
double val = va_arg(ap, double);
149328
int neg = 0;
150329
int prec = (precision < 0) ? 6 : precision;
151-
int intpart;
330+
int intpart, i;
152331
char *t;
153332
double rounder;
154-
int i;
333+
int len, pad;
334+
char sign = 0;
155335

156336
if (val < 0) { neg = 1; val = -val; }
157337

@@ -162,24 +342,38 @@ int ce_vsprintf(char *buf, const char *fmt, va_list ap) {
162342

163343
intpart = (int)val;
164344

165-
/* Output sign and integer part */
166-
t = tmp + sizeof(tmp) - 1;
345+
/* Build number in tmp */
346+
t = tmp + 30; /* Start in middle, build int part backwards */
167347
*t = '\0';
168348
if (intpart == 0) *--t = '0';
169349
while (intpart > 0) { *--t = '0' + (intpart % 10); intpart /= 10; }
170-
if (neg) *--t = '-';
350+
351+
if (neg) sign = '-';
352+
else if (flag_plus) sign = '+';
353+
else if (flag_space) sign = ' ';
354+
355+
/* Calculate length */
356+
len = (int)((tmp + 30) - t);
357+
if (prec > 0 || flag_hash) len += 1 + prec;
358+
if (sign) len++;
359+
pad = (width > len) ? width - len : 0;
360+
361+
/* Output */
362+
if (!flag_minus && !flag_zero) while (pad-- > 0) *p++ = ' ';
363+
if (sign) *p++ = sign;
364+
if (!flag_minus && flag_zero) while (pad-- > 0) *p++ = '0';
171365
while (*t) *p++ = *t++;
172366

173-
/* Output fractional part if precision > 0 */
174-
if (prec > 0) {
367+
if (prec > 0 || flag_hash) {
175368
*p++ = '.';
176-
val = val - (int)val;
369+
val = val - (int)(val + rounder);
177370
for (i = 0; i < prec; i++) {
178371
val *= 10;
179372
*p++ = '0' + (int)val;
180373
val -= (int)val;
181374
}
182375
}
376+
if (flag_minus) while (pad-- > 0) *p++ = ' ';
183377
break;
184378
}
185379
default:

src/sqlite-ce/sqlite.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,14 @@ extern "C" {
3030
** SQLite/CE versioning: "2.8.17ceX" where X is our port revision.
3131
** ce1 = Initial CE 2.0 port with reimplemented os.c
3232
** ce2 = ROUND() fix (ce_vsprintf precision/rounding)
33+
** ce3 = ABS() fix (ce_vsprintf %.*s precision for strings)
34+
** ce4 = Full C89 printf compliance (width, flags, %o, %e/%E, %l)
3335
*/
34-
#define SQLITE_CE_VERSION 2
36+
#define SQLITE_CE_VERSION 4
3537
#ifdef SQLITE_VERSION
3638
# undef SQLITE_VERSION
3739
#endif
38-
#define SQLITE_VERSION "2.8.17ce3"
40+
#define SQLITE_VERSION "2.8.17ce4"
3941

4042
/*
4143
** The version string is also compiled into the library so that a program

0 commit comments

Comments
 (0)