Tue, 22 Jan 2002 01:22:58 +0100
trunk: changeset 40
END_OPTPARSEROPTS missing too.
| 35 | 1 | /* |
| 2 | * test.c - test a portable implementation of snprintf | |
| 3 | * | |
| 4 | * AUTHOR | |
| 5 | * Mark Martinec <mark.martinec@ijs.si>, April 1999. | |
| 6 | * | |
| 7 | * Copyright 1999, Mark Martinec. All rights reserved. | |
| 8 | * | |
| 9 | * TERMS AND CONDITIONS | |
| 10 | * This program is free software; you can redistribute it and/or modify | |
| 11 | * it under the terms of the "Frontier Artistic License" which comes | |
| 12 | * with this Kit. | |
| 13 | * | |
| 14 | * This program is distributed in the hope that it will be useful, | |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty | |
| 16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
| 17 | * See the Frontier Artistic License for more details. | |
| 18 | * | |
| 19 | * You should have received a copy of the Frontier Artistic License | |
| 20 | * with this Kit in the file named LICENSE.txt . | |
| 21 | * If not, I'll be glad to provide one. | |
| 22 | * | |
| 23 | * NOTE: This test program is a QUICK and DIRTY tool | |
| 24 | * ===== used while testing and benchmarking my portable snprintf. | |
| 25 | * Certain data types are not fully supported, certain test | |
| 26 | * cases were fabricated during testing by modifying the code | |
| 27 | * or running it by specifying test parameters in the command line. | |
| 28 | * | |
| 29 | * You are on your own if you want to use this test program! | |
| 30 | */ | |
| 31 | ||
| 32 | /* If no command arguments are specified do the exhaustive test. | |
| 33 | * This takes a long time. You may want to reduce the fw and fp | |
| 34 | * upper limits in the for loops. | |
| 35 | * You may also reduce the number of test elements in the array iargs. | |
| 36 | */ | |
| 37 | ||
| 38 | #include <sys/types.h> | |
| 39 | #include <string.h> | |
| 40 | #include <stdlib.h> | |
| 41 | #include <stdio.h> | |
| 42 | #include <stdarg.h> | |
| 43 | ||
| 44 | #include <assert.h> | |
| 45 | #include <time.h> | |
| 46 | ||
| 47 | #if defined(NEED_ASPRINTF) || defined(NEED_ASNPRINTF) || defined(NEED_VASPRINTF) || defined(NEED_VASNPRINTF) | |
| 48 | # if defined(NEED_SNPRINTF_ONLY) | |
| 49 | # undef NEED_SNPRINTF_ONLY | |
| 50 | # endif | |
| 51 | # if !defined(PREFER_PORTABLE_SNPRINTF) | |
| 52 | # define PREFER_PORTABLE_SNPRINTF | |
| 53 | # endif | |
| 54 | #endif | |
| 55 | ||
| 56 | #ifdef HAVE_SNPRINTF | |
| 57 | extern int portable_snprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); | |
| 58 | #else | |
| 59 | extern int snprintf(char *, size_t, const char *, /*args*/ ...); | |
| 60 | extern int vsnprintf(char *, size_t, const char *, va_list); | |
| 61 | #endif | |
| 62 | ||
| 63 | #ifndef HAVE_SNPRINTF | |
| 64 | #define portable_snprintf snprintf | |
| 65 | #define portable_vsnprintf vsnprintf | |
| 66 | #endif | |
| 67 | ||
| 68 | #ifndef CLOCKS_PER_SEC | |
| 69 | #define CLOCKS_PER_SEC 100 | |
| 70 | #endif | |
| 71 | ||
| 72 | #define min(a,b) ((a)<(b) ? (a) : (b)) | |
| 73 | #define max(a,b) ((a)>(b) ? (a) : (b)) | |
| 74 | ||
| 75 | extern int asprintf (char **ptr, const char *fmt, /*args*/ ...); | |
| 76 | extern int vasprintf (char **ptr, const char *fmt, va_list ap); | |
| 77 | extern int asnprintf (char **ptr, size_t str_m, const char *fmt, /*args*/ ...); | |
| 78 | extern int vasnprintf(char **ptr, size_t str_m, const char *fmt, va_list ap); | |
| 79 | ||
| 80 | #ifndef NEED_SNPRINTF_ONLY | |
| 81 | int wrap_vsnprintf(char *str, size_t str_m, const char *fmt, /*args*/ ...); | |
| 82 | int wrap_vsnprintf(char *str, size_t str_m, const char *fmt, ...) { | |
| 83 | va_list ap; | |
| 84 | int str_l; | |
| 85 | ||
| 86 | va_start(ap, fmt); | |
| 87 | str_l = vsnprintf(str, str_m, fmt, ap); | |
| 88 | va_end(ap); | |
| 89 | return str_l; | |
| 90 | } | |
| 91 | #endif | |
| 92 | ||
| 93 | #ifdef NEED_VASPRINTF | |
| 94 | int wrap_vasprintf(char **ptr, const char *fmt, /*args*/ ...); | |
| 95 | int wrap_vasprintf(char **ptr, const char *fmt, ...) { | |
| 96 | va_list ap; | |
| 97 | int str_l; | |
| 98 | ||
| 99 | va_start(ap, fmt); | |
| 100 | str_l = vasprintf(ptr, fmt, ap); | |
| 101 | va_end(ap); | |
| 102 | return str_l; | |
| 103 | } | |
| 104 | #endif | |
| 105 | ||
| 106 | #ifdef NEED_VASNPRINTF | |
| 107 | int wrap_vasnprintf(char **ptr, size_t str_m, const char *fmt, /*args*/ ...); | |
| 108 | int wrap_vasnprintf(char **ptr, size_t str_m, const char *fmt, ...) { | |
| 109 | va_list ap; | |
| 110 | int str_l; | |
| 111 | ||
| 112 | va_start(ap, fmt); | |
| 113 | str_l = vasnprintf(ptr, str_m, fmt, ap); | |
| 114 | va_end(ap); | |
| 115 | return str_l; | |
| 116 | } | |
| 117 | #endif | |
| 118 | ||
| 119 | int main(int argc, char *argv[]) { | |
| 120 | char str1[256], str2[256]; | |
| 121 | #ifdef HAVE_SNPRINTF | |
| 122 | char str3[256]; | |
| 123 | #endif | |
| 124 | int len1, len2, len3; | |
| 125 | int bad = 0; | |
| 126 | size_t str_m = 20; /* declared str size */ | |
| 127 | ||
| 128 | if (0) { | |
| 129 | /* benchmarking */ | |
| 130 | const int cnt = 100000; | |
| 131 | size_t size; | |
| 132 | char str[40000]; | |
| 133 | time_t t0,t; | |
| 134 | int j,len,l1,l2; | |
| 135 | char *p; | |
| 136 | int breakpoint; | |
| 137 | ||
| 138 | size = 18000; | |
| 139 | ||
| 140 | printf("\n\nsize = %d\n", (int)size); | |
| 141 | p = malloc(size); assert(p); | |
| 142 | memset(p,'h',size); p[size-1] = '\0'; | |
| 143 | t0 = clock(); | |
| 144 | ||
| 145 | printf("\ndetermine breakeven point to see when it is worth\n"); | |
| 146 | printf("calling memcpy and when to do inline string copy\n"); | |
| 147 | printf("str_l, memcpy, inline\n"); | |
| 148 | for (breakpoint=0; breakpoint<=35; breakpoint++) { | |
| 149 | register size_t nnn = (size_t)breakpoint; | |
| 150 | printf("%5ld", nnn); | |
| 151 | for (j=10*cnt; j>0; j--) memcpy(str, p, nnn); | |
| 152 | t = clock(); printf(" %1.3f", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 153 | for (j=10*cnt; j>0; j--) { | |
| 154 | register size_t nn = (size_t)breakpoint; | |
| 155 | if (nn > 0) { | |
| 156 | register char *dd; register const char *ss; | |
| 157 | for (ss=p, dd=str; nn>0; nn--) *dd++ = *ss++; | |
| 158 | } | |
| 159 | } | |
| 160 | t = clock(); printf(" %1.3f\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 161 | } | |
| 162 | ||
| 163 | printf("\nmeasuring time to SKIP a long format with no conversions\n"); | |
| 164 | p[0] = '%'; p[1] = 's'; | |
| 165 | for (j=cnt; j>0; j--) l1=portable_snprintf(NULL,(size_t)0,p,"1234567890"); | |
| 166 | t = clock(); printf("t_port_nul = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 167 | for (j=cnt; j>0; j--) l2=portable_snprintf(str,(size_t)8,p,"1234567890"); | |
| 168 | t = clock(); printf("t_port = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 169 | assert(l1==l2); | |
| 170 | p[0] = p[1] = 'h'; | |
| 171 | ||
| 172 | printf("\nmeasuring time to copy a long format with no conversions\n"); | |
| 173 | for (j=cnt; j>0; j--) l1=portable_snprintf(NULL,(size_t)0,p); | |
| 174 | t = clock(); printf("t_port_nul = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 175 | for (j=cnt; j>0; j--) l2=portable_snprintf(str,sizeof(str),p); | |
| 176 | t = clock(); printf("t_port = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 177 | assert(l1==l2); | |
| 178 | for (j=cnt; j>0; j--) sprintf(str,p); | |
| 179 | t = clock(); printf("t_sys = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 180 | ||
| 181 | printf("\nmeasuring time to copy a long format with one conversion\n"); | |
| 182 | p[size-10] = '%'; | |
| 183 | for (j=cnt; j>0; j--) l1=portable_snprintf(NULL,(size_t)0,p); | |
| 184 | t = clock(); printf("t_port_nul = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 185 | for (j=cnt; j>0; j--) l2=portable_snprintf(str,sizeof(str),p); | |
| 186 | t = clock(); printf("t_port = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 187 | assert(l1==l2); | |
| 188 | for (j=cnt; j>0; j--) sprintf(str,p); | |
| 189 | t = clock(); printf("t_sys = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 190 | ||
| 191 | printf("\nmeasuring string argument copy speed\n"); | |
| 192 | for (j=cnt; j>0; j--) l1=portable_snprintf(NULL,(size_t)0,"%.18000s",p); | |
| 193 | t = clock(); printf("t_port_nul = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 194 | for (j=cnt; j>0; j--) l2=portable_snprintf(str,sizeof(str),"%.18000s",p); | |
| 195 | t = clock(); printf("t_port = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 196 | assert(l1==l2); | |
| 197 | for (j=cnt; j>0; j--) sprintf(str,"%.18000s",p); | |
| 198 | t = clock(); printf("t_sys = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 199 | ||
| 200 | printf("\nmeasuring left padding speed\n"); | |
| 201 | p[0] = '\0'; | |
| 202 | for (j=cnt; j>0; j--) l1=portable_snprintf(NULL,(size_t)0,"%-18000s",p); | |
| 203 | t = clock(); printf("t_port_nul = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 204 | for (j=cnt; j>0; j--) l2=portable_snprintf(str,sizeof(str),"%-18000s",p); | |
| 205 | t = clock(); printf("t_port = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 206 | assert(l1==l2); | |
| 207 | for (j=cnt; j>0; j--) sprintf(str,"%-18000s",p); | |
| 208 | t = clock(); printf("t_sys = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 209 | ||
| 210 | printf("\nmeasuring right padding speed\n"); | |
| 211 | p[0] = '\0'; | |
| 212 | for (j=cnt; j>0; j--) l1=portable_snprintf(NULL,(size_t)0,"%18000s",p); | |
| 213 | t = clock(); printf("t_port_nul = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 214 | for (j=cnt; j>0; j--) l2=portable_snprintf(str,sizeof(str),"%18000s",p); | |
| 215 | t = clock(); printf("t_port = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 216 | assert(l1==l2); | |
| 217 | for (j=cnt; j>0; j--) sprintf(str,"%18000s",p); | |
| 218 | t = clock(); printf("t_sys = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 219 | ||
| 220 | printf("\nmeasuring zero padding speed\n"); | |
| 221 | for (j=cnt; j>0; j--) l1=portable_snprintf(NULL,(size_t)0,"%018000d",1); | |
| 222 | t = clock(); printf("t_port_nul = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 223 | for (j=cnt; j>0; j--) l2=portable_snprintf(str,sizeof(str),"%018000d",1); | |
| 224 | t = clock(); printf("t_port = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 225 | assert(l1==l2); | |
| 226 | for (j=cnt; j>0; j--) sprintf(str,"%018000d",1); | |
| 227 | t = clock(); printf("t_sys = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 228 | ||
| 229 | printf("\nmeasuring system's sprintf to efficiently handle truncated strings\n"); | |
| 230 | memset(p,'h',size); p[size-1] = '\0'; | |
| 231 | t0 = clock(); | |
| 232 | for (j=cnt; j>0; j--) len = strlen(p); | |
| 233 | printf("len = %d\n", len); | |
| 234 | t = clock(); printf("t_strlen = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 235 | /* test if the system sprintf scans the whole string (e.g. by strlen) | |
| 236 | * before recognizing this was a bad idea since the format specified | |
| 237 | * a truncated string precision, e.g. "%.8s" . | |
| 238 | */ | |
| 239 | for (j=cnt; j>0; j--) sprintf(str,"%.2s",p); | |
| 240 | t = clock(); printf("t_sys = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 241 | #ifdef HAVE_SNPRINTF | |
| 242 | for (j=cnt; j>0; j--) snprintf(str,sizeof(str),"%.2s",p); | |
| 243 | t = clock(); printf("t_sys = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 244 | #endif | |
| 245 | for (j=cnt; j>0; j--) portable_snprintf(str,sizeof(str),"%.2s",p); | |
| 246 | t = clock(); printf("t_port = %1.3f s\n", (float)(t-t0)/CLOCKS_PER_SEC); t0 = t; | |
| 247 | ||
| 248 | free(p); | |
| 249 | return 0; | |
| 250 | } | |
| 251 | ||
| 252 | ||
| 253 | /* preliminary halfhearted test */ | |
| 254 | { | |
| 255 | const char fmt[] = "Bla%.4s%05iHE%%%-50sTail"; | |
| 256 | char *ptr4=0, *ptr5=0, *ptr6=0, *ptr7=0; | |
| 257 | int len1f; | |
| 258 | char str_full[256]; | |
| 259 | ||
| 260 | printf("\npreliminary test: snprintf\n"); | |
| 261 | len1 = snprintf(str1, str_m, fmt, "abcdef",-12,"str"); | |
| 262 | len1f = snprintf(str_full, sizeof(str_full), fmt, "abcdef",-12,"str"); | |
| 263 | assert(len1f==len1); | |
| 264 | assert(memcmp(str1,str_full,min(len1,str_m-1)) == 0); | |
| 265 | assert(str1[str_m-1] == '\0'); | |
| 266 | assert(str_full[sizeof(str_full)-1] == '\0'); | |
| 267 | ||
| 268 | #ifndef NEED_SNPRINTF_ONLY | |
| 269 | printf("preliminary test: vsnprintf\n"); | |
| 270 | len2 = wrap_vsnprintf(str2, str_m, fmt, "abcdef",-12,"str"); | |
| 271 | assert(len2==len1); | |
| 272 | assert(memcmp(str1,str2,min(len1+1,str_m)) == 0); | |
| 273 | assert(str2[str_m-1] == '\0'); | |
| 274 | #endif | |
| 275 | ||
| 276 | #ifdef NEED_ASPRINTF | |
| 277 | printf("preliminary test: asprintf\n"); | |
| 278 | len4 = asprintf(&ptr4, fmt, "abcdef",-12,"str"); | |
| 279 | assert(ptr4); | |
| 280 | assert(len4==len1); | |
| 281 | assert(memcmp(str_full,ptr4,min(len4+1,sizeof(str_full))) == 0); | |
| 282 | assert(ptr4[len4] == '\0'); | |
| 283 | #endif | |
| 284 | ||
| 285 | #ifdef NEED_ASNPRINTF | |
| 286 | printf("preliminary test: asnprintf\n"); | |
| 287 | len5 = asnprintf(&ptr5, str_m, fmt, "abcdef",-12,"str"); | |
| 288 | assert(ptr5); | |
| 289 | assert(len5==len1); | |
| 290 | assert(memcmp(str1,ptr5,min(len5+1,str_m)) == 0); | |
| 291 | assert(ptr5[len5] == '\0'); | |
| 292 | #endif | |
| 293 | ||
| 294 | #ifdef NEED_VASPRINTF | |
| 295 | printf("preliminary test: vasprintf\n"); | |
| 296 | len6 = wrap_vasprintf(&ptr6, fmt, "abcdef",-12,"str"); | |
| 297 | assert(ptr6); | |
| 298 | assert(len6==len1); | |
| 299 | assert(memcmp(str_full,ptr6,min(len6+1,sizeof(str_full))) == 0); | |
| 300 | assert(ptr6[len6] == '\0'); | |
| 301 | #endif | |
| 302 | ||
| 303 | #ifdef NEED_VASNPRINTF | |
| 304 | printf("preliminary test: vasnprintf\n"); | |
| 305 | len7 = wrap_vasnprintf(&ptr7, str_m, fmt, "abcdef",-12,"str"); | |
| 306 | assert(ptr7); | |
| 307 | assert(len7==len1); | |
| 308 | assert(memcmp(str1,ptr7,min(len7+1,str_m)) == 0); | |
| 309 | assert(ptr7[len7] == '\0'); | |
| 310 | #endif | |
| 311 | ||
| 312 | if (ptr4) free(ptr4); | |
| 313 | if (ptr5) free(ptr5); | |
| 314 | if (ptr6) free(ptr6); | |
| 315 | if (ptr7) free(ptr7); | |
| 316 | } | |
| 317 | ||
| 318 | /* second preliminary halfhearted test */ | |
| 319 | { | |
| 320 | printf("\nsecond preliminary test:\n"); | |
| 321 | ||
| 322 | printf("test 0a\n"); | |
| 323 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 324 | len1 = snprintf(str1, sizeof(str1), ""); | |
| 325 | len2 = sprintf (str2, ""); | |
| 326 | assert(len1==len2); | |
| 327 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 328 | ||
| 329 | printf("test 0b\n"); | |
| 330 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 331 | len1 = snprintf(str1, sizeof(str1), "YK"); | |
| 332 | len2 = sprintf (str2, "YK"); | |
| 333 | assert(len1==len2); | |
| 334 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 335 | ||
| 336 | printf("test 1\n"); | |
| 337 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 338 | len1 = snprintf(str1, sizeof(str1), "%+d",0); | |
| 339 | len2 = sprintf (str2, "%+d",0); | |
| 340 | assert(len1==len2); | |
| 341 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 342 | ||
| 343 | printf("test 2\n"); | |
| 344 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 345 | len1 = snprintf(str1, sizeof(str1), "%.2147483647s", "13"); | |
| 346 | len2 = sprintf (str2, "%.2147483647s", "13"); | |
| 347 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 348 | assert(len1==len2); | |
| 349 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 350 | ||
| 351 | printf("test 3a\n"); | |
| 352 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 353 | len1 = snprintf(str1, sizeof(str1), "%.2147483648s", "13"); | |
| 354 | len2 = sprintf (str2, "%.2147483648s", "13"); | |
| 355 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 356 | assert(len1==len2); | |
| 357 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 358 | ||
| 359 | printf("test 3b\n"); | |
| 360 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 361 | len1 = snprintf(str1, sizeof(str1), "%.2147483649s", "13"); | |
| 362 | len2 = sprintf (str2, "%.2147483649s", "13"); | |
| 363 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 364 | assert(len1==len2); | |
| 365 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 366 | ||
| 367 | printf("test 4\n"); | |
| 368 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 369 | len1 = snprintf(str1, sizeof(str1), "%-.2147483647s", "13"); | |
| 370 | len2 = sprintf (str2, "%-.2147483647s", "13"); | |
| 371 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 372 | assert(len1==len2); | |
| 373 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 374 | ||
| 375 | printf("test 5\n"); | |
| 376 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 377 | len1 = snprintf(str1, sizeof(str1), "%-.2147483648s", "13"); | |
| 378 | len2 = sprintf (str2, "%-.2147483648s", "13"); | |
| 379 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 380 | assert(len1==len2); | |
| 381 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 382 | ||
| 383 | printf("test 6\n"); | |
| 384 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 385 | len1 = snprintf(str1, sizeof(str1), "%.4294967295s", "13"); | |
| 386 | len2 = sprintf (str2, "%.4294967295s", "13"); | |
| 387 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 388 | assert(len1==len2); | |
| 389 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 390 | ||
| 391 | printf("test 7\n"); | |
| 392 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 393 | len1 = snprintf(str1, sizeof(str1), "%.4294967296s", "13"); | |
| 394 | len2 = sprintf (str2, "%.4294967296s", "13"); | |
| 395 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 396 | assert(len1==len2); | |
| 397 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 398 | ||
| 399 | ||
| 400 | printf("test 12\n"); | |
| 401 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 402 | len1 = snprintf(str1, sizeof(str1), "%.*s", 2147483647,"13"); | |
| 403 | len2 = sprintf (str2, "%.*s", 2147483647,"13"); | |
| 404 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 405 | assert(len1==len2); | |
| 406 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 407 | ||
| 408 | printf("test 13\n"); | |
| 409 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 410 | len1 = snprintf(str1, sizeof(str1), "%.*s", 2147483648U,"13"); | |
| 411 | len2 = sprintf (str2, "%.*s", 2147483648U,"13"); | |
| 412 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 413 | assert(len1==len2); | |
| 414 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 415 | ||
| 416 | printf("test 14\n"); | |
| 417 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 418 | len1 = snprintf(str1, sizeof(str1), "%-.*s", 2147483647,"13"); | |
| 419 | len2 = sprintf (str2, "%-.*s", 2147483647,"13"); | |
| 420 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 421 | assert(len1==len2); | |
| 422 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 423 | ||
| 424 | printf("test 15\n"); | |
| 425 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 426 | len1 = snprintf(str1, sizeof(str1), "%-.*s", 2147483648U,"13"); | |
| 427 | len2 = sprintf (str2, "%-.*s", 2147483648U,"13"); | |
| 428 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 429 | assert(len1==len2); | |
| 430 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 431 | ||
| 432 | printf("test 16\n"); | |
| 433 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 434 | len1 = snprintf(str1, sizeof(str1), "%.*s", 4294967295U,"13"); | |
| 435 | len2 = sprintf (str2, "%.*s", 4294967295U,"13"); | |
| 436 | printf("len1=%d, len2=%d\n", len1,len2); | |
| 437 | assert(len1==len2); | |
| 438 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 439 | ||
| 440 | printf("test 17\n"); | |
| 441 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 442 | len1 = snprintf(str1, sizeof(str1), "%.*s", 4294967296U,"13"); | |
| 443 | /* len2 = sprintf (str2, "%.*s", 4294967296U,"13"); */ /* core dumps on HPUX */ | |
| 444 | /* assert(len1==len2); | |
| 445 | * assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 446 | */ | |
| 447 | ||
| 448 | ||
| 449 | printf("test 95\n"); | |
| 450 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 451 | len1 = snprintf(str1, sizeof(str1), "%c",'A'); | |
| 452 | len2 = sprintf (str2, "%c",'A'); | |
| 453 | assert(len1==len2); | |
| 454 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 455 | ||
| 456 | printf("test 96\n"); | |
| 457 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 458 | len1 = snprintf(str1, sizeof(str1), "%10c",'A'); | |
| 459 | len2 = sprintf (str2, "%10c",'A'); | |
| 460 | assert(len1==len2); | |
| 461 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 462 | ||
| 463 | printf("test 97\n"); | |
| 464 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 465 | len1 = snprintf(str1, sizeof(str1), "%-10c",'A'); | |
| 466 | len2 = sprintf (str2, "%-10c",'A'); | |
| 467 | assert(len1==len2); | |
| 468 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 469 | ||
| 470 | printf("test 98\n"); | |
| 471 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 472 | len1 = snprintf(str1, sizeof(str1), "%.10c",'A'); | |
| 473 | len2 = sprintf (str2, "%.10c",'A'); | |
| 474 | assert(len1==len2); | |
| 475 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 476 | ||
| 477 | printf("test 99\n"); | |
| 478 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 479 | len1 = snprintf(str1, sizeof(str1), "%-.10c",'A'); | |
| 480 | len2 = sprintf (str2, "%-.10c",'A'); | |
| 481 | assert(len1==len2); | |
| 482 | assert(memcmp(str1,str2,(size_t)len1) == 0); | |
| 483 | ||
| 484 | ||
| 485 | printf("test 100\n"); | |
| 486 | memset(str1,'x',sizeof(str1)); memset(str2,'x',sizeof(str2)); | |
| 487 | len1 = snprintf(str1, (size_t)8, "blaBhb%shehe%cX","ABCD",'1'); | |
| 488 | len2 = sprintf (str2, "blaBhb%shehe%cX","ABCD",'1'); | |
| 489 | assert(len1==len2); | |
| 490 | assert(memcmp(str1,str2,(size_t)7) == 0); | |
| 491 | assert(str1[7] == '\0'); | |
| 492 | assert(memcmp(str1+14,str2+16,(size_t)(len1-16)) == 0); | |
| 493 | ||
| 494 | } | |
| 495 | ||
| 496 | /* testing for correctness and compatibility */ | |
| 497 | if (argc >= 3) { | |
| 498 | char *c; int alldigits = 1; | |
| 499 | for (c=argv[2]; *c; c++) | |
| 500 | if (! (*c == '-' || (*c >= '0' && *c <= '9'))) alldigits = 0; | |
| 501 | if (alldigits) { | |
| 502 | int j = atoi(argv[2]); | |
| 503 | len1 = portable_snprintf(str1, str_m, argv[1], j, 3); | |
| 504 | len2 = sprintf(str2, argv[1], j, 3); | |
| 505 | #ifdef HAVE_SNPRINTF | |
| 506 | len3 = snprintf(str3, str_m, argv[1], j, 3); | |
| 507 | #endif | |
| 508 | } else { | |
| 509 | len1 = portable_snprintf(str1, str_m, argv[1], argv[2], 3); | |
| 510 | len2 = sprintf(str2, argv[1], argv[2], 3); | |
| 511 | #ifdef HAVE_SNPRINTF | |
| 512 | len3 = snprintf(str3, str_m, argv[1], argv[2], 3); | |
| 513 | #endif | |
| 514 | } | |
| 515 | printf("portable: |%s| len = %d\n", str1, len1); | |
| 516 | printf("sys sprintf: |%s| len = %d\n", str2, len2); | |
| 517 | #ifdef HAVE_SNPRINTF | |
| 518 | printf("sys snprintf: |%s| len = %d\n", str3, len3); | |
| 519 | #endif | |
| 520 | } else { /* exhaustive testing */ | |
| 521 | ||
| 522 | const char flags[] = "+- 0#"; /* set of test flags (including '\0')*/ | |
| 523 | int flags_l = strlen(flags); | |
| 524 | ||
| 525 | const char fspec[] = "scdpoxXuiy"; /* set of test formats (including '\0') */ | |
| 526 | int fspec_l = strlen(fspec); | |
| 527 | ||
| 528 | #ifdef SNPRINTF_LONGLONG_SUPPORT | |
| 529 | const char datatype[] = " hl2"; /* set of datatypes */ | |
| 530 | #else | |
| 531 | const char datatype[] = " hl"; /* set of datatypes */ | |
| 532 | #endif | |
| 533 | int datatype_l = strlen(datatype); | |
| 534 | ||
| 535 | const long int iargs[] = /* set of numeric test arguments */ | |
| 536 | { 0,1,9,10,28,99,100,127,128,129,998,1000,32767,32768,32769, | |
| 537 | -1,-9,-10,-28,-99,-100,-127,-128,-129, | |
| 538 | -998,-1000,-32767,-32768,-32769 }; | |
| 539 | int iargs_l = sizeof(iargs)/sizeof(iargs[0]); | |
| 540 | const char *sargs[] = /* set of string test arguments */ | |
| 541 | { "", "a", "0", "-ab", "abcde", "abcdefghijk mnopqrstuv" }; | |
| 542 | int sargs_l = sizeof(sargs)/sizeof(sargs[0]); | |
| 543 | ||
| 544 | char fmt[256]; | |
| 545 | int fmt_l; | |
| 546 | int a, fs, fl1, fl2, fl3, fl4, fl5, fw, fp, dt; | |
| 547 | ||
| 548 | for (fs=0; fs<=fspec_l; fs++) { /* format specifier */ | |
| 549 | int strtype = (fspec[fs] == 's' || fspec[fs] == '%'); | |
| 550 | int args_l = (strtype ? sargs_l : iargs_l); | |
| 551 | ||
| 552 | for (fw= -1; fw<=3; fw++) { /* minimal field width */ | |
| 553 | ||
| 554 | printf("Trying format %%"); | |
| 555 | if (fw >= 0) printf("%d", fw); | |
| 556 | if (fspec[fs]) putchar(fspec[fs]); | |
| 557 | putchar('\n'); | |
| 558 | ||
| 559 | for (fp= -2; fp<=3; fp++) { /* format field precision */ | |
| 560 | ||
| 561 | /* data type modifiers */ | |
| 562 | for (dt=0; dt < ((strtype||fspec[fs]=='c') ? 1 : datatype_l); dt++) { | |
| 563 | ||
| 564 | int dataty = datatype[dt]; | |
| 565 | ||
| 566 | if (fspec[fs] == 'D' || fspec[fs] == 'U' || fspec[fs] == 'O') | |
| 567 | dataty = 'l'; | |
| 568 | ||
| 569 | if (fspec[fs] == 'p' && dataty == '2') continue; | |
| 570 | ||
| 571 | for (fl1=0; fl1<=flags_l; fl1++) { /* flags */ | |
| 572 | for (fl2=0; fl2<=flags_l; fl2++) { | |
| 573 | for (fl3=0; fl3<=flags_l; fl3++) { | |
| 574 | for (fl4=0; fl4<=flags_l; fl4++) { | |
| 575 | for (fl5=0; fl5<=flags_l; fl5++) { | |
| 576 | ||
| 577 | for (a=0; a<args_l; a++) { /* test arguments */ | |
| 578 | ||
| 579 | fmt_l = 0; fmt[fmt_l++] = '%'; | |
| 580 | if (flags[fl1]) fmt[fmt_l++] = flags[fl1]; | |
| 581 | if (flags[fl2]) fmt[fmt_l++] = flags[fl2]; | |
| 582 | if (flags[fl3]) fmt[fmt_l++] = flags[fl3]; | |
| 583 | if (flags[fl4]) fmt[fmt_l++] = flags[fl4]; | |
| 584 | if (flags[fl5]) fmt[fmt_l++] = flags[fl5]; | |
| 585 | if (fw >= 0) fmt_l += sprintf(fmt+fmt_l, "%d", fw); | |
| 586 | if (fp >= -1) { | |
| 587 | fmt[fmt_l++] = '.'; | |
| 588 | if (fp >= 0) fmt_l += sprintf(fmt+fmt_l, "%d", fp); | |
| 589 | } | |
| 590 | if (dataty == '2') | |
| 591 | { fmt[fmt_l++] = 'l'; fmt[fmt_l++] = 'l'; } | |
| 592 | else if (dataty != ' ') | |
| 593 | { fmt[fmt_l++] = dataty; } | |
| 594 | ||
| 595 | if (fspec[fs]) fmt[fmt_l++] = fspec[fs]; | |
| 596 | fmt[fmt_l++] = '\0'; | |
| 597 | ||
| 598 | if (a==0 && fl1==flags_l && fl2==flags_l && fl3==flags_l | |
| 599 | && fl4==flags_l && fl5==flags_l) printf("%s\n", fmt); | |
| 600 | ||
| 601 | #ifdef HAVE_SNPRINTF | |
| 602 | memset(str1,'G',sizeof(str1)); | |
| 603 | memset(str2,'G',sizeof(str2)); | |
| 604 | memset(str3,'G',sizeof(str3)); | |
| 605 | #endif | |
| 606 | len1 = len2 = len3 = 0; | |
| 607 | if (strtype) { | |
| 608 | len1 = portable_snprintf(str1, str_m, fmt, sargs[a]); | |
| 609 | len2 = sprintf(str2, fmt, sargs[a]); | |
| 610 | #ifdef HAVE_SNPRINTF | |
| 611 | len3 = snprintf(str3, str_m, fmt, sargs[a]); | |
| 612 | #endif | |
| 613 | } else if (fspec[fs] == 'p') { | |
| 614 | len1 = portable_snprintf(str1, str_m, fmt, (void *)iargs[a]); | |
| 615 | len2 = sprintf(str2, fmt, (void *)iargs[a]); | |
| 616 | #ifdef HAVE_SNPRINTF | |
| 617 | len3 = snprintf(str3, str_m, fmt, (void *)iargs[a]); | |
| 618 | #endif | |
| 619 | } else { | |
| 620 | switch (dataty) { | |
| 621 | case '\0': | |
| 622 | len1 = portable_snprintf(str1, str_m, fmt, (int) iargs[a]); | |
| 623 | len2 = sprintf(str2, fmt, (int) iargs[a]); | |
| 624 | #ifdef HAVE_SNPRINTF | |
| 625 | len3 = snprintf(str3, str_m, fmt, (int) iargs[a]); | |
| 626 | #endif | |
| 627 | break; | |
| 628 | case 'h': | |
| 629 | len1 = portable_snprintf(str1, str_m, fmt, (short int)iargs[a]); | |
| 630 | len2 = sprintf(str2, fmt, (short int)iargs[a]); | |
| 631 | #ifdef HAVE_SNPRINTF | |
| 632 | len3 = snprintf(str3, str_m, fmt, (short int)iargs[a]); | |
| 633 | #endif | |
| 634 | break; | |
| 635 | case 'l': | |
| 636 | len1 = portable_snprintf(str1, str_m, fmt, (long int)iargs[a]); | |
| 637 | len2 = sprintf(str2, fmt, (long int)iargs[a]); | |
| 638 | #ifdef HAVE_SNPRINTF | |
| 639 | len3 = snprintf(str3, str_m, fmt, (long int)iargs[a]); | |
| 640 | #endif | |
| 641 | break; | |
| 642 | #ifdef SNPRINTF_LONGLONG_SUPPORT | |
| 643 | case '2': | |
| 644 | len1 = portable_snprintf(str1, str_m, fmt, (long long int)iargs[a]); | |
| 645 | len2 = sprintf(str2, fmt, (long long int)iargs[a]); | |
| 646 | #ifdef HAVE_SNPRINTF | |
| 647 | len3 = snprintf(str3, str_m, fmt, (long long int)iargs[a]); | |
| 648 | #endif | |
| 649 | break; | |
| 650 | #endif | |
| 651 | } | |
| 652 | } | |
| 653 | ||
| 654 | if (0) { | |
| 655 | #ifdef HAVE_SNPRINTF | |
| 656 | } else if (len1 != len3 || | |
| 657 | memcmp(str1,str3,min(len1+20,sizeof(str1))) != 0) { | |
| 658 | bad = 1; | |
| 659 | if (strtype) printf("\n2: %s, <%s>\n", fmt, sargs[a]); | |
| 660 | else printf("\n2: %s, %ld\n", fmt, iargs[a]); | |
| 661 | printf("portable: |%s| len = %d\n", str1, len1); | |
| 662 | printf("sys sprintf: |%s| len = %d\n", str2, len2); | |
| 663 | printf("sys snprintf: |%s| len = %d\n", str3, len3); | |
| 664 | #else | |
| 665 | } else if (len1 != len2 || | |
| 666 | (len1>0 && memcmp(str1,str2,min(len1,str_m)-1) != 0)) { | |
| 667 | bad = 1; | |
| 668 | if (strtype) printf("\n1: %s, <%s>\n", fmt, sargs[a]); | |
| 669 | else printf("\n1: %s, %ld\n", fmt, iargs[a]); | |
| 670 | printf("portable: |%s| len = %d\n", str1, len1); | |
| 671 | printf("sys sprintf: |%s| len = %d\n", str2, len2); | |
| 672 | #endif | |
| 673 | } | |
| 674 | if (bad) return(1); | |
| 675 | } | |
| 676 | ||
| 677 | } | |
| 678 | } | |
| 679 | } | |
| 680 | } | |
| 681 | ||
| 682 | } | |
| 683 | } | |
| 684 | } | |
| 685 | } | |
| 686 | } | |
| 687 | } | |
| 688 | return (bad?1:0); | |
| 689 | } |