|
1 /************************************************************************ |
|
2 * |
|
3 * printf.cpp - definitions of the rw_printf family of functions |
|
4 * |
|
5 * $Id: printf.cpp 351515 2005-12-01 23:19:44Z sebor $ |
|
6 * |
|
7 ************************************************************************ |
|
8 * |
|
9 * Copyright (c) 1994-2005 Quovadx, Inc., acting through its Rogue Wave |
|
10 * Software division. Licensed under the Apache License, Version 2.0 (the |
|
11 * "License"); you may not use this file except in compliance with the |
|
12 * License. You may obtain a copy of the License at |
|
13 * http://www.apache.org/licenses/LICENSE-2.0. Unless required by |
|
14 * applicable law or agreed to in writing, software distributed under |
|
15 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR |
|
16 * CONDITIONS OF ANY KIND, either express or implied. See the License |
|
17 * for the specific language governing permissions and limitations under |
|
18 * the License. |
|
19 * |
|
20 **************************************************************************/ |
|
21 |
|
22 // expand _TEST_EXPORT macros |
|
23 #define _RWSTD_TEST_SRC |
|
24 #include <testdefs.h> |
|
25 #include <printf.h> |
|
26 |
|
27 #include <assert.h> // for assert |
|
28 #include <errno.h> // for errno, errno constants |
|
29 #include <float.h> // for floating point macros |
|
30 #include <locale.h> |
|
31 #ifndef __SYMBIAN32__ |
|
32 #include <signal.h> // for signal constant |
|
33 #endif |
|
34 #include <stdarg.h> // for va_list, va_start, ... |
|
35 #include <stddef.h> |
|
36 #include <stdio.h> |
|
37 #include <stdlib.h> |
|
38 #include <string.h> |
|
39 #include <wchar.h> |
|
40 |
|
41 #if (defined (_WIN32) || defined (_WIN64)) && !defined(__SYMBIAN32__) |
|
42 // define macros to enable Win98 + WinNT support in <windows.h> |
|
43 # define _WIN32_WINNT 0x0410 |
|
44 # define WINVER 0x400 |
|
45 # include <windows.h> // for IsDebuggerPresent() |
|
46 #else |
|
47 # include <dlfcn.h> |
|
48 #endif // _WIN{32,64} |
|
49 |
|
50 #include <ios> |
|
51 #include <iostream> |
|
52 #include <locale> |
|
53 //#include <string> |
|
54 #include <string.h> |
|
55 |
|
56 #ifdef __ARMCC__ |
|
57 #pragma diag_suppress 61 |
|
58 #pragma diag_suppress 63 |
|
59 #endif |
|
60 |
|
61 #define _RWSTD_NO_EXT_BIN_IO |
|
62 #define _RWSTD_NO_EXT_REENTRANT_IO |
|
63 |
|
64 #ifndef __SYMBIAN32__ |
|
65 |
|
66 _RWSTD_NAMESPACE (__rw) { |
|
67 |
|
68 _RWSTD_EXPORT _RWSTD_SSIZE_T |
|
69 __rw_memattr (const void*, size_t, int); |
|
70 |
|
71 } |
|
72 |
|
73 #endif |
|
74 |
|
75 /********************************************************************/ |
|
76 |
|
77 static const union { |
|
78 int ival; |
|
79 unsigned char bytes [sizeof (int)]; |
|
80 } _rw_one = { 1 }; |
|
81 |
|
82 static const int |
|
83 _rw_big_endian = '\0' == _rw_one.bytes [0]; |
|
84 |
|
85 |
|
86 /********************************************************************/ |
|
87 |
|
88 struct FmtSpec; |
|
89 |
|
90 static int |
|
91 _rw_fmtlong (const FmtSpec&, char**, size_t*, long); |
|
92 |
|
93 #ifdef _RWSTD_LONG_LONG |
|
94 |
|
95 static int |
|
96 _rw_fmtllong (const FmtSpec&, char**, size_t*, _RWSTD_LONG_LONG); |
|
97 |
|
98 #endif // _RWSTD_LONG_LONG |
|
99 |
|
100 static int |
|
101 _rw_fmtinteger (FmtSpec*, size_t, char**, size_t*, va_list*); |
|
102 |
|
103 static int |
|
104 _rw_fmtfloating (const FmtSpec&, char**, size_t*, const void*); |
|
105 |
|
106 _RWSTD_INTERNAL int |
|
107 _rw_fmtptr (const FmtSpec&, char**, size_t*, const void*); |
|
108 |
|
109 typedef void (*funptr_t)(); |
|
110 |
|
111 static int |
|
112 _rw_fmtfunptr (const FmtSpec&, char**, size_t*, funptr_t); |
|
113 |
|
114 struct DummyStruct; |
|
115 typedef void (DummyStruct::*memptr_t)() const; |
|
116 |
|
117 static int |
|
118 _rw_fmtmemptr (const FmtSpec&, char**, size_t*, memptr_t); |
|
119 |
|
120 static int |
|
121 _rw_fmtstr (const FmtSpec&, char**, size_t*, const char*, size_t); |
|
122 |
|
123 static int |
|
124 _rw_fmtchr (const FmtSpec&, char**, size_t*, int); |
|
125 |
|
126 static int |
|
127 _rw_fmtwchr (const FmtSpec&, char**, size_t*, wint_t); |
|
128 |
|
129 static int |
|
130 _rw_fmtwstr (const FmtSpec&, char**, size_t*, const wchar_t*, size_t); |
|
131 |
|
132 static int |
|
133 _rw_fmterrno (const FmtSpec&, char**, size_t*, int); |
|
134 |
|
135 static int |
|
136 _rw_fmtopenmode (const FmtSpec&, char**, size_t*, int); |
|
137 |
|
138 static int |
|
139 _rw_fmtevent (const FmtSpec&, char**, size_t*, int); |
|
140 |
|
141 static int |
|
142 _rw_fmtmonpat (const FmtSpec&, char**, size_t*, const char [4]); |
|
143 |
|
144 static int |
|
145 _rw_fmtsignal (const FmtSpec&, char**, size_t*, int); |
|
146 |
|
147 /********************************************************************/ |
|
148 |
|
149 struct FmtSpec |
|
150 { |
|
151 // optional flags |
|
152 unsigned fl_minus : 1; |
|
153 unsigned fl_plus : 1; |
|
154 unsigned fl_pound : 1; |
|
155 unsigned fl_space : 1; |
|
156 unsigned fl_zero : 1; |
|
157 |
|
158 // optional modifiers |
|
159 unsigned mod_A : 1; // extension (Arrays) |
|
160 unsigned mod_h : 1; // short modifier |
|
161 unsigned mod_hh : 1; // char modifier |
|
162 unsigned mod_l : 1; // long modifier |
|
163 unsigned mod_ll : 1; // long long modifier |
|
164 unsigned mod_j : 1; // intmax_t modifier |
|
165 unsigned mod_z : 1; // size_t modifier |
|
166 unsigned mod_t : 1; // ptrdiff_t modifier |
|
167 unsigned mod_L : 1; // long double modifier |
|
168 unsigned mod_I : 1; // extension |
|
169 |
|
170 unsigned cond : 1; // have an if/else clause |
|
171 unsigned cond_true : 1; // if/else clause is active (true) |
|
172 unsigned cond_begin : 1; // beginning of an if/else clause |
|
173 unsigned cond_end : 1; // end of an if/else clause |
|
174 |
|
175 // note that the signedness of a bitfield is implementation-defined |
|
176 // unless explicitly declared signed or unsigned |
|
177 |
|
178 // extension: 8, 16, 32, and 64 bit integer width modifier |
|
179 signed int iwidth : 4; |
|
180 |
|
181 // extension: optional numerical base 2 - 36 |
|
182 signed int base : 7; |
|
183 |
|
184 // extension: optional parameter number |
|
185 long paramno; |
|
186 |
|
187 // optional width and precision |
|
188 int width; |
|
189 int prec; |
|
190 |
|
191 // extension: string argument |
|
192 char *strarg; |
|
193 |
|
194 // required conversion specifier |
|
195 int cvtspec; |
|
196 |
|
197 // extension: fill character |
|
198 int fill; |
|
199 |
|
200 union { |
|
201 |
|
202 #ifndef _RWSTD_NO_LONG_DOUBLE |
|
203 |
|
204 long double ldbl; |
|
205 |
|
206 #endif // _RWSTD_NO_LONG_DOUBLE |
|
207 |
|
208 #ifdef _RWSTD_LONG_LONG |
|
209 |
|
210 _RWSTD_LONG_LONG llong; |
|
211 |
|
212 #endif // _RWSTD_LONG_LONG |
|
213 |
|
214 void* ptr; |
|
215 |
|
216 int i; |
|
217 long lng; |
|
218 |
|
219 _RWSTD_INT32_T i32; |
|
220 |
|
221 #ifdef _RWSTD_INT64_T |
|
222 _RWSTD_INT64_T i64; |
|
223 #endif // _RWSTD_INT64_T |
|
224 |
|
225 ptrdiff_t diff; |
|
226 size_t size; |
|
227 wint_t wi; |
|
228 |
|
229 double dbl; |
|
230 memptr_t memptr; |
|
231 funptr_t funptr; |
|
232 } param; |
|
233 }; |
|
234 |
|
235 /********************************************************************/ |
|
236 |
|
237 /* |
|
238 |
|
239 C99 format specifier: |
|
240 |
|
241 % flags width [ . prec ] mod cvtspec |
|
242 |
|
243 |
|
244 GNU glibc format specifier: |
|
245 |
|
246 % [ paramno $] flags width [ . prec ] mod cvtspec |
|
247 or |
|
248 % [ paramno $] flags width . * [ paramno $] mod cvtspec |
|
249 |
|
250 |
|
251 Extended format specifier: |
|
252 |
|
253 % { [ paramno $] [ flags ] [ width [. prec ]] mod cvtspec } |
|
254 or |
|
255 % { [ paramno $] [ flags ] [@ base [. width [. prec ]]] mod cvtspec } |
|
256 or |
|
257 % { $ envvar } |
|
258 |
|
259 |
|
260 */ |
|
261 |
|
262 static int |
|
263 _rw_fmtspec (FmtSpec *pspec, bool ext, const char *fmt, va_list *pva) |
|
264 { |
|
265 assert (0 != pspec); |
|
266 assert (0 != fmt); |
|
267 assert (0 != pva); |
|
268 |
|
269 memset (pspec, 0, sizeof *pspec); |
|
270 |
|
271 pspec->iwidth = -1; // integer width not specified |
|
272 pspec->width = -1; // width not specified |
|
273 pspec->prec = -1; // precision not specified |
|
274 pspec->base = -1; // base not specified |
|
275 pspec->paramno = -1; // paramno not specified |
|
276 |
|
277 const char* const fmtbeg = fmt; |
|
278 |
|
279 if (ext) { |
|
280 if ('$' == *fmt) { |
|
281 |
|
282 ++fmt; |
|
283 |
|
284 const char *str; |
|
285 if ('*' == *fmt) { |
|
286 str = va_arg (*pva, char*); |
|
287 if (!str) |
|
288 str = ""; |
|
289 ++fmt; |
|
290 } |
|
291 else { |
|
292 str = fmt; |
|
293 fmt += strlen (fmt); |
|
294 } |
|
295 |
|
296 char *tmp = (char*)malloc (strlen (str)); |
|
297 pspec->strarg = strcpy (tmp, str); |
|
298 |
|
299 return int (fmt - fmtbeg); |
|
300 } |
|
301 } |
|
302 |
|
303 // extension: extract the parameter number (if followed by '$') |
|
304 if ('1' <= *fmt && *fmt <= '9') { |
|
305 char *end; |
|
306 const long tmp = strtol (fmt, &end, 10); |
|
307 |
|
308 fmt = end; |
|
309 |
|
310 if ('$' == *fmt) { |
|
311 pspec->paramno = tmp; |
|
312 ++fmt; |
|
313 } |
|
314 else { |
|
315 // when not followed by '$' interpret the number |
|
316 // as the width (i.e., that follows the empty set |
|
317 // of flags) |
|
318 pspec->width = int (tmp); |
|
319 } |
|
320 } |
|
321 |
|
322 if (-1 == pspec->width) { |
|
323 // extract any number of optional flags |
|
324 for ( ; ; ++fmt) { |
|
325 switch (*fmt) { |
|
326 case '-': pspec->fl_minus = true; continue; |
|
327 case '+': pspec->fl_plus = true; continue; |
|
328 case '#': pspec->fl_pound = true; continue; |
|
329 case ' ': pspec->fl_space = true; continue; |
|
330 case '0': pspec->fl_zero = true; continue; |
|
331 } |
|
332 break; |
|
333 } |
|
334 } |
|
335 |
|
336 if (ext && '@' == *fmt) { |
|
337 |
|
338 ++fmt; |
|
339 |
|
340 // extract the numerical base |
|
341 if ('0' <= fmt [1] && fmt [1] <= '9') { |
|
342 char *end; |
|
343 pspec->base = int (strtol (fmt, &end, 10)); |
|
344 fmt = end; |
|
345 } |
|
346 else if ('*' == *fmt) { |
|
347 pspec->base = va_arg (*pva, int); |
|
348 ++fmt; |
|
349 } |
|
350 |
|
351 if ('.' == *fmt) |
|
352 ++fmt; |
|
353 } |
|
354 |
|
355 if (-1 == pspec->width) { |
|
356 // extract the optional width |
|
357 if ('0' <= *fmt && *fmt <= '9') { |
|
358 char *end; |
|
359 pspec->width = int (strtol (fmt, &end, 10)); |
|
360 fmt = end; |
|
361 } |
|
362 else if ('*' == *fmt) { |
|
363 pspec->width = va_arg (*pva, int); |
|
364 |
|
365 if (pspec->width < 0) { |
|
366 // 7.19.6.1, p5 of ISO/IEC 9899:1999: |
|
367 // A negative field width argument is taken |
|
368 // as a - flag followed by a positive field width. |
|
369 pspec->width = -pspec->width; |
|
370 pspec->fl_minus = true; |
|
371 } |
|
372 |
|
373 ++fmt; |
|
374 } |
|
375 } |
|
376 |
|
377 // extract the optional precision |
|
378 if ('.' == *fmt) { |
|
379 |
|
380 ++fmt; |
|
381 |
|
382 if ('0' <= *fmt && *fmt <= '9') { |
|
383 char *end; |
|
384 pspec->prec = int (strtol (fmt, &end, 10)); |
|
385 fmt = end; |
|
386 } |
|
387 else if ('*' == *fmt) { |
|
388 pspec->prec = va_arg (*pva, int); |
|
389 ++fmt; |
|
390 } |
|
391 } |
|
392 |
|
393 // extract an optional modifier |
|
394 switch (*fmt) { |
|
395 case 'A': |
|
396 if (ext) { |
|
397 ++fmt; |
|
398 pspec->mod_A = true; |
|
399 break; |
|
400 } |
|
401 // fall thru |
|
402 |
|
403 case 'h': |
|
404 if ('h' == fmt [1]) { |
|
405 ++fmt; |
|
406 pspec->mod_hh = true; |
|
407 } |
|
408 else |
|
409 pspec->mod_h = true; |
|
410 ++fmt; |
|
411 break; |
|
412 |
|
413 case 'l': |
|
414 if ('l' == fmt [1]) { |
|
415 ++fmt; |
|
416 pspec->mod_ll = true; |
|
417 } |
|
418 else |
|
419 pspec->mod_l = true; |
|
420 ++fmt; |
|
421 break; |
|
422 |
|
423 case 'j': pspec->mod_j = true; ++fmt; break; |
|
424 case 'z': pspec->mod_z = true; ++fmt; break; |
|
425 case 't': pspec->mod_t = true; ++fmt; break; |
|
426 case 'L': pspec->mod_L = true; ++fmt; break; |
|
427 |
|
428 case 'I': |
|
429 if (ext) { |
|
430 |
|
431 ++fmt; |
|
432 |
|
433 if ('8' == *fmt) { |
|
434 pspec->iwidth = 1; |
|
435 ++fmt; |
|
436 } |
|
437 else if ('1' == fmt [0] && '6' == fmt [1]) { |
|
438 pspec->iwidth = 2; |
|
439 fmt += 2; |
|
440 } |
|
441 else if ('3' == fmt [0] && '2' == fmt [1]) { |
|
442 pspec->iwidth = 3; |
|
443 fmt += 2; |
|
444 } |
|
445 else if ('6' == fmt [0] && '4' == fmt [1]) { |
|
446 pspec->iwidth = 4; |
|
447 fmt += 2; |
|
448 } |
|
449 else { |
|
450 pspec->mod_I = true; |
|
451 } |
|
452 break; |
|
453 } |
|
454 } |
|
455 |
|
456 pspec->cvtspec = *fmt; |
|
457 |
|
458 if (pspec->cvtspec) |
|
459 ++fmt; |
|
460 |
|
461 return int (fmt - fmtbeg); |
|
462 } |
|
463 |
|
464 /********************************************************************/ |
|
465 |
|
466 _RWSTD_INTERNAL char* |
|
467 _rw_bufcat (char **pbuf, size_t *pbufsize, const char *str, size_t len) |
|
468 { |
|
469 assert (0 != pbuf); |
|
470 assert (0 != pbufsize); |
|
471 |
|
472 size_t buflen = *pbuf ? strlen (*pbuf) : 0; |
|
473 const size_t bufree = *pbuf ? *pbufsize - buflen : 0; |
|
474 |
|
475 if (bufree <= len || !*pbuf) { |
|
476 |
|
477 // for guard block |
|
478 static const char deadbeef[] = "\xde\xad\xbe\xef"; |
|
479 |
|
480 size_t newbufsize = *pbufsize * 2 + 4; |
|
481 |
|
482 if (newbufsize <= buflen + len + 4) |
|
483 newbufsize = 2 * (buflen + len + 1) + 4; |
|
484 |
|
485 char* const newbuf = (char*)malloc (newbufsize); |
|
486 |
|
487 // return 0 on failure to allocate, let caller deal with it |
|
488 if (0 == newbuf) |
|
489 return 0; |
|
490 |
|
491 memcpy (newbuf, *pbuf, buflen); |
|
492 |
|
493 // append a guard block to the end of the buffer |
|
494 memcpy (newbuf + newbufsize - 4, deadbeef, 4); |
|
495 |
|
496 if (*pbuf) { |
|
497 // verify that we didn't write past the end of the buffer |
|
498 assert (0 == memcmp (*pbuf + *pbufsize, deadbeef, 4)); |
|
499 free (*pbuf); |
|
500 } |
|
501 |
|
502 *pbuf = newbuf; |
|
503 *pbufsize = newbufsize - 4; |
|
504 |
|
505 (*pbuf)[buflen] = '\0'; |
|
506 } |
|
507 |
|
508 if (0 != str) { |
|
509 memcpy (*pbuf + buflen, str, len); |
|
510 buflen += len; |
|
511 (*pbuf)[buflen] = '\0'; |
|
512 } |
|
513 |
|
514 return *pbuf + buflen; |
|
515 } |
|
516 |
|
517 /********************************************************************/ |
|
518 |
|
519 // rw_asnprintf_cb is called to format a character string according |
|
520 // to the single format specifier `fmt' to the end of the provided |
|
521 // buffer `*pbuf'; the function can reallocate the buffer |
|
522 // returns the number of characters appended to the buffer |
|
523 extern int |
|
524 (*rw_vasnprintf_cb)(FmtSpec*, size_t, char**, size_t*, const char*, va_list*); |
|
525 |
|
526 /********************************************************************/ |
|
527 |
|
528 static int |
|
529 _rw_vasnprintf_c99 (FmtSpec *pspec, size_t paramno, |
|
530 char **pbuf, size_t *pbufsize, va_list *pva) |
|
531 { |
|
532 _RWSTD_UNUSED (paramno); |
|
533 |
|
534 _RWSTD_ASSERT (0 != pspec); |
|
535 |
|
536 int len = -1; |
|
537 |
|
538 FmtSpec &spec = pspec [paramno]; |
|
539 |
|
540 #define PARAM(T, name) \ |
|
541 (0 < spec.paramno ? pspec [spec.paramno - 1].param.name : va_arg (*pva, T)) |
|
542 |
|
543 switch (spec.cvtspec) { |
|
544 |
|
545 case 'd': |
|
546 case 'i': |
|
547 case 'o': |
|
548 case 'x': |
|
549 case 'X': |
|
550 case 'u': |
|
551 len = _rw_fmtinteger (pspec, paramno, pbuf, pbufsize, pva); |
|
552 break; |
|
553 |
|
554 case 'e': |
|
555 case 'E': |
|
556 case 'f': |
|
557 case 'F': |
|
558 case 'g': |
|
559 case 'G': |
|
560 if (spec.mod_L) { |
|
561 spec.param.ldbl = PARAM (long double, ldbl); |
|
562 len = _rw_fmtfloating (spec, pbuf, pbufsize, &spec.param.ldbl); |
|
563 } |
|
564 else { |
|
565 spec.param.dbl = PARAM (double, dbl); |
|
566 len = _rw_fmtfloating (spec, pbuf, pbufsize, &spec.param.dbl); |
|
567 } |
|
568 break; |
|
569 |
|
570 case 'a': |
|
571 assert (!"%a not implemented"); |
|
572 break; |
|
573 |
|
574 case 'A': |
|
575 assert (!"%A not implemented"); |
|
576 break; |
|
577 |
|
578 case 'c': |
|
579 // If no l length modifier is present, the int argument is converted |
|
580 // to an unsigned char, and the resulting character is written. If |
|
581 // an l length modifier is present, the wint_t argument is converted |
|
582 // as if by an ls conversion specification with no precision and an |
|
583 // argument that points to the initial element of a two-element array |
|
584 // of wchar_t, the first element containing the wint_t argument to |
|
585 // the lc conversion specification and the second a null wide |
|
586 // character. |
|
587 if (spec.mod_l) { |
|
588 spec.param.wi = PARAM (wint_t, wi); |
|
589 len = _rw_fmtwchr (spec, pbuf, pbufsize, spec.param.wi); |
|
590 } |
|
591 else { |
|
592 spec.param.i = PARAM (int, i); |
|
593 len = _rw_fmtchr (spec, pbuf, pbufsize, spec.param.i); |
|
594 } |
|
595 break; |
|
596 |
|
597 case 's': |
|
598 if (spec.mod_l) { |
|
599 spec.param.ptr = PARAM (wchar_t*, ptr); |
|
600 const wchar_t* const str = (wchar_t*)spec.param.ptr; |
|
601 len = _rw_fmtwstr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX); |
|
602 } |
|
603 else { |
|
604 spec.param.ptr = PARAM (char*, ptr); |
|
605 const char* const str = (char*)spec.param.ptr; |
|
606 len = _rw_fmtstr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX); |
|
607 } |
|
608 break; |
|
609 |
|
610 case 'p': { |
|
611 // The argument shall be a pointer to void. The value of the pointer |
|
612 // is converted to a sequence of printing characters, in an |
|
613 // implementation-defined manner. |
|
614 spec.param.ptr = PARAM (char*, ptr); |
|
615 len = _rw_fmtptr (spec, pbuf, pbufsize, spec.param.ptr); |
|
616 break; |
|
617 } |
|
618 |
|
619 case 'm': { // %m (popular extension) |
|
620 spec.param.i = errno; |
|
621 len = _rw_fmterrno (spec, pbuf, pbufsize, spec.param.i); |
|
622 break; |
|
623 } |
|
624 |
|
625 case 'n': { |
|
626 // The argument shall be a pointer to signed integer into which |
|
627 // is written the number of characters written to the output |
|
628 // stream so far by this call to fprintf. No argument is converted, |
|
629 // but one is consumed. If the conversion specification includes |
|
630 // any flags, a field width, or a precision, the behavior is |
|
631 // undefined. |
|
632 |
|
633 assert (0 != pbuf); |
|
634 assert (0 != *pbuf); |
|
635 |
|
636 len = int (strlen (*pbuf)); |
|
637 |
|
638 spec.param.ptr = PARAM (void*, ptr); |
|
639 |
|
640 if (spec.mod_hh) { |
|
641 unsigned char* const ptr = (unsigned char*)spec.param.ptr; |
|
642 |
|
643 assert (0 != ptr); |
|
644 |
|
645 *ptr = len; |
|
646 } |
|
647 else if (spec.mod_h) { |
|
648 short* const ptr = (short*)spec.param.ptr; |
|
649 |
|
650 assert (0 != ptr); |
|
651 |
|
652 *ptr = len; |
|
653 } |
|
654 else if (spec.mod_L) { |
|
655 #ifdef _RWSTD_LONG_LONG |
|
656 _RWSTD_LONG_LONG* const ptr = (_RWSTD_LONG_LONG*)spec.param.ptr; |
|
657 |
|
658 assert (0 != ptr); |
|
659 |
|
660 *ptr = len; |
|
661 #else // if !defined (_RWSTD_LONG_LONG) |
|
662 assert (!"%Ln not implemented"); |
|
663 #endif // _RWSTD_LONG_LONG |
|
664 } |
|
665 else if (spec.mod_l) { |
|
666 long* const ptr = (long*)spec.param.ptr; |
|
667 |
|
668 assert (0 != ptr); |
|
669 |
|
670 *ptr = len; |
|
671 } |
|
672 else if (spec.mod_t) { |
|
673 ptrdiff_t* const ptr = (ptrdiff_t*)spec.param.ptr; |
|
674 |
|
675 assert (0 != ptr); |
|
676 |
|
677 *ptr = ptrdiff_t (unsigned (len)); |
|
678 } |
|
679 else { |
|
680 int* const ptr = (int*)spec.param.ptr; |
|
681 |
|
682 assert (0 != ptr); |
|
683 |
|
684 *ptr = len; |
|
685 } |
|
686 break; |
|
687 } |
|
688 |
|
689 case '%': |
|
690 break; |
|
691 } |
|
692 |
|
693 return len; |
|
694 } |
|
695 |
|
696 /********************************************************************/ |
|
697 |
|
698 _TEST_EXPORT int |
|
699 rw_vasnprintf (char **pbuf, size_t *pbufsize, const char *fmt, va_list varg) |
|
700 { |
|
701 va_list *pva; |
|
702 |
|
703 #ifdef va_copy |
|
704 // create a copy of va whose address can be passed to a function |
|
705 // taking a va_list* so that it can modify the original; note that |
|
706 // passing &va is not portable since when declared as a function |
|
707 // argument, va_list that is an array type decays into a pointer |
|
708 // and the address of the pointer will not match va_list* (as is |
|
709 // the case on EM64T) |
|
710 va_list vacpy; |
|
711 va_copy (vacpy, varg); |
|
712 pva = &vacpy; |
|
713 |
|
714 #else // if !defined (va_copy) |
|
715 |
|
716 # if 2 < __GNUG__ |
|
717 |
|
718 // use the gcc 3.x builtin when the va_copy macro is not defined |
|
719 // (e.g., with gcc -ansi or Intel C++ icc -ansi or -strict_ansi) |
|
720 va_list vacpy; |
|
721 __builtin_va_copy (vacpy, varg); |
|
722 pva = &vacpy; |
|
723 |
|
724 # else // if !defined (__GNUG__) |
|
725 |
|
726 // use varg (in)directly and assume it's safe (e.g., HP aCC on PA) |
|
727 pva = &varg; |
|
728 |
|
729 # endif // 2 < __GNUG__ |
|
730 |
|
731 #endif // va_copy |
|
732 |
|
733 // do not use varg of vacpy below this point -- use *pva instead |
|
734 #define varg DONT_TOUCH_ME |
|
735 #define vacpy DONT_TOUCH_ME |
|
736 |
|
737 assert (0 != pbuf); |
|
738 |
|
739 // save the initial value of `pbuf' |
|
740 char* const pbuf_save = *pbuf; |
|
741 |
|
742 if (*pbuf) |
|
743 **pbuf = '\0'; |
|
744 |
|
745 // local buffer for a small number of conversion specifiers |
|
746 // will grow dynamically if their number exceeds its capacity |
|
747 FmtSpec specbuf [32]; |
|
748 FmtSpec *pspec = specbuf; |
|
749 |
|
750 // local buffer for backtrack offsets implementing conditionals |
|
751 int backtrack [32]; |
|
752 int nextoff = 0; |
|
753 |
|
754 size_t default_bufsize = 1024; |
|
755 |
|
756 if (0 == pbufsize) |
|
757 pbufsize = &default_bufsize; |
|
758 |
|
759 char fmtspec [64]; |
|
760 |
|
761 char *next = *pbuf; |
|
762 |
|
763 size_t spec_bufsize = sizeof specbuf / sizeof *specbuf; |
|
764 size_t paramno = 0; |
|
765 |
|
766 for (const char *fc = fmt; *fc; ) { |
|
767 |
|
768 const char* const pcnt = strchr (fc, '%'); |
|
769 |
|
770 size_t nchars = pcnt ? pcnt - fmt : strlen (fc); |
|
771 |
|
772 next = _rw_bufcat (pbuf, pbufsize, fmt, nchars); |
|
773 if (0 == next) |
|
774 goto fail; |
|
775 |
|
776 assert (0 != *pbuf); |
|
777 assert (0 != *pbufsize); |
|
778 |
|
779 if (0 == pcnt) |
|
780 break; |
|
781 |
|
782 fc = pcnt + 1; |
|
783 |
|
784 if ('%' == *fc) { |
|
785 // handle "%%" |
|
786 next = _rw_bufcat (pbuf, pbufsize, "%", 1); |
|
787 if (0 == next) |
|
788 goto fail; |
|
789 |
|
790 fmt = ++fc; |
|
791 continue; |
|
792 } |
|
793 |
|
794 if (spec_bufsize == paramno) { |
|
795 // grow the buffer of conversion specifiers |
|
796 FmtSpec *tmp = (FmtSpec*)malloc (spec_bufsize * 2); |
|
797 if (tmp) { |
|
798 memcpy (tmp, pspec, spec_bufsize); |
|
799 if (pspec != specbuf) |
|
800 free (pspec); |
|
801 pspec = tmp; |
|
802 } |
|
803 else |
|
804 goto fail; |
|
805 } |
|
806 |
|
807 if ('{' == *fc) { |
|
808 const char* const endbrace = strchr (++fc, '}'); |
|
809 |
|
810 assert (0 != endbrace); |
|
811 |
|
812 const size_t fmtlen = endbrace - fc; |
|
813 |
|
814 memcpy (fmtspec, fc, fmtlen); |
|
815 fmtspec [fmtlen] = '\0'; |
|
816 |
|
817 // compute the length of the buffer so far |
|
818 const size_t buflen = next - *pbuf; |
|
819 |
|
820 assert (0 != rw_vasnprintf_cb); |
|
821 |
|
822 // initiaze the current format specification, setting |
|
823 // all unused bits to 0 |
|
824 const int speclen = |
|
825 _rw_fmtspec (pspec + paramno, true, fc, pva); |
|
826 |
|
827 _RWSTD_UNUSED (speclen); |
|
828 |
|
829 // copy the current backtrack offset if one exists |
|
830 // and set the condition and condition true bits |
|
831 if (nextoff) { |
|
832 |
|
833 // set the condition valid bit |
|
834 pspec [paramno].cond = 1; |
|
835 |
|
836 if (backtrack [nextoff - 1] < 0) { |
|
837 // negative offset indicates an active clause |
|
838 pspec [paramno].cond_true = 1; |
|
839 } |
|
840 else { |
|
841 // non-negative offset indicates an inactive clause |
|
842 // no-op |
|
843 } |
|
844 } |
|
845 |
|
846 // append formatted string to the end of the buffer |
|
847 // reallocating it if necessary; callee may change |
|
848 // the specification as necessary (e.g., based on |
|
849 // the if/else clause) |
|
850 |
|
851 int len = |
|
852 rw_vasnprintf_cb (pspec, paramno, pbuf, pbufsize, |
|
853 fmtspec, pva); |
|
854 |
|
855 // the callback returns a negative value on error |
|
856 if (len < 0) |
|
857 goto fail; |
|
858 |
|
859 assert (size_t (len) < *pbufsize); |
|
860 assert (strlen (*pbuf) < *pbufsize); |
|
861 |
|
862 const size_t offinx = nextoff - 1; |
|
863 |
|
864 if (pspec [paramno].cond_end && pspec [paramno].cond_begin) { |
|
865 // change from an if to an else clause |
|
866 |
|
867 assert (0 < nextoff); |
|
868 assert (0 == len); |
|
869 |
|
870 if (pspec [paramno].cond_true) { |
|
871 // change from an inactive if to an active else |
|
872 // (same as the end of an inactive clause) |
|
873 |
|
874 assert (0 <= backtrack [offinx]); |
|
875 |
|
876 // set the length so as to backtrack to the position |
|
877 // saved on the top of the backtrack stack |
|
878 len = -int (buflen) + backtrack [offinx]; |
|
879 |
|
880 // invert the offset to indicate an active clause |
|
881 backtrack [offinx] = ~backtrack [offinx]; |
|
882 } |
|
883 else { |
|
884 // change from an active if to an inactive else |
|
885 assert (backtrack [offinx] < 0); |
|
886 |
|
887 // save the current length of the buffer |
|
888 // as the new backtrack offset |
|
889 backtrack [offinx] = int (buflen); |
|
890 } |
|
891 } |
|
892 else if (pspec [paramno].cond_begin) { |
|
893 // start of a new if clause |
|
894 |
|
895 // push it on the stack of backtracking offsets using |
|
896 // negative values to indicate active clauses and |
|
897 // non-negative values inactive ones |
|
898 if (pspec [paramno].cond_true) |
|
899 backtrack [nextoff++] = ~int (buflen); |
|
900 else |
|
901 backtrack [nextoff++] = int (buflen); |
|
902 } |
|
903 else if (pspec [paramno].cond_end) { |
|
904 // the end of an if/else clause |
|
905 |
|
906 if (!pspec [paramno].cond_true) { |
|
907 // the end of an inactive clause |
|
908 |
|
909 assert (backtrack [offinx] <= int (buflen)); |
|
910 |
|
911 // set the length so as to backtrack to the position |
|
912 // saved on the top of the backtrack stack |
|
913 len = -int (buflen) + backtrack [offinx]; |
|
914 } |
|
915 |
|
916 // pop it off the top of the stack |
|
917 --nextoff; |
|
918 } |
|
919 |
|
920 assert (len + buflen < *pbufsize); |
|
921 |
|
922 // adjust the next pointer to point to the terminating |
|
923 // NUL in the (possibly reallocated) buffer |
|
924 next = *pbuf + buflen + len; |
|
925 *next = '\0'; |
|
926 fc = endbrace + 1; |
|
927 } |
|
928 else { |
|
929 const int speclen = |
|
930 _rw_fmtspec (pspec + paramno, false, fc, pva); |
|
931 |
|
932 if (speclen) { |
|
933 |
|
934 const int len = |
|
935 _rw_vasnprintf_c99 (pspec, paramno, pbuf, pbufsize, pva); |
|
936 |
|
937 if (-1 == len) |
|
938 goto fail; |
|
939 |
|
940 // discard positional specifiers |
|
941 if (-1 == pspec [paramno].paramno) |
|
942 ++paramno; |
|
943 |
|
944 next = _rw_bufcat (pbuf, pbufsize, 0, size_t (len)); |
|
945 if (0 == next) |
|
946 goto fail; |
|
947 |
|
948 next += len; |
|
949 fc += speclen; |
|
950 } |
|
951 else { |
|
952 next = _rw_bufcat (pbuf, pbufsize, "%", 1); |
|
953 if (0 == next) |
|
954 goto fail; |
|
955 } |
|
956 } |
|
957 |
|
958 fmt = fc; |
|
959 } |
|
960 |
|
961 // deallocate if dynamically allocated |
|
962 if (pspec != specbuf) |
|
963 free (pspec); |
|
964 |
|
965 return int (next - *pbuf); |
|
966 |
|
967 fail: // function failed |
|
968 |
|
969 fprintf (stderr, "%s:%d: rw_vasnprintf(%p, %p, \"%s\", va_list) " |
|
970 "error: errno = %d: %s\n", |
|
971 __FILE__, __LINE__, (void*)pbuf, (void*)pbufsize, fmt, |
|
972 errno, strerror (errno)); |
|
973 |
|
974 if (pspec != specbuf) |
|
975 free (pspec); |
|
976 |
|
977 if (*pbuf != pbuf_save) { |
|
978 // free any allocated memory |
|
979 free (*pbuf); |
|
980 *pbuf = 0; |
|
981 } |
|
982 |
|
983 return -1; |
|
984 |
|
985 #undef varg |
|
986 #undef vacpy |
|
987 |
|
988 } |
|
989 |
|
990 /********************************************************************/ |
|
991 |
|
992 static const char _rw_digits[] = { |
|
993 "0123456789abcdefghijklmnopqrstuvwxyz" |
|
994 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|
995 }; |
|
996 |
|
997 static int |
|
998 _rw_fmtlong (const FmtSpec &spec, char **pbuf, size_t *pbufsize, long val) |
|
999 { |
|
1000 char buffer [130]; // big enough for a 128-bit long in base 2 |
|
1001 char *end = buffer; |
|
1002 |
|
1003 long upoff = 0; |
|
1004 const char *pfx = 0; |
|
1005 |
|
1006 if ('X' == spec.cvtspec) |
|
1007 upoff = 36; |
|
1008 |
|
1009 if (spec.fl_pound) { |
|
1010 if (16 == spec.base) |
|
1011 pfx = upoff ? "0X" : "0x"; |
|
1012 else if (8 == spec.base && val) |
|
1013 pfx = "0"; |
|
1014 } |
|
1015 |
|
1016 const int base = 1 < spec.base && spec.base < 37 ? spec.base : 10; |
|
1017 |
|
1018 typedef unsigned long ULong; |
|
1019 |
|
1020 ULong uval; |
|
1021 |
|
1022 bool neg; |
|
1023 |
|
1024 if (val < 0) { |
|
1025 neg = 'd' == spec.cvtspec || 'i' == spec.cvtspec; |
|
1026 uval = ULong (neg ? -val : val); |
|
1027 } |
|
1028 else { |
|
1029 neg = false; |
|
1030 uval = ULong (val); |
|
1031 } |
|
1032 |
|
1033 do { |
|
1034 *end++ = _rw_digits [upoff + uval % base]; |
|
1035 } while (uval /= base); |
|
1036 |
|
1037 int size = int (end - buffer); |
|
1038 |
|
1039 // insert as many zeros as specified by precision |
|
1040 if (-1 < spec.prec && size < spec.prec) { |
|
1041 // FIXME: prevent buffer overrun |
|
1042 for (int i = size; i != spec.prec; ++i) |
|
1043 *end++ = '0'; |
|
1044 } |
|
1045 |
|
1046 // insert octal or hex prefix for non-zero values |
|
1047 if (pfx && val) { |
|
1048 if (pfx [1]) |
|
1049 *end++ = pfx [1]; |
|
1050 *end++ = pfx [0]; |
|
1051 } |
|
1052 |
|
1053 if (neg) |
|
1054 *end++ = '-'; |
|
1055 else if (spec.fl_plus && ('d' == spec.cvtspec || 'i' == spec.cvtspec)) |
|
1056 *end++ = '+'; |
|
1057 |
|
1058 if (0 == spec.prec && 0 == val) { |
|
1059 // 7.19.6.1 of ISO/IEC 9899:1999: |
|
1060 // The result of converting a zero value with a precision |
|
1061 // of zero is no characters. |
|
1062 end = buffer; |
|
1063 } |
|
1064 |
|
1065 *end = '\0'; |
|
1066 |
|
1067 size = int (end - buffer); |
|
1068 |
|
1069 for (char *pc = buffer; pc < end; ++pc) { |
|
1070 const char tmp = *pc; |
|
1071 *pc = *--end; |
|
1072 *end = tmp; |
|
1073 } |
|
1074 |
|
1075 // reset precision to -1 (already handled above) |
|
1076 FmtSpec newspec (spec); |
|
1077 newspec.fl_pound = 0; |
|
1078 newspec.prec = -1; |
|
1079 |
|
1080 // handle justification by formatting the resulting string |
|
1081 return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (size)); |
|
1082 } |
|
1083 |
|
1084 /********************************************************************/ |
|
1085 |
|
1086 #ifdef _RWSTD_LONG_LONG |
|
1087 |
|
1088 static int |
|
1089 _rw_fmtllong (const FmtSpec &spec, |
|
1090 char **pbuf, size_t *pbufsize, _RWSTD_LONG_LONG val) |
|
1091 { |
|
1092 char buffer [130]; // big enough for a 128-bit long long in base 2 |
|
1093 char *end = buffer; |
|
1094 |
|
1095 long upoff = 0; |
|
1096 const char *pfx = 0; |
|
1097 |
|
1098 if ('X' == spec.cvtspec) |
|
1099 upoff = 36; |
|
1100 |
|
1101 if (spec.fl_pound) { |
|
1102 if (16 == spec.base) |
|
1103 pfx = upoff ? "0X" : "0x"; |
|
1104 else if (8 == spec.base && val) |
|
1105 pfx = "0"; |
|
1106 } |
|
1107 |
|
1108 const int base = 1 < spec.base && spec.base < 37 ? spec.base : 10; |
|
1109 |
|
1110 typedef unsigned _RWSTD_LONG_LONG ULLong; |
|
1111 |
|
1112 ULLong uval; |
|
1113 |
|
1114 bool neg; |
|
1115 |
|
1116 if (val < 0) { |
|
1117 neg = 'd' == spec.cvtspec || 'i' == spec.cvtspec; |
|
1118 uval = ULLong (neg ? -val : val); |
|
1119 } |
|
1120 else { |
|
1121 neg = false; |
|
1122 uval = ULLong (val); |
|
1123 } |
|
1124 |
|
1125 do { |
|
1126 *end++ = _rw_digits [upoff + uval % base]; |
|
1127 } while (uval /= base); |
|
1128 |
|
1129 if (pfx) { |
|
1130 if (pfx [1]) |
|
1131 *end++ = pfx [1]; |
|
1132 *end++ = pfx [0]; |
|
1133 } |
|
1134 |
|
1135 char sign; |
|
1136 |
|
1137 if (neg) |
|
1138 sign = '-'; |
|
1139 else if (spec.fl_plus && ('d' == spec.cvtspec || 'i' == spec.cvtspec)) |
|
1140 sign= '+'; |
|
1141 else |
|
1142 sign = '\0'; |
|
1143 |
|
1144 assert (buffer < end); |
|
1145 size_t size = size_t (end - buffer); |
|
1146 |
|
1147 // FIXME: prevent buffer overrun |
|
1148 if (0 < spec.prec && size < size_t (spec.prec)) { |
|
1149 for (size_t i = size; i != size_t (spec.prec); ++i) |
|
1150 *end++ = '0'; |
|
1151 } |
|
1152 |
|
1153 if (sign) |
|
1154 *end++ = sign; |
|
1155 |
|
1156 *end = '\0'; |
|
1157 |
|
1158 assert (buffer < end); |
|
1159 size = size_t (end - buffer); |
|
1160 |
|
1161 for (char *pc = buffer; pc < end; ++pc) { |
|
1162 const char tmp = *pc; |
|
1163 *pc = *--end; |
|
1164 *end = tmp; |
|
1165 } |
|
1166 |
|
1167 // handle justification by formatting the resulting string |
|
1168 return _rw_fmtstr (spec, pbuf, pbufsize, buffer, size); |
|
1169 } |
|
1170 |
|
1171 #endif // _RWSTD_LONG_LONG |
|
1172 |
|
1173 /********************************************************************/ |
|
1174 |
|
1175 static int |
|
1176 _rw_fmtinteger (FmtSpec *pspec, size_t paramno, |
|
1177 char **pbuf, size_t *pbufsize, va_list *pva) |
|
1178 { |
|
1179 int len = -1; |
|
1180 |
|
1181 FmtSpec &spec = pspec [paramno]; |
|
1182 |
|
1183 switch (spec.cvtspec) { |
|
1184 case 'd': |
|
1185 case 'i': |
|
1186 if (spec.mod_hh) { |
|
1187 // promoted signed char argument |
|
1188 spec.param.i = PARAM (int, i); |
|
1189 const signed char val = spec.param.i; |
|
1190 len = _rw_fmtlong (spec, pbuf, pbufsize, long (val)); |
|
1191 } |
|
1192 else if (spec.mod_h) { |
|
1193 // promoted signed short argument |
|
1194 spec.param.i = PARAM (int, i); |
|
1195 const short val = spec.param.i; |
|
1196 len = _rw_fmtlong (spec, pbuf, pbufsize, long (val)); |
|
1197 } |
|
1198 else if (spec.mod_l) { // %li |
|
1199 spec.param.lng = PARAM (long, lng); |
|
1200 len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.lng); |
|
1201 } |
|
1202 else if (spec.mod_ll) { // %lli |
|
1203 |
|
1204 #ifdef _RWSTD_LONG_LONG |
|
1205 spec.param.llong = PARAM (_RWSTD_LONG_LONG, llong); |
|
1206 len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.llong); |
|
1207 #elif 8 == _RWSTD_LONG_SIZE |
|
1208 spec.param.llong = PARAM (long, lnng); |
|
1209 len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.llong); |
|
1210 #else |
|
1211 assert (!"%lld, %lli: long long not supported"); |
|
1212 |
|
1213 #endif // _RWSTD_LONG_LONG |
|
1214 } |
|
1215 else if (spec.mod_t) { |
|
1216 spec.param.diff = PARAM (ptrdiff_t, diff); |
|
1217 if (sizeof (ptrdiff_t) == sizeof (long)) { |
|
1218 len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.diff); |
|
1219 } |
|
1220 else { |
|
1221 #ifdef _RWSTD_LONG_LONG |
|
1222 len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.diff); |
|
1223 #else // if !defined (_RWSTD_LONG_LONG) |
|
1224 assert (!"%td, %ti: 64-bit types not supported"); |
|
1225 #endif // _RWSTD_LONG_LONG |
|
1226 } |
|
1227 } |
|
1228 else if (1 == spec.iwidth) { |
|
1229 spec.param.i = PARAM (int, i); |
|
1230 const _RWSTD_INT8_T val = spec.param.i; |
|
1231 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1232 } |
|
1233 else if (2 == spec.iwidth) { |
|
1234 spec.param.i = PARAM (int, i); |
|
1235 const _RWSTD_INT16_T val = spec.param.i; |
|
1236 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1237 } |
|
1238 else if (3 == spec.iwidth) { |
|
1239 spec.param.i32 = PARAM (_RWSTD_INT32_T, i32); |
|
1240 const long val = long (spec.param.i32); |
|
1241 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1242 } |
|
1243 else if (4 == spec.iwidth) { |
|
1244 |
|
1245 #ifdef _RWSTD_INT64_T |
|
1246 spec.param.i64 = PARAM (_RWSTD_INT64_T, i64); |
|
1247 #else // if !defined (_RWSTD_INT64_T) |
|
1248 assert (!"%I64d, %I64i: 64-bit types not supported"); |
|
1249 #endif // _RWSTD_INT64_T |
|
1250 |
|
1251 #if 8 == _RWSTD_LONG_SIZE |
|
1252 const long val = spec.param.i64; |
|
1253 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1254 #elif defined (_RWSTD_LONG_LONG) |
|
1255 const _RWSTD_LONG_LONG val = spec.param.i64; |
|
1256 len = _rw_fmtllong (spec, pbuf, pbufsize, val); |
|
1257 #else |
|
1258 assert (!"%I64d, %I64i: 64-bit types not supported"); |
|
1259 #endif |
|
1260 } |
|
1261 else { // %i |
|
1262 spec.param.i = PARAM (int, i); |
|
1263 len = _rw_fmtlong (spec, pbuf, pbufsize, long (spec.param.i)); |
|
1264 } |
|
1265 break; |
|
1266 |
|
1267 case 'o': |
|
1268 assert (-1 == spec.base); |
|
1269 spec.base = 8; |
|
1270 // fall thru |
|
1271 |
|
1272 case 'x': |
|
1273 if (-1 == spec.base) |
|
1274 spec.base = 16; |
|
1275 // fall thru |
|
1276 |
|
1277 case 'X': |
|
1278 if (-1 == spec.base) |
|
1279 spec.base = 16; |
|
1280 |
|
1281 case 'u': |
|
1282 if (spec.mod_hh) { |
|
1283 // promoted unsigned char argument |
|
1284 spec.param.i = PARAM (unsigned, i); |
|
1285 const unsigned char val = spec.param.i; |
|
1286 len = _rw_fmtlong (spec, pbuf, pbufsize, (unsigned long)val); |
|
1287 } |
|
1288 else if (spec.mod_h) { |
|
1289 // promoted unsigned short argument |
|
1290 spec.param.i = PARAM (unsigned, i); |
|
1291 const unsigned short val = spec.param.i; |
|
1292 len = _rw_fmtlong (spec, pbuf, pbufsize, (unsigned long)val); |
|
1293 } |
|
1294 else if (spec.mod_ll) { |
|
1295 #ifdef _RWSTD_LONG_LONG |
|
1296 spec.param.llong = PARAM (unsigned _RWSTD_LONG_LONG, llong); |
|
1297 const unsigned _RWSTD_LONG_LONG val = spec.param.llong; |
|
1298 len = _rw_fmtllong (spec, pbuf, pbufsize, val); |
|
1299 #elif 8 == _RWSTD_LONG_SIZE |
|
1300 spec.param.lng = PARAM (unsigned long, lng); |
|
1301 const unsigned long val = spec.param.lng; |
|
1302 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1303 #else |
|
1304 assert (!"long long not supported"); |
|
1305 #endif // _RWSTD_LONG_LONG |
|
1306 |
|
1307 } |
|
1308 else if (spec.mod_l) { |
|
1309 spec.param.lng = PARAM (unsigned long, lng); |
|
1310 const unsigned long val = spec.param.lng; |
|
1311 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1312 } |
|
1313 else if (spec.mod_t) { |
|
1314 spec.param.lng = PARAM (size_t, size); |
|
1315 if (sizeof (size_t) == sizeof (unsigned long)) { |
|
1316 len = _rw_fmtlong (spec, pbuf, pbufsize, spec.param.size); |
|
1317 } |
|
1318 else { |
|
1319 #ifdef _RWSTD_LONG_LONG |
|
1320 len = _rw_fmtllong (spec, pbuf, pbufsize, spec.param.size); |
|
1321 #else // if defined (_RWSTD_LONG_LONG) |
|
1322 assert (!"%to, %tu, %tx: 64-bit types not implemented"); |
|
1323 #endif // _RWSTD_LONG_LONG |
|
1324 } |
|
1325 } |
|
1326 else if (1 == spec.iwidth) { |
|
1327 spec.param.i = PARAM (int, i); |
|
1328 const _RWSTD_UINT8_T val = spec.param.i; |
|
1329 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1330 } |
|
1331 else if (2 == spec.iwidth) { |
|
1332 spec.param.i = PARAM (int, i); |
|
1333 const long val = (unsigned short)spec.param.i; |
|
1334 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1335 } |
|
1336 else if (3 == spec.iwidth) { |
|
1337 spec.param.i32 = PARAM (_RWSTD_INT32_T, i32); |
|
1338 const long val = long (unsigned (spec.param.i)); |
|
1339 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1340 } |
|
1341 else if (4 == spec.iwidth) { |
|
1342 #ifdef _RWSTD_INT64_T |
|
1343 spec.param.i64 = PARAM (_RWSTD_INT64_T, i64); |
|
1344 #else // if defined 9_RWSTD_INT64_T) |
|
1345 assert (!"%I64o, %I64u, %I64x: 64-bit types not supported"); |
|
1346 #endif // _RWSTD_INT64_T |
|
1347 |
|
1348 #if 8 == _RWSTD_LONG_SIZE |
|
1349 const unsigned long val = spec.param.i64; |
|
1350 len = _rw_fmtlong (spec, pbuf, pbufsize, val); |
|
1351 #elif defined (_RWSTD_LONG_LONG) |
|
1352 const unsigned _RWSTD_LONG_LONG val = spec.param.i64; |
|
1353 len = _rw_fmtllong (spec, pbuf, pbufsize, val); |
|
1354 #else |
|
1355 assert (!"%I64o, %I64u, %I64x: 64-bit types not supported"); |
|
1356 #endif |
|
1357 } |
|
1358 else { |
|
1359 spec.param.i = PARAM (unsigned, i); |
|
1360 const unsigned val = spec.param.i; |
|
1361 len = _rw_fmtlong (spec, pbuf, pbufsize, long (val)); |
|
1362 } |
|
1363 |
|
1364 break; |
|
1365 } |
|
1366 |
|
1367 return len; |
|
1368 } |
|
1369 |
|
1370 /********************************************************************/ |
|
1371 |
|
1372 static int |
|
1373 _rw_fmtfloating (const FmtSpec &spec, |
|
1374 char **pbuf, size_t *pbufsize, const void *pval) |
|
1375 { |
|
1376 char fmt [128]; |
|
1377 char *pf = fmt; |
|
1378 |
|
1379 *pf++ = '%'; |
|
1380 |
|
1381 if (spec.fl_minus) |
|
1382 *pf++ = '-'; |
|
1383 |
|
1384 if (spec.fl_plus) |
|
1385 *pf++ = '+'; |
|
1386 |
|
1387 if (spec.fl_pound) |
|
1388 *pf++ = '#'; |
|
1389 |
|
1390 if (spec.fl_space) |
|
1391 *pf++ = ' '; |
|
1392 |
|
1393 if (spec.fl_zero) |
|
1394 *pf++ = '0'; |
|
1395 |
|
1396 if (spec.mod_h) |
|
1397 *pf++ = 'h'; |
|
1398 else if (spec.mod_hh) { |
|
1399 *pf++ = 'h'; |
|
1400 *pf++ = 'h'; |
|
1401 } |
|
1402 else if (spec.mod_l) |
|
1403 *pf++ = 'l'; |
|
1404 else if (spec.mod_ll) { |
|
1405 *pf++ = 'l'; |
|
1406 *pf++ = 'l'; |
|
1407 } |
|
1408 else if (spec.mod_j) |
|
1409 *pf++ = 'j'; |
|
1410 else if (spec.mod_z) |
|
1411 *pf++ = 'z'; |
|
1412 else if (spec.mod_t) |
|
1413 *pf++ = 't'; |
|
1414 else if (spec.mod_L) { |
|
1415 strcpy (pf, _RWSTD_LDBL_PRINTF_PREFIX); |
|
1416 for ( ; *pf; ++pf); |
|
1417 } |
|
1418 else if (spec.mod_A && _RWSTD_LDBL_SIZE == spec.width) { |
|
1419 strcpy (pf, _RWSTD_LDBL_PRINTF_PREFIX); |
|
1420 for ( ; *pf; ++pf); |
|
1421 } |
|
1422 |
|
1423 if (!spec.mod_A && 0 <= spec.width) { |
|
1424 pf += sprintf (pf, "%i", spec.width); |
|
1425 } |
|
1426 |
|
1427 if (0 <= spec.prec) |
|
1428 pf += sprintf (pf, ".%i", spec.prec); |
|
1429 |
|
1430 *pf++ = char (spec.cvtspec); |
|
1431 *pf = '\0'; |
|
1432 |
|
1433 // verify that the format buffer hasn't overflowed |
|
1434 assert (size_t (pf - fmt) + 1 < sizeof fmt); |
|
1435 |
|
1436 // this might make the buffer almost 5KB |
|
1437 char buffer [_RWSTD_LDBL_MAX_10_EXP + _RWSTD_LDBL_DIG + 3]; |
|
1438 int len = -1; |
|
1439 |
|
1440 if (spec.mod_A) { |
|
1441 |
|
1442 if (_RWSTD_FLT_SIZE == spec.width) { |
|
1443 len = sprintf (buffer, fmt, *(const float*)pval); |
|
1444 } |
|
1445 else if (_RWSTD_DBL_SIZE == spec.width) { |
|
1446 len = sprintf (buffer, fmt, *(const double*)pval); |
|
1447 } |
|
1448 else if (_RWSTD_LDBL_SIZE == spec.width) { |
|
1449 len = sprintf (buffer, fmt, *(const long double*)pval); |
|
1450 } |
|
1451 else { |
|
1452 assert (!"unknown floating point size"); |
|
1453 } |
|
1454 } |
|
1455 else if (spec.mod_L) |
|
1456 len = sprintf (buffer, fmt, *(const long double*)pval); |
|
1457 else |
|
1458 len = sprintf (buffer, fmt, *(const double*)pval); |
|
1459 |
|
1460 assert (size_t (len) < sizeof buffer); |
|
1461 |
|
1462 #ifdef _MSC_VER |
|
1463 |
|
1464 if (5 < len) { |
|
1465 // remove redundant zeros from the exponent (if present) |
|
1466 if ( ('e' == buffer [len - 5] || 'E' == buffer [len - 5]) |
|
1467 && '0' == buffer [len - 3]) { |
|
1468 buffer [len - 3] = buffer [len - 2]; |
|
1469 buffer [len - 2] = buffer [len - 1]; |
|
1470 buffer [len - 1] = buffer [len]; |
|
1471 } |
|
1472 } |
|
1473 |
|
1474 #endif // _MSC_VER |
|
1475 |
|
1476 |
|
1477 if (-1 < len && 0 == _rw_bufcat (pbuf, pbufsize, buffer, size_t (len))) |
|
1478 return -1; |
|
1479 |
|
1480 return len; |
|
1481 } |
|
1482 |
|
1483 /********************************************************************/ |
|
1484 |
|
1485 // formats a data, function, or class member pointer as follows |
|
1486 // 0x<hex-long-0>[:<hex-long-1>[:...[:<hex-long-N>]]] |
|
1487 // where N is the size of the pointer in long ints |
|
1488 |
|
1489 |
|
1490 static int |
|
1491 _rw_fmtpointer (const FmtSpec &spec, char **pbuf, size_t *pbufsize, |
|
1492 const void *pptr, size_t nelems) |
|
1493 { |
|
1494 FmtSpec newspec (spec); |
|
1495 |
|
1496 // always format data pointers in hexadecimal |
|
1497 newspec.base = 16; |
|
1498 |
|
1499 // set the number of digits |
|
1500 newspec.prec = _RWSTD_LONG_SIZE * 2; |
|
1501 |
|
1502 const union { |
|
1503 const void *ptr; |
|
1504 const unsigned long *lptr; |
|
1505 } uptr = { pptr }; |
|
1506 |
|
1507 int len = 0; |
|
1508 |
|
1509 if (newspec.fl_pound) { |
|
1510 // prepend the 0x prefix even to null pointers |
|
1511 if (0 == _rw_bufcat (pbuf, pbufsize, "0x", len = 2)) { |
|
1512 return -1; |
|
1513 } |
|
1514 |
|
1515 // reset the pound flag to prevent the integer formatter |
|
1516 // from inserting it again |
|
1517 newspec.fl_pound = 0; |
|
1518 } |
|
1519 |
|
1520 for (size_t i = 0; i != nelems; ++i) { |
|
1521 const size_t inx = _rw_big_endian ? nelems - i - 1 : i; |
|
1522 |
|
1523 len += _rw_fmtlong (newspec, pbuf, pbufsize, uptr.lptr [inx]); |
|
1524 |
|
1525 if (len < 0) { |
|
1526 break; |
|
1527 } |
|
1528 |
|
1529 // separate pointer components with colons |
|
1530 int n = 0; |
|
1531 if (i + 1 < nelems) { |
|
1532 if (0 == _rw_bufcat (pbuf, pbufsize, ":", n = 1)) { |
|
1533 len = -1; |
|
1534 break; |
|
1535 } |
|
1536 } |
|
1537 |
|
1538 len += n; |
|
1539 } |
|
1540 |
|
1541 return len; |
|
1542 } |
|
1543 |
|
1544 /********************************************************************/ |
|
1545 |
|
1546 _RWSTD_INTERNAL int |
|
1547 _rw_fmtptr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, |
|
1548 const void *val) |
|
1549 { |
|
1550 return _rw_fmtpointer (spec, pbuf, pbufsize, &val, |
|
1551 sizeof val / sizeof (long)); |
|
1552 } |
|
1553 |
|
1554 /********************************************************************/ |
|
1555 |
|
1556 static int |
|
1557 _rw_fmtfunptr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, |
|
1558 funptr_t val) |
|
1559 { |
|
1560 if (spec.mod_l) { |
|
1561 |
|
1562 #if 0 // disabled until this is implemented on other platforms |
|
1563 #ifdef _RWSTD_OS_SUNOS |
|
1564 |
|
1565 char buffer [256]; |
|
1566 |
|
1567 Dl_info dli; |
|
1568 |
|
1569 // find the symbol corresponding to the address |
|
1570 if (dladdr ((void*)val, &dli)) { |
|
1571 if (!dli.dli_sname) |
|
1572 dli.dli_fname = "unknown"; |
|
1573 |
|
1574 const size_t sym_off = size_t (dli.dli_saddr); |
|
1575 |
|
1576 // compute the offset of the address from the address |
|
1577 // of the symbol dladdr() found in the address space |
|
1578 // of the calling process |
|
1579 const size_t addr_off = size_t (val) < sym_off ? |
|
1580 sym_off - size_t (val) : size_t (val) - sym_off; |
|
1581 |
|
1582 // format the address folowed by the name of the symbol |
|
1583 // followed by the offset |
|
1584 const int len = sprintf (buffer, "%#x=%s%c%lu", |
|
1585 size_t (val), dli.dli_sname, |
|
1586 size_t (val) < sym_off ? '-' : '+', |
|
1587 addr_off); |
|
1588 |
|
1589 FmtSpec newspec (spec); |
|
1590 newspec.mod_l = false; |
|
1591 |
|
1592 return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (len)); |
|
1593 } |
|
1594 |
|
1595 #endif // _RWSTD_OS_SUNOS |
|
1596 #endif // 0/1 |
|
1597 } |
|
1598 |
|
1599 return _rw_fmtpointer (spec, pbuf, pbufsize, &val, |
|
1600 sizeof val / sizeof (long)); |
|
1601 } |
|
1602 |
|
1603 /********************************************************************/ |
|
1604 |
|
1605 static int |
|
1606 _rw_fmtmemptr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, memptr_t val) |
|
1607 { |
|
1608 return _rw_fmtpointer (spec, pbuf, pbufsize, &val, |
|
1609 sizeof val / sizeof (long)); |
|
1610 } |
|
1611 |
|
1612 /********************************************************************/ |
|
1613 |
|
1614 static int |
|
1615 _rw_fmterrno (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val) |
|
1616 { |
|
1617 static const struct { |
|
1618 int val; |
|
1619 const char* str; |
|
1620 } names[] = { |
|
1621 |
|
1622 #undef ERRNO |
|
1623 #define ERRNO(val) { val, #val } |
|
1624 |
|
1625 #ifdef EPERM |
|
1626 ERRNO (EPERM), |
|
1627 #endif // EPERM |
|
1628 #ifdef ENOENT |
|
1629 ERRNO (ENOENT), |
|
1630 #endif // ENOENT |
|
1631 #ifdef ESRCH |
|
1632 ERRNO (ESRCH), |
|
1633 #endif // ESRCH |
|
1634 #ifdef EINTR |
|
1635 ERRNO (EINTR), |
|
1636 #endif // EINTR |
|
1637 #ifdef EIO |
|
1638 ERRNO (EIO), |
|
1639 #endif // EIO |
|
1640 #ifdef ENXIO |
|
1641 ERRNO (ENXIO), |
|
1642 #endif // ENXIO |
|
1643 #ifdef E2BIG |
|
1644 ERRNO (E2BIG), |
|
1645 #endif // E2BIG |
|
1646 #ifdef ENOEXEC |
|
1647 ERRNO (ENOEXEC), |
|
1648 #endif // ENOEXEC |
|
1649 #ifdef EBADF |
|
1650 ERRNO (EBADF), |
|
1651 #endif // EBADF |
|
1652 #ifdef ECHILD |
|
1653 ERRNO (ECHILD), |
|
1654 #endif // ECHILD |
|
1655 #ifdef EAGAIN |
|
1656 ERRNO (EAGAIN), |
|
1657 #endif // EAGAIN |
|
1658 #ifdef ENOMEM |
|
1659 ERRNO (ENOMEM), |
|
1660 #endif // ENOMEM |
|
1661 #ifdef EACCES |
|
1662 ERRNO (EACCES), |
|
1663 #endif // EACCES |
|
1664 #ifdef EFAULT |
|
1665 ERRNO (EFAULT), |
|
1666 #endif // EFAULT |
|
1667 #ifdef ENOTBLK |
|
1668 ERRNO (ENOTBLK), |
|
1669 #endif // ENOTBLK |
|
1670 #ifdef EBUSY |
|
1671 ERRNO (EBUSY), |
|
1672 #endif // EBUSY |
|
1673 #ifdef EEXIST |
|
1674 ERRNO (EEXIST), |
|
1675 #endif // EEXIST |
|
1676 #ifdef EXDEV |
|
1677 ERRNO (EXDEV), |
|
1678 #endif // EXDEV |
|
1679 #ifdef ENODEV |
|
1680 ERRNO (ENODEV), |
|
1681 #endif // ENODEV |
|
1682 #ifdef ENOTDIR |
|
1683 ERRNO (ENOTDIR), |
|
1684 #endif // ENOTDIR |
|
1685 #ifdef EISDIR |
|
1686 ERRNO (EISDIR), |
|
1687 #endif // EISDIR |
|
1688 #ifdef EINVAL |
|
1689 ERRNO (EINVAL), |
|
1690 #endif // EINVAL |
|
1691 #ifdef ENFILE |
|
1692 ERRNO (ENFILE), |
|
1693 #endif // ENFILE |
|
1694 #ifdef EMFILE |
|
1695 ERRNO (EMFILE), |
|
1696 #endif // EMFILE |
|
1697 #ifdef ENOTTY |
|
1698 ERRNO (ENOTTY), |
|
1699 #endif // ENOTTY |
|
1700 #ifdef ETXTBSY |
|
1701 ERRNO (ETXTBSY), |
|
1702 #endif // ETXTBSY |
|
1703 #ifdef EFBIG |
|
1704 ERRNO (EFBIG), |
|
1705 #endif // EFBIG |
|
1706 #ifdef ENOSPC |
|
1707 ERRNO (ENOSPC), |
|
1708 #endif // ENOSPC |
|
1709 #ifdef ESPIPE |
|
1710 ERRNO (ESPIPE), |
|
1711 #endif // ESPIPE |
|
1712 #ifdef EROFS |
|
1713 ERRNO (EROFS), |
|
1714 #endif // EROFS |
|
1715 #ifdef EMLINK |
|
1716 ERRNO (EMLINK), |
|
1717 #endif // EMLINK |
|
1718 #ifdef EPIPE |
|
1719 ERRNO (EPIPE), |
|
1720 #endif // EPIPE |
|
1721 #ifdef EDOM |
|
1722 ERRNO (EDOM), |
|
1723 #endif // EDOM |
|
1724 #ifdef ERANGE |
|
1725 ERRNO (ERANGE), |
|
1726 #endif // ERANGE |
|
1727 #ifdef ENOMSG |
|
1728 ERRNO (ENOMSG), |
|
1729 #endif // ENOMSG |
|
1730 #ifdef EIDRM |
|
1731 ERRNO (EIDRM), |
|
1732 #endif // EIDRM |
|
1733 #ifdef ECHRNG |
|
1734 ERRNO (ECHRNG), |
|
1735 #endif // ECHRNG |
|
1736 #ifdef EL2NSYNC |
|
1737 ERRNO (EL2NSYNC), |
|
1738 #endif // EL2NSYNC |
|
1739 #ifdef EL3HLT |
|
1740 ERRNO (EL3HLT), |
|
1741 #endif // EL3HLT |
|
1742 #ifdef EL3RST |
|
1743 ERRNO (EL3RST), |
|
1744 #endif // EL3RST |
|
1745 #ifdef ELNRNG |
|
1746 ERRNO (ELNRNG), |
|
1747 #endif // ELNRNG |
|
1748 #ifdef EUNATCH |
|
1749 ERRNO (EUNATCH), |
|
1750 #endif // EUNATCH |
|
1751 #ifdef ENOCSI |
|
1752 ERRNO (ENOCSI), |
|
1753 #endif // ENOCSI |
|
1754 #ifdef EL2HLT |
|
1755 ERRNO (EL2HLT), |
|
1756 #endif // EL2HLT |
|
1757 #ifdef EDEADLK |
|
1758 ERRNO (EDEADLK), |
|
1759 #endif // EDEADLK |
|
1760 #ifdef ENOLCK |
|
1761 ERRNO (ENOLCK), |
|
1762 #endif // ENOLCK |
|
1763 #ifdef ECANCELED |
|
1764 ERRNO (ECANCELED), |
|
1765 #endif // ECANCELED |
|
1766 #ifdef ENOTSUP |
|
1767 ERRNO (ENOTSUP), |
|
1768 #endif // ENOTSUP |
|
1769 #ifdef EDQUOT |
|
1770 ERRNO (EDQUOT), |
|
1771 #endif // EDQUOT |
|
1772 #ifdef EBADE |
|
1773 ERRNO (EBADE), |
|
1774 #endif // EBADE |
|
1775 #ifdef EBADR |
|
1776 ERRNO (EBADR), |
|
1777 #endif // EBADR |
|
1778 #ifdef EXFULL |
|
1779 ERRNO (EXFULL), |
|
1780 #endif // EXFULL |
|
1781 #ifdef ENOANO |
|
1782 ERRNO (ENOANO), |
|
1783 #endif // ENOANO |
|
1784 #ifdef EBADRQC |
|
1785 ERRNO (EBADRQC), |
|
1786 #endif // EBADRQC |
|
1787 #ifdef EBADSLT |
|
1788 ERRNO (EBADSLT), |
|
1789 #endif // EBADSLT |
|
1790 #ifdef EDEADLOCK |
|
1791 ERRNO (EDEADLOCK), |
|
1792 #endif // EDEADLOCK |
|
1793 #ifdef EBFONT |
|
1794 ERRNO (EBFONT), |
|
1795 #endif // EBFONT |
|
1796 #ifdef EOWNERDEAD |
|
1797 ERRNO (EOWNERDEAD), |
|
1798 #endif // EOWNERDEAD |
|
1799 #ifdef ENOTRECOVERABLE |
|
1800 ERRNO (ENOTRECOVERABLE), |
|
1801 #endif // ENOTRECOVERABLE |
|
1802 #ifdef ENOSTR |
|
1803 ERRNO (ENOSTR), |
|
1804 #endif // ENOSTR |
|
1805 #ifdef ENODATA |
|
1806 ERRNO (ENODATA), |
|
1807 #endif // ENODATA |
|
1808 #ifdef ETIME |
|
1809 ERRNO (ETIME), |
|
1810 #endif // ETIME |
|
1811 #ifdef ENOSR |
|
1812 ERRNO (ENOSR), |
|
1813 #endif // ENOSR |
|
1814 #ifdef ENONET |
|
1815 ERRNO (ENONET), |
|
1816 #endif // ENONET |
|
1817 #ifdef ENOPKG |
|
1818 ERRNO (ENOPKG), |
|
1819 #endif // ENOPKG |
|
1820 #ifdef EREMOTE |
|
1821 ERRNO (EREMOTE), |
|
1822 #endif // EREMOTE |
|
1823 #ifdef ENOLINK |
|
1824 ERRNO (ENOLINK), |
|
1825 #endif // ENOLINK |
|
1826 #ifdef EADV |
|
1827 ERRNO (EADV), |
|
1828 #endif // EADV |
|
1829 #ifdef ESRMNT |
|
1830 ERRNO (ESRMNT), |
|
1831 #endif // ESRMNT |
|
1832 #ifdef ECOMM |
|
1833 ERRNO (ECOMM), |
|
1834 #endif // ECOMM |
|
1835 #ifdef ELOCKUNMAPPED |
|
1836 ERRNO (ELOCKUNMAPPED), |
|
1837 #endif // ELOCKUNMAPPED |
|
1838 #ifdef ENOTACTIVE |
|
1839 ERRNO (ENOTACTIVE), |
|
1840 #endif // ENOTACTIVE |
|
1841 #ifdef EMULTIHOP |
|
1842 ERRNO (EMULTIHOP), |
|
1843 #endif // EMULTIHOP |
|
1844 #ifdef EBADMSG |
|
1845 ERRNO (EBADMSG), |
|
1846 #endif // EBADMSG |
|
1847 #ifdef ENAMETOOLONG |
|
1848 ERRNO (ENAMETOOLONG), |
|
1849 #endif // ENAMETOOLONG |
|
1850 #ifdef EOVERFLOW |
|
1851 ERRNO (EOVERFLOW), |
|
1852 #endif // EOVERFLOW |
|
1853 #ifdef ENOTUNIQ |
|
1854 ERRNO (ENOTUNIQ), |
|
1855 #endif // ENOTUNIQ |
|
1856 #ifdef EBADFD |
|
1857 ERRNO (EBADFD), |
|
1858 #endif // EBADFD |
|
1859 #ifdef EREMCHG |
|
1860 ERRNO (EREMCHG), |
|
1861 #endif // EREMCHG |
|
1862 #ifdef ELIBACC |
|
1863 ERRNO (ELIBACC), |
|
1864 #endif // ELIBACC |
|
1865 #ifdef ELIBBAD |
|
1866 ERRNO (ELIBBAD), |
|
1867 #endif // ELIBBAD |
|
1868 #ifdef ELIBSCN |
|
1869 ERRNO (ELIBSCN), |
|
1870 #endif // ELIBSCN |
|
1871 #ifdef ELIBMAX |
|
1872 ERRNO (ELIBMAX), |
|
1873 #endif // ELIBMAX |
|
1874 #ifdef ELIBEXEC |
|
1875 ERRNO (ELIBEXEC), |
|
1876 #endif // ELIBEXEC |
|
1877 #ifdef EILSEQ |
|
1878 ERRNO (EILSEQ), |
|
1879 #endif // EILSEQ |
|
1880 #ifdef ENOSYS |
|
1881 ERRNO (ENOSYS), |
|
1882 #endif // ENOSYS |
|
1883 #ifdef ELOOP |
|
1884 ERRNO (ELOOP), |
|
1885 #endif // ELOOP |
|
1886 #ifdef ERESTART |
|
1887 ERRNO (ERESTART), |
|
1888 #endif // ERESTART |
|
1889 #ifdef ESTRPIPE |
|
1890 ERRNO (ESTRPIPE), |
|
1891 #endif // ESTRPIPE |
|
1892 #ifdef ENOTEMPTY |
|
1893 ERRNO (ENOTEMPTY), |
|
1894 #endif // ENOTEMPTY |
|
1895 #ifdef EUSERS |
|
1896 ERRNO (EUSERS), |
|
1897 #endif // EUSERS |
|
1898 #ifdef ENOTSOCK |
|
1899 ERRNO (ENOTSOCK), |
|
1900 #endif // ENOTSOCK |
|
1901 #ifdef EDESTADDRREQ |
|
1902 ERRNO (EDESTADDRREQ), |
|
1903 #endif // EDESTADDRREQ |
|
1904 #ifdef EMSGSIZE |
|
1905 ERRNO (EMSGSIZE), |
|
1906 #endif // EMSGSIZE |
|
1907 #ifdef EPROTOTYPE |
|
1908 ERRNO (EPROTOTYPE), |
|
1909 #endif // EPROTOTYPE |
|
1910 #ifdef ENOPROTOOPT |
|
1911 ERRNO (ENOPROTOOPT), |
|
1912 #endif // ENOPROTOOPT |
|
1913 #ifdef EPROTONOSUPPORT |
|
1914 ERRNO (EPROTONOSUPPORT), |
|
1915 #endif // EPROTONOSUPPORT |
|
1916 #ifdef ESOCKTNOSUPPORT |
|
1917 ERRNO (ESOCKTNOSUPPORT), |
|
1918 #endif // ESOCKTNOSUPPORT |
|
1919 #ifdef EOPNOTSUPP |
|
1920 ERRNO (EOPNOTSUPP), |
|
1921 #endif // EOPNOTSUPP |
|
1922 #ifdef EPFNOSUPPORT |
|
1923 ERRNO (EPFNOSUPPORT), |
|
1924 #endif // EPFNOSUPPORT |
|
1925 #ifdef EAFNOSUPPORT |
|
1926 ERRNO (EAFNOSUPPORT), |
|
1927 #endif // EAFNOSUPPORT |
|
1928 #ifdef EADDRINUSE |
|
1929 ERRNO (EADDRINUSE), |
|
1930 #endif // EADDRINUSE |
|
1931 #ifdef EADDRNOTAVAIL |
|
1932 ERRNO (EADDRNOTAVAIL), |
|
1933 #endif // EADDRNOTAVAIL |
|
1934 #ifdef ENETDOWN |
|
1935 ERRNO (ENETDOWN), |
|
1936 #endif // ENETDOWN |
|
1937 #ifdef ENETUNREACH |
|
1938 ERRNO (ENETUNREACH), |
|
1939 #endif // ENETUNREACH |
|
1940 #ifdef ENETRESET |
|
1941 ERRNO (ENETRESET), |
|
1942 #endif // ENETRESET |
|
1943 #ifdef ECONNABORTED |
|
1944 ERRNO (ECONNABORTED), |
|
1945 #endif // ECONNABORTED |
|
1946 #ifdef ECONNRESET |
|
1947 ERRNO (ECONNRESET), |
|
1948 #endif // ECONNRESET |
|
1949 #ifdef ENOBUFS |
|
1950 ERRNO (ENOBUFS), |
|
1951 #endif // ENOBUFS |
|
1952 #ifdef EISCONN |
|
1953 ERRNO (EISCONN), |
|
1954 #endif // EISCONN |
|
1955 #ifdef ENOTCONN |
|
1956 ERRNO (ENOTCONN), |
|
1957 #endif // ENOTCONN |
|
1958 #ifdef ESHUTDOWN |
|
1959 ERRNO (ESHUTDOWN), |
|
1960 #endif // ESHUTDOWN |
|
1961 #ifdef ETOOMANYREFS |
|
1962 ERRNO (ETOOMANYREFS), |
|
1963 #endif // ETOOMANYREFS |
|
1964 #ifdef ETIMEDOUT |
|
1965 ERRNO (ETIMEDOUT), |
|
1966 #endif // ETIMEDOUT |
|
1967 #ifdef ECONNREFUSED |
|
1968 ERRNO (ECONNREFUSED), |
|
1969 #endif // ECONNREFUSED |
|
1970 #ifdef EHOSTDOWN |
|
1971 ERRNO (EHOSTDOWN), |
|
1972 #endif // EHOSTDOWN |
|
1973 #ifdef EHOSTUNREACH |
|
1974 ERRNO (EHOSTUNREACH), |
|
1975 #endif // EHOSTUNREACH |
|
1976 #ifdef EWOULDBLOCK |
|
1977 ERRNO (EWOULDBLOCK), |
|
1978 #endif // EWOULDBLOCK |
|
1979 #ifdef EALREADY |
|
1980 ERRNO (EALREADY), |
|
1981 #endif // EALREADY |
|
1982 #ifdef EINPROGRESS |
|
1983 ERRNO (EINPROGRESS), |
|
1984 #endif // EINPROGRESS |
|
1985 #ifdef ESTALE |
|
1986 ERRNO (ESTALE), |
|
1987 #endif // ESTALE |
|
1988 { -1, 0 } |
|
1989 }; |
|
1990 |
|
1991 if (spec.fl_pound) { |
|
1992 |
|
1993 char buffer [64]; |
|
1994 const char *name = 0; |
|
1995 |
|
1996 for (size_t i = 0; i != sizeof names / sizeof *names; ++i) { |
|
1997 if (names [i].val == val) { |
|
1998 name = names [i].str; |
|
1999 break; |
|
2000 } |
|
2001 } |
|
2002 |
|
2003 int len; |
|
2004 |
|
2005 if (0 == name) { |
|
2006 len = sprintf (buffer, "E#%d", val); |
|
2007 name = buffer; |
|
2008 } |
|
2009 else |
|
2010 len = int (strlen (name)); |
|
2011 |
|
2012 if (0 == _rw_bufcat (pbuf, pbufsize, name, size_t (len))) |
|
2013 return -1; |
|
2014 |
|
2015 return len; |
|
2016 } |
|
2017 |
|
2018 const char* const str = strerror (val); |
|
2019 const size_t len = strlen (str); |
|
2020 |
|
2021 if (0 == _rw_bufcat (pbuf, pbufsize, str, len)) |
|
2022 return -1; |
|
2023 |
|
2024 return int (len); |
|
2025 } |
|
2026 |
|
2027 /********************************************************************/ |
|
2028 |
|
2029 static int |
|
2030 _rw_fmtsignal (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val) |
|
2031 { |
|
2032 static const struct { |
|
2033 int val; |
|
2034 const char* str; |
|
2035 } names[] = { |
|
2036 |
|
2037 #undef SIGNAL |
|
2038 #define SIGNAL(val) { val, #val } |
|
2039 |
|
2040 #ifdef SIGABRT |
|
2041 SIGNAL (SIGABRT), |
|
2042 #endif // SIGABRT |
|
2043 #ifdef SIGALRM |
|
2044 SIGNAL (SIGALRM), |
|
2045 #endif // SIGALRM |
|
2046 #ifdef SIGBUS |
|
2047 SIGNAL (SIGBUS), |
|
2048 #endif // SIGBUS |
|
2049 #ifdef SIGCANCEL |
|
2050 SIGNAL (SIGCANCEL), |
|
2051 #endif // SIGCANCEL |
|
2052 #ifdef SIGCHLD |
|
2053 SIGNAL (SIGCHLD), |
|
2054 #endif // SIGCHLD |
|
2055 #ifdef SIGCKPT |
|
2056 SIGNAL (SIGCKPT), |
|
2057 #endif // SIGCKPT |
|
2058 #ifdef SIGCLD |
|
2059 SIGNAL (SIGCLD), |
|
2060 #endif // SIGCLD |
|
2061 #ifdef SIGCONT |
|
2062 SIGNAL (SIGCONT), |
|
2063 #endif // SIGCONT |
|
2064 #ifdef SIGDIL |
|
2065 SIGNAL (SIGDIL), |
|
2066 #endif // SIGDIL |
|
2067 #ifdef SIGEMT |
|
2068 SIGNAL (SIGEMT), |
|
2069 #endif // SIGEMT |
|
2070 #ifdef SIGFPE |
|
2071 SIGNAL (SIGFPE), |
|
2072 #endif // SIGFPE |
|
2073 #ifdef SIGFREEZE |
|
2074 SIGNAL (SIGFREEZE), |
|
2075 #endif // SIGFREEZE |
|
2076 #ifdef SIGGFAULT |
|
2077 SIGNAL (SIGGFAULT), |
|
2078 #endif // SIGGFAULT |
|
2079 #ifdef SIGHUP |
|
2080 SIGNAL (SIGHUP), |
|
2081 #endif // SIGHUP |
|
2082 #ifdef SIGILL |
|
2083 SIGNAL (SIGILL), |
|
2084 #endif // SIGILL |
|
2085 #ifdef SIGINFO |
|
2086 SIGNAL (SIGINFO), |
|
2087 #endif // SIGINFO |
|
2088 #ifdef SIGINT |
|
2089 SIGNAL (SIGINT), |
|
2090 #endif // SIGINT |
|
2091 #ifdef SIGIO |
|
2092 SIGNAL (SIGIO), |
|
2093 #endif // SIGIO |
|
2094 #ifdef SIGIOT |
|
2095 SIGNAL (SIGIOT), |
|
2096 #endif // SIGIOT |
|
2097 #ifdef SIGK32 |
|
2098 SIGNAL (SIGK32), |
|
2099 #endif // SIGK32 |
|
2100 #ifdef SIGKILL |
|
2101 SIGNAL (SIGKILL), |
|
2102 #endif // SIGKILL |
|
2103 #ifdef SIGLOST |
|
2104 SIGNAL (SIGLOST), |
|
2105 #endif // SIGLOST |
|
2106 #ifdef SIGLWP |
|
2107 SIGNAL (SIGLWP), |
|
2108 #endif // SIGLWP |
|
2109 #ifdef SIGPIPE |
|
2110 SIGNAL (SIGPIPE), |
|
2111 #endif // SIGPIPE |
|
2112 #ifdef SIGPOLL |
|
2113 SIGNAL (SIGPOLL), |
|
2114 #endif // SIGPOLL |
|
2115 #ifdef SIGPROF |
|
2116 SIGNAL (SIGPROF), |
|
2117 #endif // SIGPROF |
|
2118 #ifdef SIGPTINTR |
|
2119 SIGNAL (SIGPTINTR), |
|
2120 #endif // SIGPTINTR |
|
2121 #ifdef SIGPTRESCHED |
|
2122 SIGNAL (SIGPTRESCHED), |
|
2123 #endif // SIGPTRESCHED |
|
2124 #ifdef SIGPWR |
|
2125 SIGNAL (SIGPWR), |
|
2126 #endif // SIGPWR |
|
2127 #ifdef SIGQUIT |
|
2128 SIGNAL (SIGQUIT), |
|
2129 #endif // SIGQUIT |
|
2130 #ifdef SIGRESTART |
|
2131 SIGNAL (SIGRESTART), |
|
2132 #endif // SIGRESTART |
|
2133 #ifdef SIGRESV |
|
2134 SIGNAL (SIGRESV), |
|
2135 #endif // SIGRESV |
|
2136 #ifdef SIGSEGV |
|
2137 SIGNAL (SIGSEGV), |
|
2138 #endif // SIGSEGV |
|
2139 #ifdef SIGSTKFLT |
|
2140 SIGNAL (SIGSTKFLT), |
|
2141 #endif // SIGSTKFLT |
|
2142 #ifdef SIGSTOP |
|
2143 SIGNAL (SIGSTOP), |
|
2144 #endif // SIGSTOP |
|
2145 #ifdef SIGSYS |
|
2146 SIGNAL (SIGSYS), |
|
2147 #endif // SIGSYS |
|
2148 #ifdef SIGTERM |
|
2149 SIGNAL (SIGTERM), |
|
2150 #endif // SIGTERM |
|
2151 #ifdef SIGTHAW |
|
2152 SIGNAL (SIGTHAW), |
|
2153 #endif // SIGTHAW |
|
2154 #ifdef SIGTRAP |
|
2155 SIGNAL (SIGTRAP), |
|
2156 #endif // SIGTRAP |
|
2157 #ifdef SIGTSTP |
|
2158 SIGNAL (SIGTSTP), |
|
2159 #endif // SIGTSTP |
|
2160 #ifdef SIGTTIN |
|
2161 SIGNAL (SIGTTIN), |
|
2162 #endif // SIGTTIN |
|
2163 #ifdef SIGTTOU |
|
2164 SIGNAL (SIGTTOU), |
|
2165 #endif // SIGTTOU |
|
2166 #ifdef SIGUNUSED |
|
2167 SIGNAL (SIGUNUSED), |
|
2168 #endif // SIGUNUSED |
|
2169 #ifdef SIGURG |
|
2170 SIGNAL (SIGURG), |
|
2171 #endif // SIGURG |
|
2172 #ifdef SIGUSR1 |
|
2173 SIGNAL (SIGUSR1), |
|
2174 #endif // SIGUSR1 |
|
2175 #ifdef SIGUSR2 |
|
2176 SIGNAL (SIGUSR2), |
|
2177 #endif // SIGUSR2 |
|
2178 #ifdef SIGVTALRM |
|
2179 SIGNAL (SIGVTALRM), |
|
2180 #endif // SIGVTALRM |
|
2181 #ifdef SIGWAITING |
|
2182 SIGNAL (SIGWAITING), |
|
2183 #endif // SIGWAITING |
|
2184 #ifdef SIGWINCH |
|
2185 SIGNAL (SIGWINCH), |
|
2186 #endif // SIGWINCH |
|
2187 #ifdef SIGWINDOW |
|
2188 SIGNAL (SIGWINDOW), |
|
2189 #endif // SIGWINDOW |
|
2190 #ifdef SIGXCPU |
|
2191 SIGNAL (SIGXCPU), |
|
2192 #endif // SIGXCPU |
|
2193 #ifdef SIGXFSZ |
|
2194 SIGNAL (SIGXFSZ), |
|
2195 #endif // SIGXFSZ |
|
2196 #ifdef SIGXRES |
|
2197 SIGNAL (SIGXRES), |
|
2198 #endif // SIGXRES |
|
2199 { -1, 0 } |
|
2200 }; |
|
2201 |
|
2202 char buffer [64]; |
|
2203 const char *name = 0; |
|
2204 |
|
2205 for (size_t i = 0; i != sizeof names / sizeof *names; ++i) { |
|
2206 if (names [i].val == val) { |
|
2207 name = names [i].str; |
|
2208 break; |
|
2209 } |
|
2210 } |
|
2211 |
|
2212 if (0 == name) { |
|
2213 sprintf (buffer, "SIG#%d", val); |
|
2214 name = buffer; |
|
2215 } |
|
2216 |
|
2217 return _rw_fmtstr (spec, pbuf, pbufsize, name, _RWSTD_SIZE_MAX); |
|
2218 } |
|
2219 |
|
2220 /********************************************************************/ |
|
2221 |
|
2222 template <class charT> |
|
2223 int rw_quotechar (char *buf, charT wc, int noesc) |
|
2224 { |
|
2225 #if _RWSTD_WCHAR_T_MIN < 0 |
|
2226 |
|
2227 // wchar_t is signed, convert its value to unsigned long |
|
2228 // without widening (i.e., treat it as an unsigned type) |
|
2229 |
|
2230 # if _RWSTD_WCHAR_T_MIN == _RWSTD_SHRT_MIN |
|
2231 const unsigned long wi = (unsigned short)wc; |
|
2232 # elif _RWSTD_WCHAR_T_MIN ==_RWSTD_INT_MIN |
|
2233 const unsigned long wi = (unsigned int)wc; |
|
2234 # elif _RWSTD_WCHAR_T_MIN == _RWSTD_LONG_MIN |
|
2235 const unsigned long wi = (unsigned long)wc; |
|
2236 # endif |
|
2237 |
|
2238 #else // if _RWSTD_WCHAR_T_MIN >= 0 |
|
2239 |
|
2240 // wchar_t is unsigned |
|
2241 const unsigned long wi = (unsigned long)wc; |
|
2242 |
|
2243 #endif // _RWSTD_WCHAR_T_MIN < 0 |
|
2244 |
|
2245 if ((1 == sizeof wc || wi < 0x100) && noesc) { |
|
2246 buf [0] = char (wc); |
|
2247 buf [1] = '\0'; |
|
2248 return 1; |
|
2249 } |
|
2250 |
|
2251 int len = 3; |
|
2252 |
|
2253 buf [0] = '\\'; |
|
2254 buf [2] = '\0'; |
|
2255 |
|
2256 switch (wc) { |
|
2257 case '\a': buf [1] = 'a'; buf [len = 2] = '\0'; break; |
|
2258 case '\b': buf [1] = 'b'; buf [len = 2] = '\0'; break; |
|
2259 case '\f': buf [1] = 'f'; buf [len = 2] = '\0'; break; |
|
2260 case '\n': buf [1] = 'n'; buf [len = 2] = '\0'; break; |
|
2261 case '\r': buf [1] = 'r'; buf [len = 2] = '\0'; break; |
|
2262 case '\t': buf [1] = 't'; buf [len = 2] = '\0'; break; |
|
2263 case '\v': buf [1] = 'v'; buf [len = 2] = '\0'; break; |
|
2264 case '\\': buf [1] = '\\'; buf [len = 2] = '\0'; break; |
|
2265 case '"' : buf [1] = '"'; buf [len = 2] = '\0'; break; |
|
2266 default: |
|
2267 if (wc < ' ' || wc > '~') { |
|
2268 |
|
2269 if (0 == wc) { |
|
2270 buf [1] = '0'; |
|
2271 buf [2] = '\0'; |
|
2272 len = 2; |
|
2273 } |
|
2274 else if (1 == sizeof wc) { |
|
2275 len = 1 + sprintf (buf + 1, "x%02x", (unsigned char)wc); |
|
2276 } |
|
2277 else { |
|
2278 |
|
2279 const int width = |
|
2280 wi > 0xfffffffUL ? 8 : wi > 0xffffffUL ? 7 |
|
2281 : wi > 0xfffffUL ? 6 : wi > 0xffffUL ? 5 |
|
2282 : wi > 0xfffUL ? 4 : wi > 0xffUL ? 3 |
|
2283 : wi > 0xfUL ? 2 : 2; |
|
2284 |
|
2285 len = 1 + sprintf (buf + 1, "x%0*lx", width, (unsigned long)wi); |
|
2286 } |
|
2287 } |
|
2288 else { |
|
2289 buf [0] = wc; |
|
2290 buf [1] = '\0'; |
|
2291 len = 1; |
|
2292 } |
|
2293 } |
|
2294 |
|
2295 return len; |
|
2296 } |
|
2297 |
|
2298 |
|
2299 template <class charT> |
|
2300 int rw_quotestr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, |
|
2301 const charT *wstr, size_t nchars, int noesc) |
|
2302 { |
|
2303 assert(1); |
|
2304 return 0; |
|
2305 #if 0 |
|
2306 assert (0 != pbuf); |
|
2307 |
|
2308 if (!wstr) { |
|
2309 static const charT null[] = { '(', 'n', 'u', 'l', 'l', ')', '\0' }; |
|
2310 wstr = null; |
|
2311 nchars = sizeof null / sizeof *null - 1; |
|
2312 } |
|
2313 |
|
2314 if (0 > _RW::__rw_memattr (wstr, _RWSTD_SIZE_MAX, 0)) { |
|
2315 |
|
2316 const size_t buflen = *pbuf ? strlen (*pbuf) : 0; |
|
2317 |
|
2318 if (0 == _rw_bufcat (pbuf, pbufsize, "(invalid address ", 18)) |
|
2319 return -1; |
|
2320 |
|
2321 FmtSpec newspec (spec); |
|
2322 newspec.fl_pound = 1; |
|
2323 if (-1 == ::_rw_fmtptr (newspec, pbuf, pbufsize, wstr)) |
|
2324 return -1; |
|
2325 if (0 == _rw_bufcat (pbuf, pbufsize, ")", 2)) |
|
2326 return -1; |
|
2327 |
|
2328 return int (strlen (*pbuf) - buflen); |
|
2329 } |
|
2330 |
|
2331 if (_RWSTD_SIZE_MAX == nchars) { |
|
2332 // compute the length of the NUL-terminate string |
|
2333 nchars = 0; |
|
2334 for (const charT *pc = wstr; *pc; ++pc, ++nchars); |
|
2335 } |
|
2336 |
|
2337 char *next = _rw_bufcat (pbuf, pbufsize, 0, (nchars + 1) * 12 + 3); |
|
2338 const char* const bufend = next; |
|
2339 |
|
2340 if (0 == next) |
|
2341 return -1; |
|
2342 |
|
2343 if (0 == nchars) { |
|
2344 if (noesc) { |
|
2345 |
|
2346 #if 0 // width handling disabled (width used for array formatting) |
|
2347 for (int w = 0; w < spec.width; ++w) |
|
2348 *next++ = ' '; |
|
2349 #endif // 0/1 |
|
2350 |
|
2351 } |
|
2352 else { |
|
2353 if (_RWSTD_WCHAR_T_SIZE == sizeof (charT)) |
|
2354 *next++ = 'L'; |
|
2355 |
|
2356 *next++ = '"'; |
|
2357 #if 0 // width handling disabled (width used for array formatting) |
|
2358 for (int w = 0; w < spec.width; ++w) |
|
2359 *next++ = ' '; |
|
2360 #endif // 0/1 |
|
2361 *next++ = '"'; |
|
2362 } |
|
2363 *next++ = '\0'; |
|
2364 return int (next - bufend); |
|
2365 } |
|
2366 |
|
2367 char *s = next; |
|
2368 |
|
2369 const charT *last = wstr; |
|
2370 |
|
2371 bool any_repeats = false; |
|
2372 long last_repeat = noesc ? 0L : -1L; |
|
2373 |
|
2374 char chstr [16]; |
|
2375 |
|
2376 const ptrdiff_t N = ptrdiff_t (noesc ? 0 : 20); |
|
2377 |
|
2378 for (const charT *pwc = last + 1; ; ++pwc) { |
|
2379 |
|
2380 if (*pwc == *last && size_t (pwc - wstr) < nchars) { |
|
2381 // if the last processed character repeats, continue |
|
2382 // until a different character is encountered |
|
2383 continue; |
|
2384 } |
|
2385 |
|
2386 if (N > 1 && pwc - last > N) { |
|
2387 |
|
2388 // if the last processed character repeats N or more |
|
2389 // times, format the repeat count instead of all the |
|
2390 // repeated occurrences of the character to conserve |
|
2391 // space and make the string more readable |
|
2392 |
|
2393 const long repeat = pwc - last; |
|
2394 |
|
2395 rw_quotechar (chstr, *last, noesc); |
|
2396 |
|
2397 s += sprintf (s, "%s'%s' <repeats %ld times>", |
|
2398 -1 == last_repeat ? "" |
|
2399 : 0 == last_repeat ? "\", " : ", ", |
|
2400 chstr, repeat); |
|
2401 |
|
2402 last = pwc; |
|
2403 |
|
2404 any_repeats = true; |
|
2405 last_repeat = repeat; |
|
2406 } |
|
2407 else { |
|
2408 // otherwise (if the last processed character repeats |
|
2409 // fewer than N times) format the character that many |
|
2410 // times |
|
2411 |
|
2412 if (last_repeat < 0) { |
|
2413 // opening quote |
|
2414 if (_RWSTD_WCHAR_T_SIZE == sizeof (charT)) { |
|
2415 *s++ = 'L'; |
|
2416 } |
|
2417 *s++ = '\"'; |
|
2418 } |
|
2419 else if (last_repeat > 0) { |
|
2420 *s++ = ','; |
|
2421 *s++ = ' '; |
|
2422 *s++ = '\"'; |
|
2423 } |
|
2424 |
|
2425 rw_quotechar (chstr, *last, noesc); |
|
2426 |
|
2427 while (last != pwc) { |
|
2428 s += sprintf (s, "%s", chstr); |
|
2429 ++last; |
|
2430 } |
|
2431 |
|
2432 last_repeat = 0; |
|
2433 |
|
2434 if (size_t (pwc - wstr) == nchars) { |
|
2435 if (!noesc) |
|
2436 *s++ = '\"'; |
|
2437 *s = '\0'; |
|
2438 break; |
|
2439 } |
|
2440 } |
|
2441 |
|
2442 if (size_t (pwc - wstr) == nchars) |
|
2443 break; |
|
2444 } |
|
2445 |
|
2446 if (any_repeats) { |
|
2447 const size_t len = strlen (next); |
|
2448 memmove (next + 2, next, len); |
|
2449 next [0] = '{'; |
|
2450 next [1] = ' '; |
|
2451 next [len + 2] = ' '; |
|
2452 next [len + 3] = '}'; |
|
2453 next [len + 4] = '\0'; |
|
2454 s = next + len + 4; |
|
2455 } |
|
2456 |
|
2457 return int (s - bufend); |
|
2458 #endif |
|
2459 } |
|
2460 |
|
2461 /********************************************************************/ |
|
2462 |
|
2463 static int |
|
2464 _rw_fmtchr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val) |
|
2465 { |
|
2466 typedef unsigned char UChar; |
|
2467 const UChar uc = UChar (val); |
|
2468 |
|
2469 char buffer [8]; |
|
2470 int len = rw_quotechar (buffer + spec.fl_pound, uc, !spec.fl_pound); |
|
2471 if (spec.fl_pound) { |
|
2472 buffer [0] = buffer [len + 1] = '\''; |
|
2473 buffer [len + 2] = '\0'; |
|
2474 len += 2; |
|
2475 } |
|
2476 |
|
2477 FmtSpec newspec (spec); |
|
2478 newspec.fl_pound = 0; |
|
2479 return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (len)); |
|
2480 } |
|
2481 |
|
2482 /********************************************************************/ |
|
2483 |
|
2484 static int |
|
2485 _rw_fmtwchr (const FmtSpec &spec, char **pbuf, size_t *pbufsize, wint_t val) |
|
2486 { |
|
2487 const wchar_t wc = wchar_t (val); |
|
2488 |
|
2489 char buffer [16]; |
|
2490 int len = rw_quotechar (buffer + 2 * spec.fl_pound, wc, !spec.fl_pound); |
|
2491 if (spec.fl_pound) { |
|
2492 buffer [0] = 'L'; |
|
2493 buffer [1] = buffer [len + 2] = '\''; |
|
2494 buffer [len + 3] = '\0'; |
|
2495 len += 3; |
|
2496 } |
|
2497 |
|
2498 FmtSpec newspec (spec); |
|
2499 newspec.fl_pound = 0; |
|
2500 return _rw_fmtstr (newspec, pbuf, pbufsize, buffer, size_t (len)); |
|
2501 } |
|
2502 |
|
2503 /********************************************************************/ |
|
2504 |
|
2505 static int |
|
2506 _rw_fmtstr (const FmtSpec &spec, |
|
2507 char **pbuf, size_t *pbufsize, const char *str, size_t len) |
|
2508 { |
|
2509 assert (1); |
|
2510 return 0; |
|
2511 #if 0 |
|
2512 if (spec.fl_pound) |
|
2513 return rw_quotestr (spec, pbuf, pbufsize, str, len, 0); |
|
2514 |
|
2515 if (0 == str) |
|
2516 str = "(null)"; |
|
2517 |
|
2518 if (0 > _RW::__rw_memattr (str, _RWSTD_SIZE_MAX, 0)) { |
|
2519 |
|
2520 const size_t buflen = *pbuf ? strlen (*pbuf) : 0; |
|
2521 |
|
2522 if (0 == _rw_bufcat (pbuf, pbufsize, "(invalid address ", 18)) |
|
2523 return -1; |
|
2524 |
|
2525 FmtSpec newspec (spec); |
|
2526 newspec.fl_pound = 1; |
|
2527 |
|
2528 if (-1 == _rw_fmtptr (newspec, pbuf, pbufsize, str)) |
|
2529 return -1; |
|
2530 |
|
2531 if (0 == _rw_bufcat (pbuf, pbufsize, ")", 2)) |
|
2532 return -1; |
|
2533 |
|
2534 return int (strlen (*pbuf) - buflen); |
|
2535 } |
|
2536 |
|
2537 if (_RWSTD_SIZE_MAX == len) |
|
2538 len = strlen (str); |
|
2539 |
|
2540 // compute the minimum number of characters to be generated |
|
2541 if (-1 < spec.prec && size_t (spec.prec) < len) |
|
2542 len = size_t (spec.prec); |
|
2543 |
|
2544 // the number of generated characters depends on three variables: |
|
2545 // -- the optional field width, |
|
2546 // -- the optional precision, and |
|
2547 // -- the length of the argument |
|
2548 |
|
2549 // compute the field width |
|
2550 const size_t width = |
|
2551 -1 < spec.width && len < size_t (spec.width) ? |
|
2552 size_t (spec.width) : len; |
|
2553 |
|
2554 // compute the size of padding |
|
2555 const size_t pad = len < width ? width - len : 0; |
|
2556 |
|
2557 // [re]allocate enough space in the buffer |
|
2558 if (0 == _rw_bufcat (pbuf, pbufsize, 0, pad + len)) |
|
2559 return -1; |
|
2560 |
|
2561 assert (0 != *pbuf); |
|
2562 char *next = *pbuf + strlen (*pbuf); |
|
2563 |
|
2564 if (!spec.fl_minus) { |
|
2565 for (size_t i = 0; i != pad; ++i) |
|
2566 *next++ = ' '; |
|
2567 } |
|
2568 |
|
2569 memcpy (next, str, len); |
|
2570 next += len; |
|
2571 |
|
2572 if (spec.fl_minus) { |
|
2573 for (size_t i = 0; i != pad; ++i) |
|
2574 *next++ = ' '; |
|
2575 } |
|
2576 |
|
2577 *next++ = '\0'; |
|
2578 |
|
2579 return int (pad + len); |
|
2580 #endif |
|
2581 } |
|
2582 |
|
2583 /********************************************************************/ |
|
2584 |
|
2585 static int |
|
2586 _rw_fmtwstr (const FmtSpec &spec, |
|
2587 char **pbuf, size_t *pbufsize, const wchar_t *wstr, size_t len) |
|
2588 { |
|
2589 return rw_quotestr (spec, pbuf, pbufsize, wstr, len, 1); |
|
2590 } |
|
2591 |
|
2592 /********************************************************************/ |
|
2593 |
|
2594 struct Bitnames |
|
2595 { |
|
2596 const char *longname; |
|
2597 const char *name; |
|
2598 int bits; |
|
2599 }; |
|
2600 |
|
2601 #define BITNAME(qual, name) { #qual "::" #name, #name, qual::name } |
|
2602 |
|
2603 static int |
|
2604 rw_bmpfmt (const FmtSpec&, char **pbuf, size_t *pbufsize, |
|
2605 const Bitnames bmap[], size_t size, int bits) |
|
2606 { |
|
2607 assert (0 != pbuf); |
|
2608 |
|
2609 char buffer [1024]; |
|
2610 *buffer = '\0'; |
|
2611 |
|
2612 // string to use when no bits are set |
|
2613 const char* all_clear = "0"; |
|
2614 |
|
2615 for (size_t i = 0; i != size; ++i) { |
|
2616 if (bmap [i].bits) { |
|
2617 if ((bits & bmap [i].bits) == bmap [i].bits) { |
|
2618 strcat (*buffer ? strcat (buffer, " | ") : buffer, |
|
2619 bmap [i].name); |
|
2620 bits &= ~bmap [i].bits; |
|
2621 } |
|
2622 } |
|
2623 else { |
|
2624 // save the name of the constant to use for 0 |
|
2625 all_clear = bmap [i].name; |
|
2626 } |
|
2627 } |
|
2628 |
|
2629 size_t buffersize; |
|
2630 |
|
2631 if ('\0' == *buffer) { |
|
2632 // no constant matched, format teh value either as a number |
|
2633 // or, when 0, using the all_clear name (see above) |
|
2634 if (bits) |
|
2635 sprintf (buffer, "%#x", bits); |
|
2636 else |
|
2637 strcpy (buffer, all_clear); |
|
2638 |
|
2639 buffersize = strlen (buffer) + 1; |
|
2640 } |
|
2641 else if (bits) { |
|
2642 buffersize = strlen (buffer) + 1; |
|
2643 |
|
2644 // verify that buffer wasn't overflowed |
|
2645 assert (buffersize <= sizeof buffer); |
|
2646 |
|
2647 char bitstr [32]; |
|
2648 const int n = sprintf (bitstr, "%#x | ", bits); |
|
2649 |
|
2650 assert (0 < n); |
|
2651 |
|
2652 memmove (buffer + n, buffer, buffersize); |
|
2653 memcpy (buffer, bitstr, size_t (n)); |
|
2654 |
|
2655 buffersize += n; |
|
2656 } |
|
2657 else { |
|
2658 buffersize = strlen (buffer) + 1; |
|
2659 } |
|
2660 |
|
2661 // verify that buffer wasn't overflowed |
|
2662 assert (buffersize <= sizeof buffer); |
|
2663 |
|
2664 if (0 == _rw_bufcat (pbuf, pbufsize, buffer, buffersize)) |
|
2665 return -1; |
|
2666 |
|
2667 return int (buffersize); |
|
2668 } |
|
2669 |
|
2670 /********************************************************************/ |
|
2671 |
|
2672 static int |
|
2673 rw_fmtflags (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int bits) |
|
2674 { |
|
2675 static const Bitnames names [] = { |
|
2676 BITNAME (std::ios, adjustfield), |
|
2677 BITNAME (std::ios, basefield), |
|
2678 BITNAME (std::ios, boolalpha), |
|
2679 BITNAME (std::ios, dec), |
|
2680 BITNAME (std::ios, fixed), |
|
2681 BITNAME (std::ios, hex), |
|
2682 BITNAME (std::ios, internal), |
|
2683 BITNAME (std::ios, left), |
|
2684 BITNAME (std::ios, oct), |
|
2685 BITNAME (std::ios, right), |
|
2686 BITNAME (std::ios, scientific), |
|
2687 BITNAME (std::ios, showbase), |
|
2688 BITNAME (std::ios, showpoint), |
|
2689 BITNAME (std::ios, showpos), |
|
2690 BITNAME (std::ios, skipws), |
|
2691 BITNAME (std::ios, unitbuf), |
|
2692 BITNAME (std::ios, uppercase), |
|
2693 |
|
2694 #ifndef _RWSTD_NO_EXT_BIN_IO |
|
2695 |
|
2696 // extension: produce binary output (similar to oct, dec, and hex) |
|
2697 BITNAME (std::ios, bin), |
|
2698 |
|
2699 #endif // _RWSTD_NO_EXT_BIN_IO |
|
2700 |
|
2701 #ifndef _RWSTD_NO_EXT_REENTRANT_IO |
|
2702 |
|
2703 // extension: allow unsychronized access to stream and/or its buffer |
|
2704 BITNAME (std::ios, nolock), |
|
2705 BITNAME (std::ios, nolockbuf) |
|
2706 |
|
2707 #endif // _RWSTD_NO_EXT_REENTRANT_IO |
|
2708 |
|
2709 }; |
|
2710 |
|
2711 static const size_t count = sizeof names / sizeof *names; |
|
2712 |
|
2713 const int base = (bits >> _RWSTD_IOS_BASEOFF) & _RWSTD_IOS_BASEMASK; |
|
2714 |
|
2715 // zero out bits representingthe numeric base |
|
2716 bits &= ~(_RWSTD_IOS_BASEMASK << _RWSTD_IOS_BASEOFF); |
|
2717 |
|
2718 int len = rw_bmpfmt (spec, pbuf, pbufsize, names, count, bits); |
|
2719 |
|
2720 if (base && base != 8 && base != 10 && base != 16) { |
|
2721 |
|
2722 // for numeric bases other than those required by the standard, |
|
2723 // use the text "base (%d)" to show the extended numeric base |
|
2724 |
|
2725 #ifndef _RWSTD_NO_EXT_BIN_IO |
|
2726 |
|
2727 if (bits & std::ios::bin) |
|
2728 return len; |
|
2729 |
|
2730 #endif // _RWSTD_NO_EXT_BIN_IO |
|
2731 |
|
2732 char basestr [64]; |
|
2733 sprintf (basestr, " | std::ios::base(%d)", base); |
|
2734 |
|
2735 strcat (*pbuf, basestr); |
|
2736 |
|
2737 len = int (strlen (*pbuf)); |
|
2738 } |
|
2739 |
|
2740 return len; |
|
2741 } |
|
2742 |
|
2743 /********************************************************************/ |
|
2744 |
|
2745 static int |
|
2746 rw_fmtiostate (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int bits) |
|
2747 { |
|
2748 static const Bitnames names [] = { |
|
2749 BITNAME (std::ios, goodbit), |
|
2750 BITNAME (std::ios, badbit), |
|
2751 BITNAME (std::ios, eofbit), |
|
2752 BITNAME (std::ios, failbit) |
|
2753 }; |
|
2754 |
|
2755 static const size_t count = sizeof names / sizeof *names; |
|
2756 |
|
2757 return rw_bmpfmt (spec, pbuf, pbufsize, names, count, bits); |
|
2758 } |
|
2759 |
|
2760 /********************************************************************/ |
|
2761 |
|
2762 static int |
|
2763 _rw_fmtopenmode (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int bits) |
|
2764 { |
|
2765 static const Bitnames names [] = { |
|
2766 |
|
2767 #ifndef __SYMBIAN32__ |
|
2768 |
|
2769 #ifndef _RWSTD_NO_EXTENSIONS |
|
2770 |
|
2771 { "std::ios::nocreate", "nocreate", std::ios::nocreate }, |
|
2772 { "std::ios::noreplace", "noreplace", std::ios::noreplace }, |
|
2773 |
|
2774 #else // if defined (_RWSTD_NO_EXTENSIONS) |
|
2775 |
|
2776 { "__rw:::__rw_nocreate", "__rw_nocreate", _RW::__rw_nocreate }, |
|
2777 { "__rw::__rw_noreplace", "__rw_noreplace", _RW::__rw_noreplace }, |
|
2778 |
|
2779 #endif // _RWSTD_NO_EXTENSIONS |
|
2780 |
|
2781 #ifndef _RWSTD_NO_EXT_STDIO |
|
2782 |
|
2783 { "std::ios::stdio", "stdio", std::ios::stdio }, |
|
2784 { "std::ios::native", "native", std::ios::native }, |
|
2785 |
|
2786 #else // if defined (_RWSTD_NO_EXT_STDIO) |
|
2787 |
|
2788 { "__rw::__rw_stdio", "__rw_stdio", _RW::__rw_stdio }, |
|
2789 { "__rw::__rw_native", "__rw_native", _RW::__rw_native }, |
|
2790 |
|
2791 #endif // _RWSTD_NO_EXT_STDIO |
|
2792 #endif |
|
2793 BITNAME (std::ios, app), |
|
2794 BITNAME (std::ios, binary), |
|
2795 BITNAME (std::ios, in), |
|
2796 BITNAME (std::ios, out), |
|
2797 BITNAME (std::ios, trunc), |
|
2798 BITNAME (std::ios, ate) |
|
2799 }; |
|
2800 |
|
2801 static const size_t count = sizeof names / sizeof *names; |
|
2802 |
|
2803 return rw_bmpfmt (spec, pbuf, pbufsize, names, count, bits); |
|
2804 } |
|
2805 |
|
2806 /********************************************************************/ |
|
2807 |
|
2808 static int |
|
2809 _rw_fmtevent (const FmtSpec&, char **pbuf, size_t *pbufsize, int event) |
|
2810 { |
|
2811 const char* str = |
|
2812 std::ios::copyfmt_event == event ? "copyfmt_event" |
|
2813 : std::ios::imbue_event == event ? "imbue_event" |
|
2814 : std::ios::erase_event == event ? "erase_event" |
|
2815 : 0; |
|
2816 |
|
2817 char buffer [64]; |
|
2818 |
|
2819 if (!str) { |
|
2820 sprintf (buffer, "copyfmt_event(%d)", event); |
|
2821 str = buffer; |
|
2822 } |
|
2823 |
|
2824 const size_t len = strlen (str); |
|
2825 |
|
2826 if (0 == _rw_bufcat (pbuf, pbufsize, str, len)) |
|
2827 return -1; |
|
2828 |
|
2829 return int (len); |
|
2830 } |
|
2831 |
|
2832 /********************************************************************/ |
|
2833 |
|
2834 static int |
|
2835 rw_fmtlc (const FmtSpec &spec, char **pbuf, size_t *pbufsize, int val) |
|
2836 { |
|
2837 const char *str = 0; |
|
2838 |
|
2839 switch (val) { |
|
2840 case LC_ALL: str = "LC_ALL"; break; |
|
2841 case LC_COLLATE: str = "LC_COLLATE"; break; |
|
2842 case LC_CTYPE: str = "LC_CTYPE"; break; |
|
2843 case LC_MONETARY: str = "LC_MONETARY"; break; |
|
2844 case LC_NUMERIC: str = "LC_NUMERIC"; break; |
|
2845 case LC_TIME: str = "LC_TIME"; break; |
|
2846 |
|
2847 #ifdef LC_MESSAGES |
|
2848 case LC_MESSAGES: str = "LC_MESSAGES"; break; |
|
2849 #endif // LC_MESSAGES |
|
2850 |
|
2851 } |
|
2852 |
|
2853 if (str) { |
|
2854 const std::size_t len = strlen (str); |
|
2855 |
|
2856 if (0 == _rw_bufcat (pbuf, pbufsize, str, len)) |
|
2857 return -1; |
|
2858 |
|
2859 return int (len); |
|
2860 } |
|
2861 |
|
2862 static const Bitnames names [] = { |
|
2863 BITNAME (std::locale, all), |
|
2864 BITNAME (std::locale, none), |
|
2865 BITNAME (std::locale, collate), |
|
2866 BITNAME (std::locale, ctype), |
|
2867 BITNAME (std::locale, monetary), |
|
2868 BITNAME (std::locale, numeric), |
|
2869 BITNAME (std::locale, messages), |
|
2870 BITNAME (std::locale, time) |
|
2871 }; |
|
2872 |
|
2873 static const size_t count = sizeof names / sizeof *names; |
|
2874 |
|
2875 return rw_bmpfmt (spec, pbuf, pbufsize, names, count, val); |
|
2876 } |
|
2877 |
|
2878 /********************************************************************/ |
|
2879 |
|
2880 static int |
|
2881 _rw_fmtmonpat (const FmtSpec&, |
|
2882 char **pbuf, size_t *pbufsize, const char pat [4]) |
|
2883 { |
|
2884 char buffer [80]; |
|
2885 |
|
2886 buffer [0] = '\0'; |
|
2887 |
|
2888 for (int i = 0; i != 4; ++i) { |
|
2889 switch (pat [i]) { |
|
2890 case std::money_base::symbol: |
|
2891 strcat (buffer, "symbol "); |
|
2892 break; |
|
2893 |
|
2894 case std::money_base::sign: |
|
2895 strcat (buffer, "sign "); |
|
2896 break; |
|
2897 |
|
2898 case std::money_base::none: |
|
2899 strcat (buffer, "none "); |
|
2900 break; |
|
2901 |
|
2902 case std::money_base::value: |
|
2903 strcat (buffer, "value "); |
|
2904 break; |
|
2905 |
|
2906 case std::money_base::space: |
|
2907 strcat (buffer, "space "); |
|
2908 break; |
|
2909 |
|
2910 default: |
|
2911 sprintf (buffer + strlen (buffer), "\\%03o", pat [i]); |
|
2912 break; |
|
2913 } |
|
2914 } |
|
2915 |
|
2916 const size_t len = strlen (buffer); |
|
2917 |
|
2918 if (0 == _rw_bufcat (pbuf, pbufsize, buffer, len)) |
|
2919 return -1; |
|
2920 |
|
2921 return int (len); |
|
2922 } |
|
2923 |
|
2924 /********************************************************************/ |
|
2925 |
|
2926 static int |
|
2927 libstd_vasnprintf (FmtSpec *pspec, size_t paramno, |
|
2928 char **pbuf, size_t *pbufsize, |
|
2929 const char *fmt, va_list *pva) |
|
2930 { |
|
2931 assert (0 != pva); |
|
2932 assert (0 != pspec); |
|
2933 |
|
2934 _RWSTD_UNUSED (fmt); |
|
2935 |
|
2936 FmtSpec &spec = pspec [paramno]; |
|
2937 |
|
2938 // the length of the sequence appended to the buffer to return |
|
2939 // to the caller, or a negative value (such as -1) on error |
|
2940 int len = -1; |
|
2941 |
|
2942 switch (spec.cvtspec) { |
|
2943 |
|
2944 case '?': // %{?} |
|
2945 // beginning of an if clause |
|
2946 spec.cond = 1; |
|
2947 spec.cond_begin = 1; |
|
2948 spec.cond_true = 0 != va_arg (*pva, int); |
|
2949 len = 0; |
|
2950 break; |
|
2951 |
|
2952 case ':': // %{:} |
|
2953 if (spec.cond) { |
|
2954 // end of an active if clause and the beginning |
|
2955 // of an inactive else clause |
|
2956 |
|
2957 spec.cond_begin = 1; // beginning of an else clause |
|
2958 spec.cond_end = 1; // end of an if clause |
|
2959 spec.cond_true = !spec.cond_true; |
|
2960 len = 0; |
|
2961 } |
|
2962 else { |
|
2963 // misplaced "%{:}"? |
|
2964 static const char str[] = "%{:}"; |
|
2965 len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0); |
|
2966 } |
|
2967 break; |
|
2968 |
|
2969 case ';': // %{;} |
|
2970 if (spec.cond) { |
|
2971 spec.cond_end = 1; // end of an if or else clause |
|
2972 len = 0; |
|
2973 } |
|
2974 else { |
|
2975 // misplaced "%{;}"? |
|
2976 static const char str[] = "%{;}"; |
|
2977 len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0); |
|
2978 } |
|
2979 break; |
|
2980 |
|
2981 case 'c': // %{c}, %{Ac}, %{Lc}, %{lc} |
|
2982 if (spec.mod_A) { |
|
2983 if (-1 == spec.width || 1 == spec.width) { |
|
2984 spec.param.ptr = PARAM (_RWSTD_UINT8_T*, ptr); |
|
2985 const _RWSTD_UINT8_T* const array = |
|
2986 (_RWSTD_UINT8_T*)spec.param.ptr; |
|
2987 len = rw_quotestr (spec, pbuf, pbufsize, array, |
|
2988 _RWSTD_SIZE_MAX, 0); |
|
2989 } |
|
2990 else if (2 == spec.width) { |
|
2991 spec.param.ptr = PARAM (_RWSTD_UINT16_T*, ptr); |
|
2992 const _RWSTD_UINT16_T* const array = |
|
2993 (_RWSTD_UINT16_T*)spec.param.ptr; |
|
2994 len = rw_quotestr (spec, pbuf, pbufsize, array, |
|
2995 _RWSTD_SIZE_MAX, 0); |
|
2996 } |
|
2997 else if (4 == spec.width) { |
|
2998 spec.param.ptr = PARAM (_RWSTD_UINT32_T*, ptr); |
|
2999 const _RWSTD_UINT32_T* const array = |
|
3000 (_RWSTD_UINT32_T*)spec.param.ptr; |
|
3001 len = rw_quotestr (spec, pbuf, pbufsize, array, |
|
3002 _RWSTD_SIZE_MAX, 0); |
|
3003 } |
|
3004 |
|
3005 #ifdef _RWSTD_UINT64_T |
|
3006 |
|
3007 else if (8 == spec.width) { |
|
3008 spec.param.ptr = PARAM (_RWSTD_UINT64_T*, ptr); |
|
3009 const _RWSTD_UINT64_T* const array = |
|
3010 (_RWSTD_UINT64_T*)spec.param.ptr; |
|
3011 len = rw_quotestr (spec, pbuf, pbufsize, array, |
|
3012 _RWSTD_SIZE_MAX, 0); |
|
3013 } |
|
3014 |
|
3015 #endif // _RWSTD_UINT64_T |
|
3016 |
|
3017 else { |
|
3018 assert (!"%{Ac} not implemented for this character size"); |
|
3019 } |
|
3020 } |
|
3021 else if (spec.mod_L) { // locale category or LC_XXX constant |
|
3022 spec.param.i = PARAM (int, i); |
|
3023 len = rw_fmtlc (spec, pbuf, pbufsize, spec.param.i); |
|
3024 } |
|
3025 else if (spec.mod_l) { // wchar_t |
|
3026 spec.param.wi = PARAM (wint_t, i); |
|
3027 return _rw_fmtwchr (spec, pbuf, pbufsize, spec.param.wi); |
|
3028 } |
|
3029 else { // char |
|
3030 spec.param.i = PARAM (int, i); |
|
3031 return _rw_fmtchr (spec, pbuf, pbufsize, spec.param.i); |
|
3032 } |
|
3033 break; |
|
3034 |
|
3035 case 'e': // %{e}, %{Ae} |
|
3036 if (spec.mod_A) { // array of floating point values |
|
3037 spec.param.ptr = PARAM (void*, ptr); |
|
3038 len = _rw_fmtfloating (spec, pbuf, pbufsize, spec.param.ptr); |
|
3039 } |
|
3040 else if (spec.mod_I) { // ios::copyfmt_event |
|
3041 spec.param.i = PARAM (int, i); |
|
3042 len = _rw_fmtevent (spec, pbuf, pbufsize, spec.param.i); |
|
3043 } |
|
3044 break; |
|
3045 |
|
3046 case 'f': // %{f}, %{Af}, %{If} |
|
3047 if (spec.mod_A) { // array of floating point values |
|
3048 spec.param.ptr = PARAM (void*, ptr); |
|
3049 len = _rw_fmtfloating (spec, pbuf, pbufsize, spec.param.ptr); |
|
3050 } |
|
3051 if (spec.mod_I) { // ios::fmtflags |
|
3052 spec.param.i = PARAM (int, i); |
|
3053 len = rw_fmtflags (spec, pbuf, pbufsize, spec.param.i); |
|
3054 } |
|
3055 else { // function pointer |
|
3056 spec.param.funptr = PARAM (funptr_t, funptr); |
|
3057 len = _rw_fmtfunptr (spec, pbuf, pbufsize, spec.param.funptr); |
|
3058 } |
|
3059 break; |
|
3060 |
|
3061 case 'g': // %{g}, %{Ag} |
|
3062 if (spec.mod_A) { // array of floating point values |
|
3063 spec.param.ptr = PARAM (void*, ptr); |
|
3064 len = _rw_fmtfloating (spec, pbuf, pbufsize, spec.param.ptr); |
|
3065 } |
|
3066 else { |
|
3067 assert (!"%{g} not implemented"); |
|
3068 } |
|
3069 |
|
3070 case 'd': // %{Id} |
|
3071 case 'i': // %{Ii} |
|
3072 case 'o': // %{Io} |
|
3073 if (spec.mod_I) { // ios::openmode |
|
3074 spec.param.i = PARAM (int, i); |
|
3075 len = _rw_fmtopenmode (spec, pbuf, pbufsize, spec.param.i); |
|
3076 break; |
|
3077 } |
|
3078 case 'x': // %{x} |
|
3079 case 'X': // %{X} |
|
3080 case 'u': // %{u} |
|
3081 len = _rw_fmtinteger (pspec, paramno, pbuf, pbufsize, pva); |
|
3082 break; |
|
3083 |
|
3084 case 'K': // %{K} -- signal |
|
3085 spec.param.i = PARAM (int, i); |
|
3086 len = _rw_fmtsignal (spec, pbuf, pbufsize, spec.param.i); |
|
3087 break; |
|
3088 |
|
3089 case 'm': // %{m} -- errno |
|
3090 if (-1 == spec.width) |
|
3091 len = _rw_fmterrno (spec, pbuf, pbufsize, errno); |
|
3092 else |
|
3093 len = _rw_fmterrno (spec, pbuf, pbufsize, spec.width); |
|
3094 break; |
|
3095 |
|
3096 case 'M': // %{M}, %{LM} |
|
3097 if (spec.mod_L) { // money_base::pattern |
|
3098 spec.param.ptr = PARAM (char*, ptr); |
|
3099 len = _rw_fmtmonpat (spec, pbuf, pbufsize, (char*)spec.param.ptr); |
|
3100 } |
|
3101 else { // member pointer |
|
3102 spec.param.memptr = PARAM (memptr_t, memptr); |
|
3103 len = _rw_fmtmemptr (spec, pbuf, pbufsize, spec.param.memptr); |
|
3104 } |
|
3105 break; |
|
3106 |
|
3107 case 'n': { // %{n} |
|
3108 // The argument shall be a pointer to signed integer into which |
|
3109 // is written the size of the buffer allocated by this call to |
|
3110 // fprintf. No argument is converted, but one is consumed. If |
|
3111 // the conversion specification includes any flags, a field |
|
3112 // width, or a precision, the behavior is undefined. |
|
3113 |
|
3114 assert (0 != pbuf); |
|
3115 assert (0 != *pbuf); |
|
3116 |
|
3117 const size_t nbytes = pbufsize ? *pbufsize : 0; |
|
3118 |
|
3119 spec.param.ptr = PARAM (void*, ptr); |
|
3120 |
|
3121 if (spec.mod_hh) { |
|
3122 unsigned char* const ptr = (unsigned char*)spec.param.ptr; |
|
3123 |
|
3124 assert (0 != ptr); |
|
3125 |
|
3126 *ptr = (unsigned char)nbytes; |
|
3127 } |
|
3128 else if (spec.mod_h) { |
|
3129 short* const ptr = (short*)spec.param.ptr; |
|
3130 |
|
3131 assert (0 != ptr); |
|
3132 |
|
3133 *ptr = short (nbytes); |
|
3134 } |
|
3135 else if (spec.mod_L) { |
|
3136 #ifdef _RWSTD_LONG_LONG |
|
3137 _RWSTD_LONG_LONG* const ptr = (_RWSTD_LONG_LONG*)spec.param.ptr; |
|
3138 |
|
3139 assert (0 != ptr); |
|
3140 |
|
3141 *ptr = (_RWSTD_LONG_LONG)(nbytes); |
|
3142 #else // if !defined (_RWSTD_LONG_LONG) |
|
3143 assert (!"%{Ln} not implemented"); |
|
3144 #endif // _RWSTD_LONG_LONG |
|
3145 } |
|
3146 else if (spec.mod_l) { |
|
3147 long* const ptr = (long*)spec.param.ptr; |
|
3148 |
|
3149 assert (0 != ptr); |
|
3150 |
|
3151 *ptr = long (nbytes); |
|
3152 } |
|
3153 else if (spec.mod_t) { |
|
3154 ptrdiff_t* const ptr = (ptrdiff_t*)spec.param.ptr; |
|
3155 |
|
3156 assert (0 != ptr); |
|
3157 |
|
3158 *ptr = ptrdiff_t (nbytes); |
|
3159 } |
|
3160 else { |
|
3161 int* const ptr = (int*)spec.param.ptr; |
|
3162 |
|
3163 assert (0 != ptr); |
|
3164 |
|
3165 *ptr = int (nbytes); |
|
3166 } |
|
3167 len = 0; |
|
3168 break; |
|
3169 } |
|
3170 |
|
3171 case 's': // %{s}, %{Is}, %{ls} |
|
3172 if (spec.mod_I) { // ios::iostate |
|
3173 spec.param.i = PARAM (int, i); |
|
3174 len = rw_fmtiostate (spec, pbuf, pbufsize, spec.param.i); |
|
3175 } |
|
3176 else if (spec.mod_l) { // wchar_t* |
|
3177 spec.param.ptr = PARAM (wchar_t*, ptr); |
|
3178 const wchar_t* const wstr = (wchar_t*)spec.param.ptr; |
|
3179 len = rw_quotestr (spec, pbuf, pbufsize, wstr, _RWSTD_SIZE_MAX, 0); |
|
3180 } |
|
3181 else { // char* |
|
3182 spec.param.ptr = PARAM (char*, ptr); |
|
3183 const char* const str = (char*)spec.param.ptr; |
|
3184 len = rw_quotestr (spec, pbuf, pbufsize, str, _RWSTD_SIZE_MAX, 0); |
|
3185 } |
|
3186 break; |
|
3187 |
|
3188 case 'S': // %{S}, %{lS} |
|
3189 if (spec.mod_l) { // std::wstring |
|
3190 spec.param.ptr = PARAM (std::wstring*, ptr); |
|
3191 |
|
3192 const std::wstring* const pstr = (std::wstring*)spec.param.ptr; |
|
3193 const wchar_t* const wstr = pstr->data (); |
|
3194 const std::wstring::size_type size = pstr->size (); |
|
3195 |
|
3196 len = _rw_fmtwstr (spec, pbuf, pbufsize, wstr, size); |
|
3197 } |
|
3198 else { // std::string |
|
3199 spec.param.ptr = PARAM (std::string*, ptr); |
|
3200 |
|
3201 const std::string* const pstr = (std::string*)spec.param.ptr; |
|
3202 const char* const str = pstr->data (); |
|
3203 const std::string::size_type size = pstr->size (); |
|
3204 |
|
3205 len = _rw_fmtstr (spec, pbuf, pbufsize, str, size); |
|
3206 } |
|
3207 break; |
|
3208 |
|
3209 default: |
|
3210 if (spec.strarg) { |
|
3211 // environment variable |
|
3212 const char* val = getenv (spec.strarg); |
|
3213 |
|
3214 if (!val) |
|
3215 val = ""; |
|
3216 |
|
3217 len = int (strlen (val)); |
|
3218 |
|
3219 if (0 == _rw_bufcat (pbuf, pbufsize, val, size_t (len))) |
|
3220 return -1; |
|
3221 |
|
3222 free (spec.strarg); |
|
3223 } |
|
3224 else { |
|
3225 assert (!"not implemented"); |
|
3226 } |
|
3227 } |
|
3228 |
|
3229 return len; |
|
3230 } |
|
3231 |
|
3232 /********************************************************************/ |
|
3233 |
|
3234 /* extern */ int |
|
3235 (*rw_vasnprintf_cb)(FmtSpec*, size_t, char**, size_t*, const char*, va_list*) |
|
3236 = libstd_vasnprintf; |
|
3237 |
|
3238 /********************************************************************/ |
|
3239 |
|
3240 _TEST_EXPORT int |
|
3241 rw_asnprintf (char **pbuf, size_t *pbufsize, const char *fmt, ...) |
|
3242 { |
|
3243 assert (0 == pbuf || 0 == *pbuf || pbufsize); |
|
3244 |
|
3245 va_list va; |
|
3246 va_start (va, fmt); |
|
3247 |
|
3248 char* buf = 0; |
|
3249 size_t bufsize = 0; |
|
3250 |
|
3251 if (0 == pbuf) { |
|
3252 // if pbyf is 0 (i.e., this is a request for the size of the |
|
3253 // buffer necessary to format all the arguments), set pbuf to |
|
3254 // point to a local buf |
|
3255 pbuf = &buf; |
|
3256 } |
|
3257 |
|
3258 if (0 == pbufsize) { |
|
3259 // pbuf may be 0 regardless of the value of pbuf |
|
3260 pbufsize = &bufsize; |
|
3261 } |
|
3262 |
|
3263 const int nchars = rw_vasnprintf (pbuf, pbufsize, fmt, va); |
|
3264 |
|
3265 va_end (va); |
|
3266 |
|
3267 // verify that the length of the fomatted buffer is less than |
|
3268 // its size (this test is unreliable if there are any embedded |
|
3269 // NULs in the output) |
|
3270 assert (nchars < 0 || strlen (*pbuf) < *pbufsize); |
|
3271 |
|
3272 if (pbuf == &buf) { |
|
3273 // free the character buffer if pbuf was initially 0 |
|
3274 free (pbuf); |
|
3275 } |
|
3276 |
|
3277 return nchars; |
|
3278 } |
|
3279 |
|
3280 /********************************************************************/ |
|
3281 |
|
3282 _TEST_EXPORT char* |
|
3283 rw_snprintfa (char *buf, size_t bufsize, const char* fmt, ...) |
|
3284 { |
|
3285 if (buf) |
|
3286 *buf = '\0'; |
|
3287 |
|
3288 va_list va; |
|
3289 va_start (va, fmt); |
|
3290 |
|
3291 const int nchars = rw_vasnprintf (&buf, &bufsize, fmt, va); |
|
3292 |
|
3293 va_end (va); |
|
3294 |
|
3295 // verify that the length of the fomatted buffer is less than |
|
3296 // its size (this test is unreliable if there are any embedded |
|
3297 // NULs in the output) |
|
3298 assert (nchars < 0 || strlen (buf) < bufsize); |
|
3299 |
|
3300 _RWSTD_UNUSED (nchars); |
|
3301 |
|
3302 return buf; |
|
3303 } |
|
3304 |
|
3305 /********************************************************************/ |
|
3306 |
|
3307 _TEST_EXPORT char* |
|
3308 rw_sprintfa (const char *fmt, ...) |
|
3309 { |
|
3310 char* buf = 0; |
|
3311 size_t bufsize = 0; |
|
3312 |
|
3313 va_list va; |
|
3314 va_start (va, fmt); |
|
3315 |
|
3316 const int nchars = rw_vasnprintf (&buf, &bufsize, fmt, va); |
|
3317 |
|
3318 va_end (va); |
|
3319 |
|
3320 // verify that the length of the fomatted buffer is less than |
|
3321 // its size (this test is unreliable if there are any embedded |
|
3322 // NULs in the output) |
|
3323 assert (nchars < 0 || strlen (buf) < bufsize); |
|
3324 |
|
3325 _RWSTD_UNUSED (nchars); |
|
3326 |
|
3327 return buf; |
|
3328 } |
|
3329 |
|
3330 |
|
3331 /********************************************************************/ |
|
3332 |
|
3333 // avoid re-declaring these as exported here and instead rely on the |
|
3334 // declaration in the header #included above in order to prevent the |
|
3335 // bogus MSVC error: |
|
3336 // error C2201: 'rw_stdout' : must have external linkage in order to |
|
3337 // be exported/imported |
|
3338 |
|
3339 /* _TEST_EXPORT */ rw_file* const |
|
3340 rw_stdout = _RWSTD_REINTERPRET_CAST (rw_file*, stdout); |
|
3341 |
|
3342 /* _TEST_EXPORT */ rw_file* const |
|
3343 rw_stderr = _RWSTD_REINTERPRET_CAST (rw_file*, stderr); |
|
3344 |
|
3345 /********************************************************************/ |
|
3346 |
|
3347 static int |
|
3348 _rw_vfprintf (rw_file *file, const char *fmt, va_list va) |
|
3349 { |
|
3350 assert (0 != file); |
|
3351 |
|
3352 char* buf = 0; |
|
3353 size_t bufsize = 0; |
|
3354 |
|
3355 const int nchars = rw_vasnprintf (&buf, &bufsize, fmt, va); |
|
3356 |
|
3357 // FIXME: implement this in terms of POSIX write() |
|
3358 // for async-signal safety |
|
3359 FILE* const stdio_file = _RWSTD_REINTERPRET_CAST (FILE*, file); |
|
3360 |
|
3361 const int nwrote = 0 < nchars ? |
|
3362 fwrite (buf, 1, nchars, stdio_file) : nchars; |
|
3363 |
|
3364 // flush in case stderr isn't line-buffered (e.g., when |
|
3365 // it's determined not to refer to a terminal device, |
|
3366 // for example after it has been redirected to a file) |
|
3367 fflush (stdio_file); |
|
3368 |
|
3369 #ifdef _MSC_VER |
|
3370 |
|
3371 // IsDebuggerPresent() depends on the macros _WIN32_WINNT and WINVER |
|
3372 // being appropriately #defined prior to the #inclusion of <windows.h> |
|
3373 if (IsDebuggerPresent ()) { |
|
3374 |
|
3375 // write string to the attached debugger (if any) |
|
3376 OutputDebugString (buf); |
|
3377 } |
|
3378 |
|
3379 #endif // _MSC_VER |
|
3380 |
|
3381 free (buf); |
|
3382 |
|
3383 return nwrote; |
|
3384 } |
|
3385 |
|
3386 /********************************************************************/ |
|
3387 |
|
3388 _TEST_EXPORT int |
|
3389 rw_fprintf (rw_file *file, const char *fmt, ...) |
|
3390 { |
|
3391 va_list va; |
|
3392 va_start (va, fmt); |
|
3393 |
|
3394 const int nchars = _rw_vfprintf (file, fmt, va); |
|
3395 |
|
3396 va_end (va); |
|
3397 |
|
3398 return nchars; |
|
3399 } |
|
3400 |
|
3401 /********************************************************************/ |
|
3402 |
|
3403 _TEST_EXPORT int |
|
3404 rw_printf (const char *fmt, ...) |
|
3405 { |
|
3406 va_list va; |
|
3407 va_start (va, fmt); |
|
3408 |
|
3409 const int nchars = _rw_vfprintf (rw_stdout, fmt, va); |
|
3410 |
|
3411 va_end (va); |
|
3412 |
|
3413 return nchars; |
|
3414 } |