File indexing completed on 2025-01-05 04:11:58

0001 /*                           (C) 2002 C. Barth Netterfield */
0002 /***************************************************************************
0003  *                                                                         *
0004  *   This program is free software; you can redistribute it and/or modify  *
0005  *   it under the terms of the GNU General Public License as published by  *
0006  *   the Free Software Foundation; either version 2 of the License, or     *
0007  *   (at your option) any later version.                                   *
0008  *                                                                         *
0009  ***************************************************************************/
0010 #include <assert.h>
0011 #include <stdio.h>
0012 #include <stdlib.h>
0013 #include <fcntl.h>
0014 #include <libgen.h>
0015 #include <sys/stat.h>
0016 #include <sys/types.h>
0017 #include <unistd.h>
0018 #include <string.h>
0019 #include <math.h>
0020 
0021 #include "getdata.h"
0022 #include "getdata_struct.h"
0023 
0024 const char *GD_ERROR_CODES[15] = {"OK",
0025                             "Could not open Format file",
0026                             "Error in Format file",
0027                             "Could not open Data file",
0028                             "Field name too long",
0029                             "Field code not found in File Format",
0030                             "Unrecognized return type",
0031                             "Could not open field file",
0032                             "Could not open included Format file",
0033                             "Internal error",
0034                             " ",
0035                             " ",
0036                             "Size mismatch in linear combination",
0037                             "Could not open interpolation file",
0038                             "Too many levels of recursion"
0039 };
0040 
0041 /* Suberror codes -- these don't need to be public */
0042 #define GD_E_FORMAT_SE_BAD_TYPE   0
0043 #define GD_E_FORMAT_SE_BAD_SPF    1
0044 #define GD_E_FORMAT_SE_N_FIELDS   2
0045 #define GD_E_FORMAT_SE_N_COLS     3
0046 #define GD_E_FORMAT_SE_MAX_I      4
0047 #define GD_E_FORMAT_SE_NUMBITS    5
0048 #define GD_E_FORMAT_SE_BITNUM     6
0049 #define GD_E_FORMAT_SE_BITSIZE    7
0050 #define GD_E_FORMAT_SE_FIELD_LEN  8
0051 #define GD_E_FORMAT_SE_BAD_LINE   9
0052 #define GD_E_FORMAT_SE_N_RAW     10
0053 
0054 #define GD_E_LINFILE_SE_OPEN      0
0055 #define GD_E_LINFILE_SE_LENGTH    1
0056 
0057 static struct {
0058   int n;
0059   struct FormatType *F;
0060 } Formats;
0061 
0062 static int recurse_level = 0;
0063 static int first_time = 1;
0064 static int getdata_error = GD_E_OK;
0065 static int getdata_suberror = 0;
0066 static char getdata_error_string[MAX_FILENAME_LENGTH + 6];
0067 static char getdata_error_file[MAX_FILENAME_LENGTH + 6];
0068 static int getdata_error_line = 0;
0069 
0070 static int DoField(struct FormatType *F, const char *field_code,
0071     int first_frame, int first_samp,
0072     int num_frames, int num_samp,
0073     char return_type, void *data_out,
0074     int *error_code);
0075 
0076 /***************************************************************************/
0077 /*                                                                         */
0078 /*    GetLine: read non-comment line from format file                      */
0079 /*        The line is placed in *line.                                     */
0080 /*        Returns 1 if successful, 0 if unsuccessful                       */
0081 /*                                                                         */
0082 /***************************************************************************/
0083 static int GetLine(FILE *fp, char *line, int* linenum) {
0084   char *ret_val;
0085   int first_char;
0086   int i, len;
0087 
0088   do {
0089     ret_val = fgets(line, MAX_LINE_LENGTH, fp);
0090     (*linenum)++;
0091     first_char = 0;
0092     while (line[first_char] == ' ' || line[first_char] == '\t') ++first_char;
0093     line += first_char;
0094   } while (ret_val && (line[0] == '#' || line[0] == 0 || line[1] == 0));
0095 
0096 
0097   if (ret_val) {
0098     /* truncate comments from end of lines */
0099     len = strlen(line);
0100     for (i = 0; i < len; i++) {
0101       if (line[i]=='#')
0102         line[i] = '\0';
0103     }
0104 
0105     return(1); /* a line was read */
0106   }
0107   return(0);  /* there were no valid lines */
0108 }
0109 
0110 /* SetGetDataError: Sets the global error variables for a library error */
0111 static int SetGetDataError(int error, int suberror,
0112     const char* format_file, int line, const char* token)
0113 {
0114   getdata_error = error;
0115   getdata_suberror = suberror;
0116   getdata_error_line = line;
0117   if (format_file != NULL)
0118     strncpy(getdata_error_file, format_file, MAX_FILENAME_LENGTH + 6);
0119   if (token != NULL)
0120     strncpy(getdata_error_string, token, MAX_FILENAME_LENGTH + 6);
0121 
0122   return error;
0123 }
0124 
0125 /***************************************************************************/
0126 /*                                                                         */
0127 /*    GetDataErrorString: Write a descriptive message in the supplied      */
0128 /*    buffer describing the last library error.  The message may be        */
0129 /*    truncated but should be null terminated.                             */
0130 /*                                                                         */
0131 /*      buffer: memory into which to write the string                      */
0132 /*      buflen: length of the buffer.  GetDataErrorString will not write   */
0133 /*              more than buflen characters (including the trailing '\0')  */
0134 /*                                                                         */
0135 /*    return value: buffer or NULL if buflen < 1                           */
0136 /*                                                                         */
0137 /***************************************************************************/
0138 char* GetDataErrorString(char* buffer, size_t buflen)
0139 {
0140   char* ptr;
0141 
0142   /* Sanity check */
0143   if (buffer == NULL || buflen < 1)
0144     return NULL;
0145 
0146   /* Copy the default error message into the buffer and make sure
0147    * the result is null terminated */
0148   strncpy(buffer, GD_ERROR_CODES[getdata_error], buflen - 1);
0149   buffer[buflen - 1] = 0;
0150 
0151   /* point to the end of the string and reduce buflen appropriately */
0152   ptr = buffer + strlen(buffer);
0153   buflen -= strlen(buffer);
0154 
0155   /* add the anciliary data - we use snprintfs here to ensure the resultant
0156    * string is properly null terminated (while not overflowing the buffer) */
0157   switch (getdata_error) {
0158     case GD_E_INTERNAL_ERROR: /* internal error: report line and source file
0159                                  where it happened */
0160       snprintf(ptr, buflen, "  [%s,%i]", getdata_error_file,
0161           getdata_error_line);
0162       break;
0163     case GD_E_OPEN_FORMAT: /* main format file couldn't be opened -- report
0164                               the filename we tried to open */
0165       snprintf(ptr, buflen, " %s", getdata_error_file);
0166       break;
0167     case GD_E_FORMAT: /* syntax errors in the format file -- lots of
0168                          suberror types here */
0169 
0170       /* No RAW fields specified -- this isn't tied to a particular line */
0171       if (getdata_suberror == GD_E_FORMAT_SE_N_RAW) {
0172         snprintf(ptr, buflen, ": no raw fields defined");
0173         break;
0174       }
0175 
0176       /* otherwise, add the format filename and line number where the
0177        * syntax error was found */
0178       snprintf(ptr, buflen, " on line %i of %s: ", getdata_error_line,
0179           getdata_error_file);
0180       buflen -= strlen(ptr);
0181       ptr += strlen(ptr);
0182 
0183       switch (getdata_suberror) {
0184         case GD_E_FORMAT_SE_BAD_TYPE: /* bad field type; include the thing
0185                                          we thought was the type specifier */
0186           snprintf(ptr, buflen, "bad raw field type: %c",
0187               getdata_error_string[0]);
0188           break;
0189         case GD_E_FORMAT_SE_BAD_SPF: /* SPF < 0 -- print the column we expected
0190                                         to hold the SPF */
0191           snprintf(ptr, buflen, "samples per frame out of range: %s",
0192               getdata_error_string);
0193           break;
0194         case GD_E_FORMAT_SE_N_FIELDS: /* number of fields in the LINCOM and
0195                                          the number of columns in the format
0196                                          file don't match */
0197           snprintf(ptr, buflen, "lincom field count out of range: %s",
0198               getdata_error_string);
0199           break;
0200         case GD_E_FORMAT_SE_N_COLS: /* missing data we expected to find on this
0201                                        line */
0202           snprintf(ptr, buflen, "missing column");
0203           break;
0204         case GD_E_FORMAT_SE_MAX_I: /* max_i out of range (what is an MPLEX?) */
0205           snprintf(ptr, buflen, "max_i out of range: %s", getdata_error_string);
0206           break;
0207         case GD_E_FORMAT_SE_NUMBITS: /* bitfield numbits is less than 1 */
0208           snprintf(ptr, buflen, "numbits out of range");
0209           break;
0210         case GD_E_FORMAT_SE_BITNUM: /* bitnum is less than 0 */
0211           snprintf(ptr, buflen, "starting bit out of range");
0212           break;
0213         case GD_E_FORMAT_SE_BITSIZE: /* bitfield extends past 32 bits */
0214           snprintf(ptr, buflen, "end of bitfield is out of bounds");
0215           break;
0216         case GD_E_FORMAT_SE_FIELD_LEN: /* field name is too long */
0217           snprintf(ptr, buflen, "field name too long: %s",
0218               getdata_error_string);
0219           break;
0220         case GD_E_FORMAT_SE_BAD_LINE: /* couldn't make heads nor tails of the
0221                                          line -- ie. a mistyped keyword &c. */
0222           snprintf(ptr, buflen, "line indecypherable");
0223           break;
0224       }
0225       break;
0226     case GD_E_OPEN_INCLUDE: /* Couldn't open an INCLUDEd file -- report the
0227                                included filename as well as the line and name
0228                                of the format file where it was encountered */
0229       snprintf(ptr, buflen, "%s on line %i of %s", getdata_error_string,
0230           getdata_error_line, getdata_error_file);
0231       break;
0232     case GD_E_BAD_RETURN_TYPE: /* unsupported data return type passed to
0233                                   GetData */
0234       snprintf(ptr, buflen, ": %c", (char)getdata_suberror);
0235       break;
0236     case GD_E_RECURSE_LEVEL: /* recursion too deep -- report field name for
0237                                 which this happened */
0238       snprintf(ptr, buflen, " while resolving field %s", getdata_error_string);
0239       break;
0240     case GD_E_BAD_CODE: /* A required field name wasn't defined */
0241     case GD_E_OPEN_RAWFIELD: /* A raw field file wasn't found on disk */
0242       snprintf(ptr, buflen, ": %s", getdata_error_string);
0243       break;
0244     case GD_E_OPEN_LINFILE: /* problems with LINTERPs: report the linterp
0245                                filename with the error message */
0246       snprintf(ptr, buflen, " %s: %s", getdata_error_string,
0247           (getdata_suberror == GD_E_LINFILE_SE_OPEN) ? "open failed"
0248           : "file too short");
0249       break;
0250   }
0251 
0252   return buffer;
0253 }
0254 
0255 /***************************************************************************/
0256 /*                                                                         */
0257 /*   FreeF: free any entries that have been allocated in F                 */
0258 /*                                                                         */
0259 /***************************************************************************/
0260 static void FreeF(struct FormatType *F) {
0261   if (F->n_raw > 0) free(F->rawEntries);
0262   if (F->n_lincom > 0) free(F->lincomEntries);
0263   if (F->n_multiply > 0) free(F->multiplyEntries);
0264   if (F->n_linterp >0) free(F->linterpEntries);
0265   if (F->n_mplex > 0) free(F->mplexEntries);
0266   if (F->n_bit > 0) free(F->bitEntries);
0267 }
0268 
0269 /***************************************************************************/
0270 /*                                                                         */
0271 /*   ParseRaw: parse a RAW data type in the formats file                   */
0272 /*                                                                         */
0273 /***************************************************************************/
0274 static int ParseRaw(char in_cols[MAX_IN_COLS][MAX_LINE_LENGTH],
0275     struct RawEntryType *R, const char* subdir, const char* format_file,
0276     int line)
0277 {
0278   strcpy(R->field, in_cols[0]); /* field */
0279   snprintf(R->file, MAX_FILENAME_LENGTH + FIELD_LENGTH + 2, "%s/%s", subdir,
0280       in_cols[0]); /* path and filename */
0281   R->fp = -1; /* file not opened yet */
0282   switch (in_cols[2][0]) {
0283     case 'c':
0284       R->size = 1;
0285       break;
0286     case 's': case 'u':
0287       R->size = 2;
0288       break;
0289     case 'S': case 'U': case 'f': case 'i':
0290       R->size = 4;
0291       break;
0292     case 'd':
0293       R->size = 8;
0294       break;
0295     default:
0296       return SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_BAD_TYPE, format_file,
0297           line, in_cols[2]);
0298   }
0299   R->type = in_cols[2][0];
0300   R->samples_per_frame = atoi(in_cols[3]);
0301   if (R->samples_per_frame<=0) {
0302     return SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_BAD_SPF, format_file,
0303         line, in_cols[3]);
0304   }
0305 
0306   return SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
0307 }
0308 
0309 /***************************************************************************/
0310 /*                                                                         */
0311 /*  ParseLincom: parse a LINCOM data type in the formats file              */
0312 /*                                                                         */
0313 /***************************************************************************/
0314 static int ParseLincom(char in_cols[MAX_IN_COLS][MAX_LINE_LENGTH], int n_cols,
0315     struct LincomEntryType *L, const char* format_file, int line)
0316 {
0317   int i;
0318   strcpy(L->field, in_cols[0]); /* field */
0319   L->n_infields = atoi(in_cols[2]);
0320   if ((L->n_infields<1) || (L->n_infields>MAX_LINCOM) ||
0321       (n_cols < L->n_infields*3 + 3)) {
0322     return SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_N_FIELDS, format_file,
0323         line, in_cols[2]);
0324   }
0325 
0326   for (i=0; i<L->n_infields; i++) {
0327     strncpy(L->in_fields[i], in_cols[i*3+3], FIELD_LENGTH);
0328     L->m[i] = atof(in_cols[i*3+4]);
0329     L->b[i] = atof(in_cols[i*3+5]);
0330   }
0331 
0332   return SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
0333 }
0334 /***************************************************************************/
0335 /*                                                                         */
0336 /*  ParseLinterp: parse a LINTERP data type in the formats file            */
0337 /*                                                                         */
0338 /***************************************************************************/
0339 static int ParseLinterp(char in_cols[MAX_IN_COLS][MAX_LINE_LENGTH],
0340     struct LinterpEntryType *L)
0341 {
0342   strcpy(L->field, in_cols[0]); /* field */
0343   strncpy(L->raw_field, in_cols[2], FIELD_LENGTH);
0344   strcpy(L->linterp_file, in_cols[3]);
0345   L->n_interp = -1; /* linterp file not read yet */
0346 
0347   return SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
0348 }
0349 
0350 /***************************************************************************/
0351 /*                                                                         */
0352 /*   ParseMultiply: parse MULTIPLY data type entry in formats file         */
0353 /*                                                                         */
0354 /***************************************************************************/
0355 static int ParseMultiply(char in_cols[MAX_IN_COLS][MAX_LINE_LENGTH], int n_cols,
0356     struct MultiplyEntryType *M, const char* format_file, int line)
0357 {
0358   if (n_cols < 4)
0359     return SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_N_COLS, format_file,
0360         line, NULL);
0361 
0362   strcpy(M->field, in_cols[0]); /* field */
0363 
0364   strncpy(M->in_fields[0], in_cols[2], FIELD_LENGTH);
0365   strncpy(M->in_fields[1], in_cols[3], FIELD_LENGTH);
0366 
0367   return SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
0368 }
0369 
0370 /***************************************************************************/
0371 /*                                                                         */
0372 /*   ParseMplex: parse MPLEX data type entry in formats file               */
0373 /*                                                                         */
0374 /***************************************************************************/
0375 static int ParseMplex(char in_cols[MAX_IN_COLS][MAX_LINE_LENGTH], int n_cols,
0376     struct MplexEntryType *M, const char* format_file, int line)
0377 {
0378   if (n_cols < 6)
0379     return SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_N_COLS, format_file,
0380         line, NULL);
0381 
0382   strcpy(M->field, in_cols[0]); /* field */
0383   strncpy(M->cnt_field, in_cols[2], FIELD_LENGTH);
0384   strncpy(M->data_field, in_cols[3], FIELD_LENGTH);
0385   M->i = atoi(in_cols[4]);
0386   M->max_i = atoi(in_cols[5]);
0387   if ((M->max_i < 1) || (M->max_i < M->i))
0388     return SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_MAX_I, format_file,
0389         line, NULL);
0390 
0391   return SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
0392 }
0393 
0394 /***************************************************************************/
0395 /*                                                                         */
0396 /*   ParseBit: parse BIT data type entry in formats file                   */
0397 /*                                                                         */
0398 /***************************************************************************/
0399 static int ParseBit(char in_cols[MAX_IN_COLS][MAX_LINE_LENGTH], int n_cols,
0400     struct BitEntryType *B, const char* format_file, int line)
0401 {
0402 
0403   strcpy(B->field, in_cols[0]); /* field */
0404   strncpy(B->raw_field, in_cols[2], FIELD_LENGTH); /* field */
0405 
0406   B->bitnum=atoi(in_cols[3]);
0407   if (n_cols>4) {
0408     B->numbits=atoi(in_cols[4]);
0409   } else {
0410     B->numbits=1;
0411   }
0412 
0413   if (B->numbits < 1)
0414     return SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_NUMBITS, format_file,
0415         line, NULL);
0416   if (B->bitnum < 0)
0417     return SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_BITNUM, format_file,
0418         line, NULL);
0419   if (B->bitnum + B->numbits - 1 > 31)
0420     return SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_BITSIZE, format_file,
0421         line, NULL);
0422 
0423   return SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
0424 }
0425 
0426 /***************************************************************************/
0427 /*                                                                         */
0428 /*   Compare functions for sorting the lists (using stdlib qsort)          */
0429 /*                                                                         */
0430 /***************************************************************************/
0431 static int RawCmp(const void *A, const void *B) {
0432   return (strcmp(((struct RawEntryType *)A)->field,
0433         ((struct RawEntryType *)B)->field));
0434 }
0435 
0436 static int LincomCmp(const void *A, const void *B) {
0437   return (strcmp(((struct LincomEntryType *)A)->field,
0438         ((struct LincomEntryType *)B)->field));
0439 }
0440 
0441 static int LinterpCmp(const void *A, const void *B) {
0442   return (strcmp(((struct LinterpEntryType *)A)->field,
0443         ((struct LinterpEntryType *)B)->field));
0444 }
0445 
0446 static int MultiplyCmp(const void *A, const void *B) {
0447   return (strcmp(((struct MultiplyEntryType *)A)->field,
0448         ((struct MultiplyEntryType *)B)->field));
0449 }
0450 
0451 static int MplexCmp(const void *A, const void *B) {
0452   return (strcmp(((struct MplexEntryType *)A)->field,
0453         ((struct MplexEntryType *)B)->field));
0454 }
0455 
0456 static int BitCmp(const void *A, const void *B) {
0457   return (strcmp(((struct BitEntryType *)A)->field,
0458         ((struct BitEntryType *)B)->field));
0459 }
0460 
0461 /***************************************************************************/
0462 /*                                                                         */
0463 /*  ParseFormatFile: Perform the actual parsing of the format file.  This  */
0464 /*     function is called from GetFormat once for the main format file and */
0465 /*     once for each included file.                                        */
0466 /*                                                                         */
0467 /***************************************************************************/
0468 static int ParseFormatFile(FILE* fp, struct FormatType *F, const char* filedir,
0469     const char* subdir, const char* format_file, char*** IncludeList,
0470     int *i_include)
0471 {
0472   char instring[MAX_LINE_LENGTH];
0473   char in_cols[MAX_IN_COLS][MAX_LINE_LENGTH];
0474   int n_cols, error_code = SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
0475   int linenum = 0;
0476 
0477   /***** start parsing ****/
0478   while (GetLine(fp, instring, &linenum)) {
0479     /* ok, brute force parse...  slow and ugly but convenient... */
0480     n_cols = sscanf(instring, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
0481         in_cols[0], in_cols[1], in_cols[2], in_cols[3],
0482         in_cols[4], in_cols[5], in_cols[6], in_cols[7],
0483         in_cols[8], in_cols[9], in_cols[10], in_cols[11],
0484         in_cols[12], in_cols[13], in_cols[14]);
0485 
0486     if (n_cols<2) {
0487       error_code = SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_N_COLS,
0488           format_file, linenum, NULL);
0489     } else if (strlen(in_cols[0])>FIELD_LENGTH) {
0490       error_code = SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_FIELD_LEN,
0491           format_file, linenum, in_cols[0]);
0492     } else if (strcmp(in_cols[1], "RAW")==0) {
0493       F->n_raw++;
0494       F->rawEntries =
0495         realloc(F->rawEntries, F->n_raw*sizeof(struct RawEntryType));
0496       error_code = ParseRaw(in_cols, F->rawEntries+F->n_raw - 1, subdir,
0497           format_file, linenum);
0498     } else if (strcmp(in_cols[1], "LINCOM")==0) {
0499       F->n_lincom++;
0500       F->lincomEntries =
0501         realloc(F->lincomEntries,
0502             F->n_lincom*sizeof(struct LincomEntryType));
0503       error_code = ParseLincom(in_cols, n_cols, F->lincomEntries+F->n_lincom
0504           - 1, format_file, linenum);
0505     } else if (strcmp(in_cols[1], "LINTERP")==0) {
0506       F->n_linterp++;
0507       F->linterpEntries =
0508         realloc(F->linterpEntries,
0509             F->n_linterp*sizeof(struct LinterpEntryType));
0510       error_code = ParseLinterp(in_cols, F->linterpEntries+F->n_linterp - 1);
0511     } else if (strcmp(in_cols[1], "MULTIPLY")==0) {
0512       F->n_multiply++;
0513       F->multiplyEntries =
0514         realloc(F->multiplyEntries,
0515             F->n_multiply*sizeof(struct MultiplyEntryType));
0516       error_code = ParseMultiply(in_cols, n_cols, F->multiplyEntries +
0517           F->n_multiply - 1, format_file, linenum);
0518     } else if (strcmp(in_cols[1], "MPLEX")==0) {
0519       F->n_mplex++;
0520       F->mplexEntries =
0521         realloc(F->mplexEntries,
0522             F->n_mplex*sizeof(struct MplexEntryType));
0523       error_code = ParseMplex(in_cols, n_cols, F->mplexEntries+F->n_mplex - 1,
0524           format_file, linenum);
0525     } else if (strcmp(in_cols[1], "BIT")==0) {
0526       F->n_bit++;
0527       F->bitEntries =
0528         realloc(F->bitEntries,
0529             F->n_bit*sizeof(struct BitEntryType));
0530       error_code = ParseBit(in_cols, n_cols, F->bitEntries+F->n_bit - 1,
0531           format_file, linenum);
0532     } else if (strcmp(in_cols[0], "FRAMEOFFSET")==0) {
0533       F->frame_offset = atoi(in_cols[1]);
0534     } else if (strcmp(in_cols[0], "INCLUDE")==0) {
0535       int i, found = 0;
0536       char new_format_file[MAX_FILENAME_LENGTH + 6];
0537       char new_subdir[MAX_FILENAME_LENGTH + 1];
0538       FILE* new_fp = NULL;
0539 
0540       /* Run through the include list to see if we've already included this
0541        * file */
0542       for (i = 0; i < *i_include; ++i)
0543         if (strcmp(in_cols[1], (*IncludeList)[i]) == 0) {
0544           found = 1;
0545           break;
0546         }
0547 
0548       /* If we found the file, we won't reopen it.  Continue parsing. */
0549       if (found)
0550         continue;
0551 
0552       /* Otherwise, try to open the file */
0553       snprintf(new_format_file, MAX_FILENAME_LENGTH + 6, "%s/%s/%s", filedir,
0554           subdir, in_cols[1]);
0555       new_fp = fopen(new_format_file, "r");
0556 
0557       /* If opening the file failed, set the error code and abort parsing. */
0558       if (new_fp == NULL) {
0559         error_code = SetGetDataError(GD_E_OPEN_INCLUDE, 0, format_file, linenum,
0560             new_format_file);
0561         break;
0562       }
0563 
0564       /* If we got here, we managed to open the inlcuded file; parse it */
0565       *IncludeList = realloc(*IncludeList, ++(*i_include) * sizeof(char*));
0566       (*IncludeList)[*i_include - 1] = strdup(in_cols[1]);
0567 
0568       /* extract the subdirectory name - dirname both returns a volatile string
0569        * and modifies its argument, ergo strcpy */
0570       strcpy(new_format_file, in_cols[1]);
0571       if (strcmp(subdir, ".") == 0)
0572         strcpy(new_subdir, dirname(new_format_file));
0573       else
0574         snprintf(new_subdir, MAX_FILENAME_LENGTH, "%s/%s", subdir,
0575             dirname(new_format_file));
0576 
0577       error_code = ParseFormatFile(new_fp, F, filedir, new_subdir,
0578           new_format_file, IncludeList, i_include);
0579       fclose(new_fp);
0580     } else
0581       error_code = SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_BAD_LINE,
0582           format_file, linenum, NULL);
0583 
0584     /* break out of loop (so we can return) if we've encountered an error */
0585     if (error_code != GD_E_OK)
0586       break;
0587   }
0588 
0589   return error_code;
0590 }
0591 
0592 /***************************************************************************/
0593 /*                                                                         */
0594 /*   GetFormat: Read format file and fill structure.  The format           */
0595 /*      is cached.                                                         */
0596 /*                                                                         */
0597 /***************************************************************************/
0598 struct FormatType *GetFormat(const char *filedir, int *error_code) {
0599   int i_format, i;
0600   struct stat statbuf;
0601   FILE *fp;
0602   char format_file[MAX_FILENAME_LENGTH+6];
0603   struct FormatType *F;
0604   char raw_data_filename[MAX_FILENAME_LENGTH+FIELD_LENGTH+2];
0605   char **IncludeList = NULL;
0606   int i_include;
0607 
0608   /** first check to see if we have already read it **/
0609   for (i_format=0; i_format<Formats.n; i_format++) {
0610     if (strncmp(filedir,
0611           Formats.F[i_format].FileDirName, MAX_FILENAME_LENGTH) == 0) {
0612       *error_code = SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
0613       return(Formats.F + i_format);
0614     }
0615   }
0616 
0617   /** if we get here, the file has not yet been read */
0618   /** Allocate the memory, then fill.  If we have an error, */
0619   /*  we will have to free the memory... */
0620   Formats.n++;
0621   Formats.F = realloc(Formats.F, Formats.n * sizeof(struct FormatType));
0622 
0623   F = Formats.F+Formats.n-1;
0624 
0625   /***** open the format file (if there is one) ******/
0626   snprintf(format_file, MAX_FILENAME_LENGTH+6, "%s/format", filedir);
0627   fp = fopen(format_file, "r");
0628   if (fp == NULL) {
0629     *error_code = SetGetDataError(GD_E_OPEN_FORMAT, 0, format_file, 0, NULL);
0630     Formats.n--; /* no need to free.  The next realloc will just do nothing */
0631     return (NULL);
0632   }
0633 
0634   strcpy(F->FileDirName, filedir);
0635   F->n_raw = F->n_lincom = F->n_multiply = F->n_linterp = F->n_mplex = F->n_bit
0636     = 0;
0637   F->frame_offset = 0;
0638   F->rawEntries = NULL;
0639   F->lincomEntries = NULL;
0640   F->multiplyEntries = NULL;
0641   F->linterpEntries = NULL;
0642   F->mplexEntries = NULL;
0643   F->bitEntries = NULL;
0644 
0645   /* Parse the file.  This will take care of any necessary inclusions */
0646   i_include = 1;
0647   IncludeList = malloc(sizeof(char*));
0648   IncludeList[0] = strdup("format");
0649   *error_code = ParseFormatFile(fp, F, filedir, ".", format_file, &IncludeList,
0650       &i_include);
0651   fclose(fp);
0652 
0653   /* Clean up IncludeList.  We don't need it anymore */
0654   for (i = 0; i < i_include; ++i)
0655     free(IncludeList[i]);
0656   free(IncludeList);
0657 
0658   if (*error_code!=GD_E_OK) {
0659     FreeF(F);
0660     Formats.n--;
0661     return(NULL);
0662   }
0663 
0664   /** Now sort the lists */
0665   if (F->n_raw > 1) {
0666     for (i=0; i<F->n_raw; i++) {
0667       snprintf(raw_data_filename, MAX_FILENAME_LENGTH+FIELD_LENGTH+2, 
0668           "%s/%s", filedir, F->rawEntries[i].file);
0669       if (stat(raw_data_filename, &statbuf) >=0) {
0670         F->first_field = F->rawEntries[i];
0671         break;
0672       }
0673     }
0674 
0675     qsort(F->rawEntries, F->n_raw, sizeof(struct RawEntryType),
0676         RawCmp);
0677   }
0678 
0679   if (F->n_lincom > 1) {
0680     qsort(F->lincomEntries, F->n_lincom, sizeof(struct LincomEntryType),
0681         LincomCmp);
0682   }
0683   if (F->n_linterp > 1) {
0684     qsort(F->linterpEntries, F->n_linterp, sizeof(struct LinterpEntryType),
0685         LinterpCmp);
0686   }
0687   if (F->n_multiply > 1) {
0688     qsort(F->multiplyEntries, F->n_multiply, sizeof(struct MultiplyEntryType),
0689         MultiplyCmp);
0690   }
0691   if (F->n_mplex > 1) {
0692     qsort(F->mplexEntries, F->n_mplex, sizeof(struct MplexEntryType),
0693         MplexCmp);
0694   }
0695   if (F->n_bit > 1) {
0696     qsort(F->bitEntries, F->n_bit, sizeof(struct BitEntryType),
0697         BitCmp);
0698   }
0699   return(F);
0700 }
0701 
0702 /***************************************************************************/
0703 /*                                                                         */
0704 /*     File File Frame numbers into dataout                                */
0705 /*                                                                         */
0706 /***************************************************************************/
0707 static void FillFileFrame(void *dataout, char rtype, int s0, int n) {
0708   int i;
0709 
0710   switch(rtype) {
0711     case 'c':
0712       for (i=0; i<n; i++) {
0713         ((unsigned char*)dataout)[i] = (unsigned char)i+s0;
0714       }
0715       break;
0716     case 'i': /* for compatibility with creaddata. (deprecated) */
0717     case 'S':
0718       for (i=0; i<n; i++) {
0719         ((int*)dataout)[i] = (int)i+s0;
0720       }
0721       break;
0722     case 's':
0723       for (i=0; i<n; i++) {
0724         ((short*)dataout)[i] = (short)i+s0;
0725       }
0726       break;
0727     case 'U':
0728       for (i=0; i<n; i++) {
0729         ((unsigned int *)dataout)[i] = (unsigned int)i+s0;
0730       }
0731       break;
0732     case 'u':
0733       for (i=0; i<n; i++) {
0734         ((unsigned short *)dataout)[i] = (unsigned short)i+s0;
0735       }
0736       break;
0737     case 'f':
0738       for (i=0; i<n; i++) {
0739         ((float*)dataout)[i] = (float)i+s0;
0740       }
0741       break;
0742     case 'd':
0743       for (i=0; i<n; i++) {
0744         ((double*)dataout)[i] = (double)i+s0;
0745       }
0746       break;
0747   }
0748 }
0749 /***************************************************************************/
0750 /*                                                                         */
0751 /*    ConvertType: copy data to output buffer while converting type        */
0752 /*           Returns error code                                            */
0753 /*                                                                         */
0754 /***************************************************************************/
0755 static int ConvertType(unsigned char *data_in, char in_type,
0756                        void *data_out, char out_type, int n) {
0757   int i;
0758 
0759   if (out_type=='n') { /* null return type: don't return data */
0760     return(0);
0761   }
0762 
0763   switch (in_type) {
0764     case 'c':
0765       switch (out_type) {
0766         case 'c':
0767           for (i=0;i<n;i++) ((unsigned char*) data_out)[i]=data_in[i];
0768           break;
0769         case 's':
0770           for (i=0;i<n;i++) ((short*)data_out)[i]=data_in[i];
0771           break;
0772         case 'u':
0773           for (i=0;i<n;i++) ((unsigned short*)data_out)[i]=data_in[i];
0774           break;
0775         case 'i': case 'S':
0776           for (i=0;i<n;i++) ((int*)data_out)[i]=data_in[i];
0777           break;
0778         case 'U':
0779           for (i=0;i<n;i++)  ((unsigned int*)data_out)[i]=data_in[i];
0780           break;
0781         case 'f':
0782           for (i=0;i<n;i++) ((float*)data_out)[i]=data_in[i];
0783           break;
0784         case 'd':
0785           for (i=0;i<n;i++) ((double*)data_out)[i]=data_in[i];
0786           break;
0787         default:
0788           return SetGetDataError(GD_E_BAD_RETURN_TYPE, out_type, NULL, 0, NULL);
0789       }
0790       break;
0791     case 's':
0792       switch (out_type) {
0793         case 'c':
0794           for (i=0;i<n;i++) ((unsigned char*) data_out)[i]=((short *)data_in)[i];
0795           break;
0796         case 's':
0797           for (i=0;i<n;i++) ((short*)data_out)[i]=((short *)data_in)[i];
0798           break;
0799         case 'u':
0800           for (i=0;i<n;i++) ((unsigned short*)data_out)[i]=((short *)data_in)[i];
0801           break;
0802         case 'S': case 'i':
0803           for (i=0;i<n;i++) ((int*)data_out)[i]=((short *)data_in)[i];
0804           break;
0805         case 'U':
0806           for (i=0;i<n;i++) ((unsigned int*)data_out)[i]=((short *)data_in)[i];
0807           break;
0808         case 'f':
0809           for (i=0;i<n;i++) ((float*)data_out)[i]=((short *)data_in)[i];
0810           break;
0811         case 'd':
0812           for (i=0;i<n;i++) ((double*)data_out)[i]=((short *)data_in)[i];
0813           break;
0814         default:
0815           return SetGetDataError(GD_E_BAD_RETURN_TYPE, out_type, NULL, 0, NULL);
0816       }
0817       break;
0818     case 'u':
0819       switch (out_type) {
0820         case 'c':
0821           for (i=0;i<n;i++) ((unsigned char*) data_out)[i]=
0822             ((unsigned short *)data_in)[i];
0823           break;
0824         case 's':
0825           for (i=0;i<n;i++) ((short*)data_out)[i]=
0826             ((unsigned short *)data_in)[i];
0827           break;
0828         case 'u':
0829           for (i=0;i<n;i++) ((unsigned short*)data_out)[i]=
0830             ((unsigned short *)data_in)[i];
0831           break;
0832         case 'i': case 'S':
0833           for (i=0;i<n;i++) ((int*)data_out)[i]=
0834             ((unsigned short *)data_in)[i];
0835           break;
0836         case 'U':
0837           for (i=0;i<n;i++)  ((unsigned int*)data_out)[i]=
0838             ((unsigned short *)data_in)[i];
0839           break;
0840         case 'f':
0841           for (i=0;i<n;i++) ((float*)data_out)[i]=
0842             ((unsigned short *)data_in)[i];
0843           break;
0844         case 'd':
0845           for (i=0;i<n;i++) ((double*)data_out)[i]=
0846             ((unsigned short *)data_in)[i];
0847           break;
0848         default:
0849           return SetGetDataError(GD_E_BAD_RETURN_TYPE, out_type, NULL, 0, NULL);
0850       }
0851       break;
0852     case 'i':
0853     case 'S':
0854       switch (out_type) {
0855         case 'c':
0856           for (i=0;i<n;i++) ((unsigned char*) data_out)[i]=((int *)data_in)[i];
0857           break;
0858         case 's':
0859           for (i=0;i<n;i++) ((short*)data_out)[i]=((int *)data_in)[i];
0860           break;
0861         case 'u':
0862           for (i=0;i<n;i++) ((unsigned short*)data_out)[i]=((int *)data_in)[i];
0863           break;
0864         case 'i': case 'S':
0865           for (i=0;i<n;i++) ((int*)data_out)[i]=((int *)data_in)[i];
0866           break;
0867         case 'U':
0868           for (i=0;i<n;i++)  ((unsigned int*)data_out)[i]=((int *)data_in)[i];
0869           break;
0870         case 'f':
0871           for (i=0;i<n;i++) ((float*)data_out)[i]=((int *)data_in)[i];
0872           break;
0873         case 'd':
0874           for (i=0;i<n;i++) ((double*)data_out)[i]=((int *)data_in)[i];
0875           break;
0876         default:
0877           return SetGetDataError(GD_E_BAD_RETURN_TYPE, out_type, NULL, 0, NULL);
0878       }
0879       break;
0880     case 'U':
0881       switch (out_type) {
0882         case 'c':
0883           for (i=0;i<n;i++) ((unsigned char*) data_out)[i]=
0884             ((unsigned *)data_in)[i];
0885           break;
0886         case 's':
0887           for (i=0;i<n;i++) ((short*)data_out)[i]=
0888             ((unsigned *)data_in)[i];
0889           break;
0890         case 'u':
0891           for (i=0;i<n;i++) ((unsigned short*)data_out)[i]=
0892             ((unsigned *)data_in)[i];
0893           break;
0894         case 'i': case 'S':
0895           for (i=0;i<n;i++) ((int*)data_out)[i]=
0896             ((unsigned *)data_in)[i];
0897           break;
0898         case 'U':
0899           for (i=0;i<n;i++)  ((unsigned int*)data_out)[i]=
0900             ((unsigned *)data_in)[i];
0901           break;
0902         case 'f':
0903           for (i=0;i<n;i++) ((float*)data_out)[i]=
0904             ((unsigned *)data_in)[i];
0905           break;
0906         case 'd':
0907           for (i=0;i<n;i++) ((double*)data_out)[i]=
0908             ((unsigned *)data_in)[i];
0909           break;
0910         default:
0911           return SetGetDataError(GD_E_BAD_RETURN_TYPE, out_type, NULL, 0, NULL);
0912       }
0913       break;
0914     case 'f':
0915       switch (out_type) {
0916         case 'c':
0917           for (i=0;i<n;i++) ((unsigned char*) data_out)[i]=((float *)data_in)[i];
0918           break;
0919         case 's':
0920           for (i=0;i<n;i++) ((short*)data_out)[i]=((float *)data_in)[i];
0921           break;
0922         case 'u':
0923           for (i=0;i<n;i++) ((unsigned short*)data_out)[i]=((float *)data_in)[i];
0924           break;
0925         case 'i': case 'S':
0926           for (i=0;i<n;i++) ((int*)data_out)[i]=((float *)data_in)[i];
0927           break;
0928         case 'U':
0929           for (i=0;i<n;i++)  ((unsigned int*)data_out)[i]=((float *)data_in)[i];
0930           break;
0931         case 'f':
0932           for (i=0;i<n;i++) ((float*)data_out)[i]=((float *)data_in)[i];
0933           break;
0934         case 'd':
0935           for (i=0;i<n;i++) ((double*)data_out)[i]=((float *)data_in)[i];
0936           break;
0937         default:
0938           return SetGetDataError(GD_E_BAD_RETURN_TYPE, out_type, NULL, 0, NULL);
0939       }
0940       break;
0941     case 'd':
0942       switch (out_type) {
0943         case 'c':
0944           for (i=0;i<n;i++) ((unsigned char*) data_out)[i]=((double *)data_in)[i];
0945           break;
0946         case 's':
0947           for (i=0;i<n;i++) ((short*)data_out)[i]=((double *)data_in)[i];
0948           break;
0949         case 'u':
0950           for (i=0;i<n;i++) ((unsigned short*)data_out)[i]=((double *)data_in)[i];
0951           break;
0952         case 'i': case 'S':
0953           for (i=0;i<n;i++) ((int*)data_out)[i]=((double *)data_in)[i];
0954           break;
0955         case 'U':
0956           for (i=0;i<n;i++)  ((unsigned int*)data_out)[i]=((double *)data_in)[i];
0957           break;
0958         case 'f':
0959           for (i=0;i<n;i++) ((float*)data_out)[i]=((double *)data_in)[i];
0960           break;
0961         case 'd':
0962           for (i=0;i<n;i++) ((double*)data_out)[i]=((double *)data_in)[i];
0963           break;
0964         default:
0965           return SetGetDataError(GD_E_BAD_RETURN_TYPE, out_type, NULL, 0, NULL);
0966       }
0967       break;
0968     default:
0969       return SetGetDataError(GD_E_INTERNAL_ERROR, in_type, __FILE__, __LINE__,
0970           NULL);
0971   }
0972 
0973   return SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
0974 }
0975 
0976 
0977 /***************************************************************************/
0978 /*                                                                         */
0979 /*      FillZero: fill data buffer with zero/NaN of the appropriate type   */
0980 /*        used if s0<0 - fill up to 0, or up to ns+s0, whichever is less   */
0981 /*                                                                         */
0982 /***************************************************************************/
0983 static int FillZero(char *databuffer, char type, int s0, int ns) {
0984   int i, nz;
0985   const double NaN = NAN;
0986 
0987   if (s0>=0) return 0;
0988 
0989   if (s0+ns>0) nz = -s0;
0990   else nz = ns;
0991 
0992   switch (type) {
0993     case 'c':
0994       memset(databuffer, 0, nz);
0995       break;
0996     case 's':
0997     case 'u':
0998       memset(databuffer, 0, nz*sizeof(short));
0999       break;
1000     case 'i':
1001     case 'S':
1002     case 'U':
1003       memset(databuffer, 0, nz*sizeof(int));
1004       break;
1005     case 'f':
1006       for (i = 0; i < nz; ++i)
1007         *((float*)databuffer + i) = (float)NaN;
1008       break;
1009     case 'd':
1010       for (i = 0; i < nz; ++i)
1011         *((double*)databuffer + i) = (double)NaN;
1012       break;
1013   }
1014 
1015   return (nz);
1016 
1017 }
1018 /***************************************************************************/
1019 /*                                                                         */
1020 /*   Get samples per frame for field, given FormatType *F                  */
1021 /*                                                                         */
1022 /***************************************************************************/
1023 static int GetSPF(const char *field_code, struct FormatType *F, int *error_code) {
1024   struct RawEntryType tR;
1025   struct RawEntryType *R;
1026   struct LincomEntryType tL;
1027   struct LincomEntryType *L;
1028   struct MultiplyEntryType tM;
1029   struct MultiplyEntryType *M;
1030   struct BitEntryType tB;
1031   struct BitEntryType *B;
1032   struct LinterpEntryType tI;
1033   struct LinterpEntryType *I;
1034   int spf;
1035 
1036   if (!F) { /* don't crash */
1037     return(0);
1038   }
1039 
1040   if (recurse_level > 10) {
1041     *error_code = SetGetDataError(GD_E_RECURSE_LEVEL, 0, NULL, 0, field_code);
1042     return(0);
1043   }
1044 
1045   if ((strcmp(field_code,"FILEFRAM")==0) ||
1046       (strcmp(field_code,"INDEX")==0)) {
1047     return(1);
1048   }
1049 
1050   /***************************************/
1051   /** Check to see if it is a raw entry **/
1052   /* binary search for the field */
1053   /* make a RawEntry we can compare to */
1054   strncpy(tR.field, field_code, FIELD_LENGTH);
1055   /** use the stdlib binary search */
1056   R = bsearch(&tR, F->rawEntries, F->n_raw,
1057       sizeof(struct RawEntryType), RawCmp);
1058   if (R!=NULL) {
1059     spf = R->samples_per_frame;
1060     return(spf);
1061   }
1062 
1063   /***************************************/
1064   /** Check to see if it is a lincom entry **/
1065   /* binary search for the field */
1066   /* make a RawEntry we can compare to */
1067   strncpy(tL.field, field_code, FIELD_LENGTH);
1068   /** use the stdlib binary search */
1069   L = bsearch(&tL, F->lincomEntries, F->n_lincom,
1070       sizeof(struct LincomEntryType), LincomCmp);
1071   if (L!=NULL) {
1072     recurse_level++;
1073     spf = GetSPF(L->in_fields[0], F, error_code);
1074     recurse_level--;
1075     return(spf);
1076   }
1077 
1078   /***************************************/
1079   /** Check to see if it is a multiply entry **/
1080   /* binary search for the field */
1081   /* make a RawEntry we can compare to */
1082   strncpy(tM.field, field_code, FIELD_LENGTH);
1083   /** use the stdlib binary search */
1084   M = bsearch(&tM, F->multiplyEntries, F->n_multiply,
1085       sizeof(struct MultiplyEntryType), MultiplyCmp);
1086   if (M != NULL) {
1087     int spf2;
1088     recurse_level++;
1089     spf = GetSPF(M->in_fields[0], F, error_code);
1090     spf2 = GetSPF(M->in_fields[1], F, error_code);
1091     recurse_level--;
1092     if (spf2 > spf)
1093       spf = spf2;
1094     return(spf);
1095   }
1096 
1097   /***************************************/
1098   /** Check to see if it is a bit entry **/
1099   /* binary search for the field */
1100   /* make a BitEntry we can compare to */
1101   strncpy(tB.field, field_code, FIELD_LENGTH);
1102   /** use the stdlib binary search */
1103   B = bsearch(&tB, F->bitEntries, F->n_bit,
1104       sizeof(struct BitEntryType), BitCmp);
1105   if (B!=NULL) {
1106     recurse_level++;
1107     spf = GetSPF(B->raw_field, F, error_code);
1108     recurse_level--;
1109     return(spf);
1110   }
1111 
1112   /***************************************/
1113   /** Check to see if it is a linterp entry **/
1114   /* binary search for the field */
1115   /* make a LinterpEntry we can compare to */
1116   strncpy(tI.field, field_code, FIELD_LENGTH);
1117   /** use the stdlib binary search */
1118   I = bsearch(&tI, F->linterpEntries, F->n_linterp,
1119       sizeof(struct LinterpEntryType), LinterpCmp);
1120   if (I!=NULL) {
1121     recurse_level++;
1122     spf = GetSPF(I->raw_field, F, error_code);
1123     recurse_level--;
1124     return(spf);
1125   }
1126 
1127   *error_code = SetGetDataError(GD_E_BAD_CODE, 0, NULL, 0, field_code);
1128   return(0);
1129 }
1130 
1131 /***************************************************************************/
1132 /*                                                                         */
1133 /*   Look to see if the field code belongs to a raw.  If so, parse it.     */
1134 /*                                                                         */
1135 /***************************************************************************/
1136 static int DoIfRaw(struct FormatType *F, const char *field_code,
1137     int first_frame, int first_samp,
1138     int num_frames, int num_samp,
1139     char return_type, void *data_out,
1140     int *error_code, int *n_read) {
1141 
1142   struct RawEntryType tR;
1143   struct RawEntryType *R;
1144   int s0, ns, bytes_read;
1145   char datafilename[2 * MAX_FILENAME_LENGTH + FIELD_LENGTH + 2];
1146   unsigned char *databuffer;
1147 
1148   /******* binary search for the field *******/
1149   /* make a RawEntry we can compare to */
1150   strncpy(tR.field, field_code, FIELD_LENGTH);
1151   /** use the stdlib binary search */
1152   R = bsearch(&tR, F->rawEntries, F->n_raw,
1153       sizeof(struct RawEntryType), RawCmp);
1154   if (R==NULL) return(0);
1155 
1156   /** if we got here, we found the field! **/
1157   s0 = first_samp + first_frame*R->samples_per_frame;
1158   ns = num_samp + num_frames*R->samples_per_frame;
1159 
1160   /** open the file (and cache the fp) if it hasn't been opened yet. */
1161   if (R->fp <0) {
1162     snprintf(datafilename, 2 * MAX_FILENAME_LENGTH + FIELD_LENGTH + 2, 
1163         "%s/%s", F->FileDirName, R->file);
1164     R->fp = open(datafilename, O_RDONLY);
1165     if (R->fp<0) {
1166       *n_read = 0;
1167       *error_code = SetGetDataError(GD_E_OPEN_RAWFIELD, 0, NULL, 0,
1168           datafilename);
1169       return(1);
1170     }
1171   }
1172 
1173   databuffer = (unsigned char *)malloc(ns*R->size);
1174 
1175   *n_read = 0;
1176   if (s0 < 0) {
1177     *n_read = FillZero(databuffer, R->type, s0, ns);
1178     ns -= *n_read;
1179     s0 = 0;
1180   }
1181 
1182   if (ns>0) {
1183     lseek(R->fp, s0*R->size, SEEK_SET);
1184     bytes_read = read(R->fp, databuffer + *n_read*R->size, ns*R->size);
1185     *n_read += bytes_read/R->size;
1186   }
1187 
1188   *error_code =
1189     ConvertType(databuffer, R->type, data_out, return_type, *n_read);
1190 
1191   free(databuffer);
1192 
1193   return(1);
1194 }
1195 
1196 
1197 /***************************************************************************/
1198 /*                                                                         */
1199 /*            AllocTmpbuff: allocate a buffer of the right type and size   */
1200 /*                                                                         */
1201 /***************************************************************************/
1202 static void *AllocTmpbuff(char type, int n) {
1203   assert(n > 0);
1204   void *buff=NULL;
1205   switch(type) {
1206     case 'n':
1207       buff = NULL;
1208       break;
1209     case 'c':
1210       buff = malloc(n*sizeof(char));
1211       break;
1212     case 'i':
1213     case 'S':
1214     case 'U':
1215       buff = malloc(n*sizeof(int));
1216       break;
1217     case 's':
1218     case 'u':
1219       buff = malloc(n*sizeof(short));
1220       break;
1221     case 'f':
1222       buff = malloc(n*sizeof(float));
1223       break;
1224     case 'd':
1225       buff = malloc(n*sizeof(double));
1226       break;
1227     default:
1228       printf("Unexpected bad type error in AllocTmpbuff (%c)\n",type);
1229       abort();
1230       break;
1231   }
1232   if ((type != 'n') && (buff==NULL)) {
1233     printf("Memory Allocation error in AllocTmpbuff\n");
1234   }
1235   return(buff);
1236 }
1237 
1238 /***************************************************************************/
1239 /*                                                                         */
1240 /*   ScaleData: out = m*in+b                                               */
1241 /*                                                                         */
1242 /***************************************************************************/
1243 static void ScaleData(void *data, char type, int npts, double m, double b) {
1244   unsigned char *data_c;
1245   short *data_s;
1246   unsigned short *data_u;
1247   unsigned *data_U;
1248   int *data_i;
1249   float *data_f;
1250   double *data_d;
1251 
1252   int i;
1253 
1254   switch(type) {
1255     case 'n':
1256       break;
1257     case 'c':
1258       data_c = (unsigned char *)data;
1259       for (i=0; i<npts; i++) {
1260         data_c[i] =(unsigned char)((double)data_c[i] * m + b);
1261       }
1262       break;
1263     case 's':
1264       data_s = (short *)data;
1265       for (i=0; i<npts; i++) {
1266         data_s[i] =  (short)((double)data_s[i] * m + b);
1267       }
1268       break;
1269     case 'u':
1270       data_u = (unsigned short *)data;
1271       for (i=0; i<npts; i++) {
1272         data_u[i] = (unsigned short)((double)data_u[i] * m + b);
1273       }
1274       break;
1275     case 'S': case 'i':
1276       data_i = (int *)data;
1277       for (i=0; i<npts; i++) {
1278         data_i[i] = (int)((double)data_i[i] * m + b);
1279       }
1280       break;
1281     case 'U':
1282       data_U = (unsigned*)data;
1283       for (i=0; i<npts; i++) {
1284         data_U[i] = (unsigned)((double)data_U[i] * m + b);
1285       }
1286       break;
1287     case 'f':
1288       data_f = (float *)data;
1289       for (i=0; i<npts; i++) {
1290         data_f[i] = (float)((double)data_f[i] * m + b);
1291       }
1292       break;
1293     case 'd':
1294       data_d = (double *)data;
1295       for (i=0; i<npts; i++) {
1296         data_d[i] = data_d[i] * m + b;
1297       }
1298       break;
1299     default:
1300       printf("Another impossible error\n");
1301       abort();
1302       break;
1303   }
1304 }
1305 
1306 /***************************************************************************/
1307 /*                                                                         */
1308 /*            AddData: add B to A.  B is unchanged                         */
1309 /*                                                                         */
1310 /***************************************************************************/
1311 static void AddData(void *A, int spfA, void *B, int spfB, char type, int n) {
1312   int i;
1313 
1314   switch(type) {
1315     case 'n': /* null read */
1316       break;
1317     case 'c':
1318       for (i=0; i<n; i++) {
1319         ((unsigned char*)A)[i] += ((unsigned char*)B)[i * spfB / spfA];
1320       }
1321       break;
1322     case 'S': case 'i':
1323       for (i=0; i<n; i++) {
1324         ((int*)A)[i] += ((int*)B)[i * spfB / spfA];
1325       }
1326       break;
1327     case 's':
1328       for (i=0; i<n; i++) {
1329         ((short*)A)[i] += ((short*)B)[i * spfB / spfA];
1330       }
1331       break;
1332     case 'u':
1333       for (i=0; i<n; i++) {
1334         ((unsigned short*)A)[i] += ((unsigned short*)B)[i * spfB / spfA];
1335       }
1336       break;
1337     case 'U':
1338       for (i=0; i<n; i++) {
1339         ((unsigned*)A)[i] += ((unsigned*)B)[i * spfB / spfA];
1340       }
1341       break;
1342     case 'f':
1343       for (i=0; i<n; i++) {
1344         ((float*)A)[i] += ((float*)B)[i * spfB / spfA];
1345       }
1346       break;
1347     case 'd':
1348       for (i=0; i<n; i++) {
1349         ((double*)A)[i] += ((double*)B)[i * spfB / spfA];
1350       }
1351       break;
1352     default:
1353       printf("Unexpected bad type error in AddData\n");
1354       abort();
1355       break;
1356   }
1357 }
1358 
1359 /***************************************************************************/
1360 /*                                                                         */
1361 /*            MultiplyData: multiply B by A.  B is unchanged               */
1362 /*                                                                         */
1363 /***************************************************************************/
1364 static void MultiplyData(void *A, int spfA, void *B, int spfB, char type, int n)
1365 {
1366   int i;
1367 
1368   switch(type) {
1369     case 'n': /* null read */
1370       break;
1371     case 'c':
1372       for (i=0; i<n; i++) {
1373         ((unsigned char*)A)[i] *= ((unsigned char*)B)[i * spfB / spfA];
1374       }
1375       break;
1376     case 'S': case 'i':
1377       for (i=0; i<n; i++) {
1378         ((int*)A)[i] *= ((int*)B)[i * spfB / spfA];
1379       }
1380       break;
1381     case 's':
1382       for (i=0; i<n; i++) {
1383         ((short*)A)[i] *= ((short*)B)[i * spfB / spfA];
1384       }
1385       break;
1386     case 'u':
1387       for (i=0; i<n; i++) {
1388         ((unsigned short*)A)[i] *= ((unsigned short*)B)[i * spfB / spfA];
1389       }
1390       break;
1391     case 'U':
1392       for (i=0; i<n; i++) {
1393         ((unsigned*)A)[i] *= ((unsigned*)B)[i * spfB / spfA];
1394       }
1395       break;
1396     case 'f':
1397       for (i=0; i<n; i++) {
1398         ((float*)A)[i] *= ((float*)B)[i * spfB / spfA];
1399       }
1400       break;
1401     case 'd':
1402       for (i=0; i<n; i++) {
1403         ((double*)A)[i] *= ((double*)B)[i * spfB / spfA];
1404       }
1405       break;
1406     default:
1407       printf("Unexpected bad type error in MultiplyData\n");
1408       abort();
1409       break;
1410   }
1411 }
1412 
1413 
1414 /***************************************************************************/
1415 /*                                                                         */
1416 /*   Look to see if the field code belongs to a lincom.  If so, parse it.  */
1417 /*                                                                         */
1418 /***************************************************************************/
1419 static int DoIfLincom(struct FormatType *F, const char *field_code,
1420     int first_frame, int first_samp,
1421     int num_frames, int num_samp,
1422     char return_type, void *data_out,
1423     int *error_code, int *n_read) {
1424   struct LincomEntryType tL;
1425   struct LincomEntryType *L;
1426   void *tmpbuf;
1427   int i;
1428   int spf1, spf2, num_samp2, first_samp2;
1429   int n_read2;
1430 
1431   /******* binary search for the field *******/
1432   /* make a LincomEntry we can compare to */
1433   strncpy(tL.field, field_code, FIELD_LENGTH);
1434   /** use the stdlib binary search */
1435   L = bsearch(&tL, F->lincomEntries, F->n_lincom,
1436       sizeof(struct LincomEntryType), LincomCmp);
1437   if (L==NULL) return(0);
1438 
1439   /*****************************************/
1440   /** if we got here, we found the field! **/
1441   /** read into dataout and scale the first element **/
1442   recurse_level++;
1443   spf1 = GetSPF(L->in_fields[0], F, error_code);
1444   if (*error_code != GD_E_OK) return(1);
1445 
1446   /* read and scale the first field and record the number of samples
1447    * returned */
1448   *n_read = DoField(F, L->in_fields[0],
1449       first_frame, first_samp,
1450       num_frames, num_samp,
1451       return_type, data_out,
1452       error_code);
1453 
1454   recurse_level--;
1455 
1456   if (*error_code != GD_E_OK)
1457     return(1);
1458 
1459   /* Nothing to lincomise */
1460   if (*n_read == 0)
1461     return 1;
1462   
1463   ScaleData(data_out, return_type, *n_read, L->m[0], L->b[0]);
1464 
1465   if (L->n_infields > 1) {
1466     for (i=1; i<L->n_infields; i++) {
1467       recurse_level++;
1468 
1469       /* find the samples per frame of the next field */
1470       spf2 = GetSPF(L->in_fields[i], F, error_code);
1471       if (*error_code != GD_E_OK) return(1);
1472 
1473       /* calculate the first sample and number of samples to read of the
1474        * next field */
1475       num_samp2 = (int)ceil((double)*n_read * spf2 / spf1);
1476       first_samp2 = (first_frame * spf2 + first_samp * spf2 / spf1);
1477 
1478       /* Allocate a temporary buffer for the next field */
1479       tmpbuf = AllocTmpbuff(return_type, num_samp2);
1480       if (!tmpbuf && return_type != 'n') {
1481         return(0);
1482       }
1483 
1484       /* read the next field */
1485       n_read2 = DoField(F, L->in_fields[i],
1486           0, first_samp2,
1487           0, num_samp2,
1488           return_type, tmpbuf,
1489           error_code);
1490       recurse_level--;
1491       if (*error_code != GD_E_OK) {
1492         free(tmpbuf);
1493         return(1);
1494       }
1495 
1496       ScaleData(tmpbuf, return_type, n_read2, L->m[i], L->b[i]);
1497 
1498       if (n_read2 > 0 && n_read2 * spf1 != *n_read * spf2) {
1499         *n_read = n_read2 * spf1 / spf2;
1500       }
1501 
1502       AddData(data_out, spf1, tmpbuf, spf2, return_type, *n_read);
1503 
1504       free(tmpbuf);
1505     }
1506   }
1507 
1508   return(1);
1509 }
1510 
1511 /***************************************************************************/
1512 /*                                                                         */
1513 /*  Look to see if the field code belongs to a multiply.  If so, parse it. */
1514 /*                                                                         */
1515 /***************************************************************************/
1516 static int DoIfMultiply(struct FormatType *F, const char *field_code,
1517     int first_frame, int first_samp,
1518     int num_frames, int num_samp,
1519     char return_type, void *data_out,
1520     int *error_code, int *n_read) {
1521   struct MultiplyEntryType tM;
1522   struct MultiplyEntryType *M;
1523   void *tmpbuf;
1524   int spf1, spf2, num_samp2, first_samp2;
1525   int n_read2;
1526 
1527   /******* binary search for the field *******/
1528   /* make a LincomEntry we can compare to */
1529   strncpy(tM.field, field_code, FIELD_LENGTH);
1530   /** use the stdlib binary search */
1531   M = bsearch(&tM, F->multiplyEntries, F->n_multiply,
1532       sizeof(struct MultiplyEntryType), MultiplyCmp);
1533   if (M==NULL) return(0);
1534 
1535   /*****************************************/
1536   /** if we got here, we found the field! **/
1537   /** read into dataout and scale the first element **/
1538   recurse_level++;
1539 
1540   /* find the samples per frame of the first field */
1541   spf1 = GetSPF(M->in_fields[0], F, error_code);
1542   if (*error_code != GD_E_OK) return(1);
1543 
1544   /* read the first field and record the number of samples
1545    * returned */
1546   *n_read = DoField(F, M->in_fields[0],
1547       first_frame, first_samp,
1548       num_frames, num_samp,
1549       return_type, data_out,
1550       error_code);
1551 
1552   recurse_level--;
1553 
1554   if (*error_code != GD_E_OK)
1555     return 1;
1556 
1557   /* Nothing to multiply */
1558   if (*n_read == 0)
1559     return 1;
1560 
1561   recurse_level++;
1562 
1563   /* find the samples per frame of the second field */
1564   spf2 = GetSPF(M->in_fields[1], F, error_code);
1565   if (*error_code != GD_E_OK) return(1);
1566 
1567   /* calculate the first sample and number of samples to read of the
1568    * second field */
1569   num_samp2 = (int)ceil((double)*n_read * spf2 / spf1);
1570   first_samp2 = (first_frame * spf2 + first_samp * spf2 / spf1);
1571 
1572   /* Allocate a temporary buffer for the second field */
1573   tmpbuf = AllocTmpbuff(return_type, num_samp2);
1574   if (!tmpbuf && return_type != 'n') {
1575     return(0);
1576   }
1577 
1578   /* read the second field */
1579   n_read2 = DoField(F, M->in_fields[1],
1580       0, first_samp2,
1581       0, num_samp2,
1582       return_type, tmpbuf,
1583       error_code);
1584   recurse_level--;
1585   if (*error_code != GD_E_OK) {
1586     free(tmpbuf);
1587     return(1);
1588   }
1589 
1590   if (n_read2 > 0 && n_read2 * spf1 < *n_read * spf2) {
1591     *n_read = n_read2 * spf1 / spf2;
1592   }
1593   MultiplyData(data_out, spf1, tmpbuf, spf2, return_type, *n_read);
1594   free(tmpbuf);
1595 
1596   return(1);
1597 }
1598 
1599 /***************************************************************************/
1600 /*                                                                         */
1601 /*   Look to see if the field code belongs to a bitfield.  If so, parse it.*/
1602 /*                                                                         */
1603 /***************************************************************************/
1604 static int DoIfBit(struct FormatType *F, const char *field_code,
1605     int first_frame, int first_samp,
1606     int num_frames, int num_samp,
1607     char return_type, void *data_out,
1608     int *error_code, int *n_read) {
1609   struct BitEntryType tB;
1610   struct BitEntryType *B;
1611   unsigned *tmpbuf;
1612   int i;
1613   int spf;
1614   int ns;
1615   unsigned mask;
1616 
1617   /******* binary search for the field *******/
1618   /* make a BitEntry we can compare to */
1619   strncpy(tB.field, field_code, FIELD_LENGTH);
1620   /** use the stdlib binary search */
1621   B = bsearch(&tB, F->bitEntries, F->n_bit,
1622       sizeof(struct BitEntryType), BitCmp);
1623   if (B==NULL) return(0);
1624 
1625   /*****************************************/
1626   /** if we got here, we found the field! **/
1627   recurse_level++;
1628   spf = GetSPF(B->raw_field, F, error_code);
1629   recurse_level--;
1630   if (*error_code!=GD_E_OK) {
1631     *n_read = 0;
1632     return(1);
1633   }
1634 
1635   ns = num_samp + num_frames*spf;
1636   tmpbuf = (unsigned *)malloc(ns*sizeof(unsigned));
1637 
1638   recurse_level++;
1639   *n_read = DoField(F, B->raw_field,
1640       first_frame, first_samp,
1641       num_frames, num_samp,
1642       'U', tmpbuf,
1643       error_code);
1644   recurse_level--;
1645   if (*error_code!=GD_E_OK) {
1646     free(tmpbuf);
1647     return(1);
1648   }
1649 
1650   if (B->numbits==32) mask = 0xffffffff;
1651   else mask = (unsigned)(pow(2,B->numbits)-0.9999);
1652 
1653   for (i=0; i<*n_read; i++) {
1654     tmpbuf[i] = (tmpbuf[i]>>B->bitnum) & mask;
1655   }
1656 
1657   *error_code = ConvertType((unsigned char *)tmpbuf, 'U',
1658       data_out, return_type, *n_read);
1659   free(tmpbuf);
1660 
1661   return(1);
1662 }
1663 
1664 /***************************************************************************/
1665 /*                                                                         */
1666 /*   ReadLinterpFile: Read in the linterp data for this field              */
1667 /*                                                                         */
1668 /***************************************************************************/
1669 void MakeDummyLinterp(struct LinterpEntryType *E); /* prototype => no warning... */
1670 void MakeDummyLinterp(struct LinterpEntryType *E) {
1671   E->n_interp = 2;
1672   E->x = (double *)malloc(2*sizeof(double));
1673   E->y = (double *)malloc(2*sizeof(double));
1674   E->x[0] = 0;
1675   E->y[0] = 0;
1676   E->x[1] = 1;
1677   E->y[1] = 1;
1678 }
1679 
1680 static int ReadLinterpFile(struct LinterpEntryType *E) {
1681   FILE *fp;
1682   int i;
1683   char line[255];
1684   int linenum = 0;
1685 
1686   fp = fopen(E->linterp_file, "r");
1687   if (fp==NULL) {
1688     MakeDummyLinterp(E);
1689     return SetGetDataError(GD_E_OPEN_LINFILE, GD_E_LINFILE_SE_OPEN, NULL, 0,
1690         E->linterp_file);
1691   }
1692 
1693   /* first read the file to see how big it is */
1694   i=0;
1695   while (GetLine(fp, line, &linenum)) {
1696     i++;
1697   }
1698   if (i<2) {
1699     MakeDummyLinterp(E);
1700     return SetGetDataError(GD_E_OPEN_LINFILE, GD_E_LINFILE_SE_LENGTH, NULL, 0,
1701         E->linterp_file);
1702   }
1703   E->n_interp = i;
1704   E->x = (double *)malloc(i*sizeof(double));
1705   E->y = (double *)malloc(i*sizeof(double));
1706   /* now read in the data */
1707   rewind(fp);
1708   linenum = 0;
1709   for (i=0; i<E->n_interp; i++) {
1710     GetLine(fp, line, &linenum);
1711     sscanf(line, "%lg %lg",&(E->x[i]), &(E->y[i]));
1712   }
1713   return (GD_E_OK);
1714 }
1715 
1716 /***************************************************************************/
1717 /*                                                                         */
1718 /*   GetIndex: just linearly search - we are probably right to start with  */
1719 /*                                                                         */
1720 /***************************************************************************/
1721 static int GetIndex(double x, double lx[], int idx, int n) {
1722   /* increment until we are bigger */
1723   while ((idx < n-2) && (x > lx[idx])) {
1724     idx++;
1725   }
1726   /* decrement until we are smaller */
1727   while ((idx > 0) && (x < lx[idx])) {
1728     idx--;
1729   }
1730 
1731   return(idx);
1732 }
1733 
1734 /***************************************************************************/
1735 /*                                                                         */
1736 /*   LinterpData: calibrate data using lookup table lx and ly              */
1737 /*                                                                         */
1738 /***************************************************************************/
1739 static void LinterpData(void *data, char type, int npts,
1740     double *lx, double *ly, int n_ln) {
1741   int i, idx=0;
1742   double x;
1743 
1744   for (i=0; i<npts; i++) {
1745     switch(type) {
1746       case 'n':
1747         return;
1748         break;
1749       case 'c':
1750         x = ((unsigned char *)data)[i];
1751         idx = GetIndex(x, lx, idx, n_ln);
1752         ((unsigned char *)data)[i] =
1753           (unsigned char)(ly[idx] + (ly[idx+1]-ly[idx])/
1754                           (lx[idx+1]-lx[idx]) * (x-lx[idx]));
1755         break;
1756       case 's':
1757         x = ((short *)data)[i];
1758         idx = GetIndex(x, lx, idx, n_ln);
1759         ((short *)data)[i] = (short)(ly[idx] + (ly[idx+1]-ly[idx])/
1760                                      (lx[idx+1]-lx[idx]) * (x-lx[idx]));
1761         break;
1762       case 'u':
1763         x = ((unsigned short *)data)[i];
1764         idx = GetIndex(x, lx, idx,n_ln);
1765         ((unsigned short *)data)[i] =
1766           (unsigned short)(ly[idx] + (ly[idx+1]-ly[idx])/
1767                            (lx[idx+1]-lx[idx]) * (x-lx[idx]));
1768         break;
1769       case 'S': case 'i':
1770         x = ((int *)data)[i];
1771         idx = GetIndex(x, lx, idx, n_ln);
1772         ((int *)data)[i] = (int)(ly[idx] + (ly[idx+1]-ly[idx])/
1773                                  (lx[idx+1]-lx[idx]) * (x-lx[idx]));
1774         break;
1775       case 'U':
1776         x = ((unsigned *)data)[i];
1777         idx = GetIndex(x, lx, idx, n_ln);
1778         ((unsigned *)data)[i] =
1779           (unsigned)(ly[idx] + (ly[idx+1]-ly[idx])/
1780                      (lx[idx+1]-lx[idx]) * (x-lx[idx]));
1781         break;
1782       case 'f':
1783         x = ((float *)data)[i];
1784         idx = GetIndex(x, lx, idx, n_ln);
1785         ((float *)data)[i] = (float)(ly[idx] + (ly[idx+1]-ly[idx])/
1786                                      (lx[idx+1]-lx[idx]) * (x-lx[idx]));
1787         break;
1788       case 'd':
1789         x = ((double *)data)[i];
1790         idx = GetIndex(x, lx, idx, n_ln);
1791         ((double *)data)[i] = (double)(ly[idx] + (ly[idx+1]-ly[idx])/
1792                                        (lx[idx+1]-lx[idx]) * (x-lx[idx]));
1793         break;
1794       default:
1795         printf("Another impossible error\n");
1796         abort();
1797         break;
1798     }
1799   }
1800 }
1801 
1802 /***************************************************************************/
1803 /*                                                                         */
1804 /*   Look to see if the field code belongs to a bitfield.  If so, parse it.*/
1805 /*                                                                         */
1806 /***************************************************************************/
1807 static int DoIfLinterp(struct FormatType *F, const char *field_code,
1808     int first_frame, int first_samp,
1809     int num_frames, int num_samp,
1810     char return_type, void *data_out,
1811     int *error_code, int *n_read) {
1812   struct LinterpEntryType tI;
1813   struct LinterpEntryType *I;
1814 
1815   /******* binary search for the field *******/
1816   /* make a LinterpEntry we can compare to */
1817   strncpy(tI.field, field_code, FIELD_LENGTH);
1818   /** use the stdlib binary search */
1819   I = bsearch(&tI, F->linterpEntries, F->n_linterp,
1820       sizeof(struct LinterpEntryType), LinterpCmp);
1821   if (I==NULL) return(0);
1822 
1823   /*****************************************/
1824   /** if we got here, we found the field! **/
1825   if (I->n_interp<0) {
1826     *error_code = ReadLinterpFile(I);
1827     if (*error_code != GD_E_OK) {
1828       *n_read = 0;
1829       return(1);
1830     }
1831   }
1832   recurse_level++;
1833   *n_read = DoField(F, I->raw_field,
1834       first_frame, first_samp,
1835       num_frames, num_samp,
1836       return_type, data_out,
1837       error_code);
1838   recurse_level--;
1839   if (*error_code!=GD_E_OK) return(1);
1840   LinterpData(data_out, return_type, *n_read, I->x, I->y, I->n_interp);
1841   return(1);
1842 
1843 }
1844 
1845 /***************************************************************************/
1846 /*                                                                         */
1847 /*  DoField: Doing one field once F has been identified                    */
1848 /*                                                                         */
1849 /***************************************************************************/
1850 static int DoField(struct FormatType *F, const char *field_code,
1851     int first_frame, int first_samp,
1852     int num_frames, int num_samp,
1853     char return_type, void *data_out,
1854     int *error_code) {
1855   int n_read;
1856 
1857   if (recurse_level>10) {
1858     *error_code = SetGetDataError(GD_E_RECURSE_LEVEL, 0, NULL, 0, field_code);
1859     return(0);
1860   }
1861 
1862 
1863   /********************************************/
1864   /* if Asking for "FILEFRAM" or "INDEX", just return it */
1865   if ((strcmp(field_code,"FILEFRAM")==0) ||
1866       (strcmp(field_code,"INDEX")==0)) {
1867     n_read = num_frames + num_samp;
1868     if (data_out!=NULL) {
1869       FillFileFrame(data_out, return_type, first_frame+first_samp+
1870           F->frame_offset, n_read);
1871     }
1872     *error_code = SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
1873     return(n_read);
1874   }
1875 
1876   if (DoIfRaw(F, field_code,
1877         first_frame, first_samp,
1878         num_frames, num_samp,
1879         return_type, data_out,
1880         error_code, &n_read)) {
1881     return(n_read);
1882   } else if (DoIfLincom(F, field_code,
1883         first_frame, first_samp,
1884         num_frames, num_samp,
1885         return_type, data_out,
1886         error_code, &n_read)) {
1887     return(n_read);
1888   } else if (DoIfBit(F, field_code,
1889         first_frame, first_samp,
1890         num_frames, num_samp,
1891         return_type, data_out,
1892         error_code, &n_read)) {
1893     return(n_read);
1894   } else if (DoIfLinterp(F, field_code,
1895         first_frame, first_samp,
1896         num_frames, num_samp,
1897         return_type, data_out,
1898         error_code, &n_read)) {
1899     return(n_read);
1900   } else if (DoIfMultiply(F, field_code,
1901         first_frame, first_samp,
1902         num_frames, num_samp,
1903         return_type, data_out,
1904         error_code, &n_read)) {
1905     return(n_read);
1906   } else {
1907     *error_code = SetGetDataError(GD_E_BAD_CODE, 0, NULL, 0, field_code);
1908     return(0);
1909   }
1910 }
1911 
1912 /***************************************************************************/
1913 /*                                                                         */
1914 /*  GetData: read BLAST format files.                                      */
1915 /*    filename_in: the name of the file directory (raw files are in here)  */
1916 /*    field_code: the name of the field you want to read                   */
1917 /*    first_frame, first_samp: the first sample read is                    */
1918 /*              first_samp + samples_per_frame*first_frame                 */
1919 /*    num_frames, num_samps: the number of samples read is                 */
1920 /*              num_samps + samples_per_frame*num_frames                   */
1921 /*    return_type: data type of *data_out.  's': 16 bit signed             */
1922 /*              'u' 16bit unsigned 'S' 32bit signed 'U' 32bit unsigned     */
1923 /*              'c' 8 bit unsigned                                         */
1924 /*    void *data_out: array to put the data                                */
1925 /*    *error_code: error code is returned here.                            */
1926 /*                                                                         */
1927 /*    return value: returns number of samples actually read into data_out  */
1928 /*                                                                         */
1929 /***************************************************************************/
1930 int GetData(const char *filename_in, const char *field_code,
1931     int first_frame, int first_samp,
1932     int num_frames, int num_samp,
1933     char return_type, void *data_out,
1934     int *error_code) {
1935 
1936   struct FormatType *F;
1937   int n_read=0;
1938   char filename[MAX_FILENAME_LENGTH+1];
1939 
1940   *error_code = SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
1941 
1942   if (first_time) {
1943     Formats.n = 0;
1944     Formats.F = NULL;
1945     first_time = 0;
1946   }
1947 
1948   strncpy(filename, filename_in, MAX_FILENAME_LENGTH);
1949   if (filename[strlen(filename)-1]=='/') filename[strlen(filename)-1]='\0';
1950   F = GetFormat(filename, error_code);
1951   if (!F || *error_code != GD_E_OK) {
1952     return(0);
1953   }
1954   first_frame -= F->frame_offset;
1955 
1956   n_read = DoField(F, field_code,
1957       first_frame, first_samp,
1958       num_frames, num_samp,
1959       return_type, data_out,
1960       error_code);
1961 
1962   return(n_read);
1963 }
1964 
1965 /***************************************************************************/
1966 /*                                                                         */
1967 /*    Get the number of frames available                                   */
1968 /*                                                                         */
1969 /***************************************************************************/
1970 int GetNFrames(const char *filename_in, int *error_code, const char *in_field) {
1971   struct FormatType *F;
1972   char filename[MAX_FILENAME_LENGTH+1];
1973   char raw_data_filename[2 * MAX_FILENAME_LENGTH + FIELD_LENGTH + 2];
1974   struct stat statbuf;
1975   int nf;
1976 
1977   *error_code = SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
1978 
1979   if (first_time) {
1980     Formats.n = 0;
1981     Formats.F = NULL;
1982     first_time = 0;
1983   }
1984 
1985   strncpy(filename, filename_in, MAX_FILENAME_LENGTH);
1986   if (filename[strlen(filename)-1]=='/') filename[strlen(filename)-1]='\0';
1987   F = GetFormat(filename, error_code);
1988   if (*error_code != GD_E_OK) {
1989     return(0);
1990   }
1991 
1992   if (!F || F->n_raw==0) {
1993     *error_code = SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_N_RAW, NULL, 0,
1994         NULL);
1995     return(0);
1996   }
1997 
1998   /* load the first valid raw field */
1999   snprintf(raw_data_filename, 2 * MAX_FILENAME_LENGTH + FIELD_LENGTH + 2, 
2000       "%s/%s", filename, F->first_field.file);
2001   if (stat(raw_data_filename, &statbuf) < 0) {
2002     return(0);
2003   }
2004 
2005   nf = statbuf.st_size/
2006     (F->first_field.size*F->first_field.samples_per_frame);
2007   nf += F->frame_offset;
2008 
2009   nf -= 2;
2010   if (nf < 0)
2011     nf = 0;
2012   return(nf);
2013 }
2014 
2015 /***************************************************************************/
2016 /*                                                                         */
2017 /*    Get the number of samples for each frame for the given field         */
2018 /*                                                                         */
2019 /***************************************************************************/
2020 int GetSamplesPerFrame(const char *filename_in, const char *field_name, int *error_code) {
2021   struct FormatType *F;
2022   char filename[MAX_FILENAME_LENGTH+1];
2023 
2024   *error_code = SetGetDataError(GD_E_OK, 0, NULL, 0, NULL);
2025 
2026   if (first_time) {
2027     Formats.n = 0;
2028     Formats.F = NULL;
2029     first_time = 0;
2030   }
2031 
2032   strncpy(filename, filename_in, MAX_FILENAME_LENGTH);
2033   if (filename[strlen(filename)-1]=='/') filename[strlen(filename)-1]='\0';
2034   F = GetFormat(filename, error_code);
2035   if (*error_code!=GD_E_OK) {
2036     return(0);
2037   }
2038 
2039   if (!F || F->n_raw==0) {
2040     *error_code = SetGetDataError(GD_E_FORMAT, GD_E_FORMAT_SE_N_RAW, NULL, 0,
2041         NULL);
2042     return(0);
2043   }
2044 
2045   return GetSPF(field_name, F, error_code);
2046 }
2047 /* vim: ts=2 sw=2 et
2048 */