/*
 * snprintf.c -- formatted output to a string
 *
 * This is an implementation of snprintf(), and vsnprintf(),
 * for operating systems which do not have a native version.
 */


#include <h/mh.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>


/*
 * Define snprintf(), by calling vsnprintf().  The security
 * of this depends on which vsnprintf() you are using.
 */

int
snprintf (char *buf, size_t n, const char *fmt, ...)
{
    va_list ap;
    int ret;

    va_start (ap, fmt);
    ret = vsnprintf (buf, n, fmt, ap);
    va_end (ap);
    return ret;
}


#ifdef INSECURE_VSNPRINTF

/*
 * Here is a simple version of vsnprintf(), which just ignores
 * the buffer length and calls your native vsprintf().
 * If is fast, but insecure.
 */

int
vsnprintf (char *buf, size_t n, const char *fmt, va_list ap)
{
    return vsprintf (buf, fmt, ap);
}

#else	/* It's slow, but secure */

/*
 * This is a simple version of vsnprintf() for systems
 * that don't have a native version.  This is a simple
 * version using temporary files.
 *
 * Returns the number of bytes that would have been output by printf.
 * Does not check whether a negative value if passed in for n
 * (as it's unsigned); some implementations cast n to int and than
 * compare with 0.
 *
 * Originally written by Casper Dik (Casper.Dik@Holland.Sun.COM)
 */

static char template[] = "/tmp/snprintfXXXXXX";

int
vsnprintf (char *buf, size_t n, const char *fmt, va_list ap)
{
    char templ[sizeof(template)];
    int s;
    int ret, cnt = 0, nread;
    FILE *fp;

    strcpy(templ,template);

    if ((s = mkstemp(templ)) < 0)
	return -1;

    (void) unlink(templ);

    if ((fp = fdopen(s, "w+")) == NULL) {
	close (s);
	return -1;
    }

    ret = vfprintf(fp, fmt, ap);

    if (ret < 0 || fseek(fp, 0, SEEK_SET) < 0) {
	fclose(fp);
	return -1;
    }

    /*
     * read at most n-1 characters, since
     * we need to leave last space for '\0'
     */
    while (cnt < (n-1) && (nread = fread(buf + cnt, 1, n - cnt - 1, fp)) > 0)
	cnt += nread;

    buf[cnt] = '\0';  /* cnt is at most n-1 */

    fclose(fp);
    return ret;
}

#endif
