00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <stdarg.h>
00032 #include <stdlib.h>
00033 #include <ctype.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036
00037 #include "RConfig.h"
00038
00039 #if defined(NEED_SNPRINTF) || defined(SNTEST)
00040
00041
00042 #ifndef NEED_SNPRINTF
00043 #define snprintf r__snprintf
00044 #define vsnprintf r__vsnprintf
00045 #endif
00046
00047 #if defined(R__WIN32) && !defined(__CINT__)
00048 typedef __int64 Long64_t;
00049 typedef unsigned __int64 ULong64_t;
00050 #else
00051 typedef long long Long64_t;
00052 typedef unsigned long long ULong64_t;
00053 #endif
00054
00055 #undef isdigit
00056 #define isdigit(ch) ((ch) >= '0' && (ch) <= '9')
00057
00058 #define MINUS_FLAG 0x1
00059 #define PLUS_FLAG 0x2
00060 #define SPACE_FLAG 0x4
00061 #define HASH_FLAG 0x8
00062 #define CONV_TO_SHORT 0x10
00063 #define IS_LONG_INT 0x20
00064 #define IS_LONG_DOUBLE 0x40
00065 #define X_UPCASE 0x80
00066 #define IS_NEGATIVE 0x100
00067 #define UNSIGNED_DEC 0x200
00068 #define ZERO_PADDING 0x400
00069 #define IS_LONG_LONG_INT 0x800
00070
00071 #ifndef DONTNEED_VSNPRINTF
00072
00073
00074
00075
00076 static int snprintf_get_directive(const char *str, int *flags, int *width,
00077 int *precision, char *format_char,
00078 va_list *ap)
00079 {
00080 int length, value;
00081 const char *orig_str = str;
00082
00083 *flags = 0;
00084 *width = 0;
00085 *precision = -1;
00086 *format_char = (char) 0;
00087
00088 if (*str == '%') {
00089
00090 str++;
00091 while (*str == '-' || *str == '+' || *str == ' '
00092 || *str == '#' || *str == '0') {
00093 switch (*str) {
00094 case '-':
00095 *flags |= MINUS_FLAG;
00096 break;
00097 case '+':
00098 *flags |= PLUS_FLAG;
00099 break;
00100 case ' ':
00101 *flags |= SPACE_FLAG;
00102 break;
00103 case '#':
00104 *flags |= HASH_FLAG;
00105 break;
00106 case '0':
00107 *flags |= ZERO_PADDING;
00108 break;
00109 }
00110 str++;
00111 }
00112
00113
00114 if ((*flags & MINUS_FLAG) && (*flags & ZERO_PADDING))
00115 *flags &= ~ZERO_PADDING;
00116
00117
00118 if (isdigit(*str)) {
00119 for (value = 0; *str && isdigit(*str); str++)
00120 value = 10 * value + *str - '0';
00121 *width = value;
00122 } else if (*str == '*') {
00123 *width = va_arg(*ap, int);
00124 str++;
00125 }
00126
00127
00128 if (*str == '.') {
00129 str++;
00130 if (isdigit(*str)) {
00131 for (value = 0; *str && isdigit(*str); str++)
00132 value = 10 * value + *str - '0';
00133 *precision = value;
00134 } else if (*str == '*') {
00135 *precision = va_arg(*ap, int);
00136 str++;
00137 } else
00138 *precision = 0;
00139 }
00140
00141
00142 if (*str == 'h') {
00143 *flags |= CONV_TO_SHORT;
00144 str++;
00145 } else {
00146 if (*str == 'l') {
00147 if (*(str+1)=='l') {
00148 *flags |= IS_LONG_LONG_INT;
00149 str++;
00150 } else {
00151 *flags |= IS_LONG_INT;
00152 }
00153 str++;
00154 } else {
00155
00156 if (*str == 'I' && *(str+1)=='6' && *(str+2)=='4') {
00157 *flags |= IS_LONG_LONG_INT;
00158 str += 3;
00159 } else if (*str == 'L') {
00160 *flags |= IS_LONG_DOUBLE;
00161 str++;
00162 }
00163 }
00164 }
00165
00166
00167
00168 *format_char = *str;
00169 str++;
00170 length = str - orig_str;
00171
00172 switch (*format_char) {
00173 case 'i':
00174 case 'd':
00175 case 'o':
00176 case 'u':
00177 case 'x':
00178 case 'X':
00179 case 'f':
00180 case 'e':
00181 case 'E':
00182 case 'g':
00183 case 'G':
00184 case 'c':
00185 case 's':
00186 case 'p':
00187 case 'n':
00188 if (*format_char == 'X')
00189 *flags |= X_UPCASE;
00190 if (*format_char == 'o')
00191 *flags |= UNSIGNED_DEC;
00192 return length;
00193
00194 default:
00195 return 0;
00196 }
00197 } else {
00198 return 0;
00199 }
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 static int snprintf_convert_ulong(char *buffer, size_t buf_size, int base,
00211 char *digits, ULong64_t ulong_val,
00212 int flags, int width, int precision)
00213 {
00214 int tmp_buf_len = 100 + width, len;
00215 char *tmp_buf, *tmp_buf_ptr, prefix[2];
00216 tmp_buf = malloc(tmp_buf_len);
00217
00218 prefix[0] = '\0';
00219 prefix[1] = '\0';
00220
00221
00222 tmp_buf_ptr = tmp_buf + tmp_buf_len;
00223
00224
00225 do {
00226 *--tmp_buf_ptr = digits[ulong_val % base];
00227 ulong_val /= base;
00228 precision--;
00229 }
00230 while ((ulong_val != 0 || precision > 0) && tmp_buf_ptr > tmp_buf);
00231
00232
00233 if (!(flags & IS_NEGATIVE)) {
00234 if (base == 16 && (flags & HASH_FLAG)) {
00235 if (flags && X_UPCASE) {
00236 prefix[0] = 'x';
00237 prefix[1] = '0';
00238 } else {
00239 prefix[0] = 'X';
00240 prefix[1] = '0';
00241 }
00242 }
00243
00244 if (base == 8 && (flags & HASH_FLAG))
00245 prefix[0] = '0';
00246
00247 if (base == 10 && !(flags & UNSIGNED_DEC) && (flags & PLUS_FLAG))
00248 prefix[0] = '+';
00249 else
00250 if (base == 10 && !(flags & UNSIGNED_DEC)
00251 && (flags & SPACE_FLAG)) prefix[0] = ' ';
00252 } else
00253 prefix[0] = '-';
00254
00255 if (prefix[0] != '\0' && tmp_buf_ptr > tmp_buf) {
00256 *--tmp_buf_ptr = prefix[0];
00257 if (prefix[1] != '\0' && tmp_buf_ptr > tmp_buf)
00258 *--tmp_buf_ptr = prefix[1];
00259 }
00260
00261 len = (tmp_buf + tmp_buf_len) - tmp_buf_ptr;
00262
00263 if (len <= (int)buf_size) {
00264 if (len < width) {
00265 if (width > (tmp_buf_ptr - tmp_buf))
00266 width = (tmp_buf_ptr - tmp_buf);
00267 if (flags & MINUS_FLAG) {
00268 memcpy(buffer, tmp_buf_ptr, len);
00269 memset(buffer + len, (flags & ZERO_PADDING) ? '0' : ' ',
00270 width - len);
00271 len = width;
00272 } else {
00273 memset(buffer, (flags & ZERO_PADDING) ? '0' : ' ',
00274 width - len);
00275 memcpy(buffer + width - len, tmp_buf_ptr, len);
00276 len = width;
00277 }
00278 } else {
00279 memcpy(buffer, tmp_buf_ptr, len);
00280 }
00281 free(tmp_buf);
00282 return len;
00283 } else {
00284 memcpy(buffer, tmp_buf_ptr, buf_size);
00285 free(tmp_buf);
00286 return buf_size;
00287 }
00288 }
00289
00290
00291 static int snprintf_convert_float(char *buffer, size_t buf_size,
00292 double dbl_val, int flags, int width,
00293 int precision, char format_char)
00294 {
00295 char print_buf[160], print_buf_len = 0;
00296 char format_str[80], *format_str_ptr;
00297
00298 format_str_ptr = format_str;
00299
00300 if (width > 155)
00301 width = 155;
00302 if (precision <= 0)
00303 precision = 6;
00304 if (precision > 120)
00305 precision = 120;
00306
00307
00308
00309
00310 *format_str_ptr++ = '%';
00311
00312 if (flags & MINUS_FLAG)
00313 *format_str_ptr++ = '-';
00314 if (flags & PLUS_FLAG)
00315 *format_str_ptr++ = '+';
00316 if (flags & SPACE_FLAG)
00317 *format_str_ptr++ = ' ';
00318 if (flags & ZERO_PADDING)
00319 *format_str_ptr++ = '0';
00320 if (flags & HASH_FLAG)
00321 *format_str_ptr++ = '#';
00322
00323 sprintf(format_str_ptr, "%d.%d", width, precision);
00324 format_str_ptr += strlen(format_str_ptr);
00325
00326 if (flags & IS_LONG_DOUBLE)
00327 *format_str_ptr++ = 'L';
00328 *format_str_ptr++ = format_char;
00329 *format_str_ptr++ = '\0';
00330
00331 sprintf(print_buf, format_str, dbl_val);
00332 print_buf_len = strlen(print_buf);
00333
00334 if (print_buf_len > (int)buf_size)
00335 print_buf_len = buf_size;
00336 strncpy(buffer, print_buf, print_buf_len);
00337 return print_buf_len;
00338 }
00339
00340 int vsnprintf(char *str, size_t size, const char *format, va_list ap)
00341 {
00342 int status, left = (int) size - 1;
00343 const char *format_ptr = format;
00344 int flags, width, precision, i;
00345 char format_char, *orig_str = str;
00346 int *int_ptr;
00347 Long64_t long_val;
00348 ULong64_t ulong_val;
00349 char *str_val;
00350 double dbl_val;
00351 int precision_specified = 0;
00352
00353 if (size <= 0 || str == NULL || format == NULL)
00354 return -1;
00355
00356 flags = 0;
00357 while (format_ptr < format + strlen(format)) {
00358 if (*format_ptr == '%') {
00359 if (format_ptr[1] == '%' && left > 0) {
00360 *str++ = '%';
00361 left--;
00362 format_ptr += 2;
00363 } else {
00364 if (left <= 0) {
00365 *str = '\0';
00366 return -1;
00367 } else {
00368 status = snprintf_get_directive(format_ptr, &flags, &width,
00369 &precision, &format_char,
00370 &ap);
00371 if (status == 0) {
00372 *str = '\0';
00373 return -2;
00374 } else {
00375 if (precision >= 0) {
00376 precision_specified = 1;
00377 } else {
00378 precision_specified = 0;
00379 precision = 0;
00380 }
00381 format_ptr += status;
00382
00383 switch (format_char) {
00384 case 'i':
00385 case 'd':
00386
00387
00388 if (flags & IS_LONG_LONG_INT)
00389 long_val = va_arg(ap, Long64_t);
00390 else if (flags & IS_LONG_INT)
00391 long_val = (Long64_t) va_arg(ap, long int);
00392 else
00393 long_val = (Long64_t) va_arg(ap, int);
00394
00395 if (long_val < 0) {
00396 ulong_val = (ULong64_t) -long_val;
00397 flags |= IS_NEGATIVE;
00398 } else {
00399 ulong_val = (ULong64_t) long_val;
00400 }
00401 status = snprintf_convert_ulong(str, left, 10,
00402 "0123456789",
00403 ulong_val, flags,
00404 width, precision);
00405 str += status;
00406 left -= status;
00407 break;
00408
00409 case 'x':
00410 if (flags & IS_LONG_LONG_INT)
00411 ulong_val = va_arg(ap, ULong64_t);
00412 else if (flags & IS_LONG_INT)
00413 ulong_val = (ULong64_t) va_arg(ap, unsigned long int);
00414 else
00415 ulong_val = (ULong64_t) va_arg(ap, unsigned int);
00416
00417 status = snprintf_convert_ulong(str, left, 16,
00418 "0123456789abcdef",
00419 ulong_val, flags,
00420 width, precision);
00421 str += status;
00422 left -= status;
00423 break;
00424
00425 case 'X':
00426 if (flags & IS_LONG_LONG_INT)
00427 ulong_val = va_arg(ap, ULong64_t);
00428 else if (flags & IS_LONG_INT)
00429 ulong_val = (ULong64_t) va_arg(ap, unsigned long int);
00430 else
00431 ulong_val = (ULong64_t) va_arg(ap, unsigned int);
00432
00433 status = snprintf_convert_ulong(str, left, 16,
00434 "0123456789ABCDEF",
00435 ulong_val, flags,
00436 width, precision);
00437 str += status;
00438 left -= status;
00439 break;
00440
00441 case 'o':
00442 if (flags & IS_LONG_LONG_INT)
00443 ulong_val = va_arg(ap, ULong64_t);
00444 else if (flags & IS_LONG_INT)
00445 ulong_val = (ULong64_t) va_arg(ap, unsigned long int);
00446 else
00447 ulong_val = (ULong64_t) va_arg(ap, unsigned int);
00448
00449 status = snprintf_convert_ulong(str, left, 8,
00450 "01234567",
00451 ulong_val, flags,
00452 width, precision);
00453 str += status;
00454 left -= status;
00455 break;
00456
00457 case 'u':
00458 if (flags & IS_LONG_LONG_INT)
00459 ulong_val = va_arg(ap, ULong64_t);
00460 else if (flags & IS_LONG_INT)
00461 ulong_val = (ULong64_t) va_arg(ap, unsigned long int);
00462 else
00463 ulong_val = (ULong64_t) va_arg(ap, unsigned int);
00464
00465 status = snprintf_convert_ulong(str, left, 10,
00466 "0123456789",
00467 ulong_val, flags,
00468 width, precision);
00469 str += status;
00470 left -= status;
00471 break;
00472
00473 case 'p':
00474 *str++ = '0';
00475 *str++ = 'x';
00476 ulong_val = (ULong64_t) va_arg(ap, unsigned long int);
00477
00478 status = snprintf_convert_ulong(str, left, 16,
00479 "0123456789abcdef",
00480 ulong_val, flags,
00481 width, precision);
00482 str += status;
00483 left -= status;
00484 break;
00485
00486 case 'c':
00487 if (flags & IS_LONG_LONG_INT)
00488 ulong_val = va_arg(ap, ULong64_t);
00489 else if (flags & IS_LONG_INT)
00490 ulong_val = (ULong64_t) va_arg(ap, unsigned long int);
00491 else
00492 ulong_val = (ULong64_t) va_arg(ap, unsigned int);
00493
00494 if (width==0) {
00495 *str++ = (unsigned char) ulong_val;
00496 --left;
00497 } else {
00498 if (width > left)
00499 width = left;
00500 i = width - 1;
00501
00502 if (flags & MINUS_FLAG) {
00503 *str = (unsigned char) ulong_val;
00504 memset(str + 1,
00505 (flags & ZERO_PADDING) ? '0' : ' ', i);
00506 } else {
00507 memset(str, (flags & ZERO_PADDING) ? '0' : ' ', i);
00508 *(str+i) = (unsigned char) ulong_val;
00509 }
00510 str += width;
00511 left -= width;
00512 }
00513 break;
00514
00515 case 's':
00516 str_val = va_arg(ap, char *);
00517
00518 if (str_val == NULL || ((long)str_val) == -1)
00519 str_val = "(null)";
00520
00521 if (!precision_specified)
00522 precision = strlen(str_val);
00523 else {
00524 if (memchr(str_val, 0, precision) != NULL)
00525 precision = strlen(str_val);
00526 }
00527 if (precision > left)
00528 precision = left;
00529
00530 if (width > left)
00531 width = left;
00532 if (width < precision)
00533 width = precision;
00534 i = width - precision;
00535
00536 if (flags & MINUS_FLAG) {
00537 strncpy(str, str_val, precision);
00538 memset(str + precision,
00539 (flags & ZERO_PADDING) ? '0' : ' ', i);
00540 } else {
00541 memset(str, (flags & ZERO_PADDING) ? '0' : ' ', i);
00542 strncpy(str + i, str_val, precision);
00543 }
00544 str += width;
00545 left -= width;
00546 break;
00547
00548 case 'n':
00549 int_ptr = va_arg(ap, int *);
00550 *int_ptr = str - orig_str;
00551 break;
00552
00553 case 'f':
00554 case 'e':
00555 case 'E':
00556 case 'g':
00557 case 'G':
00558 if (flags & IS_LONG_DOUBLE)
00559 dbl_val = (double) va_arg(ap, long double);
00560 else
00561 dbl_val = va_arg(ap, double);
00562 status =
00563 snprintf_convert_float(str, left, dbl_val, flags,
00564 width, precision,
00565 format_char);
00566 str += status;
00567 left -= status;
00568 break;
00569
00570 default:
00571 break;
00572 }
00573 }
00574 }
00575 }
00576 } else {
00577 if (left > 0) {
00578 *str++ = *format_ptr++;
00579 left--;
00580 } else {
00581 *str = '\0';
00582 return -1;
00583 }
00584 }
00585 }
00586 *str = '\0';
00587
00588 if (left <= 0)
00589 return -1;
00590
00591 return size - left - 1;
00592 }
00593 #endif
00594
00595 int snprintf(char *str, size_t size, const char *format, ...)
00596 {
00597 int ret;
00598 va_list ap;
00599 va_start(ap, format);
00600 ret = vsnprintf(str, size, format, ap);
00601 va_end(ap);
00602
00603 return ret;
00604 }
00605
00606
00607
00608 #ifdef SNTEST
00609
00610 #include <stdio.h>
00611
00612
00613 int main()
00614 {
00615 char holder[100];
00616 int i;
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 printf("/%%d/, 336\n");
00627 snprintf(holder, sizeof holder, "/%d/\n", 336);
00628 printf("/%d/\n", 336);
00629 printf("%s\n", holder);
00630
00631 printf("/%%2d/, 336\n");
00632 snprintf(holder, sizeof holder, "/%2d/\n", 336);
00633 printf("/%2d/\n", 336);
00634 printf("%s\n", holder);
00635
00636 printf("/%%10d/, 336\n");
00637 snprintf(holder, sizeof holder, "/%10d/\n", 336);
00638 printf("/%10d/\n", 336);
00639 printf("%s\n", holder);
00640
00641 printf("/%%-10d/, 336\n");
00642 snprintf(holder, sizeof holder, "/%-10d/\n", 336);
00643 printf("/%-10d/\n", 336);
00644 printf("%s\n", holder);
00645
00646
00647 printf("/%%f/, 1234.56\n");
00648 snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
00649 printf("/%f/\n", 1234.56);
00650 printf("%s\n", holder);
00651
00652 printf("/%%e/, 1234.56\n");
00653 snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
00654 printf("/%e/\n", 1234.56);
00655 printf("%s\n", holder);
00656
00657 printf("/%%4.2f/, 1234.56\n");
00658 snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
00659 printf("/%4.2f/\n", 1234.56);
00660 printf("%s\n", holder);
00661
00662 printf("/%%3.1f/, 1234.56\n");
00663 snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
00664 printf("/%3.1f/\n", 1234.56);
00665 printf("%s\n", holder);
00666
00667 printf("/%%10.3f/, 1234.56\n");
00668 snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
00669 printf("/%10.3f/\n", 1234.56);
00670 printf("%s\n", holder);
00671
00672 printf("/%%10.3e/, 1234.56\n");
00673 snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
00674 printf("/%10.3e/\n", 1234.56);
00675 printf("%s\n", holder);
00676
00677 printf("/%%+4.2f/, 1234.56\n");
00678 snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
00679 printf("/%+4.2f/\n", 1234.56);
00680 printf("%s\n", holder);
00681
00682 printf("/%%010.2f/, 1234.56\n");
00683 snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
00684 printf("/%010.2f/\n", 1234.56);
00685 printf("%s\n", holder);
00686
00687 #define BLURB "Outstanding acting !"
00688
00689 printf("/%%2s/, \"%s\"\n", BLURB);
00690 snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
00691 printf("/%2s/\n", BLURB);
00692 printf("%s\n", holder);
00693
00694 printf("/%%22s/ %s\n", BLURB);
00695 snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
00696 printf("/%22s/\n", BLURB);
00697 printf("%s\n", holder);
00698
00699 printf("/%%22.5s/ %s\n", BLURB);
00700 snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
00701 printf("/%22.5s/\n", BLURB);
00702 printf("%s\n", holder);
00703
00704 printf("/%%-22.5s/ %s\n", BLURB);
00705 snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
00706 printf("/%-22.5s/\n", BLURB);
00707 printf("%s\n", holder);
00708
00709
00710 printf("%%x %%X %%#x, 31, 31, 31\n");
00711 snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
00712 printf("%x %X %#x\n", 31, 31, 31);
00713 printf("%s\n", holder);
00714
00715 printf("**%%d**%% d**%% d**, 42, 42, -42\n");
00716 snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
00717 printf("**%d**% d**% d**\n", 42, 42, -42);
00718 printf("%s\n", holder);
00719
00720
00721 printf("/%%g/, 31.4\n");
00722 snprintf(holder, sizeof holder, "/%g/\n", 31.4);
00723 printf("/%g/\n", 31.4);
00724 printf("%s\n", holder);
00725
00726 printf("/%%.6g/, 31.4\n");
00727 snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
00728 printf("/%.6g/\n", 31.4);
00729 printf("%s\n", holder);
00730
00731 printf("/%%.1G/, 31.4\n");
00732 snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
00733 printf("/%.1G/\n", 31.4);
00734 printf("%s\n", holder);
00735
00736 printf("abc%%n\n");
00737 printf("abc%n", &i);
00738 printf("%d\n", i);
00739 snprintf(holder, sizeof holder, "abc%n", &i);
00740 printf("%s", holder);
00741 printf("%d\n\n", i);
00742
00743 printf("%%*.*s --> 10.10\n");
00744 snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
00745 printf("%*.*s\n", 10, 10, BLURB);
00746 printf("%s\n", holder);
00747
00748 printf("%%%%%%%%\n");
00749 snprintf(holder, sizeof holder, "%%%%\n");
00750 printf("%%%%\n");
00751 printf("%s\n", holder);
00752
00753 #define BIG "Hello this is a too big string for the buffer"
00754
00755 printf("<%%s>, %s\n", BIG);
00756 i = snprintf(holder, 10, "%s", BIG);
00757 printf("<%s>\n", BIG);
00758 printf("<%s> i = %d\n", holder, i);
00759 i = snprintf(holder, sizeof holder, "%s", BIG);
00760 printf("<%s> i = %d\n", holder, i);
00761
00762 return 0;
00763 }
00764 #endif
00765
00766 #endif