Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] View of /branches/pure-cfg/src/lib/common/input.c
ViewVC logotype

View of /branches/pure-cfg/src/lib/common/input.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1260 - (download) (as text) (annotate)
Thu May 26 12:29:07 2011 UTC (8 years, 4 months ago) by glk
File size: 17104 byte(s)
adding more comments, and cosmetic tweaks
/*! \file input.c
 *
 * \author John Reppy, Gordon Kindlmann
 */

/*
 * COPYRIGHT (c) 2011 The Diderot Project (http://diderot-language.cs.uchicago.edu)
 * All rights reserved.
 */
#include "Diderot/diderot.h"
#include <teem/hest.h>

/* FIXME: eventally we should change the naming conventions in the header files to be generic */
#if defined(DIDEROT_SINGLE_PRECISION)
#define vec2(a,b)      vec2f(a,b)
#define vec3(a,b,c)    vec3f(a,b,c)
#define vec4(a,b,c,d)  vec4f(a,b,c,d)
#else
#define vec2(a,b)      vec2d(a,b)
#define vec3(a,b,c)    vec3d(a,b,c)
#define vec4(a,b,c,d)  vec4d(a,b,c,d)
#endif

Status_t Diderot_InputString (const char *name, const char **v, bool hasDflt)
{
    return DIDEROT_FAIL;
}

Status_t Diderot_InputReal (const char *name, Diderot_real_t *v, bool hasDflt)
{
    char   buf[256];
    double   f;
    
    while (true) {
        if (hasDflt)
            printf("Enter value for %s (default %lf): ", name, (double)*v);
        else
            printf("Enter value for %s: ", name);
        fflush (stdout);
        
        char *p = fgets(buf, sizeof(buf), stdin);
        if (p == NULL)
            return DIDEROT_FAIL;   // EOF
        int n = sscanf(buf, "%lf\n", &f);
        if (n == 1) {
            *v = (Diderot_real_t)f;
            return DIDEROT_OK;;
        }
        else if (hasDflt)
            return DIDEROT_OK;;
    }
    
}

Status_t Diderot_InputVec2 (const char *name, Diderot_vec2_t *v, bool hasDflt)
{
    char   buf[256];
    double   f1, f2;
    
    while (true) {
        if (hasDflt) {
            Diderot_union2_t u;
            u.v = *v;
            printf("Enter value for %s (default %f %f): ",
                   name, (double)(u.r[0]), (double)(u.r[1]));
        }
        else
            printf("Enter value for %s: ", name);
        fflush (stdout);
        
        char *p = fgets(buf, sizeof(buf), stdin);
        if (p == NULL)
            return DIDEROT_FAIL;   // EOF
        int n = sscanf(buf, "%lf %lf\n", &f1, &f2);
        if (n == 2) {
            *v = vec2((Diderot_real_t)f1, (Diderot_real_t)f2);
            return DIDEROT_OK;;
        }
        else if (hasDflt)
            return DIDEROT_OK;;
    }
    
}

Status_t Diderot_InputVec3 (const char *name, Diderot_vec3_t *v, bool hasDflt)
{
    char   buf[256];
    double   f1, f2, f3;
    
    while (true) {
        if (hasDflt) {
            Diderot_union3_t u;
            u.v = *v;
            printf("Enter value for %s (default %f %f %f): ",
                   name, (double)(u.r[0]), (double)(u.r[1]), (double)(u.r[2]));
        }
        else
            printf("Enter value for %s: ", name);
        fflush (stdout);
        
        char *p = fgets(buf, sizeof(buf), stdin);
        if (p == NULL)
            return DIDEROT_FAIL;   // EOF
        int n = sscanf(buf, "%lf %lf %lf\n", &f1, &f2, &f3);
        if (n == 3) {
            *v = vec3((Diderot_real_t)f1, (Diderot_real_t)f2, (Diderot_real_t)f3);
            return DIDEROT_OK;;
        }
        else if (hasDflt)
            return DIDEROT_OK;;
    }
    
}

//! Option type tags
typedef enum {
    optTypeUnknown,       // 0 
    optTypeFlag,          // 1
    optTypeBool,          // 2
    optTypeInt,           // 3
    optTypeReal,          // 4
    optTypeReal2,         // 5
    optTypeReal3,         // 6
    optTypeReal4,         // 7
    optTypeString         // 8
} optType_t;

/* 
** optDef_t
**
** the struct containing the definition of *one* option, and storage
** for its value once parsed
*/
typedef struct {
    char   *name;         // option name
    char   *desc;         // option description (a phrase or sentence)
    optType_t ty;         // option type
    union {               // storage that is passed into hest
        int b;            // storage for boolean-valued options
        double r[4];      // storage for real-valued options
        int64_t i[4];     // storage for integer-valued options
        char *s;          // storage for string-valued options
    } hval;
    void *valp;           // pointer to Diderot global variable being set
} optDef_t;

