2004-08-11 01:13:08 +04:00
|
|
|
/*
|
2005-11-05 22:57:48 +03:00
|
|
|
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
|
|
|
* University Research and Technology
|
|
|
|
* Corporation. All rights reserved.
|
2013-03-26 18:34:29 +04:00
|
|
|
* Copyright (c) 2004-2013 The University of Tennessee and The University
|
2005-11-05 22:57:48 +03:00
|
|
|
* of Tennessee Research Foundation. All rights
|
|
|
|
* reserved.
|
2004-11-28 23:09:25 +03:00
|
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
|
|
|
* University of Stuttgart. All rights reserved.
|
2005-03-24 15:43:37 +03:00
|
|
|
* Copyright (c) 2004-2005 The Regents of the University of California.
|
|
|
|
* All rights reserved.
|
2014-12-13 16:09:34 +03:00
|
|
|
* Copyright (c) 2007-2014 Cisco Systems, Inc. All rights reserved.
|
2004-11-22 04:38:40 +03:00
|
|
|
* $COPYRIGHT$
|
|
|
|
*
|
|
|
|
* Additional copyrights may follow
|
|
|
|
*
|
2004-08-11 01:13:08 +04:00
|
|
|
* $HEADER$
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Buffer safe printf functions for portability to archaic platforms.
|
|
|
|
*/
|
|
|
|
|
2006-02-12 04:33:29 +03:00
|
|
|
#include "opal_config.h"
|
2004-08-11 01:13:08 +04:00
|
|
|
|
2005-07-04 06:16:57 +04:00
|
|
|
#include "opal/util/printf.h"
|
2007-07-19 16:28:43 +04:00
|
|
|
#include "opal/util/output.h"
|
2004-08-11 01:13:08 +04:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make a good guess about how long a printf-style varargs formatted
|
|
|
|
* string will be once all the % escapes are filled in. We don't
|
|
|
|
* handle every % escape here, but we handle enough, and then add a
|
|
|
|
* fudge factor in at the end.
|
|
|
|
*/
|
|
|
|
static int guess_strlen(const char *fmt, va_list ap)
|
|
|
|
{
|
2014-12-13 16:09:34 +03:00
|
|
|
#if HAVE_VSNPRINTF
|
|
|
|
char dummy[1];
|
|
|
|
|
|
|
|
/* vsnprintf() returns the number of bytes that would have been
|
|
|
|
copied if the provided buffer were infinite. */
|
|
|
|
return 1 + vsnprintf(dummy, sizeof(dummy), fmt, ap);
|
|
|
|
#else
|
2012-08-08 16:43:13 +04:00
|
|
|
char *sarg, carg;
|
2004-08-11 01:13:08 +04:00
|
|
|
double darg;
|
|
|
|
float farg;
|
2004-10-18 19:38:19 +04:00
|
|
|
size_t i;
|
2004-08-11 01:13:08 +04:00
|
|
|
int iarg;
|
|
|
|
int len;
|
|
|
|
long larg;
|
|
|
|
|
|
|
|
/* Start off with a fudge factor of 128 to handle the % escapes that
|
|
|
|
we aren't calculating here */
|
|
|
|
|
2006-08-23 04:29:35 +04:00
|
|
|
len = (int)strlen(fmt) + 128;
|
2004-08-11 01:13:08 +04:00
|
|
|
for (i = 0; i < strlen(fmt); ++i) {
|
|
|
|
if ('%' == fmt[i] && i + 1 < strlen(fmt)
|
|
|
|
&& '%' != fmt[i + 1]) {
|
|
|
|
++i;
|
|
|
|
switch (fmt[i]) {
|
2007-03-02 00:48:31 +03:00
|
|
|
case 'c':
|
2012-08-08 16:43:13 +04:00
|
|
|
carg = va_arg(ap, int);
|
2007-03-02 00:48:31 +03:00
|
|
|
len += 1; /* let's suppose it's a printable char */
|
2013-03-26 18:34:29 +04:00
|
|
|
(void)carg; /* prevent compiler from complaining about set but not used variables */
|
2007-03-02 00:48:31 +03:00
|
|
|
break;
|
2004-08-11 01:13:08 +04:00
|
|
|
case 's':
|
|
|
|
sarg = va_arg(ap, char *);
|
|
|
|
|
|
|
|
/* If there's an arg, get the strlen, otherwise we'll
|
|
|
|
* use (null) */
|
|
|
|
|
2007-07-19 16:28:43 +04:00
|
|
|
if (NULL != sarg) {
|
2006-08-23 04:29:35 +04:00
|
|
|
len += (int)strlen(sarg);
|
2007-07-19 16:28:43 +04:00
|
|
|
} else {
|
2009-05-07 00:11:28 +04:00
|
|
|
#if OPAL_ENABLE_DEBUG
|
2007-07-19 21:18:10 +04:00
|
|
|
opal_output(0, "OPAL DEBUG WARNING: Got a NULL argument to opal_vasprintf!\n");
|
2007-07-19 16:28:43 +04:00
|
|
|
#endif
|
2004-08-11 01:13:08 +04:00
|
|
|
len += 5;
|
2007-07-19 16:28:43 +04:00
|
|
|
}
|
2004-08-11 01:13:08 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
case 'i':
|
|
|
|
iarg = va_arg(ap, int);
|
|
|
|
/* Alloc for minus sign */
|
|
|
|
if (iarg < 0)
|
|
|
|
++len;
|
|
|
|
/* Now get the log10 */
|
|
|
|
do {
|
|
|
|
++len;
|
|
|
|
iarg /= 10;
|
|
|
|
} while (0 != iarg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'x':
|
|
|
|
case 'X':
|
|
|
|
iarg = va_arg(ap, int);
|
|
|
|
/* Now get the log16 */
|
|
|
|
do {
|
|
|
|
++len;
|
|
|
|
iarg /= 16;
|
|
|
|
} while (0 != iarg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'f':
|
2006-10-05 09:12:57 +04:00
|
|
|
farg = (float)va_arg(ap, int);
|
2004-08-11 01:13:08 +04:00
|
|
|
/* Alloc for minus sign */
|
|
|
|
if (farg < 0) {
|
|
|
|
++len;
|
|
|
|
farg = -farg;
|
|
|
|
}
|
|
|
|
/* Alloc for 3 decimal places + '.' */
|
|
|
|
len += 4;
|
|
|
|
/* Now get the log10 */
|
|
|
|
do {
|
|
|
|
++len;
|
|
|
|
farg /= 10.0;
|
|
|
|
} while (0 != farg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'g':
|
|
|
|
darg = va_arg(ap, int);
|
|
|
|
/* Alloc for minus sign */
|
|
|
|
if (darg < 0) {
|
|
|
|
++len;
|
|
|
|
darg = -darg;
|
|
|
|
}
|
|
|
|
/* Alloc for 3 decimal places + '.' */
|
|
|
|
len += 4;
|
|
|
|
/* Now get the log10 */
|
|
|
|
do {
|
|
|
|
++len;
|
|
|
|
darg /= 10.0;
|
|
|
|
} while (0 != darg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'l':
|
|
|
|
/* Get %ld %lx %lX %lf */
|
|
|
|
if (i + 1 < strlen(fmt)) {
|
|
|
|
++i;
|
|
|
|
switch (fmt[i]) {
|
|
|
|
case 'x':
|
|
|
|
case 'X':
|
|
|
|
larg = va_arg(ap, int);
|
|
|
|
/* Now get the log16 */
|
|
|
|
do {
|
|
|
|
++len;
|
|
|
|
larg /= 16;
|
|
|
|
} while (0 != larg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'f':
|
|
|
|
darg = va_arg(ap, int);
|
|
|
|
/* Alloc for minus sign */
|
|
|
|
if (darg < 0) {
|
|
|
|
++len;
|
|
|
|
darg = -darg;
|
|
|
|
}
|
|
|
|
/* Alloc for 3 decimal places + '.' */
|
|
|
|
len += 4;
|
|
|
|
/* Now get the log10 */
|
|
|
|
do {
|
|
|
|
++len;
|
|
|
|
darg /= 10.0;
|
|
|
|
} while (0 != darg);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd':
|
|
|
|
default:
|
|
|
|
larg = va_arg(ap, int);
|
|
|
|
/* Now get the log10 */
|
|
|
|
do {
|
|
|
|
++len;
|
|
|
|
larg /= 10;
|
|
|
|
} while (0 != larg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
2014-12-13 16:09:34 +03:00
|
|
|
#endif
|
2004-08-11 01:13:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-04 06:16:57 +04:00
|
|
|
int opal_asprintf(char **ptr, const char *fmt, ...)
|
2004-08-11 01:13:08 +04:00
|
|
|
{
|
|
|
|
int length;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
2005-07-04 06:16:57 +04:00
|
|
|
length = opal_vasprintf(ptr, fmt, ap);
|
2004-08-11 01:13:08 +04:00
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-04 06:16:57 +04:00
|
|
|
int opal_vasprintf(char **ptr, const char *fmt, va_list ap)
|
2004-08-11 01:13:08 +04:00
|
|
|
{
|
|
|
|
int length;
|
2006-03-09 08:06:37 +03:00
|
|
|
va_list ap2;
|
|
|
|
|
|
|
|
/* va_list might have pointer to internal state and using
|
|
|
|
it twice is a bad idea. So make a copy for the second
|
|
|
|
use. Copy order taken from Autoconf docs. */
|
2009-05-07 00:11:28 +04:00
|
|
|
#if OPAL_HAVE_VA_COPY
|
2007-03-02 00:48:31 +03:00
|
|
|
va_copy(ap2, ap);
|
2009-05-07 00:11:28 +04:00
|
|
|
#elif OPAL_HAVE_UNDERSCORE_VA_COPY
|
2007-03-02 00:48:31 +03:00
|
|
|
__va_copy(ap2, ap);
|
2006-03-09 08:06:37 +03:00
|
|
|
#else
|
2007-03-02 00:48:31 +03:00
|
|
|
memcpy (&ap2, &ap, sizeof(va_list));
|
2006-03-09 08:06:37 +03:00
|
|
|
#endif
|
2004-08-11 01:13:08 +04:00
|
|
|
|
|
|
|
/* guess the size */
|
|
|
|
length = guess_strlen(fmt, ap);
|
|
|
|
|
|
|
|
/* allocate a buffer */
|
|
|
|
*ptr = (char *) malloc((size_t) length + 1);
|
|
|
|
if (NULL == *ptr) {
|
|
|
|
errno = ENOMEM;
|
2007-08-07 16:25:20 +04:00
|
|
|
va_end(ap2);
|
2004-08-11 01:13:08 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fill the buffer */
|
2006-03-09 08:06:37 +03:00
|
|
|
length = vsprintf(*ptr, fmt, ap2);
|
2009-05-07 00:11:28 +04:00
|
|
|
#if OPAL_HAVE_VA_COPY || OPAL_HAVE_UNDERSCORE_VA_COPY
|
2006-03-09 08:06:37 +03:00
|
|
|
va_end(ap2);
|
2009-05-07 00:11:28 +04:00
|
|
|
#endif /* OPAL_HAVE_VA_COPY || OPAL_HAVE_UNDERSCORE_VA_COPY */
|
2004-08-11 01:13:08 +04:00
|
|
|
|
|
|
|
/* realloc */
|
2004-10-18 19:38:19 +04:00
|
|
|
*ptr = (char*) realloc(*ptr, (size_t) length + 1);
|
2004-08-11 01:13:08 +04:00
|
|
|
if (NULL == *ptr) {
|
|
|
|
errno = ENOMEM;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-04 06:16:57 +04:00
|
|
|
int opal_snprintf(char *str, size_t size, const char *fmt, ...)
|
2004-08-11 01:13:08 +04:00
|
|
|
{
|
|
|
|
int length;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
2005-07-04 06:16:57 +04:00
|
|
|
length = opal_vsnprintf(str, size, fmt, ap);
|
2004-08-11 01:13:08 +04:00
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-04 06:16:57 +04:00
|
|
|
int opal_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
|
2004-08-11 01:13:08 +04:00
|
|
|
{
|
|
|
|
int length;
|
|
|
|
char *buf;
|
|
|
|
|
2005-07-04 06:16:57 +04:00
|
|
|
length = opal_vasprintf(&buf, fmt, ap);
|
2004-08-11 01:13:08 +04:00
|
|
|
if (length < 0) {
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return the length when given a null buffer (C99) */
|
|
|
|
if (str) {
|
|
|
|
if ((size_t) length < size) {
|
|
|
|
strcpy(str, buf);
|
|
|
|
} else {
|
|
|
|
memcpy(str, buf, size - 1);
|
|
|
|
str[size] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-29 15:59:11 +03:00
|
|
|
/* free allocated buffer */
|
|
|
|
free(buf);
|
|
|
|
|
2004-08-11 01:13:08 +04:00
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef TEST
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
char a[10];
|
|
|
|
char b[173];
|
|
|
|
char *s;
|
|
|
|
int length;
|
|
|
|
|
|
|
|
puts("test for NULL buffer in snprintf:");
|
2005-07-04 06:16:57 +04:00
|
|
|
length = opal_snprintf(NULL, 0, "this is a string %d", 1004);
|
2004-08-11 01:13:08 +04:00
|
|
|
printf("length = %d\n", length);
|
|
|
|
|
|
|
|
puts("test of snprintf to an undersize buffer:");
|
2005-07-04 06:16:57 +04:00
|
|
|
length = opal_snprintf(a, sizeof(a), "this is a string %d", 1004);
|
2004-08-11 01:13:08 +04:00
|
|
|
printf("string = %s\n", a);
|
|
|
|
printf("length = %d\n", length);
|
|
|
|
printf("strlen = %d\n", (int) strlen(a));
|
|
|
|
|
|
|
|
puts("test of snprintf to an oversize buffer:");
|
2005-07-04 06:16:57 +04:00
|
|
|
length = opal_snprintf(b, sizeof(b), "this is a string %d", 1004);
|
2004-08-11 01:13:08 +04:00
|
|
|
printf("string = %s\n", b);
|
|
|
|
printf("length = %d\n", length);
|
|
|
|
printf("strlen = %d\n", (int) strlen(b));
|
|
|
|
|
|
|
|
puts("test of asprintf:");
|
2005-07-04 06:16:57 +04:00
|
|
|
length = opal_asprintf(&s, "this is a string %d", 1004);
|
2004-08-11 01:13:08 +04:00
|
|
|
printf("string = %s\n", s);
|
|
|
|
printf("length = %d\n", length);
|
|
|
|
printf("strlen = %d\n", (int) strlen(s));
|
|
|
|
|
|
|
|
free(s);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|