Exemple #1
0
/*
******** nrrdCommentAdd()
**
** Adds a given string to the list of comments
** Leading spaces (' ') and comment chars ('#') are not included.
**
** This function does NOT use biff.
*/
int
nrrdCommentAdd(Nrrd *nrrd, const char *_str)
{
  char /* me[]="nrrdCommentAdd", err[512], */ *str;
  int i;

  if (!(nrrd && _str))
  {
    /*
    sprintf(err, "%s: got NULL pointer", me);
    biffMaybeAdd(NRRD, err, useBiff);
    */
    return 1;
  }
  _str += strspn(_str, " #");
  if (!strlen(_str))
  {
    /* we don't bother adding comments with no length */
    return 0;
  }
  if (!strcmp(_str, _nrrdFormatURLLine0)
      || !strcmp(_str, _nrrdFormatURLLine1))
  {
    /* sneaky hack: don't store the format URL comment lines */
    return 0;
  }
  str = airStrdup(_str);
  if (!str)
  {
    /*
    sprintf(err, "%s: couldn't strdup given string", me);
    biffMaybeAdd(NRRD, err, useBiff);
    */
    return 1;
  }
  /* clean out carraige returns that would screw up reader */
  airOneLinify(str);
  i = airArrayLenIncr(nrrd->cmtArr, 1);
  if (!nrrd->cmtArr->data)
  {
    /*
    sprintf(err, "%s: couldn't lengthen comment array", me);
    biffMaybeAdd(NRRD, err, useBiff);
    */
    return 1;
  }
  nrrd->cmt[i] = str;
  return 0;
}
Exemple #2
0
/*
** adds a given message to the given entry.  The message is processed to
** convert all whitespace into ' ', and to eliminate whitespace at the
** end of the message.
*/
void
biffMsgAdd(biffMsg *msg, const char *err) {
  static const char me[]="biffMsgAdd";
  unsigned int idx;

  if (biffMsgNoop == msg) {
    return;
  }
  if (!( msg && err )) {
    fprintf(stderr, "%s: PANIC got NULL msg (%p) or err (%p)\n", me,
            AIR_VOIDP(msg), AIR_CVOIDP(err));
    /* exit(1); */
  }
  idx = airArrayLenIncr(msg->errArr, 1);
  if (!msg->err) {
    fprintf(stderr, "%s: PANIC: couldn't add message to %s\n", me, msg->key);
    /* exit(1); */
  }
  if (!( msg->err[idx] = airOneLinify(airStrdup(err)) )) {
    fprintf(stderr, "%s: PANIC: couldn't alloc message to %s\n", me, msg->key);
    /* exit(1); */
  }
  return;
}
Exemple #3
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;
}
Exemple #4
0
/*
** _nrrdSprintFieldInfo
**
** this prints "<prefix><field>: <info>" into *strP (after allocating it for
** big enough, usually with a stupidly big margin of error), in a form
** suitable to be written to NRRD or other image headers.  This will always
** print something (for valid inputs), even stupid <info>s like
** "(unknown endian)".  It is up to the caller to decide which fields
** are worth writing, via _nrrdFieldInteresting().
**
** NOTE: some of these fields make sense in non-NRRD files (e.g. all
** the per-axis information), but many only make sense in NRRD files.
** This is just one example of NRRD-format-specific stuff that is not
** in formatNRRD.c
*/
void
_nrrdSprintFieldInfo(char **strP, char *prefix,
                     const Nrrd *nrrd, NrrdIoState *nio, int field)
{
    char me[]="_nrrdSprintFieldInfo", buff[AIR_STRLEN_MED], *fnb;
    double colvec[NRRD_SPACE_DIM_MAX];
    const char *fs;
    unsigned int ii, dd,
             uintStrlen = 11,
             size_tStrlen = 33,
             doubleStrlen = 513;
    int fslen, fdlen, endi, maxl;

    if (!( strP && prefix
            && nrrd
            && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)
            && AIR_IN_OP(nrrdField_unknown, field, nrrdField_last) ))
    {
        return;
    }
    if (!_nrrdFieldInteresting(nrrd, nio, field))
    {
        *strP = airStrdup("");
    }

    fs = airEnumStr(nrrdField, field);
    fslen = strlen(prefix) + strlen(fs) + strlen(": ") + 1;
    switch (field)
    {
    case nrrdField_comment:
    case nrrdField_keyvalue:
        fprintf(stderr, "%s: CONFUSION: why are you calling me on \"%s\"?\n", me,
                airEnumStr(nrrdField, nrrdField_comment));
        *strP = airStrdup("");
        break;
    case nrrdField_content:
        airOneLinify(nrrd->content);
        *strP = (char *)calloc(fslen + strlen(nrrd->content), sizeof(char));
        sprintf(*strP, "%s%s: %s", prefix, fs, nrrd->content);
        break;
    case nrrdField_number:
        *strP = (char *)calloc(fslen + size_tStrlen, sizeof(char));
        sprintf(*strP, "%s%s: " _AIR_SIZE_T_CNV, prefix, fs,
                nrrdElementNumber(nrrd));
        break;
    case nrrdField_type:
        *strP = (char *)calloc(fslen + strlen(airEnumStr(nrrdType, nrrd->type)),
                               sizeof(char));
        sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdType, nrrd->type));
        break;
    case nrrdField_block_size:
        *strP = (char *)calloc(fslen + size_tStrlen, sizeof(char));
        sprintf(*strP, "%s%s: " _AIR_SIZE_T_CNV, prefix, fs, nrrd->blockSize);
        break;
    case nrrdField_dimension:
        *strP = (char *)calloc(fslen + uintStrlen, sizeof(char));
        sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->dim);
        break;
    case nrrdField_space:
        *strP = (char *)calloc(fslen + strlen(airEnumStr(nrrdSpace, nrrd->space)),
                               sizeof(char));
        sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdSpace, nrrd->space));
        break;
    case nrrdField_space_dimension:
        *strP = (char *)calloc(fslen + uintStrlen, sizeof(char));
        sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->spaceDim);
        break;
    /* ---- begin per-axis fields ---- */
    case nrrdField_sizes:
        *strP = (char *)calloc(fslen + nrrd->dim*(size_tStrlen + 1), sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            sprintf(buff, " " _AIR_SIZE_T_CNV, nrrd->axis[ii].size);
            strcat(*strP, buff);
        }
        break;
    case nrrdField_spacings:
        *strP = (char *)calloc(fslen + nrrd->dim*(doubleStrlen + 1), sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            airSinglePrintf(NULL, buff, " %g", nrrd->axis[ii].spacing);
            strcat(*strP, buff);
        }
        break;
    case nrrdField_thicknesses:
        *strP = (char *)calloc(fslen + nrrd->dim*(doubleStrlen + 1), sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            airSinglePrintf(NULL, buff, " %g", nrrd->axis[ii].thickness);
            strcat(*strP, buff);
        }
        break;
    case nrrdField_axis_mins:
        *strP = (char *)calloc(fslen + nrrd->dim*(doubleStrlen + 1), sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            airSinglePrintf(NULL, buff, " %g", nrrd->axis[ii].min);
            strcat(*strP, buff);
        }
        break;
    case nrrdField_axis_maxs:
        *strP = (char *)calloc(fslen + nrrd->dim*(doubleStrlen + 1), sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            airSinglePrintf(NULL, buff, " %g", nrrd->axis[ii].max);
            strcat(*strP, buff);
        }
        break;
    case nrrdField_space_directions:
        *strP = (char *)calloc(fslen +
                               nrrd->dim*nrrd->spaceDim*(doubleStrlen
                                       + strlen("(,) ")),
                               sizeof(char));
        sprintf(*strP, "%s%s: ", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim,
                                   nrrd->axis[ii].spaceDirection);
            if (ii < nrrd->dim-1)
            {
                strcat(*strP, " ");
            }
        }
        break;
    case nrrdField_centers:
        fdlen = 0;
        for (ii=0; ii<nrrd->dim; ii++)
        {
            fdlen += 1 + airStrlen(nrrd->axis[ii].center
                                   ? airEnumStr(nrrdCenter, nrrd->axis[ii].center)
                                   : NRRD_UNKNOWN);
        }
        *strP = (char *)calloc(fslen + fdlen, sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            sprintf(buff, " %s",
                    (nrrd->axis[ii].center
                     ? airEnumStr(nrrdCenter, nrrd->axis[ii].center)
                     : NRRD_UNKNOWN));
            strcat(*strP, buff);
        }
        break;
    case nrrdField_kinds:
        fdlen = 0;
        for (ii=0; ii<nrrd->dim; ii++)
        {
            fdlen += 1 + airStrlen(nrrd->axis[ii].kind
                                   ? airEnumStr(nrrdKind, nrrd->axis[ii].kind)
                                   : NRRD_UNKNOWN);
        }
        *strP = (char *)calloc(fslen + fdlen, sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            sprintf(buff, " %s",
                    (nrrd->axis[ii].kind
                     ? airEnumStr(nrrdKind, nrrd->axis[ii].kind)
                     : NRRD_UNKNOWN));
            strcat(*strP, buff);
        }
        break;
    case nrrdField_labels:
        fdlen = 0;
        for (ii=0; ii<nrrd->dim; ii++)
        {
            fdlen += airStrlen(nrrd->axis[ii].label) + 4;
        }
        *strP = (char *)calloc(fslen + fdlen, sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            strcat(*strP, " \"");
            if (airStrlen(nrrd->axis[ii].label))
            {
                strcat(*strP, nrrd->axis[ii].label);
            }
            strcat(*strP, "\"");
        }
        break;
    case nrrdField_units:
        fdlen = 0;
        for (ii=0; ii<nrrd->dim; ii++)
        {
            fdlen += airStrlen(nrrd->axis[ii].units) + 4;
        }
        *strP = (char *)calloc(fslen + fdlen, sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->dim; ii++)
        {
            strcat(*strP, " \"");
            if (airStrlen(nrrd->axis[ii].units))
            {
                strcat(*strP, nrrd->axis[ii].units);
            }
            strcat(*strP, "\"");
        }
        break;
    /* ---- end per-axis fields ---- */
    case nrrdField_min:
    case nrrdField_max:
        /* we're basically a no-op, now that these fields became meaningless */
        *strP = (char *)calloc(fslen + doubleStrlen, sizeof(char));
        sprintf(*strP, "%s%s: 0.0", prefix, fs);
        strcat(*strP, buff);
        break;
    case nrrdField_old_min:
        *strP = (char *)calloc(fslen + doubleStrlen, sizeof(char));
        sprintf(*strP, "%s%s: ", prefix, fs);
        airSinglePrintf(NULL, buff, "%g", nrrd->oldMin);
        strcat(*strP, buff);
        break;
    case nrrdField_old_max:
        *strP = (char *)calloc(fslen + doubleStrlen, sizeof(char));
        sprintf(*strP, "%s%s: ", prefix, fs);
        airSinglePrintf(NULL, buff, "%g", nrrd->oldMax);
        strcat(*strP, buff);
        break;
    case nrrdField_endian:
        if (airEndianUnknown != nio->endian)
        {
            /* we know a specific endianness because either it was recorded as
               part of "unu make -h", or it was set (and data was possibly
               altered) as part of "unu save" */
            endi = nio->endian;
        }
        else
        {
            /* we record our current architecture's endian because we're
               going to writing out data */
            endi = AIR_ENDIAN;
        }
        *strP = (char *)calloc(fslen + strlen(airEnumStr(airEndian, endi)),
                               sizeof(char));
        sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(airEndian, endi));
        break;
    case nrrdField_encoding:
        *strP = (char *)calloc(fslen + strlen(nio->encoding->name),
                               sizeof(char));
        sprintf(*strP, "%s%s: %s", prefix, fs, nio->encoding->name);
        break;
    case nrrdField_line_skip:
        *strP = (char *)calloc(fslen + uintStrlen, sizeof(char));
        sprintf(*strP, "%s%s: %d", prefix, fs, nio->lineSkip);
        break;
    case nrrdField_byte_skip:
        *strP = (char *)calloc(fslen + uintStrlen, sizeof(char));
        sprintf(*strP, "%s%s: %d", prefix, fs, nio->byteSkip);
        break;
    case nrrdField_sample_units:
        airOneLinify(nrrd->sampleUnits);
        *strP = (char *)calloc(fslen + strlen(nrrd->sampleUnits), sizeof(char));
        sprintf(*strP, "%s%s: \"%s\"", prefix, fs, nrrd->sampleUnits);
        break;
    case nrrdField_space_units:
        fdlen = 0;
        for (ii=0; ii<nrrd->spaceDim; ii++)
        {
            fdlen += airStrlen(nrrd->spaceUnits[ii]) + 4;
        }
        *strP = (char *)calloc(fslen + fdlen, sizeof(char));
        sprintf(*strP, "%s%s:", prefix, fs);
        for (ii=0; ii<nrrd->spaceDim; ii++)
        {
            strcat(*strP, " \"");
            if (airStrlen(nrrd->spaceUnits[ii]))
            {
                strcat(*strP, nrrd->spaceUnits[ii]);
            }
            strcat(*strP, "\"");
        }
        break;
    case nrrdField_space_origin:
        *strP = (char *)calloc(fslen + nrrd->spaceDim*(doubleStrlen
                               + strlen("(,) ")),
                               sizeof(char));
        sprintf(*strP, "%s%s: ", prefix, fs);
        _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, nrrd->spaceOrigin);
        break;
    case nrrdField_measurement_frame:
        *strP = (char *)calloc(fslen + (nrrd->spaceDim*
                                        nrrd->spaceDim*(doubleStrlen
                                                + strlen("(,) "))),
                               sizeof(char));
        sprintf(*strP, "%s%s: ", prefix, fs);
        for (dd=0; dd<nrrd->spaceDim; dd++)
        {
            for (ii=0; ii<nrrd->spaceDim; ii++)
            {
                colvec[ii] = nrrd->measurementFrame[dd][ii];
            }
            _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, colvec);
            if (dd < nrrd->spaceDim-1)
            {
                strcat(*strP, " ");
            }
        }
        break;
    case nrrdField_data_file:
        /* NOTE: this comes last (nrrdField_data_file is the highest-valued
           member of the nrrdField* enum) because the "LIST" form of the
           data file specification requires that the following lines be
           the filenames */
        /* error checking elsewhere: assumes there is data file info */
        if (nio->dataFNFormat)
        {
            *strP = (char *)calloc(fslen + strlen(nio->dataFNFormat) + 4*uintStrlen,
                                   sizeof(char));
            if (nio->dataFileDim == nrrd->dim-1)
            {
                sprintf(*strP, "%s%s: %s %d %d %d", prefix, fs, nio->dataFNFormat,
                        nio->dataFNMin, nio->dataFNMax, nio->dataFNStep);
            }
            else
            {
                sprintf(*strP, "%s%s: %s %d %d %d %d", prefix, fs, nio->dataFNFormat,
                        nio->dataFNMin, nio->dataFNMax, nio->dataFNStep,
                        nio->dataFileDim);
            }
        }
        else if (nio->dataFNArr->len > 1)
        {
            maxl = 0;
            for (ii=0; ii<nio->dataFNArr->len; ii++)
            {
                maxl = AIR_MAX(maxl, (int)strlen(nio->dataFN[ii]));
            }
            *strP = (char *)calloc(fslen + strlen(NRRD_LIST_FLAG)
                                   + uintStrlen + nio->dataFNArr->len * (maxl + 1),
                                   sizeof(char));
            fnb = (char *)calloc(fslen + strlen(NRRD_LIST_FLAG)
                                 + uintStrlen + maxl + 1,
                                 sizeof(char));
            if (nio->dataFileDim == nrrd->dim-1)
            {
                sprintf(*strP, "%s%s: LIST\n", prefix, fs);
            }
            else
            {
                sprintf(*strP, "%s%s: LIST %d\n", prefix, fs, nio->dataFileDim);
            }
            for (ii=0; ii<nio->dataFNArr->len; ii++)
            {
                sprintf(fnb, "%s%s", nio->dataFN[ii],
                        ii<nio->dataFNArr->len-1 ? "\n" : "");
                strcat(*strP, fnb);
            }
            free(fnb);
        }
        else
        {
            /* there is some ambiguity between a "LIST" of length one,
               and a single explicit data filename, but that's harmless */
            *strP = (char *)calloc(fslen + strlen("./")
                                   + strlen(nio->dataFN[0]) + 1,
                                   sizeof(char));
            sprintf(*strP, "%s%s: %s%s", prefix, fs,
                    /* this is a favor to older readers that can deal with
                       this NRRD file because its being saved in a NRRD0003
                       (or below) version, so we don't want to confuse them
                       by not having the old explicit header-relative flag */
                    (_nrrdFormatNRRD_whichVersion(nrrd, nio) < 4 ? "./" : ""),
                    nio->dataFN[0]);
        }
        break;
    default:
        fprintf(stderr, "%s: CONFUSION: field %d unrecognized\n", me, field);
        break;
    }

    return;
}
/*
** _nrrdSprintFieldInfo
**
** this prints "<prefix><field>: <info>" into *strP (after allocating it for
** big enough, usually with a stupidly big margin of error), in a form
** suitable to be written to NRRD or other image headers.  This will always
** print something (for valid inputs), even stupid <info>s like
** "(unknown endian)".  It is up to the caller to decide which fields
** are worth writing, via _nrrdFieldInteresting().
**
** NOTE: some of these fields make sense in non-NRRD files (e.g. all
** the per-axis information), but many only make sense in NRRD files.
** This is just one example of NRRD-format-specific stuff that is not
** in formatNRRD.c
*/
void
_nrrdSprintFieldInfo(char **strP, const char *prefix,
                     const Nrrd *nrrd, NrrdIoState *nio, int field) {
  static const char me[]="_nrrdSprintFieldInfo";
  char buff[AIR_STRLEN_MED], *fnb, stmp[AIR_STRLEN_SMALL],
    *strtmp=NULL;
  double colvec[NRRD_SPACE_DIM_MAX];
  const char *fs;
  unsigned int ii, dd,
    uintStrlen = 11,
    size_tStrlen = 33,
    doubleStrlen = 513;
  size_t fslen, fdlen, maxl;
  int endi;

  if (!( strP && prefix
         && nrrd
         && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX)
         && AIR_IN_OP(nrrdField_unknown, field, nrrdField_last) )) {
    return;
  }
  /* As of Sun Dec  2 01:57:48 CST 2012 (revision 5832) the only
     places where this function is called is when it has been guarded
     by "if (_nrrdFieldInteresting())" (except for in formatText.c when
     its called on the dimension field, which is always interesting).
     So, the following:

     if (!_nrrdFieldInteresting(nrrd, nio, field)) {
       *strP = airStrdup("");
     }

     was redundant and confusingly created the appearance of a memory
     leak waiting to happen.  We now let the default switch statement
     set *strP to NULL (all the other cases set it), to smoke out
     errors in how this function is called */

  fs = airEnumStr(nrrdField, field);
  fslen = strlen(prefix) + strlen(fs) + strlen(": ") + 1;
  switch (field) {
  case nrrdField_comment:
  case nrrdField_keyvalue:
    fprintf(stderr, "%s: CONFUSION: why are you calling me on \"%s\"?\n", me,
            airEnumStr(nrrdField, nrrdField_comment));
    *strP = airStrdup("");
    break;
  case nrrdField_content:
    strtmp = airOneLinify(airStrdup(nrrd->content));
    *strP = AIR_CALLOC(fslen + strlen(strtmp), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, strtmp);
    airFree(strtmp); strtmp = NULL;
    break;
  case nrrdField_number:
    *strP = AIR_CALLOC(fslen + size_tStrlen, char);
    sprintf(*strP, "%s%s: %s", prefix, fs,
            airSprintSize_t(stmp, nrrdElementNumber(nrrd)));
    break;
  case nrrdField_type:
    *strP = AIR_CALLOC(fslen + strlen(airEnumStr(nrrdType, nrrd->type)), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdType, nrrd->type));
    break;
  case nrrdField_block_size:
    *strP = AIR_CALLOC(fslen + size_tStrlen, char);
    sprintf(*strP, "%s%s: %s", prefix, fs,
            airSprintSize_t(stmp, nrrd->blockSize));
    break;
  case nrrdField_dimension:
    *strP = AIR_CALLOC(fslen + uintStrlen, char);
    sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->dim);
    break;
  case nrrdField_space:
    *strP = AIR_CALLOC(fslen
                       + strlen(airEnumStr(nrrdSpace, nrrd->space)), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(nrrdSpace, nrrd->space));
    break;
  case nrrdField_space_dimension:
    *strP = AIR_CALLOC(fslen + uintStrlen, char);
    sprintf(*strP, "%s%s: %d", prefix, fs, nrrd->spaceDim);
    break;
    /* ---- begin per-axis fields ---- */
  case nrrdField_sizes:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(size_tStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      sprintf(buff, " %s", airSprintSize_t(stmp, nrrd->axis[ii].size));
      strcat(*strP, buff);
    }
    break;
  case nrrdField_spacings:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].spacing);
      strcat(*strP, buff);
    }
    break;
  case nrrdField_thicknesses:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].thickness);
      strcat(*strP, buff);
    }
    break;
  case nrrdField_axis_mins:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].min);
      strcat(*strP, buff);
    }
    break;
  case nrrdField_axis_maxs:
    *strP = AIR_CALLOC(fslen + nrrd->dim*(doubleStrlen + 1), char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      airSinglePrintf(NULL, buff, " %.17g", nrrd->axis[ii].max);
      strcat(*strP, buff);
    }
    break;
  case nrrdField_space_directions:
    *strP = AIR_CALLOC(fslen
                       + nrrd->dim*nrrd->spaceDim*(doubleStrlen
                                                   + strlen("(,) ")), char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim,
                             nrrd->axis[ii].spaceDirection);
      if (ii < nrrd->dim-1) {
        strcat(*strP, " ");
      }
    }
    break;
  case nrrdField_centers:
    fdlen = 0;
    for (ii=0; ii<nrrd->dim; ii++) {
      fdlen += 1 + airStrlen(nrrd->axis[ii].center
                             ? airEnumStr(nrrdCenter, nrrd->axis[ii].center)
                             : NRRD_UNKNOWN);
    }
    *strP = AIR_CALLOC(fslen + fdlen, char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      sprintf(buff, " %s",
              (nrrd->axis[ii].center
               ? airEnumStr(nrrdCenter, nrrd->axis[ii].center)
               : NRRD_UNKNOWN));
      strcat(*strP, buff);
    }
    break;
  case nrrdField_kinds:
    fdlen = 0;
    for (ii=0; ii<nrrd->dim; ii++) {
      fdlen += 1 + airStrlen(nrrd->axis[ii].kind
                             ? airEnumStr(nrrdKind, nrrd->axis[ii].kind)
                             : NRRD_UNKNOWN);
    }
    *strP = AIR_CALLOC(fslen + fdlen, char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      sprintf(buff, " %s",
              (nrrd->axis[ii].kind
               ? airEnumStr(nrrdKind, nrrd->axis[ii].kind)
               : NRRD_UNKNOWN));
      strcat(*strP, buff);
    }
    break;
  case nrrdField_labels:
  case nrrdField_units:
