root/opal/util/printf.c

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

DEFINITIONS

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

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