/* 
** struct Diderot_Options_s
**
** container for *all* options, and the machinery for parsing them,
** and means of managing their allocation.  There is an opaque typedef
** around this in src/include/Diderot/options.h.
**
** The "airArray *mop" is the primary means of managing the things that
** are dynamically allocated; anything that is allocated is registered
** in the mop so that it can be freed from a single place later (look
** for calls to airMopAdd)
**
**  Note that "odef" is a dynamically re-allocated array (managed by
** "odefArr"), and it is an array of optDef_t pointers, and not an
** array of optDef_t's, which is necessary: the values that hest sets
** are set via a pointer, and those values are stored in the optDef_t,
** so the memory location of the optDef_t cannot change, so these are
** allocated individually once.  If odef was an array of optDef_t's,
** then the location of the individual optDef_t would change if odef
** was reallocated for a different lenth.
*/
struct Diderot_Options_s {
    char *progInfo;       // documentation string for describing whole program,
                          // intended to be one or more sentences
    hestOpt *hopt;        // dynamically managed hest options
    hestParm *hparm;      // hest parameters
    optDef_t **odef;      // dynamically reallocated via odefArr
    unsigned int odefNum; // length of meaningful values in odef[]
    airArray *odefArr;    // manages odef and odefNum;
    airArray *mop;        // manages hopt, hparm, and odefArr
};

/*
** optDefNew
**
** allocate and initialize one optDef_t.  This doesn't need to be
** called directly; it will be used by the airArray to manage "odef"
** and what it points to.
*/
static void *optDefNew () {
    optDef_t *odef = AIR_CALLOC(1, optDef_t);
    odef->name = odef->desc = NULL;
    odef->ty = optTypeUnknown;
    /* not trying to initialize hval */
    odef->valp = NULL;
    return (void*)odef;
}

/*
** optDefNix
**
** free one optDef_t. This doesn't need to be called directly; it will
** be used by the airArray to manage "odef" and what it points to.
*/
static void *optDefNix (void *_odef) {
    optDef_t *odef = (optDef_t *)_odef;
    airFree(odef->name);
    airFree(odef->desc);
    if (optTypeString == odef->ty) {
        airFree(odef->hval.s);
    }
    airFree(odef);
    return NULL;
}

/*
******** Diderot_Options_New
**
** create the container for all option information
*/
struct Diderot_Options_s *Diderot_Options_New (void) {
    static const char me[]="Diderot_Options_New";
    struct Diderot_Options_s *dopts = AIR_CALLOC(1, struct Diderot_Options_s);
    if (!dopts) {
        fprintf(stderr, "%s: unable to allocate output\n", me);
        exit(1);
    }
    dopts->progInfo = NULL;
    dopts->mop = airMopNew();
    dopts->hopt = NULL;
    dopts->hparm = hestParmNew();
    dopts->hparm->noArgsIsNoProblem = AIR_TRUE;
    airMopAdd(dopts->mop, dopts->hparm, (airMopper)hestParmFree, airMopAlways);
    dopts->odef = NULL;
    dopts->odefNum = 0;
    /* 
    ** the airArray odefArr manages the allocation of odef, and as a
    ** convenience also sets odefNum to the number of values reliably
    ** set in odef
    */
    dopts->odefArr = airArrayNew((void**)(&dopts->odef), &dopts->odefNum, 
                                 sizeof(optDef_t*), 8 /* allocation increment */);
    if (!(dopts->odefArr)) {
        fprintf(stderr, "%s: unable to allocate option array\n", me);
        exit(1);
    }
    /*
    ** the airArray will set odef[I] = optDefNew for newly allocated
    ** elements I of odef, and will call optDefNix(odef[I]) for
    ** elements of odef that are about to be freed
    */
    airArrayPointerCB(dopts->odefArr, optDefNew, optDefNix);
    airMopAdd(dopts->mop, dopts->odefArr, (airMopper)airArrayNuke, airMopAlways);
    
    return dopts;
}

/*
******** Diderot_Options_Nix
**
** free everything associated with a struct Diderot_Options_s
*/
void Diderot_Options_Nix (struct Diderot_Options_s *dopts) {
    if (dopts) {
        airFree(dopts->progInfo);
        /* frees everything connected to the mop, and the mop itself */
        airMopOkay(dopts->mop);
        free(dopts);
    }
    return;
}

