Complete.Org: Mailing Lists: Archives: freeciv-dev: June 1999:
Re: [Freeciv-Dev] patch: provide snprintf
Home

Re: [Freeciv-Dev] patch: provide snprintf

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: freeciv-dev@xxxxxxxxxxx
Subject: Re: [Freeciv-Dev] patch: provide snprintf
From: David Pfitzner <dwp@xxxxxxxxxxxxxx>
Date: Wed, 2 Jun 1999 11:47:51 +1000 (EST)

Oops, sorry for empty message, lets try that again...

David Pfitzner wrote:

>    frankly if we're going to include
> a more portable alternative, I'd prefer to include _just_ the
> more portable version, and accept any performance penalties (or
> whatever) on platforms where mprotect would have worked.

Actually, if we were to ignore performance issues, one option
would be the "write to a file" trick.  The following patch does
this; I think it works, and it should be pretty portable.  
Just don't using snprintf inside tight loops :-)

Any system for which this doesn't work (eg, broken tmpfile()?) 
we can probably laugh at for not providing ANSI/ISO Standard C.  
Though in the past, after composing ourselves we have tried 
somewhat to support such systems anyway...

I think this works ok regardless of funny \n\r treatment etc;
it doesn't do the traditional "write to /dev/null to work out 
the size" thing, so we don't depend on /dev/null existing, and 
plus it just works better this way.

I'm not sure if I'm seriously suggesting this...  Any takers? :-)
Remember this would only be for systems without a native vsnprintf.

-- David

ps: errata: ok, some of my int vars should be size_t, and it 
should check the return value of vfprintf for error.
/* by dwp */

#include <stdio.h>
#include <stdarg.h>

/* vsnprintf using tmpfile().
 *
 * We never close or remove the file; if tmpfile() works,
 * that should happen automatically when the program terminates
 * (assuming normal termination).
 *
 */
int my_vsnprintf(char *str, size_t nspec, const char *format, va_list ap)
{
  static FILE *fp = NULL;
  int nwrite, nread, n;

  if (fp == NULL) {
    fp = tmpfile();
    if (fp == NULL) {
      fprintf(stderr, "vsnprintf: tmpfile failed");
      exit(1);
    }
  }
  nwrite = vfprintf(fp, format, ap);
  n = (nwrite < nspec ? nwrite : nspec);
  rewind(fp);
  nread = fread(str, 1, n, fp);
  if (nread != n) {
    fprintf(stderr, "vsnprintf: short fread n=%ld nread=%ld",
            (long)n, (long)nread);
  }
  if (nread < nspec) {
    str[nread] = '\0';
  }
  rewind(fp);                   /* for next time */
  return nread;
}

int my_snprintf(char *str, size_t n, const char *format, ...)
{
  int ret;
  va_list ap;
  va_start(ap, format);
  ret = my_vsnprintf(str, n, format, ap);
  va_end(ap);
  return ret;
}

#ifdef TEST
int main(void)
{
  char s[] = "012345678";
  static char buf[50];

  my_snprintf(s, 3, "%s", "abcdefg");
  puts(s);
  my_snprintf(buf, 3, "%s", "abcdefg");
  puts(buf);
  my_snprintf(buf, 49, "%s", "abcdefg");
  puts(buf);
  return 0;
}
#endif

[Prev in Thread] Current Thread [Next in Thread]