space allocation for sprintf()
Chris Torek
torek at elf.ee.lbl.gov
Fri Jun 7 02:24:23 AEST 1991
In article <1991Jun5.174543.266 at dg-rtp.dg.com> vook at narnia.rtp.dg.com
(Eric R Vook) writes:
>How do you know how much space to allocate [for sprintf]?
>How do you know when you didn't allocate enough?
A very good question indeed---by which I mean there are no good answers.
The new BSD stdio has snprintf and vsnprintf functions, which take a
buffer length, and guarantee not to overrun that buffer; they both
return the number of characters they would have printed, were the
buffer infinitely long, and thus:
char small[40], *p = small;
needed = snprintf(small, sizeof small, "%s%s%s", a1, a2, a3);
if (needed >= sizeof small) {
/* the string was truncated */
p = malloc(needed + 1);
if (p == NULL) die("malloc failed");
(void) snprintf(p, needed + 1, "%s%s%s", a1, a2, a3);
}
Since many uses of sprintf() are simply to transform the arguments into
a set of characters so that those characters can be displayed somewhere
(e.g., a window), the new BSD stdio also provides `funopen', through
which you can open your own analogue to the `write' function. This
allows you to pass arbitrarily long items through a short buffer.
Of course, none of these are remotely portable.
I have an approximation for a portable `vsnprintf', included below. It
depends on vfprintf and on `byte' files (hence will not work with fancy
record files such as found on VMS). It uses open-but-unlinked files
(easily changed, provided you have atexit()).
/*
* The function we want is called `vsnprintf': sprintf,
* with output limited to at most some number of bytes.
* This exists in the `function stdio' library already.
* Here we roll our own.
*
* MAJOR BOGOSITY: System V stdio has no way to limit the length
* to an sprintf. Instead, we use vfprintf to a temp file which we
* keep open but unlinked.
*/
#include <stdio.h>
#include <varargs.h>
static FILE *
setfil()
{
register FILE *f;
char buf[100];
(void) sprintf(buf, "/tmp/vsnprintf.%d", getpid());
if ((f = fopen(buf, "w+")) == NULL) {
perror(buf);
(void) fprintf(stderr, "cannot set up vsnprintf, help\n");
exit(1);
}
(void) unlink(buf);
return (f);
}
int
vsnprintf(str, len, fmt, ap)
char *str;
size_t len;
char *fmt;
va_list ap;
{
register int nch;
static FILE *fil;
if (len == 0)
return (0);
if (fil == NULL)
fil = setfil();
(void) fseek(fil, 0L, 0);
nch = vfprintf(fil, fmt, ap);
(void) fseek(fil, 0L, 0);
len--;
if (nch < len)
len = nch;
nch = fread(str, 1, len, fil);
str[nch] = '\0';
return (nch);
}
--
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA Domain: torek at ee.lbl.gov
More information about the Comp.lang.c
mailing list