/*
******** Diderot_OptProgramInfoSet
**
** sets the one piece of information in the struct Diderot_Options_s
** which is not really for the options; "progInfo" is to describe the
** whole program.
*/
void Diderot_OptProgramInfoSet (struct Diderot_Options_s *dopts,
                                const char *progInfo) {
    static const char me[]="Diderot_OptProgramInfoSet";

    if (progInfo) {
        if (!( dopts->progInfo = airStrdup(progInfo) )) {
            fprintf(stderr, "%s: unable to copy program info", me);
            exit(1);
        }
    }
}

/*
** optAdd
**
** main function for adding options to a struct Diderot_Options_s.
*/
static optDef_t *optAdd (struct Diderot_Options_s *dopts,
                         const char *name, const char *desc, 
                         void *valp, optType_t ty) {
    static const char me[]="optAdd";
    unsigned int nidx;
    
    if (!( name && desc )) {
        fprintf(stderr, "%s: need both name (%p) and desc (%p) non-NULL\n",
                me, name, desc);
        exit(1);
    }
    /* calling airArrayLenIncr may trigger re-allocation of odef; 
       nidx is the index of the newly reserved element, odef[nidx] */
    nidx = airArrayLenIncr(dopts->odefArr, 1);
    if (!dopts->odef) {
        fprintf(stderr, "%s: unable to reallocate option array\n", me);
        exit(1);
    }
    /* code here uses "odf" to copy one value of odef[] */
    optDef_t *odf = dopts->odef[nidx];
    odf->name = airStrdup(name);
    odf->desc = airStrdup(desc);
    if (!(odf->name && odf->desc)) {
        fprintf(stderr, "%s: unable to allocate strings (%p,%p)\n",
                me, odf->name, odf->desc);
        exit(1);
    }
    odf->valp = valp;
    odf->ty = ty;
    
    return odf;
}

void Diderot_OptAddFlag (struct Diderot_Options_s *dopts,
                         const char *name, const char *desc,
                         bool *flg) {
    optDef_t *odf = optAdd(dopts, name, desc, (void*)flg, optTypeFlag);
    hestOptAdd(&dopts->hopt, name, NULL, airTypeInt, 0, 0, &odf->hval.b,
               NULL, desc);
}

void Diderot_OptAddBool (struct Diderot_Options_s *dopts,
                         const char *name, const char *desc,
                         bool *v, bool hasDflt) {
    optDef_t *odf = optAdd(dopts, name, desc, (void*)v, optTypeBool);
    hestOptAdd(&dopts->hopt, name, "bool", airTypeBool, 1, 1, &odf->hval.b, 
               hasDflt ? (*v ? "true" : "false") : NULL, desc);
}

/*
** On the use of AIR_STRLEN_HUGE below: default values for
** command-line options are communicated to hest by a *string*, but
** the actual default value comes to us in Diderot global.  So these
** functions have to convert the value from the Diderot variable into
** a string.
**
** The problem is that we don't know how long string will have to be,
** and there are few good functions for dealing with this.  snprintf
** is good for making sure you don't over-write a buffer of fixed
** size, but you still have to allocate the buffer.  asprintf allocates
** as needed, but GLK didn't want to assume it was available (perhaps
** this should be revisited)
**
** So instead, we just use a huge buffer, and assume that it will be
** more than big enough.  Feel free to fix this.
*/

void Diderot_OptAddInt (struct Diderot_Options_s *dopts,
                        const char *name, const char *desc,
                        Diderot_int_t *v, bool hasDflt) {
    char buf[AIR_STRLEN_HUGE] = "";
    if (hasDflt) {
        sprintf(buf, "%ld", (long)*v);
    }
    optDef_t *odf = optAdd(dopts, name, desc, (void*)v, optTypeInt);
    hestOptAdd(&dopts->hopt, name, "int", airTypeLongInt, 1, 1, odf->hval.i, 
               hasDflt ? buf : NULL, desc);
}

void Diderot_OptAddReal (struct Diderot_Options_s *dopts,
                         const char *name, const char *desc,
                         Diderot_real_t *v, bool hasDflt) {
    char buf[AIR_STRLEN_HUGE] = "";
    if (hasDflt) {
        sprintf(buf, "%lf", (double)*v);
    }
    optDef_t *odf = optAdd(dopts, name, desc, (void*)v, optTypeReal);
    hestOptAdd(&dopts->hopt, name, "val", airTypeDouble, 1, 1, odf->hval.r,
               hasDflt ? buf : NULL, desc);
}

void Diderot_OptAddReal2 (struct Diderot_Options_s *dopts,
                          const char *name, const char *desc,
                          Diderot_vec2_t *v, bool hasDflt) {
    char buf[AIR_STRLEN_HUGE] = "";

    if (hasDflt) {
        Diderot_union2_t u;
        u.v = *v;
        sprintf(buf, "%lf %lf", (double)(u.r[0]), (double)(u.r[1]));
    }
    optDef_t *odf = optAdd(dopts, name, desc, (void*)v, optTypeReal2);
    hestOptAdd(&dopts->hopt, name, "x y", airTypeDouble, 2, 2, odf->hval.r,
               hasDflt ? buf : NULL, desc);
}

