Example #1
0
/*
** as of Sept 2013 this returns information: the index of the
** option just added.  Returns UINT_MAX in case of error.
*/
unsigned int
hestOptAdd(hestOpt **optP,
           const char *flag, const char *name,
           int type, int min, int max,
           void *valueP, const char *dflt, const char *info, ...) {
  hestOpt *ret = NULL;
  int num;
  va_list ap;
  unsigned int retIdx;

  if (!optP)
    return UINT_MAX;

  num = *optP ? _hestNumOpts(*optP) : 0;
  if (!( ret = AIR_CALLOC(num+2, hestOpt) )) {
    return UINT_MAX;
  }
  if (num)
    memcpy(ret, *optP, num*sizeof(hestOpt));
  retIdx = AIR_UINT(num);
  ret[num].flag = airStrdup(flag);
  ret[num].name = airStrdup(name);
  ret[num].type = type;
  ret[num].min = min;
  ret[num].max = max;
  ret[num].valueP = valueP;
  ret[num].dflt = airStrdup(dflt);
  ret[num].info = airStrdup(info);
  /* initialize the things that may be set below */
  ret[num].sawP = NULL;
  ret[num].enm = NULL;
  ret[num].CB = NULL;
  /* seems to be redundant with above _hestOptInit() */
  ret[num].source = hestSourceUnknown;
  /* deal with var args */
  if (5 == _hestKind(&(ret[num]))) {
    va_start(ap, info);
    ret[num].sawP = va_arg(ap, unsigned int*);
    va_end(ap);
  }
Example #2
0
/*
******** hestMinNumArgs
**
** The idea is that this helps quickly determine if the options given
** on the command line are insufficient, in order to produce general
** usage information instead of some specific parse error.
**
** Because hest is strictly agnostic with respect to how many command-line
** arguments actually constitute the command itself ("rmdir": one argument,
** "cvs checkout": two arguments), it only concerns itself with the 
** command-line arguments following the command.
**
** Thus, hestMinMinArgs() returns the minimum number of command-line
** arguments (following the command) that could be valid.  If your 
** command is only one argument (like "rmdir"), then you might use
** the true argc passed by the OS to main() as such:
**
**   if (argc-1 < hestMinNumArgs(opt)) {
**     ... usage ...
**   }
**
** But if your command is two arguments (like "cvs checkout"):
**
**   if (argc-2 < hestMinNumArgs(opt)) {
**     ... usage ...
**   }
**
** HOWEVER! don't forget the response files can complicate all this:
** in one argument a response file can provide information for any
** number of arguments, and the argc itself is kind of meaningless.
** The code examples above only really apply when
** hparm->respFileEnable is false.  For example, in unrrdu (private.h)
** we find:
**
**   if ( (hparm->respFileEnable && !argc) ||
**        (!hparm->respFileEnable && argc < hestMinNumArgs(opt)) ) { 
**     ... usage ...
**   }
**
*/
int
hestMinNumArgs(hestOpt *opt) {
  hestParm *parm;
  int i, count, numOpts;

  parm = hestParmNew();
  if (_hestPanic(opt, NULL, parm)) {
    parm = hestParmFree(parm);
    return _hestMax(-1);
  }
  count = 0;
  numOpts = _hestNumOpts(opt);
  for (i=0; i<numOpts; i++) {
    if (!opt[i].dflt) {
      count += opt[i].min;
      if (!(0 == opt[i].min && 0 == opt[i].max)) {
        count += !!opt[i].flag;
      }
    }
  }  
  parm = hestParmFree(parm);
  return count;
}
Example #3
0
void
hestUsage(FILE *f, hestOpt *opt, const char *argv0, hestParm *_parm) {
  int i, numOpts;
  char buff[2*AIR_STRLEN_HUGE], tmpS[AIR_STRLEN_HUGE];
  hestParm *parm;

  parm = !_parm ? hestParmNew() : _parm;

  if (_hestPanic(opt, NULL, parm)) {
    /* we can't continue; the opt array is botched */
    parm = !_parm ? hestParmFree(parm) : NULL;
    return;
  }
    
  numOpts = _hestNumOpts(opt);
  fprintf(f, "\n");
  strcpy(buff, "Usage: ");
  strcat(buff, argv0 ? argv0 : "");
  if (parm && parm->respFileEnable) {
    sprintf(tmpS, " [%cfile\t...]", parm->respFileFlag);
    strcat(buff, tmpS);
  }
  for (i=0; i<numOpts; i++) {
    strcat(buff, " ");
    if (1 == opt[i].kind || (opt[i].flag && opt[i].dflt))
      strcat(buff, "[");
    _hestSetBuff(buff, opt + i, parm, AIR_TRUE, AIR_TRUE);
    if (1 == opt[i].kind || (opt[i].flag && opt[i].dflt))
      strcat(buff, "]");
  }

  _hestPrintStr(f, strlen("Usage: "), 0, parm->columns, buff, AIR_TRUE);

  parm = !_parm ? hestParmFree(parm) : NULL;
  return;
}
Example #4
0
void
hestGlossary(FILE *f, hestOpt *opt, hestParm *_parm) {
  int i, j, len, maxlen, numOpts;
  char buff[2*AIR_STRLEN_HUGE], tmpS[AIR_STRLEN_HUGE];
  hestParm *parm;

  parm = !_parm ? hestParmNew() : _parm;

  if (_hestPanic(opt, NULL, parm)) {
    /* we can't continue; the opt array is botched */
    parm = !_parm ? hestParmFree(parm) : NULL;
    return;
  }
    
  numOpts = _hestNumOpts(opt);

  maxlen = 0;
  if (numOpts) {
    fprintf(f, "\n");
  }
  for (i=0; i<numOpts; i++) {
    strcpy(buff, "");
    _hestSetBuff(buff, opt + i, parm, AIR_TRUE, AIR_FALSE);
    maxlen = AIR_MAX((int)strlen(buff), maxlen);
  }
  if (parm && parm->respFileEnable) {
    sprintf(buff, "%cfile ...", parm->respFileFlag);
    len = strlen(buff);
    for (j=len; j<maxlen; j++) {
      fprintf(f, " ");
    }
    fprintf(f, "%s = ", buff);
    strcpy(buff, "response file(s) containing command-line arguments");
    _hestPrintStr(f, maxlen + 3, maxlen + 3, parm->columns, buff, AIR_FALSE);
  }
  for (i=0; i<numOpts; i++) {
    strcpy(buff, "");
    _hestSetBuff(buff, opt + i, parm, AIR_TRUE, AIR_FALSE);
    airOneLinify(buff);
    len = strlen(buff);
    for (j=len; j<maxlen; j++) {
      fprintf(f, " ");
    }
    fprintf(f, "%s", buff);
    strcpy(buff, "");
#if 1
    if (opt[i].flag && strchr(opt[i].flag, parm->multiFlagSep)) {
      /* there is a long-form flag as well as short */
      _hestSetBuff(buff, opt + i, parm, AIR_FALSE, AIR_TRUE);
      strcat(buff, " = ");
      fprintf(f, " , ");
    } else {
      /* there is only a short-form flag */
      fprintf(f, " = ");
    }
#else
    fprintf(f, " = ");
#endif
    if (opt[i].info) {
      strcat(buff, opt[i].info);
    }
    if ((opt[i].min || _hestMax(opt[i].max))
        && (!( 2 == opt[i].kind
               && airTypeEnum == opt[i].type 
               && parm->elideSingleEnumType )) 
        && (!( 2 == opt[i].kind
               && airTypeOther == opt[i].type 
               && parm->elideSingleOtherType )) 
        ) {
      /* if there are newlines in the info, then we want to clarify the
         type by printing it on its own line */
      if (opt[i].info && strchr(opt[i].info, '\n')) {
        strcat(buff, "\n ");
      }
      else {
        strcat(buff, " ");
      }
      strcat(buff, "(");
      if (opt[i].min == 0 && _hestMax(opt[i].max) == 1) {
        strcat(buff, "optional\t");
      }
      else {
        if ((int)opt[i].min == _hestMax(opt[i].max) && _hestMax(opt[i].max) > 1) { /* HEY scrutinize casts */
          sprintf(tmpS, "%d\t", _hestMax(opt[i].max));
          strcat(buff, tmpS);
        }
        else if ((int)opt[i].min < _hestMax(opt[i].max)) { /* HEY scrutinize casts */
          if (-1 == opt[i].max) {
            sprintf(tmpS, "%d\tor\tmore\t", opt[i].min);
          }
          else {
            sprintf(tmpS, "%d..%d\t", opt[i].min, _hestMax(opt[i].max));
          }
          strcat(buff, tmpS);
        }
      }
      sprintf(tmpS, "%s%s", 
              (airTypeEnum == opt[i].type
               ? opt[i].enm->name
               : (airTypeOther == opt[i].type
                  ? opt[i].CB->type
                  : airTypeStr[opt[i].type])),
              (_hestMax(opt[i].max) > 1 
               ? (airTypeOther == opt[i].type
                  && 'y' == opt[i].CB->type[airStrlen(opt[i].CB->type)-1]
                  && parm->cleverPluralizeOtherY
                  ? "\bies" 
                  : "s")
               : ""));
      strcat(buff, tmpS);
      strcat(buff, ")");
    }
    /*
    fprintf(stderr, "!%s: parm->elideSingleOtherDefault = %d\n",
            "hestGlossary", parm->elideSingleOtherDefault);
    */
    if (opt[i].dflt 
        && (opt[i].min || _hestMax(opt[i].max))
        && (!( 2 == opt[i].kind
               && (airTypeFloat == opt[i].type || airTypeDouble == opt[i].type)
               && !AIR_EXISTS(airAtod(opt[i].dflt)) 
               && parm->elideSingleNonExistFloatDefault ))
        && (!( (3 == opt[i].kind || 5 == opt[i].kind) 
               && (airTypeFloat == opt[i].type || airTypeDouble == opt[i].type)
               && !AIR_EXISTS(airAtod(opt[i].dflt)) 
               && parm->elideMultipleNonExistFloatDefault ))
        && (!( 2 == opt[i].kind
               && airTypeOther == opt[i].type
               && parm->elideSingleOtherDefault ))
        && (!( 2 == opt[i].kind
               && airTypeString == opt[i].type
               && parm->elideSingleEmptyStringDefault 
               && 0 == airStrlen(opt[i].dflt) ))
        && (!( (3 == opt[i].kind || 5 == opt[i].kind) 
               && airTypeString == opt[i].type
               && parm->elideMultipleEmptyStringDefault 
               && 0 == airStrlen(opt[i].dflt) ))
        ) {
      /* if there are newlines in the info, then we want to clarify the
         default by printing it on its own line */
      if (opt[i].info && strchr(opt[i].info, '\n')) {
        strcat(buff, "\n ");
      }
      else {
        strcat(buff, "; ");
      }
      strcat(buff, "default:\t");
      strcpy(tmpS, opt[i].dflt);
      airStrtrans(tmpS, ' ', '\t');
      strcat(buff, "\"");
      strcat(buff, tmpS);
      strcat(buff, "\"");
    }
    _hestPrintStr(f, maxlen + 3, maxlen + 3, parm->columns, buff, AIR_FALSE);
  }
  parm = !_parm ? hestParmFree(parm) : NULL;

  return;
}