Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!sdd.hp.com!caen!hellgate.utah.edu!dog.ee.lbl.gov!elf.ee.lbl.gov!torek From: torek@elf.ee.lbl.gov (Chris Torek) Newsgroups: comp.lang.c Subject: Re: space allocation for sprintf() Keywords: sprintf, space allocation Message-ID: <13984@dog.ee.lbl.gov> Date: 6 Jun 91 16:24:23 GMT References: <1991Jun5.174543.266@dg-rtp.dg.com> Reply-To: torek@elf.ee.lbl.gov (Chris Torek) Organization: Lawrence Berkeley Laboratory, Berkeley Lines: 92 X-Local-Date: Thu, 6 Jun 91 09:24:23 PDT In article <1991Jun5.174543.266@dg-rtp.dg.com> vook@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 #include 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@ee.lbl.gov