/****************************************************************************/
/* CLIB.C: assorted C routines with prototypes in stdinc.h.                 */
/* Copyright (c) 1999 by Joshua E. Barnes, Tokyo, JAPAN.                    */
/****************************************************************************/

#include "stdinc.h"
#include "getparam.h"
#include <sys/types.h>
#include <sys/times.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdarg.h>

/*
 * ALLOCATE: memory allocation, with error checking.
 */

void *allocate(int nb)
{
    void *mem;

    mem = calloc(nb, 1);                /* allocate, also clearing memory   */
    if (mem == NULL)
        error("allocate in %s: not enuf memory (%d bytes)\n",
              getargv0(), nb);
    return (mem);
}

/*
 * CPUTIME: compute total process CPU time in minutes.
 */

double cputime(void)
{
    struct tms buffer;

    if (times(&buffer) == -1)
        error("cputime in %s: times() call failed\n", getargv0());
    return ((buffer.tms_utime + buffer.tms_stime) / (60.0 * HZ));
}

/*
 * ERROR: scream and die quickly.
 */

void error(string fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);          /* invoke interface to printf       */
    fflush(stderr);                     /* drain std error buffer           */
    va_end(ap);
    exit(1);                            /* quit with error status           */
}

/*
 * EPRINTF: scream, but don't die yet.
 */

void eprintf(string fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);          /* invoke interface to printf       */
    fflush(stderr);                     /* drain std error buffer           */
    va_end(ap);
}

/*
 * SCANOPT: scan string of the form "word1,word2,..." for a match.
 * Words must be separated by commas only -- no spaces allowed!
 */

bool scanopt(string opt, string key)
{
    char *op, *kp;

    op = (char *) opt;                  /* start scan of option strings     */
    while (*op != NULL) {               /* loop while words left to check   */
        kp = key;			/* (re)start scan of key word       */
        while ((*op != ',' ? *op : (char) NULL) == *kp) {
                                        /* char by char, compare word, key  */
            if (*kp++ == NULL)          /* reached end of key word, so...   */
                return (TRUE);          /* indicate success                 */
            op++;                       /* else go on to next char          */ 
        }
        while (*op != NULL && *op++ != ',')
					/* scan for start of next word      */
	    continue;
    }
    return (FALSE);                     /* indicate failure                 */
}

/*
 * STROPEN: open a STDIO stream like fopen, with these extensions: (1)
 * existing files cannot be opend for writing unless mode == "w!"  or
 * mode == "a", (2) names of form "-" map to stdin/stdout, depending on
 * mode, and (3) names of the form "-num" up a stream to read/write file
 * descriptor num.
 */

stream stropen(string name, string mode)
{
    bool inflag;
    int fds;
    stream res;
    struct stat buf;

    inflag = streq(mode, "r");
    if (name[0] == '-') {                       
        if (streq(name, "-")) {
            fds = dup(fileno(inflag ? stdin : stdout));
            if (fds == -1)
                error("stropen in %s: cannot dup %s\n",
                      getargv0(), inflag ? "stdin" : "stdout");
        } else
            fds = atoi(&name[1]);
        res = fdopen(fds, streq(mode, "w!") ? "w" : mode);
        if (res == NULL)
            error("stropen in %s: cannot open f.d. %d for %s\n",
                  getargv0(), fds, inflag ? "input" : "output");
    } else {
        if (streq(mode, "w") && stat(name, &buf) == 0)
            error("stropen in %s: file \"%s\" already exists\n",
                  getargv0(), name);
        res = fopen(name, streq(mode, "w!") ? "w" : mode);
        if (res == NULL)
            error("stropen in %s: cannot open file \"%s\" for %s\n",
                  getargv0(), name, inflag ? "input" : "output");
    }
    return (res);
}