void Diderot_OptAddReal3 (struct Diderot_Options_s *dopts,
                          const char *name, const char *desc,
                          Diderot_vec3_t *v, bool hasDflt) {
    char buf[AIR_STRLEN_HUGE] = "";

    if (hasDflt) {
        Diderot_union3_t u;
        u.v = *v;
        sprintf(buf, "%lf %lf %lf",
                (double)(u.r[0]), (double)(u.r[1]), (double)(u.r[2]));
    }
    optDef_t *odf = optAdd(dopts, name, desc, (void*)v, optTypeReal3);
    hestOptAdd(&dopts->hopt, name, "x y z", airTypeDouble, 3, 3, odf->hval.r,
               hasDflt ? buf : NULL, desc);
}

void Diderot_OptAddReal4 (struct Diderot_Options_s *dopts,
                          const char *name, const char *desc,
                          Diderot_vec4_t *v, bool hasDflt) {
    char buf[AIR_STRLEN_HUGE] = "";

    if (hasDflt) {
        Diderot_union4_t u;
        u.v = *v;
        sprintf(buf, "%lf %lf %lf %lf",
                (double)(u.r[0]), (double)(u.r[1]),
                (double)(u.r[2]), (double)(u.r[3]));
    }
    optDef_t *odf = optAdd(dopts, name, desc, (void*)v, optTypeReal4);
    hestOptAdd(&dopts->hopt, name, "x y z w", airTypeDouble, 4, 4, odf->hval.r,
               hasDflt ? buf : NULL, desc);
}

void Diderot_OptAddString (struct Diderot_Options_s *dopts,
                           const char *name, const char *desc,
                           char **v, bool hasDflt) {
    optDef_t *odf = optAdd(dopts, name, desc, (void*)v, optTypeString);
    hestOptAdd(&dopts->hopt, name, "str", airTypeString, 1, 1, &odf->hval.s,
               hasDflt ? *v : NULL, desc);
}

/*
******** Diderot_ProcessOptions
**
** given argc/argv, learn values for all options and set them
*/
void Diderot_ProcessOptions (struct Diderot_Options_s *dopts,
                             int argc, const char **argv) {
    static const char me[]="Diderot_ProcessOptions";

    hestParseOrDie(dopts->hopt, argc-1, argv+1, dopts->hparm, argv[0],
                   dopts->progInfo ? dopts->progInfo : "(no program info set)",
                   AIR_TRUE, AIR_TRUE, AIR_TRUE);
    airMopAdd(dopts->mop, dopts->hopt, (airMopper)hestOptFree, airMopAlways);
    airMopAdd(dopts->mop, dopts->hopt, (airMopper)hestParseFree, airMopAlways);

    // convert values learned by hest to their Diderot representations
    for (int i = 0;  i < dopts->odefNum;  i++) {
        optDef_t *odf = dopts->odef[i];
        switch (odf->ty) {
        case optTypeFlag:
        case optTypeBool:
            *(bool*)(odf->valp) = odf->hval.b ? true : false;
            break;
        case optTypeInt:
            *(Diderot_int_t *)(odf->valp) = (Diderot_int_t)(odf->hval.i[0]);
            break;
        case optTypeReal:
            *(Diderot_real_t *)(odf->valp) = (Diderot_real_t)(odf->hval.r[0]);
            break;
        case optTypeReal2:
            *(Diderot_vec2_t *)(odf->valp) = vec2((Diderot_real_t)(odf->hval.r[0]),
                                                  (Diderot_real_t)(odf->hval.r[1]));
            break;
        case optTypeReal3:
            *(Diderot_vec3_t *)(odf->valp) = vec3((Diderot_real_t)(odf->hval.r[0]),
                                                  (Diderot_real_t)(odf->hval.r[1]),
                                                  (Diderot_real_t)(odf->hval.r[2]));
            break;
        case optTypeReal4:
            *(Diderot_vec4_t *)(odf->valp) = vec4((Diderot_real_t)(odf->hval.r[0]),
                                                  (Diderot_real_t)(odf->hval.r[1]),
                                                  (Diderot_real_t)(odf->hval.r[2]),
                                                  (Diderot_real_t)(odf->hval.r[3]));
            break;
        case optTypeString: 
            if (!( *(char **)(odf->valp) = airStrdup(odf->hval.s) )) {
                fprintf(stderr, "%s: unable to allocate string copy\n", me);
                exit(1);
            }
            break;
        default:
            fprintf(stderr, "%s: unknown option type %d\n", me, odf->ty);
            exit(1);
        }
    }
}

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0