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

SCM Repository

[diderot] View of /trunk/src/lib/common/input.c
ViewVC logotype

View of /trunk/src/lib/common/input.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3349 - (download) (as text) (annotate)
Tue Oct 27 15:16:36 2015 UTC (3 years, 9 months ago) by jhr
File size: 16470 byte(s)
making copyrights consistent for all code in the repository
/*! \file input.c
 *
 * \author John Reppy, Gordon Kindlmann
 */

/*
 * This code is part of the Diderot Project (http://diderot-language.cs.uchicago.edu)
 *
 * COPYRIGHT (c) 2015 The University of Chicago
 * All rights reserved.
 */
#include "Diderot/diderot.h"
#include <teem/hest.h>

bool     VerboseFlg = false;            //! true if running in verbose mode
bool     TimingFlg = false;             //! true if timing computation
bool     NrrdOutputFlg = false;         //! true if output is in Nrrd format

//! Option type tags
typedef enum {
    optTypeUnknown,       // 0 
    optTypeFlag,          // 1
    optTypeBool,          // 2
    optTypeInt,           // 3
    optTypeReal,          // 4
    optTypeReal2,         // 5
    optTypeReal3,         // 6
    optTypeReal4,         // 7
    optTypeString         // 8
} opt_type_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)
    opt_type_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
} opt_def_t;

/*! container for *all* options, 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 opt_def_t pointers, and not an
 * array of opt_def_t's, which is necessary: the values that hest sets
 * are set via a pointer, and those values are stored in the opt_def_t,
 * so the memory location of the opt_def_t cannot change, so these are
 * allocated individually once.  If odef was an array of opt_def_t's,
 * then the location of the individual op_def_t would change if odef
 * was reallocated for a different length.
 */
struct Diderot_struct_options {
    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
    opt_def_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
};

static void *OptDefNew ()
{
    opt_def_t *odef = AIR_CALLOC(1, opt_def_t);
    odef->name = odef->desc = 0;
    odef->ty = optTypeUnknown;
    odef->valp = 0;
    return odef;
}

/*! free an opt_def_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)
{
    opt_def_t *odef = (opt_def_t *)_odef;
    airFree(odef->name);
    airFree(odef->desc);
    if (optTypeString == odef->ty) {
        airFree(odef->hval.s);
    }
    airFree(odef);
    return 0;
}

/*! create the container for all option information and register standard
 *  command-line options.
 */
Diderot_Options_t *Diderot_OptNew ()
{
    static const char *me = "Diderot_Options_New";
    Diderot_Options_t *opts = AIR_CALLOC(1, Diderot_Options_t);
    if (opts == 0) {
        fprintf(stderr, "%s: unable to allocate output\n", me);
        exit(1);
    }
    opts->progInfo = 0;
    opts->mop = airMopNew();
    opts->hopt = 0;
    opts->hparm = hestParmNew();
    opts->hparm->noArgsIsNoProblem = AIR_TRUE;
    airMopAdd (opts->mop, opts->hparm, (airMopper)hestParmFree, airMopAlways);
    opts->odef = 0;
    opts->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
  */
    opts->odefArr = airArrayNew (
        (void**)(&opts->odef),
        &opts->odefNum, 
        sizeof(opt_def_t *),
        8 /* allocation increment */);

    if (opts->odefArr == 0) {
        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 (opts->odefArr, OptDefNew, optDefNix);
    airMopAdd (opts->mop, opts->odefArr, (airMopper)airArrayNuke, airMopAlways);

  // register standard command-line options
    Diderot_OptAddFlag (opts, "verbose", "enable runtime-system messages", &VerboseFlg);
    Diderot_OptAddFlag (opts, "timing", "enable execution timing", &TimingFlg);
    Diderot_OptAddFlag (opts, "nrrd", "enable nrrd output", &NrrdOutputFlg);

    return opts;
}

/*! free everything associated with a Diderot_Options_t
 */
void Diderot_OptFree (Diderot_Options_t *dopts)
{
    if (dopts != 0) {
        airFree(dopts->progInfo);
        /* frees everything connected to the mop, and the mop itself */
        airMopOkay(dopts->mop);
        free(dopts);
    }
    return;
}

/*! sets the one piece of information in the Diderot_Options_t
 * which is not really for the options; "progInfo" is to describe the
 * whole program.
 */
void Diderot_OptProgramInfoSet (
    Diderot_Options_t *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);
        }
    }
}

/*! main function for adding options to a Diderot_Options_t.
 */
