root/opal/mca/pmix/pmix4x/pmix/src/util/printf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. guess_strlen
  2. pmix_asprintf
  3. pmix_vasprintf
  4. pmix_snprintf
  5. pmix_vsnprintf
  6. main

   1 /*
   2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   3  *                         University Research and Technology
   4  *                         Corporation.  All rights reserved.
   5  * Copyright (c) 2004-2013 The University of Tennessee and The University
   6  *                         of Tennessee Research Foundation.  All rights
   7  *                         reserved.
   8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
   9  *                         University of Stuttgart.  All rights reserved.
  10  * Copyright (c) 2004-2005 The Regents of the University of California.
  11  *                         All rights reserved.
  12  * Copyright (c) 2007      Cisco Systems, Inc.  All rights reserved.
  13  * Copyright (c) 2015      Intel, Inc. All rights reserved.
  14  * $COPYRIGHT$
  15  *
  16  * Additional copyrights may follow
  17  *
  18  * $HEADER$
  19  */
  20 
  21 /*
  22  * Buffer safe printf functions for portability to archaic platforms.
  23  */
  24 
  25 #include <src/include/pmix_config.h>
  26 
  27 
  28 #include <errno.h>
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <string.h>
  32 
  33 #include "src/util/printf.h"
  34 #include "src/util/output.h"
  35 
  36 /*
  37  * Make a good guess about how long a printf-style varargs formatted
  38  * string will be once all the % escapes are filled in.  We don't
  39  * handle every % escape here, but we handle enough, and then add a
  40  * fudge factor in at the end.
  41  */
  42 static int guess_strlen(const char *fmt, va_list ap)
  43 {
  44     char *sarg, carg;
  45     double darg;
  46     float farg;
  47     size_t i;
  48     int iarg;
  49     int len;
  50     long larg;
  51 
  52     /* Start off with a fudge factor of 128 to handle the % escapes that
  53        we aren't calculating here */
  54 
  55     len = (int)strlen(fmt) + 128;
  56     for (i = 0; i < strlen(fmt); ++i) {
  57         if ('%' == fmt[i] && i + 1 < strlen(fmt)
  58             && '%' != fmt[i + 1]) {
  59             ++i;
  60             switch (fmt[i]) {
  61             case 'c':
  62                 carg = va_arg(ap, int);
  63                 len += 1;  /* let's suppose it's a printable char */
  64                 (void)carg;  /* prevent compiler from complaining about set but not used variables */
  65                 break;
  66             case 's':
  67                 sarg = va_arg(ap, char *);
  68 
  69                 /* If there's an arg, get the strlen, otherwise we'll
  70                  * use (null) */
  71 
  72                 if (NULL != sarg) {
  73                     len += (int)strlen(sarg);
  74                 } else {
  75 #if PMIX_ENABLE_DEBUG
  76                     pmix_output(0, "PMIX DEBUG WARNING: Got a NULL argument to pmix_vasprintf!\n");
  77 #endif
  78                     len += 5;
  79                 }
  80                 break;
  81 
  82             case 'd':
  83             case 'i':
  84                 iarg = va_arg(ap, int);
  85                 /* Alloc for minus sign */
  86                 if (iarg < 0)
  87                     ++len;
  88                 /* Now get the log10 */
  89                 do {
  90                     ++len;
  91                     iarg /= 10;
  92                 } while (0 != iarg);
  93                 break;
  94 
  95             case 'x':
  96             case 'X':
  97                 iarg = va_arg(ap, int);
  98                 /* Now get the log16 */
  99                 do {
 100                     ++len;
 101                     iarg /= 16;
 102                 } while (0 != iarg);
 103                 break;
 104 
 105             case 'f':
 106                 farg = (float)va_arg(ap, int);
 107                 /* Alloc for minus sign */
 108                 if (farg < 0) {
 109                     ++len;
 110                     farg = -farg;
 111                 }
 112                 /* Alloc for 3 decimal places + '.' */
 113                 len += 4;
 114                 /* Now get the log10 */
 115                 do {
 116                     ++len;
 117                     farg /= 10.0;
 118                 } while (0 != farg);
 119                 break;
 120 
 121             case 'g':
 122                 darg = va_arg(ap, int);
 123                 /* Alloc for minus sign */
 124                 if (darg < 0) {
 125                     ++len;
 126                     darg = -darg;
 127                 }
 128                 /* Alloc for 3 decimal places + '.' */
 129                 len += 4;
 130                 /* Now get the log10 */
 131                 do {
 132                     ++len;
 133                     darg /= 10.0;
 134                 } while (0 != darg);
 135                 break;
 136 
 137             case 'l':
 138                 /* Get %ld %lx %lX %lf */
 139                 if (i + 1 < strlen(fmt)) {
 140                     ++i;
 141                     switch (fmt[i]) {
 142                     case 'x':
 143                     case 'X':
 144                         larg = va_arg(ap, int);
 145                         /* Now get the log16 */
 146                         do {
 147                             ++len;
 148                             larg /= 16;
 149                         } while (0 != larg);
 150                         break;
 151 
 152                     case 'f':
 153                         darg = va_arg(ap, int);
 154                         /* Alloc for minus sign */
 155                         if (darg < 0) {
 156                             ++len;
 157                             darg = -darg;
 158                         }
 159                         /* Alloc for 3 decimal places + '.' */
 160                         len += 4;
 161                         /* Now get the log10 */
 162                         do {
 163                             ++len;
 164                             darg /= 10.0;
 165                         } while (0 != darg);
 166                         break;
 167 
 168                     case 'd':
 169                     default:
 170                         larg = va_arg(ap, int);
 171                         /* Now get the log10 */
 172                         do {
 173                             ++len;
 174                             larg /= 10;
 175                         } while (0 != larg);
 176                         break;
 177                     }
 178                 }
 179 
 180             default:
 181                 break;
 182             }
 183         }
 184     }
 185 
 186     return len;
 187 }
 188 
 189 
 190 int pmix_asprintf(char **ptr, const char *fmt, ...)
 191 {
 192     int length;
 193     va_list ap;
 194 
 195     va_start(ap, fmt);
 196     length = pmix_vasprintf(ptr, fmt, ap);
 197     va_end(ap);
 198 
 199     return length;
 200 }
 201 
 202 
 203 int pmix_vasprintf(char **ptr, const char *fmt, va_list ap)
 204 {
 205     int length;
 206     va_list ap2;
 207 
 208     /* va_list might have pointer to internal state and using
 209        it twice is a bad idea.  So make a copy for the second
 210        use.  Copy order taken from Autoconf docs. */
 211 #if PMIX_HAVE_VA_COPY
 212     va_copy(ap2, ap);
 213 #elif PMIX_HAVE_UNDERSCORE_VA_COPY
 214     __va_copy(ap2, ap);
 215 #else
 216     memcpy (&ap2, &ap, sizeof(va_list));
 217 #endif
 218 
 219     /* guess the size */
 220     length = guess_strlen(fmt, ap);
 221 
 222     /* allocate a buffer */
 223     *ptr = (char *) malloc((size_t) length + 1);
 224     if (NULL == *ptr) {
 225         errno = ENOMEM;
 226         va_end(ap2);
 227         return -1;
 228     }
 229 
 230     /* fill the buffer */
 231     length = vsprintf(*ptr, fmt, ap2);
 232 #if PMIX_HAVE_VA_COPY || PMIX_HAVE_UNDERSCORE_VA_COPY
 233     va_end(ap2);
 234 #endif  /* PMIX_HAVE_VA_COPY || PMIX_HAVE_UNDERSCORE_VA_COPY */
 235 
 236     /* realloc */
 237     *ptr = (char*) realloc(*ptr, (size_t) length + 1);
 238     if (NULL == *ptr) {
 239         errno = ENOMEM;
 240         return -1;
 241     }
 242 
 243     return length;
 244 }
 245 
 246 
 247 int pmix_snprintf(char *str, size_t size, const char *fmt, ...)
 248 {
 249     int length;
 250     va_list ap;
 251 
 252     va_start(ap, fmt);
 253     length = pmix_vsnprintf(str, size, fmt, ap);
 254     va_end(ap);
 255 
 256     return length;
 257 }
 258 
 259 
 260 int pmix_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
 261 {
 262     int length;
 263     char *buf;
 264 
 265     length = pmix_vasprintf(&buf, fmt, ap);
 266     if (length < 0) {
 267         return length;
 268     }
 269 
 270     /* return the length when given a null buffer (C99) */
 271     if (str) {
 272         if ((size_t) length < size) {
 273             strcpy(str, buf);
 274         } else {
 275             memcpy(str, buf, size - 1);
 276             str[size] = '\0';
 277         }
 278     }
 279 
 280     /* free allocated buffer */
 281     free(buf);
 282 
 283     return length;
 284 }
 285 
 286 
 287 #ifdef TEST
 288 
 289 int main(int argc, char *argv[])
 290 {
 291     char a[10];
 292     char b[173];
 293     char *s;
 294     int length;
 295 
 296     puts("test for NULL buffer in snprintf:");
 297     length = pmix_snprintf(NULL, 0, "this is a string %d", 1004);
 298     printf("length = %d\n", length);
 299 
 300     puts("test of snprintf to an undersize buffer:");
 301     length = pmix_snprintf(a, sizeof(a), "this is a string %d", 1004);
 302     printf("string = %s\n", a);
 303     printf("length = %d\n", length);
 304     printf("strlen = %d\n", (int) strlen(a));
 305 
 306     puts("test of snprintf to an oversize buffer:");
 307     length = pmix_snprintf(b, sizeof(b), "this is a string %d", 1004);
 308     printf("string = %s\n", b);
 309     printf("length = %d\n", length);
 310     printf("strlen = %d\n", (int) strlen(b));
 311 
 312     puts("test of asprintf:");
 313     length = pmix_asprintf(&s, "this is a string %d", 1004);
 314     printf("string = %s\n", s);
 315     printf("length = %d\n", length);
 316     printf("strlen = %d\n", (int) strlen(s));
 317 
 318     free(s);
 319 
 320     return 0;
 321 }
 322 
 323 #endif

/* [<][>][^][v][top][bottom][index][help] */