Mercurial > pidgin
comparison plugins/jabber/snprintf.c @ 1347:afa63ac2fd84
[gaim-migrate @ 1357]
jabber for those not fortunate enough to have libjabber and libxode on their systems
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Thu, 21 Dec 2000 14:54:13 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1346:83f78eb7c472 | 1347:afa63ac2fd84 |
---|---|
1 /* ==================================================================== | |
2 * Copyright (c) 1995-1998 The Apache Group. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * | |
11 * 2. Redistributions in binary form must reproduce the above copyright | |
12 * notice, this list of conditions and the following disclaimer in | |
13 * the documentation and/or other materials provided with the | |
14 * distribution. | |
15 * | |
16 * 3. All advertising materials mentioning features or use of this | |
17 * software must display the following acknowledgment: | |
18 * "This product includes software developed by the Apache Group | |
19 * for use in the Apache HTTP server project (http://www.apache.org/)." | |
20 * | |
21 * 4. The names "Apache Server" and "Apache Group" must not be used to | |
22 * endorse or promote products derived from this software without | |
23 * prior written permission. | |
24 * | |
25 * 5. Redistributions of any form whatsoever must retain the following | |
26 * acknowledgment: | |
27 * "This product includes software developed by the Apache Group | |
28 * for use in the Apache HTTP server project (http://www.apache.org/)." | |
29 * | |
30 * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY | |
31 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR | |
34 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
41 * OF THE POSSIBILITY OF SUCH DAMAGE. | |
42 * ==================================================================== | |
43 * | |
44 * This software consists of voluntary contributions made by many | |
45 * individuals on behalf of the Apache Group and was originally based | |
46 * on public domain software written at the National Center for | |
47 * Supercomputing Applications, University of Illinois, Urbana-Champaign. | |
48 * For more information on the Apache Group and the Apache HTTP server | |
49 * project, please see <http://www.apache.org/>. | |
50 * | |
51 * This code is based on, and used with the permission of, the | |
52 * SIO stdio-replacement strx_* functions by Panos Tsirigotis | |
53 * <panos@alumni.cs.colorado.edu> for xinetd. | |
54 */ | |
55 | |
56 #include <libxode.h> | |
57 | |
58 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) | |
59 | |
60 #include <stdio.h> | |
61 #include <ctype.h> | |
62 #include <sys/types.h> | |
63 #include <stdarg.h> | |
64 #include <string.h> | |
65 #include <stdlib.h> | |
66 #include <math.h> | |
67 | |
68 | |
69 #ifdef HAVE_GCVT | |
70 | |
71 #define ap_ecvt ecvt | |
72 #define ap_fcvt fcvt | |
73 #define ap_gcvt gcvt | |
74 | |
75 #else | |
76 | |
77 /* | |
78 * cvt.c - IEEE floating point formatting routines for FreeBSD | |
79 * from GNU libc-4.6.27 | |
80 */ | |
81 | |
82 /* | |
83 * ap_ecvt converts to decimal | |
84 * the number of digits is specified by ndigit | |
85 * decpt is set to the position of the decimal point | |
86 * sign is set to 0 for positive, 1 for negative | |
87 */ | |
88 | |
89 #define NDIG 80 | |
90 | |
91 static char * | |
92 ap_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag) | |
93 { | |
94 register int r2; | |
95 double fi, fj; | |
96 register char *p, *p1; | |
97 static char buf[NDIG]; | |
98 | |
99 if (ndigits >= NDIG - 1) | |
100 ndigits = NDIG - 2; | |
101 r2 = 0; | |
102 *sign = 0; | |
103 p = &buf[0]; | |
104 if (arg < 0) { | |
105 *sign = 1; | |
106 arg = -arg; | |
107 } | |
108 arg = modf(arg, &fi); | |
109 p1 = &buf[NDIG]; | |
110 /* | |
111 * Do integer part | |
112 */ | |
113 if (fi != 0) { | |
114 p1 = &buf[NDIG]; | |
115 while (fi != 0) { | |
116 fj = modf(fi / 10, &fi); | |
117 *--p1 = (int) ((fj + .03) * 10) + '0'; | |
118 r2++; | |
119 } | |
120 while (p1 < &buf[NDIG]) | |
121 *p++ = *p1++; | |
122 } else if (arg > 0) { | |
123 while ((fj = arg * 10) < 1) { | |
124 arg = fj; | |
125 r2--; | |
126 } | |
127 } | |
128 p1 = &buf[ndigits]; | |
129 if (eflag == 0) | |
130 p1 += r2; | |
131 *decpt = r2; | |
132 if (p1 < &buf[0]) { | |
133 buf[0] = '\0'; | |
134 return (buf); | |
135 } | |
136 while (p <= p1 && p < &buf[NDIG]) { | |
137 arg *= 10; | |
138 arg = modf(arg, &fj); | |
139 *p++ = (int) fj + '0'; | |
140 } | |
141 if (p1 >= &buf[NDIG]) { | |
142 buf[NDIG - 1] = '\0'; | |
143 return (buf); | |
144 } | |
145 p = p1; | |
146 *p1 += 5; | |
147 while (*p1 > '9') { | |
148 *p1 = '0'; | |
149 if (p1 > buf) | |
150 ++ * --p1; | |
151 else { | |
152 *p1 = '1'; | |
153 (*decpt)++; | |
154 if (eflag == 0) { | |
155 if (p > buf) | |
156 *p = '0'; | |
157 p++; | |
158 } | |
159 } | |
160 } | |
161 *p = '\0'; | |
162 return (buf); | |
163 } | |
164 | |
165 static char * | |
166 ap_ecvt(double arg, int ndigits, int *decpt, int *sign) | |
167 { | |
168 return (ap_cvt(arg, ndigits, decpt, sign, 1)); | |
169 } | |
170 | |
171 static char * | |
172 ap_fcvt(double arg, int ndigits, int *decpt, int *sign) | |
173 { | |
174 return (ap_cvt(arg, ndigits, decpt, sign, 0)); | |
175 } | |
176 | |
177 /* | |
178 * ap_gcvt - Floating output conversion to | |
179 * minimal length string | |
180 */ | |
181 | |
182 static char * | |
183 ap_gcvt(double number, int ndigit, char *buf) | |
184 { | |
185 int sign, decpt; | |
186 register char *p1, *p2; | |
187 int i; | |
188 | |
189 p1 = ap_ecvt(number, ndigit, &decpt, &sign); | |
190 p2 = buf; | |
191 if (sign) | |
192 *p2++ = '-'; | |
193 for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) | |
194 ndigit--; | |
195 if ((decpt >= 0 && decpt - ndigit > 4) | |
196 || (decpt < 0 && decpt < -3)) { /* use E-style */ | |
197 decpt--; | |
198 *p2++ = *p1++; | |
199 *p2++ = '.'; | |
200 for (i = 1; i < ndigit; i++) | |
201 *p2++ = *p1++; | |
202 *p2++ = 'e'; | |
203 if (decpt < 0) { | |
204 decpt = -decpt; | |
205 *p2++ = '-'; | |
206 } else | |
207 *p2++ = '+'; | |
208 if (decpt / 100 > 0) | |
209 *p2++ = decpt / 100 + '0'; | |
210 if (decpt / 10 > 0) | |
211 *p2++ = (decpt % 100) / 10 + '0'; | |
212 *p2++ = decpt % 10 + '0'; | |
213 } else { | |
214 if (decpt <= 0) { | |
215 if (*p1 != '0') | |
216 *p2++ = '.'; | |
217 while (decpt < 0) { | |
218 decpt++; | |
219 *p2++ = '0'; | |
220 } | |
221 } | |
222 for (i = 1; i <= ndigit; i++) { | |
223 *p2++ = *p1++; | |
224 if (i == decpt) | |
225 *p2++ = '.'; | |
226 } | |
227 if (ndigit < decpt) { | |
228 while (ndigit++ < decpt) | |
229 *p2++ = '0'; | |
230 *p2++ = '.'; | |
231 } | |
232 } | |
233 if (p2[-1] == '.') | |
234 p2--; | |
235 *p2 = '\0'; | |
236 return (buf); | |
237 } | |
238 | |
239 #endif /* HAVE_CVT */ | |
240 | |
241 typedef enum { | |
242 NO = 0, YES = 1 | |
243 } boolean_e; | |
244 | |
245 #define FALSE 0 | |
246 #define TRUE 1 | |
247 #define NUL '\0' | |
248 #define INT_NULL ((int *)0) | |
249 #define WIDE_INT long | |
250 | |
251 typedef WIDE_INT wide_int; | |
252 typedef unsigned WIDE_INT u_wide_int; | |
253 typedef int bool_int; | |
254 | |
255 #define S_NULL "(null)" | |
256 #define S_NULL_LEN 6 | |
257 | |
258 #define FLOAT_DIGITS 6 | |
259 #define EXPONENT_LENGTH 10 | |
260 | |
261 /* | |
262 * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions | |
263 * | |
264 * XXX: this is a magic number; do not decrease it | |
265 */ | |
266 #define NUM_BUF_SIZE 512 | |
267 | |
268 | |
269 /* | |
270 * Descriptor for buffer area | |
271 */ | |
272 struct buf_area { | |
273 char *buf_end; | |
274 char *nextb; /* pointer to next byte to read/write */ | |
275 }; | |
276 | |
277 typedef struct buf_area buffy; | |
278 | |
279 /* | |
280 * The INS_CHAR macro inserts a character in the buffer and writes | |
281 * the buffer back to disk if necessary | |
282 * It uses the char pointers sp and bep: | |
283 * sp points to the next available character in the buffer | |
284 * bep points to the end-of-buffer+1 | |
285 * While using this macro, note that the nextb pointer is NOT updated. | |
286 * | |
287 * NOTE: Evaluation of the c argument should not have any side-effects | |
288 */ | |
289 #define INS_CHAR( c, sp, bep, cc ) \ | |
290 { \ | |
291 if ( sp < bep ) \ | |
292 { \ | |
293 *sp++ = c ; \ | |
294 cc++ ; \ | |
295 } \ | |
296 } | |
297 | |
298 #define NUM( c ) ( c - '0' ) | |
299 | |
300 #define STR_TO_DEC( str, num ) \ | |
301 num = NUM( *str++ ) ; \ | |
302 while ( isdigit((int)*str ) ) \ | |
303 { \ | |
304 num *= 10 ; \ | |
305 num += NUM( *str++ ) ; \ | |
306 } | |
307 | |
308 /* | |
309 * This macro does zero padding so that the precision | |
310 * requirement is satisfied. The padding is done by | |
311 * adding '0's to the left of the string that is going | |
312 * to be printed. | |
313 */ | |
314 #define FIX_PRECISION( adjust, precision, s, s_len ) \ | |
315 if ( adjust ) \ | |
316 while ( s_len < precision ) \ | |
317 { \ | |
318 *--s = '0' ; \ | |
319 s_len++ ; \ | |
320 } | |
321 | |
322 /* | |
323 * Macro that does padding. The padding is done by printing | |
324 * the character ch. | |
325 */ | |
326 #define PAD( width, len, ch ) do \ | |
327 { \ | |
328 INS_CHAR( ch, sp, bep, cc ) ; \ | |
329 width-- ; \ | |
330 } \ | |
331 while ( width > len ) | |
332 | |
333 /* | |
334 * Prefix the character ch to the string str | |
335 * Increase length | |
336 * Set the has_prefix flag | |
337 */ | |
338 #define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES | |
339 | |
340 | |
341 /* | |
342 * Convert num to its decimal format. | |
343 * Return value: | |
344 * - a pointer to a string containing the number (no sign) | |
345 * - len contains the length of the string | |
346 * - is_negative is set to TRUE or FALSE depending on the sign | |
347 * of the number (always set to FALSE if is_unsigned is TRUE) | |
348 * | |
349 * The caller provides a buffer for the string: that is the buf_end argument | |
350 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer | |
351 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) | |
352 */ | |
353 static char * | |
354 conv_10(register wide_int num, register bool_int is_unsigned, | |
355 register bool_int * is_negative, char *buf_end, register int *len) | |
356 { | |
357 register char *p = buf_end; | |
358 register u_wide_int magnitude; | |
359 | |
360 if (is_unsigned) { | |
361 magnitude = (u_wide_int) num; | |
362 *is_negative = FALSE; | |
363 } else { | |
364 *is_negative = (num < 0); | |
365 | |
366 /* | |
367 * On a 2's complement machine, negating the most negative integer | |
368 * results in a number that cannot be represented as a signed integer. | |
369 * Here is what we do to obtain the number's magnitude: | |
370 * a. add 1 to the number | |
371 * b. negate it (becomes positive) | |
372 * c. convert it to unsigned | |
373 * d. add 1 | |
374 */ | |
375 if (*is_negative) { | |
376 wide_int t = num + 1; | |
377 | |
378 magnitude = ((u_wide_int) - t) + 1; | |
379 } else | |
380 magnitude = (u_wide_int) num; | |
381 } | |
382 | |
383 /* | |
384 * We use a do-while loop so that we write at least 1 digit | |
385 */ | |
386 do { | |
387 register u_wide_int new_magnitude = magnitude / 10; | |
388 | |
389 *--p = magnitude - new_magnitude * 10 + '0'; | |
390 magnitude = new_magnitude; | |
391 } | |
392 while (magnitude); | |
393 | |
394 *len = buf_end - p; | |
395 return (p); | |
396 } | |
397 | |
398 | |
399 | |
400 /* | |
401 * Convert a floating point number to a string formats 'f', 'e' or 'E'. | |
402 * The result is placed in buf, and len denotes the length of the string | |
403 * The sign is returned in the is_negative argument (and is not placed | |
404 * in buf). | |
405 */ | |
406 static char * | |
407 conv_fp(register char format, register double num, | |
408 boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len) | |
409 { | |
410 register char *s = buf; | |
411 register char *p; | |
412 int decimal_point; | |
413 | |
414 if (format == 'f') | |
415 p = ap_fcvt(num, precision, &decimal_point, is_negative); | |
416 else /* either e or E format */ | |
417 p = ap_ecvt(num, precision + 1, &decimal_point, is_negative); | |
418 | |
419 /* | |
420 * Check for Infinity and NaN | |
421 */ | |
422 if (isalpha((int)*p)) { | |
423 *len = strlen(strcpy(buf, p)); | |
424 *is_negative = FALSE; | |
425 return (buf); | |
426 } | |
427 if (format == 'f') { | |
428 if (decimal_point <= 0) { | |
429 *s++ = '0'; | |
430 if (precision > 0) { | |
431 *s++ = '.'; | |
432 while (decimal_point++ < 0) | |
433 *s++ = '0'; | |
434 } else if (add_dp) { | |
435 *s++ = '.'; | |
436 } | |
437 } else { | |
438 while (decimal_point-- > 0) { | |
439 *s++ = *p++; | |
440 } | |
441 if (precision > 0 || add_dp) { | |
442 *s++ = '.'; | |
443 } | |
444 } | |
445 } else { | |
446 *s++ = *p++; | |
447 if (precision > 0 || add_dp) | |
448 *s++ = '.'; | |
449 } | |
450 | |
451 /* | |
452 * copy the rest of p, the NUL is NOT copied | |
453 */ | |
454 while (*p) | |
455 *s++ = *p++; | |
456 | |
457 if (format != 'f') { | |
458 char temp[EXPONENT_LENGTH]; /* for exponent conversion */ | |
459 int t_len; | |
460 bool_int exponent_is_negative; | |
461 | |
462 *s++ = format; /* either e or E */ | |
463 decimal_point--; | |
464 if (decimal_point != 0) { | |
465 p = conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, | |
466 &temp[EXPONENT_LENGTH], &t_len); | |
467 *s++ = exponent_is_negative ? '-' : '+'; | |
468 | |
469 /* | |
470 * Make sure the exponent has at least 2 digits | |
471 */ | |
472 if (t_len == 1) | |
473 *s++ = '0'; | |
474 while (t_len--) | |
475 *s++ = *p++; | |
476 } else { | |
477 *s++ = '+'; | |
478 *s++ = '0'; | |
479 *s++ = '0'; | |
480 } | |
481 } | |
482 *len = s - buf; | |
483 return (buf); | |
484 } | |
485 | |
486 | |
487 /* | |
488 * Convert num to a base X number where X is a power of 2. nbits determines X. | |
489 * For example, if nbits is 3, we do base 8 conversion | |
490 * Return value: | |
491 * a pointer to a string containing the number | |
492 * | |
493 * The caller provides a buffer for the string: that is the buf_end argument | |
494 * which is a pointer to the END of the buffer + 1 (i.e. if the buffer | |
495 * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) | |
496 */ | |
497 static char * | |
498 conv_p2(register u_wide_int num, register int nbits, | |
499 char format, char *buf_end, register int *len) | |
500 { | |
501 register int mask = (1 << nbits) - 1; | |
502 register char *p = buf_end; | |
503 static char low_digits[] = "0123456789abcdef"; | |
504 static char upper_digits[] = "0123456789ABCDEF"; | |
505 register char *digits = (format == 'X') ? upper_digits : low_digits; | |
506 | |
507 do { | |
508 *--p = digits[num & mask]; | |
509 num >>= nbits; | |
510 } | |
511 while (num); | |
512 | |
513 *len = buf_end - p; | |
514 return (p); | |
515 } | |
516 | |
517 | |
518 /* | |
519 * Do format conversion placing the output in buffer | |
520 */ | |
521 static int format_converter(register buffy * odp, const char *fmt, | |
522 va_list ap) | |
523 { | |
524 register char *sp; | |
525 register char *bep; | |
526 register int cc = 0; | |
527 register int i; | |
528 | |
529 register char *s = NULL; | |
530 char *q; | |
531 int s_len; | |
532 | |
533 register int min_width = 0; | |
534 int precision = 0; | |
535 enum { | |
536 LEFT, RIGHT | |
537 } adjust; | |
538 char pad_char; | |
539 char prefix_char; | |
540 | |
541 double fp_num; | |
542 wide_int i_num = (wide_int) 0; | |
543 u_wide_int ui_num; | |
544 | |
545 char num_buf[NUM_BUF_SIZE]; | |
546 char char_buf[2]; /* for printing %% and %<unknown> */ | |
547 | |
548 /* | |
549 * Flag variables | |
550 */ | |
551 boolean_e is_long; | |
552 boolean_e alternate_form; | |
553 boolean_e print_sign; | |
554 boolean_e print_blank; | |
555 boolean_e adjust_precision; | |
556 boolean_e adjust_width; | |
557 bool_int is_negative; | |
558 | |
559 sp = odp->nextb; | |
560 bep = odp->buf_end; | |
561 | |
562 while (*fmt) { | |
563 if (*fmt != '%') { | |
564 INS_CHAR(*fmt, sp, bep, cc); | |
565 } else { | |
566 /* | |
567 * Default variable settings | |
568 */ | |
569 adjust = RIGHT; | |
570 alternate_form = print_sign = print_blank = NO; | |
571 pad_char = ' '; | |
572 prefix_char = NUL; | |
573 | |
574 fmt++; | |
575 | |
576 /* | |
577 * Try to avoid checking for flags, width or precision | |
578 */ | |
579 if (isascii((int)*fmt) && !islower((int)*fmt)) { | |
580 /* | |
581 * Recognize flags: -, #, BLANK, + | |
582 */ | |
583 for (;; fmt++) { | |
584 if (*fmt == '-') | |
585 adjust = LEFT; | |
586 else if (*fmt == '+') | |
587 print_sign = YES; | |
588 else if (*fmt == '#') | |
589 alternate_form = YES; | |
590 else if (*fmt == ' ') | |
591 print_blank = YES; | |
592 else if (*fmt == '0') | |
593 pad_char = '0'; | |
594 else | |
595 break; | |
596 } | |
597 | |
598 /* | |
599 * Check if a width was specified | |
600 */ | |
601 if (isdigit((int)*fmt)) { | |
602 STR_TO_DEC(fmt, min_width); | |
603 adjust_width = YES; | |
604 } else if (*fmt == '*') { | |
605 min_width = va_arg(ap, int); | |
606 fmt++; | |
607 adjust_width = YES; | |
608 if (min_width < 0) { | |
609 adjust = LEFT; | |
610 min_width = -min_width; | |
611 } | |
612 } else | |
613 adjust_width = NO; | |
614 | |
615 /* | |
616 * Check if a precision was specified | |
617 * | |
618 * XXX: an unreasonable amount of precision may be specified | |
619 * resulting in overflow of num_buf. Currently we | |
620 * ignore this possibility. | |
621 */ | |
622 if (*fmt == '.') { | |
623 adjust_precision = YES; | |
624 fmt++; | |
625 if (isdigit((int)*fmt)) { | |
626 STR_TO_DEC(fmt, precision); | |
627 } else if (*fmt == '*') { | |
628 precision = va_arg(ap, int); | |
629 fmt++; | |
630 if (precision < 0) | |
631 precision = 0; | |
632 } else | |
633 precision = 0; | |
634 } else | |
635 adjust_precision = NO; | |
636 } else | |
637 adjust_precision = adjust_width = NO; | |
638 | |
639 /* | |
640 * Modifier check | |
641 */ | |
642 if (*fmt == 'l') { | |
643 is_long = YES; | |
644 fmt++; | |
645 } else | |
646 is_long = NO; | |
647 | |
648 /* | |
649 * Argument extraction and printing. | |
650 * First we determine the argument type. | |
651 * Then, we convert the argument to a string. | |
652 * On exit from the switch, s points to the string that | |
653 * must be printed, s_len has the length of the string | |
654 * The precision requirements, if any, are reflected in s_len. | |
655 * | |
656 * NOTE: pad_char may be set to '0' because of the 0 flag. | |
657 * It is reset to ' ' by non-numeric formats | |
658 */ | |
659 switch (*fmt) { | |
660 case 'u': | |
661 if (is_long) | |
662 i_num = va_arg(ap, u_wide_int); | |
663 else | |
664 i_num = (wide_int) va_arg(ap, unsigned int); | |
665 /* | |
666 * The rest also applies to other integer formats, so fall | |
667 * into that case. | |
668 */ | |
669 case 'd': | |
670 case 'i': | |
671 /* | |
672 * Get the arg if we haven't already. | |
673 */ | |
674 if ((*fmt) != 'u') { | |
675 if (is_long) | |
676 i_num = va_arg(ap, wide_int); | |
677 else | |
678 i_num = (wide_int) va_arg(ap, int); | |
679 }; | |
680 s = conv_10(i_num, (*fmt) == 'u', &is_negative, | |
681 &num_buf[NUM_BUF_SIZE], &s_len); | |
682 FIX_PRECISION(adjust_precision, precision, s, s_len); | |
683 | |
684 if (*fmt != 'u') { | |
685 if (is_negative) | |
686 prefix_char = '-'; | |
687 else if (print_sign) | |
688 prefix_char = '+'; | |
689 else if (print_blank) | |
690 prefix_char = ' '; | |
691 } | |
692 break; | |
693 | |
694 | |
695 case 'o': | |
696 if (is_long) | |
697 ui_num = va_arg(ap, u_wide_int); | |
698 else | |
699 ui_num = (u_wide_int) va_arg(ap, unsigned int); | |
700 s = conv_p2(ui_num, 3, *fmt, | |
701 &num_buf[NUM_BUF_SIZE], &s_len); | |
702 FIX_PRECISION(adjust_precision, precision, s, s_len); | |
703 if (alternate_form && *s != '0') { | |
704 *--s = '0'; | |
705 s_len++; | |
706 } | |
707 break; | |
708 | |
709 | |
710 case 'x': | |
711 case 'X': | |
712 if (is_long) | |
713 ui_num = (u_wide_int) va_arg(ap, u_wide_int); | |
714 else | |
715 ui_num = (u_wide_int) va_arg(ap, unsigned int); | |
716 s = conv_p2(ui_num, 4, *fmt, | |
717 &num_buf[NUM_BUF_SIZE], &s_len); | |
718 FIX_PRECISION(adjust_precision, precision, s, s_len); | |
719 if (alternate_form && i_num != 0) { | |
720 *--s = *fmt; /* 'x' or 'X' */ | |
721 *--s = '0'; | |
722 s_len += 2; | |
723 } | |
724 break; | |
725 | |
726 | |
727 case 's': | |
728 s = va_arg(ap, char *); | |
729 if (s != NULL) { | |
730 s_len = strlen(s); | |
731 if (adjust_precision && precision < s_len) | |
732 s_len = precision; | |
733 } else { | |
734 s = S_NULL; | |
735 s_len = S_NULL_LEN; | |
736 } | |
737 pad_char = ' '; | |
738 break; | |
739 | |
740 | |
741 case 'f': | |
742 case 'e': | |
743 case 'E': | |
744 fp_num = va_arg(ap, double); | |
745 | |
746 s = conv_fp(*fmt, fp_num, alternate_form, | |
747 (adjust_precision == NO) ? FLOAT_DIGITS : precision, | |
748 &is_negative, &num_buf[1], &s_len); | |
749 if (is_negative) | |
750 prefix_char = '-'; | |
751 else if (print_sign) | |
752 prefix_char = '+'; | |
753 else if (print_blank) | |
754 prefix_char = ' '; | |
755 break; | |
756 | |
757 | |
758 case 'g': | |
759 case 'G': | |
760 if (adjust_precision == NO) | |
761 precision = FLOAT_DIGITS; | |
762 else if (precision == 0) | |
763 precision = 1; | |
764 /* | |
765 * * We use &num_buf[ 1 ], so that we have room for the sign | |
766 */ | |
767 s = ap_gcvt(va_arg(ap, double), precision, &num_buf[1]); | |
768 if (*s == '-') | |
769 prefix_char = *s++; | |
770 else if (print_sign) | |
771 prefix_char = '+'; | |
772 else if (print_blank) | |
773 prefix_char = ' '; | |
774 | |
775 s_len = strlen(s); | |
776 | |
777 if (alternate_form && (q = strchr(s, '.')) == NULL) | |
778 s[s_len++] = '.'; | |
779 if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) | |
780 *q = 'E'; | |
781 break; | |
782 | |
783 | |
784 case 'c': | |
785 char_buf[0] = (char) (va_arg(ap, int)); | |
786 s = &char_buf[0]; | |
787 s_len = 1; | |
788 pad_char = ' '; | |
789 break; | |
790 | |
791 | |
792 case '%': | |
793 char_buf[0] = '%'; | |
794 s = &char_buf[0]; | |
795 s_len = 1; | |
796 pad_char = ' '; | |
797 break; | |
798 | |
799 | |
800 case 'n': | |
801 *(va_arg(ap, int *)) = cc; | |
802 break; | |
803 | |
804 /* | |
805 * Always extract the argument as a "char *" pointer. We | |
806 * should be using "void *" but there are still machines | |
807 * that don't understand it. | |
808 * If the pointer size is equal to the size of an unsigned | |
809 * integer we convert the pointer to a hex number, otherwise | |
810 * we print "%p" to indicate that we don't handle "%p". | |
811 */ | |
812 case 'p': | |
813 ui_num = (u_wide_int) va_arg(ap, char *); | |
814 | |
815 if (sizeof(char *) <= sizeof(u_wide_int)) | |
816 s = conv_p2(ui_num, 4, 'x', | |
817 &num_buf[NUM_BUF_SIZE], &s_len); | |
818 else { | |
819 s = "%p"; | |
820 s_len = 2; | |
821 } | |
822 pad_char = ' '; | |
823 break; | |
824 | |
825 | |
826 case NUL: | |
827 /* | |
828 * The last character of the format string was %. | |
829 * We ignore it. | |
830 */ | |
831 continue; | |
832 | |
833 | |
834 /* | |
835 * The default case is for unrecognized %'s. | |
836 * We print %<char> to help the user identify what | |
837 * option is not understood. | |
838 * This is also useful in case the user wants to pass | |
839 * the output of format_converter to another function | |
840 * that understands some other %<char> (like syslog). | |
841 * Note that we can't point s inside fmt because the | |
842 * unknown <char> could be preceded by width etc. | |
843 */ | |
844 default: | |
845 char_buf[0] = '%'; | |
846 char_buf[1] = *fmt; | |
847 s = char_buf; | |
848 s_len = 2; | |
849 pad_char = ' '; | |
850 break; | |
851 } | |
852 | |
853 if (prefix_char != NUL) { | |
854 *--s = prefix_char; | |
855 s_len++; | |
856 } | |
857 if (adjust_width && adjust == RIGHT && min_width > s_len) { | |
858 if (pad_char == '0' && prefix_char != NUL) { | |
859 INS_CHAR(*s, sp, bep, cc) | |
860 s++; | |
861 s_len--; | |
862 min_width--; | |
863 } | |
864 PAD(min_width, s_len, pad_char); | |
865 } | |
866 /* | |
867 * Print the string s. | |
868 */ | |
869 for (i = s_len; i != 0; i--) { | |
870 INS_CHAR(*s, sp, bep, cc); | |
871 s++; | |
872 } | |
873 | |
874 if (adjust_width && adjust == LEFT && min_width > s_len) | |
875 PAD(min_width, s_len, pad_char); | |
876 } | |
877 fmt++; | |
878 } | |
879 odp->nextb = sp; | |
880 return (cc); | |
881 } | |
882 | |
883 | |
884 /* | |
885 * This is the general purpose conversion function. | |
886 */ | |
887 static void strx_printv(int *ccp, char *buf, size_t len, const char *format, | |
888 va_list ap) | |
889 { | |
890 buffy od; | |
891 int cc; | |
892 | |
893 /* | |
894 * First initialize the descriptor | |
895 * Notice that if no length is given, we initialize buf_end to the | |
896 * highest possible address. | |
897 */ | |
898 od.buf_end = len ? &buf[len] : (char *) ~0; | |
899 od.nextb = buf; | |
900 | |
901 /* | |
902 * Do the conversion | |
903 */ | |
904 cc = format_converter(&od, format, ap); | |
905 if (len == 0 || od.nextb <= od.buf_end) | |
906 *(od.nextb) = '\0'; | |
907 if (ccp) | |
908 *ccp = cc; | |
909 } | |
910 | |
911 | |
912 int ap_snprintf(char *buf, size_t len, const char *format,...) | |
913 { | |
914 int cc; | |
915 va_list ap; | |
916 | |
917 va_start(ap, format); | |
918 strx_printv(&cc, buf, (len - 1), format, ap); | |
919 va_end(ap); | |
920 return (cc); | |
921 } | |
922 | |
923 | |
924 int ap_vsnprintf(char *buf, size_t len, const char *format, va_list ap) | |
925 { | |
926 int cc; | |
927 | |
928 strx_printv(&cc, buf, (len - 1), format, ap); | |
929 return (cc); | |
930 } | |
931 | |
932 #endif /* HAVE_SNPRINTF */ |