static opt_def_t *OptAdd (
    Diderot_Options_t *dopts,
    const char *name,
    const char *desc, 
    void *valp,
    opt_type_t ty)
{
    static const char *me = "OptAdd";
    unsigned int nidx;
    
    if ((name == 0) || (desc == 0)) {
        fprintf(stderr, "%s: need both name (%p) and desc (%p) non-NULL\n",
            me, (void *)name, (void *)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 == 0) {
        fprintf(stderr, "%s: unable to reallocate option array\n", me);
        exit(1);
    }
  /* code here uses "odf" to copy one value of odef[] */
    opt_def_t *odf = dopts->odef[nidx];
    odf->name = airStrdup(name);
    odf->desc = airStrdup(desc);
    if ((odf->name == 0) || (odf->desc == 0)) {
        fprintf(stderr, "%s: unable to allocate strings (%p, %p)\n",
            me, (void *)odf->name,(void *) odf->desc);
        exit(1);
    }
    odf->valp = valp;
    odf->ty = ty;
    
    return odf;
}

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

/*! \brief add a boolean-valued option to the list of options.
 *  \param dopts   the list of options
 *  \param name    the name of the option
 *  \param desc    a short description string
 *  \param v       a pointer to the location where the value gets stored
 *  \param hasDflt true if there is an initial value
 */
void Diderot_OptAddBool (
    Diderot_Options_t *dopts,
    const char *name, const char *desc,
    bool *v, bool hasDflt)
{
    opt_def_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.
*/

/*! \brief add an integer option to the list of options.
 *  \param dopts   the list of options
 *  \param name    the name of the option
 *  \param desc    a short description string
 *  \param v       a pointer to the location where the value gets stored
 *  \param hasDflt true if there is an initial value
 */
void Diderot_OptAddInt (
    Diderot_Options_t *dopts,
    const char *name, const char *desc, Diderot_int_t *v, bool hasDflt)
{
    char buf[AIR_STRLEN_HUGE] = "";
    if (hasDflt) {
        snprintf(buf, sizeof(buf), "%ld", (long)*v);
    }
    opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeInt);
    hestOptAdd (
        &dopts->hopt, name, "int", airTypeLongInt, 1, 1, odf->hval.i, 
        hasDflt ? buf : NULL, desc);
}

/*! \brief add a real-valued option to the list of options.
 *  \param dopts   the list of options
 *  \param name    the name of the option
 *  \param desc    a short description string
 *  \param v       a pointer to the location where the value gets stored
 *  \param hasDflt true if there is an initial value
 */
void Diderot_OptAddReal (
    Diderot_Options_t *dopts,
    const char *name, const char *desc, Diderot_real_t *v, bool hasDflt)
{
    char buf[AIR_STRLEN_HUGE] = "";
    if (hasDflt) {
        snprintf(buf, sizeof(buf), "%lf", (double)*v);
    }
    opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeReal);
    hestOptAdd (
        &dopts->hopt, name, "val", airTypeDouble, 1, 1, odf->hval.r,
        hasDflt ? buf : NULL, desc);
}

/*! \brief add a 2-element vector option to the list of options.
 *  \param dopts   the list of options
 *  \param name    the name of the option
 *  \param desc    a short description string
 *  \param v       a pointer to the location where the value gets stored
 *  \param hasDflt true if there is an initial value
 */
void Diderot_OptAddReal2 (
    Diderot_Options_t *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;
        snprintf(buf, sizeof(buf), "%lf %lf", (double)(u.r[0]), (double)(u.r[1]));
    }
    opt_def_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);
}

/*! \brief add a 3-element vector option to the list of options.
 *  \param dopts   the list of options
 *  \param name    the name of the option
 *  \param desc    a short description string
 *  \param v       a pointer to the location where the value gets stored
 *  \param hasDflt true if there is an initial value
 */
void Diderot_OptAddReal3 (
    Diderot_Options_t *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;
        snprintf(buf, sizeof(buf), "%lf %lf %lf",
            (double)(u.r[0]), (double)(u.r[1]), (double)(u.r[2]));
    }
    opt_def_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);
}

/*! \brief add a 4-element vector option to the list of options.
 *  \param dopts   the list of options
 *  \param name    the name of the option
 *  \param desc    a short description string
 *  \param v       a pointer to the location where the value gets stored
 *  \param hasDflt true if there is an initial value
 */
void Diderot_OptAddReal4 (
    Diderot_Options_t *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;
        snprintf(buf, sizeof(buf), "%lf %lf %lf %lf",
            (double)(u.r[0]), (double)(u.r[1]),
            (double)(u.r[2]), (double)(u.r[3]));
    }
    opt_def_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);
}

/*! \brief add a string-vauled option to the list of options.
 *  \param dopts   the list of options
 *  \param name    the name of the option
 *  \param desc    a short description string
 *  \param v       a pointer to the location where the value gets stored
 *  \param hasDflt true if there is an initial value
 */
void Diderot_OptAddString (
    Diderot_Options_t *dopts,
    const char *name, const char *desc,
    char **v, bool hasDflt)
{
    opt_def_t *odf = OptAdd(dopts, name, desc, (void*)v, optTypeString);
    hestOptAdd (
        &dopts->hopt, name, "str", airTypeString, 1, 1, &odf->hval.s,
        hasDflt ? *v : NULL, desc);
}

/*! given argc/argv, learn values for all options and set them
 */
void Diderot_OptProcess (Diderot_Options_t *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++) {
        opt_def_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: {
                char *s = airStrdup(odf->hval.s);
                if (s == 0) {
                    fprintf(stderr, "%s: unable to allocate string copy\n", me);
                    exit(1);
                }
                *(char **)(odf->valp) = s;
            } break;
          default:
            fprintf(stderr, "%s: unknown option type %d\n", me, odf->ty);
            exit(1);
        } /* switch */
    }
}

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