#define LABEL_OR_UNITS (nrrdField_labels == field \
                        ? nrrd->axis[ii].label \
                        : nrrd->axis[ii].units)
    fdlen = 0;
    for (ii=0; ii<nrrd->dim; ii++) {
      /* The "2*" is because at worst every character needs escaping.
         The "+ 3" for the |" "| between each part */
      fdlen += 2*airStrlen(LABEL_OR_UNITS) + 3;
    }
    fdlen += 1; /* for '\0' */
    *strP = AIR_CALLOC(fslen + fdlen, char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->dim; ii++) {
      strcat(*strP, " \"");
      if (airStrlen(nrrd->axis[ii].label)) {
        _nrrdWriteEscaped(NULL, *strP, LABEL_OR_UNITS,
                          "\"", _NRRD_WHITESPACE_NOTAB);
      }
      strcat(*strP, "\"");
    }
#undef LABEL_OR_UNITS
    break;
    /* ---- end per-axis fields ---- */
  case nrrdField_min:
  case nrrdField_max:
    /* we're basically a no-op, now that these fields became meaningless */
    *strP = AIR_CALLOC(fslen + doubleStrlen, char);
    sprintf(*strP, "%s%s: 0.0", prefix, fs);
    strcat(*strP, buff);
    break;
  case nrrdField_old_min:
    *strP = AIR_CALLOC(fslen + doubleStrlen, char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    airSinglePrintf(NULL, buff, "%.17g", nrrd->oldMin);
    strcat(*strP, buff);
    break;
  case nrrdField_old_max:
    *strP = AIR_CALLOC(fslen + doubleStrlen, char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    airSinglePrintf(NULL, buff, "%.17g", nrrd->oldMax);
    strcat(*strP, buff);
    break;
  case nrrdField_endian:
    if (airEndianUnknown != nio->endian) {
      /* we know a specific endianness because either it was recorded as
         part of "unu make -h", or it was set (and data was possibly
         altered) as part of "unu save" */
      endi = nio->endian;
    } else {
      /* we record our current architecture's endian because we're
         going to writing out data */
      endi = airMyEndian();
    }
    *strP = AIR_CALLOC(fslen + strlen(airEnumStr(airEndian, endi)), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, airEnumStr(airEndian, endi));
    break;
  case nrrdField_encoding:
    *strP = AIR_CALLOC(fslen + strlen(nio->encoding->name), char);
    sprintf(*strP, "%s%s: %s", prefix, fs, nio->encoding->name);
    break;
  case nrrdField_line_skip:
    *strP = AIR_CALLOC(fslen + uintStrlen, char);
    sprintf(*strP, "%s%s: %d", prefix, fs, nio->lineSkip);
    break;
  case nrrdField_byte_skip:
    *strP = AIR_CALLOC(fslen + uintStrlen, char);
    sprintf(*strP, "%s%s: %ld", prefix, fs, nio->byteSkip);
    break;
  case nrrdField_sample_units:
    strtmp = airOneLinify(airStrdup(nrrd->sampleUnits));
    *strP = AIR_CALLOC(fslen + strlen(strtmp), char);
    sprintf(*strP, "%s%s: \"%s\"", prefix, fs, strtmp);
    airFree(strtmp); strtmp = NULL;
    break;
  case nrrdField_space_units:
    fdlen = 0;
    for (ii=0; ii<nrrd->spaceDim; ii++) {
      /* The "2*" is because at worst every character needs escaping.
         See note in formatNRRD.c about how even though its not part
         of the format, we have worst-case scenario of having to
         escape a space units which is nothing but ". The "+ 3" for
         the |" "| between each part */
      fdlen += 2*airStrlen(nrrd->spaceUnits[ii]) + 3;
    }
    fdlen += 1; /* for '\0' */
    *strP = AIR_CALLOC(fslen + fdlen, char);
    sprintf(*strP, "%s%s:", prefix, fs);
    for (ii=0; ii<nrrd->spaceDim; ii++) {
      strcat(*strP, " \"");
      if (airStrlen(nrrd->spaceUnits[ii])) {
        _nrrdWriteEscaped(NULL, *strP, nrrd->spaceUnits[ii],
                          "\"", _NRRD_WHITESPACE_NOTAB);
      }
      strcat(*strP, "\"");
    }
    break;
  case nrrdField_space_origin:
    *strP = AIR_CALLOC(fslen + nrrd->spaceDim*(doubleStrlen
                                               + strlen("(,) ")), char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, nrrd->spaceOrigin);
    break;
  case nrrdField_measurement_frame:
    *strP = AIR_CALLOC(fslen + (nrrd->spaceDim*
                                nrrd->spaceDim*(doubleStrlen
                                                + strlen("(,) "))), char);
    sprintf(*strP, "%s%s: ", prefix, fs);
    for (dd=0; dd<nrrd->spaceDim; dd++) {
      for (ii=0; ii<nrrd->spaceDim; ii++) {
        colvec[ii] = nrrd->measurementFrame[dd][ii];
      }
      _nrrdStrcatSpaceVector(*strP, nrrd->spaceDim, colvec);
      if (dd < nrrd->spaceDim-1) {
        strcat(*strP, " ");
      }
    }
    break;
  case nrrdField_data_file:
    /* NOTE: this comes last (nrrdField_data_file is the highest-valued
       member of the nrrdField* enum) because the "LIST" form of the
       data file specification requires that the following lines be
       the filenames */
    /* error checking elsewhere: assumes there is data file info */
    if (nio->dataFNFormat) {
      *strP = AIR_CALLOC(fslen + strlen(nio->dataFNFormat) + 4*uintStrlen,
                         char);
      if (nio->dataFileDim == nrrd->dim-1) {
        sprintf(*strP, "%s%s: %s %d %d %d", prefix, fs, nio->dataFNFormat,
                nio->dataFNMin, nio->dataFNMax, nio->dataFNStep);
      } else {
        sprintf(*strP, "%s%s: %s %d %d %d %u", prefix, fs, nio->dataFNFormat,
                nio->dataFNMin, nio->dataFNMax, nio->dataFNStep,
                nio->dataFileDim);
      }
    } else if (nio->dataFNArr->len > 1) {