diskread.c
上传用户:szhypcb168
上传日期:2007-01-06
资源大小:2187k
文件大小:42k
源码类别:

语音压缩

开发平台:

Unix_Linux

  1. /*  ----------------------  DATA FILE READ ROUTINES  -----------------------  */
  2. /*  ---------------------  designed and coded by rpc  ----------------------  */
  3. /*  ----------------------  Version 1.5   July 1988  -----------------------  */
  4. /*  ------------------------------------------------------------------------  */
  5. /*   RELEASE NOTES:
  6.      Version 1.0:  The original version for the SUNGRAPH signal data input
  7. module.
  8.      Version 1.1:  Modified the argument list of some routines.  Other changes?
  9.      Version 1.2:  Added the auto error reporting feature.  This feature is
  10. enabled or disabled via disk_io_erh(flag) which is in its own source file.
  11. Also changed dfe[] & ffe[] to DFE & FFE.
  12.      Version 1.3:  Added relative positioning to goto_block & goto_sample.
  13. Deleted all checking for lseek errors since they can't occur.
  14.      Version 1.4:  Increased the amount of text in error reporting and changed
  15. it to print on stderr instead of stdout.
  16.      Version 1.5:  Made goto_sample, read_variable, goto_block and read_block
  17. return the sample or block number to be read next, i.e. the current position.
  18. */
  19. #include "diskio.h"
  20. #include <stdio.h>
  21. #include <strings.h>
  22. #include <sys/file.h>
  23. #include <sys/types.h>   /*  these two files are included for the call  */
  24. #include <sys/stat.h>    /*  to fstat in file length routine            */
  25. /*    variable type definitions:
  26.  *
  27.  *    TYPE  #  |  C TYPE  |  # of BYTES  |  FORTRAN TYPE
  28.  *    --------------------------------------------------
  29.  *       1     |  short   |      2       |  integer*2
  30.  *       2     |   int   |      4       |  integer*4
  31.  *       3     |  float   |      4       |    real*4
  32.  */
  33. static short bytes_in[] = { 2, 4, 4 }; /* number of bytes in the data types */
  34. #define NUM_DATA_TYPES sizeof(bytes_in)/sizeof(bytes_in[0]) /* elements in bytes_in */
  35. struct file_data {
  36.    char filename[MAX_FILENAME_LENG+1];/* file connected to this channel */
  37.    int fd;                            /* file descriptor assigned to above */
  38.    int format[2+2*MAX_VARS_PER_BLK];  /* the format of the data file */
  39.    short open;                        /* channel's status: 0-closed, 1-open */
  40.    short ch_type;                     /* channel type */
  41.    short v;                           /* variable # read on type 1 channels */
  42.    int next;                          /* next sample to read on type 1 chan */
  43.                                       /* next block to read on type 2 chan */
  44.    short samp_p_blk;                  /* total # of samples/block */
  45.    int byte_p_blk;                    /* total # of bytes/block */
  46.    int bytes[MAX_VARS_PER_BLK];       /* # of bytes/block for each variable */
  47.    short samp_avail;                  /* # of unread samples in current block */
  48.    int gap_head;                      /* # of bytes in block before selected variable */
  49.    int gap_total;                     /* # of block bytes not in selected variable */
  50.    };
  51. static struct file_data fd[MAX_CHANNELS];
  52. #define PARAM_OK -999
  53. struct errs {
  54.    char routine[20];               /* name of routine where error was */
  55.    char name[MAX_FILENAME_LENG+1]; /* filename or variable name */
  56.    int param;                      /* illegal argument of call in error */
  57.    };
  58. static struct errs ervar = { "", "", PARAM_OK };
  59. #define DFE   ".sg_data"
  60. #define FFE   ".sg_format"
  61. extern int errno;
  62. extern short auto_er;      /* flag to enable/disable auto error report & halt */
  63. extern long lseek();
  64. extern char *strcpy(), *strcat(), *strncat(), *rindex();
  65. /*  --------------------  OPEN VARIABLE CHANNEL ROUTINE  -------------------  */
  66. /*   DESCRIPTION:
  67.      chan_id = open_var_channel ( filename, var_name )
  68.      This routine is called to establish a new channel to access the values of
  69. one of the variables in a data file.  "filename" is the name of the file and
  70. "var_name" is the name of the variable whose values are to be read.  The
  71. variable's values are accessed with the read_variable routine.  This function
  72. returns a channel id  ("chan_id") which is used to identify the opened channel
  73. when calling other disk read routines.  "filename" can have an extension, but
  74. it is not mandatory.
  75. If "filename" has an extension:
  76.      a) The extension is tested for validity.  (eg. Is it .sg_data or one of
  77.         the other types that can be read by these routines?)  Valid extensions
  78.         are these:  .sg_data; .spd
  79.      b) If the extension is valid, open_var_channel tries to open "filename".
  80.         If the extension is not valid, an error is returned.
  81. If "filename" does not have an extension:
  82.      a) Each valid extension is concatenated with a copy of filename and the
  83.         resulting filename is tested for existance.
  84.      b) If this file exists, open_var_channel tries to open it.
  85.         If none of these files exist, an error is returned.
  86. If the file to be opened has the .sg_data extension, the format information
  87. must reside in a corresponding .sg_format file.
  88. Returned value:
  89.      If there are no errors, the returned value is a channel id which is used to
  90. identify the open channel when using other disk read routines.  A valid channel
  91. id is >= 0.  If an error occurs, the returned value is < 0.
  92. The following errors are detected:
  93.      - filename is too long
  94.      - all channels are open
  95.      - there is a format file problem
  96.      - the specified variable was not found
  97.      - invalid extension in filename
  98.      - no data file found
  99.      - the data file could not be opened
  100. */
  101. open_var_channel ( filename, var_name )
  102. char filename[], var_name[];
  103. {
  104.    int chan_id;
  105.    chan_id = open_channel(filename, 1, var_name);
  106.    strcpy(ervar.routine, "open_var_channel");
  107.    strncpy(ervar.name, filename, MAX_FILENAME_LENG);
  108.    if (chan_id == -15)  strncpy(ervar.name, var_name, MAX_FILENAME_LENG);
  109.    strcat(ervar.name, "");
  110.    if (chan_id < 0 && auto_er) error_exit(chan_id);
  111.    return(chan_id);
  112. }
  113. /*  ---------------------  OPEN BLOCK CHANNEL ROUTINE  ---------------------  */
  114. /*   DESCRIPTION:
  115.      chan_id = open_block_channel ( filename )
  116.      This routine is called to establish a new channel to access the values of
  117. all of the variables in a data file.  The values of the data file variables are
  118. accessed with the read_block routine.  This function returns a channel id
  119. ("chan_id") which is used to identify the opened channel when calling other
  120. disk read routines.  "filename" can have an extension, but it is not mandatory.
  121. If "filename" has an extension:
  122.      a) The extension is tested for validity.  (eg. Is it .sg_data or one of
  123.         the other types that can be read by these routines?)  Valid extensions
  124.         are these:  .sg_data; .spd
  125.      b) If the extension is valid, open_var_channel tries to open "filename".
  126.         If the extension is not valid, an error is returned.
  127. If "filename" does not have an extension:
  128.      a) Each valid extension is concatenated with a copy of filename and the
  129.         resulting filename is tested for existance.
  130.      b) If this file exists, open_var_channel tries to open it.
  131.         If none of these files exist, an error is returned.
  132. If the file to be opened has the .sg_data extension, the format information
  133. must reside in a corresponding .sg_format file.
  134. Returned value:
  135.      If there are no errors, the returned value is a channel id which is used to
  136. identify the open channel when using other disk read routines.  A valid channel
  137. id is >= 0.  If an error occurs, the returned value is < 0.
  138. The following errors are detected:
  139.      - filename is too long
  140.      - all channels are open
  141.      - there is a format file problem
  142.      - invalid extension in filename
  143.      - no data file found
  144.      - the data file could not be opened
  145. */
  146. open_block_channel ( filename )
  147. char filename[];
  148. {
  149.    int chan_id;
  150.    chan_id = open_channel(filename, 2, "");
  151.    strcpy(ervar.routine, "open_block_channel");
  152.    strncpy(ervar.name, filename, MAX_FILENAME_LENG);
  153.    strcat(ervar.name, "");
  154.    if (chan_id < 0 && auto_er) error_exit(chan_id);
  155.    return(chan_id);
  156. }
  157. /*  ------------------------  OPEN CHANNEL ROUTINE  ------------------------  */
  158. /*   DESCRIPTION:
  159.      chan_id = open_channel ( file, chan_type, vname )
  160.      This routine is for use only by the disk_read module; it cannot be called
  161. from anywhere else.  It does the actual channel opening operations for each
  162. channel type.  "chan_type" indicates the type of channel being requested.  Two
  163. channel types are currently defined according to the type of access desired:
  164.      1 - single variable access
  165.      2 - block access (all block variables)
  166. "vname" is the name of the variable accessed on type 1 channels.
  167. */
  168. static open_channel ( file, chan_type, vname )
  169. char file[], vname[];
  170. int chan_type;
  171. {
  172.    int format[2 + 2*MAX_VARS_PER_BLK], var_num, i, temp_fd, chan, file_status;
  173.    char filename[MAX_FILENAME_LENG + sizeof(DFE)];
  174.    static char varnames[MAX_VARS_PER_BLK][MAX_VARNAME_LENG + 1];
  175.    static char *vnames[MAX_VARS_PER_BLK] = {
  176. varnames[ 0], varnames[ 1], varnames[ 2], varnames[ 3],
  177. varnames[ 4], varnames[ 5], varnames[ 6], varnames[ 7],
  178. varnames[ 8], varnames[ 9], varnames[10], varnames[11],
  179. varnames[12], varnames[13], varnames[14], varnames[15],
  180. varnames[16], varnames[17], varnames[18], varnames[19],
  181. varnames[20], varnames[21], varnames[22], varnames[23],
  182. varnames[24], varnames[25], varnames[26], varnames[27],
  183. varnames[28], varnames[29], varnames[30], varnames[31],
  184. varnames[32], varnames[33], varnames[34], varnames[35] };
  185. /*
  186.  *    do the easy error checking:
  187.  */
  188.    if (strlen(file) > MAX_FILENAME_LENG) return(-2);
  189. /*
  190.  *    look for first available channel:
  191.  */
  192.    chan = -1;
  193.    for (i=0; i<MAX_CHANNELS; i++)
  194.    {
  195.       if (fd[i].open == 0)
  196.       {
  197.          chan = i;
  198.          break;
  199.       }
  200.    }
  201.    if (chan == -1) return(-14);
  202. /*
  203.  *    read format file:
  204.  */
  205.    if (read_format( file, format, vnames ) < 0)  return(-12);
  206. /*
  207.  *    if type 1 channel, find the variable number from the variable name:
  208.  */
  209.    var_num = 0;
  210.    if (chan_type==1)
  211.    {
  212.       for (i=0; i<format[1]; i++)
  213.       {
  214.          if (strcmp(vname, vnames[i]) == 0)
  215.          {
  216.             var_num = i+1;
  217.             break;
  218.          }
  219.       }
  220.       if (var_num == 0) return(-15);
  221.    }
  222. /*
  223.  *    check for filename extension options and open the data file:
  224.  */
  225.    file_status = test_filename(file, filename, 1);
  226.    if (file_status == -2) return(-10);  /* invalid extension */
  227.    if (file_status == -1) return(-16);  /* no data file found */
  228.    if( (temp_fd = open(filename, O_RDONLY)) == -1)  /* couldn't open */
  229.    {
  230.       perror("The system call error in disk read is");
  231.       return(-13);
  232.    }
  233. /*
  234.  *    write the data file structure variables:
  235.  */
  236.    fd[chan].open = 1;
  237.    strcpy( fd[chan].filename, file );
  238.    for (i=0; i < 2*format[1]+2; i++) fd[chan].format[i] = format[i];
  239.    fd[chan].fd = temp_fd;
  240.    fd[chan].ch_type = chan_type;
  241.    fd[chan].v = var_num;
  242.    fd[chan].next = 1;
  243.    fd[chan].samp_p_blk = 0;
  244.    fd[chan].byte_p_blk = 0;
  245.    for (i=1; i<=format[1]; i++)
  246.    {
  247.       fd[chan].samp_p_blk += format[2*i+1];
  248.       fd[chan].byte_p_blk += bytes_in[format[2*i] -1] * format[2*i+1];
  249.       fd[chan].bytes[i-1]  = bytes_in[format[2*i] -1] * format[2*i+1];
  250.    }
  251.    fd[chan].gap_head = 0;
  252.    fd[chan].gap_total = 0;
  253.    if (chan_type == 1 && format[1] > 1)  /*  the general case  */
  254.    {
  255.       fd[chan].samp_avail = format[2*var_num + 1];
  256.       fd[chan].gap_total = fd[chan].byte_p_blk
  257.               - bytes_in[format[2*var_num] -1] * format[2*var_num + 1];
  258.       for (i=1; i<var_num; i++)
  259.             fd[chan].gap_head += bytes_in[format[2*i] -1] * format[2*i+1];
  260.       lseek(fd[chan].fd, (long) fd[chan].gap_head, 1);
  261. /*
  262.  *    for testing only, print gap_head & gap_total:
  263.  *
  264.       printf("n%d gap_headn%d gap_totaln",
  265.              fd[chan].gap_head, fd[chan].gap_total );
  266.  */
  267.    }
  268. /*
  269.  *    for testing only, print samples/block & bytes/block:
  270.  *
  271.    printf("n%d samples/blockn%d bytes/blocknn",
  272.           fd[chan].samp_p_blk, fd[chan].byte_p_blk );
  273.  */
  274.    return(chan);
  275. }
  276. /*  ------------------------  READ FORMAT ROUTINE  -------------------------  */
  277. /*   DESCRIPTION:
  278.      status = read_format ( filename, format, vnames )
  279.      This routine determines the format associated with file "filename" and
  280. returns this information.  As with the filename argument in the open channel
  281. routines, read_format accepts filenames with or without extensions.  It uses the
  282. same process that the open channel routines use to determine for what data file
  283. the format information is sought.  Hence, for a given filename, read_format
  284. always gets the format which corresponds to the data file opened by an open
  285. channel routine.  (However, read_format accepts filenames that end with
  286. .sg_format.  Such a filename would cause an error if given to an open channel
  287. routine.)
  288. The format array contains the following information:
  289.      format[0]   -   file type indicator
  290.                      current meaning (will be expanded later):
  291.                      1 if .sg_data file allows sample & block positioning;
  292.                      0 if this is NOT allowed
  293.      format[1]   -   number of variables/block in .sg_data file
  294.      format[2*n]  -  data type of variable n in .sg_data file
  295.                      1 - short; 2 - int; 3 - float
  296.      format[2*n+1] - number of entries/block of variable n in .sg_data file
  297. "vnames" is an array of pointers to the names of variables saved in the data
  298. file.  Thus, vnames[0] points to the name of the first variable, vnames[1]
  299. points to the name of the second variable, etc.
  300.      The format information comes from a .sg_format file when the data file is
  301. a .sg_data file.  Other data file types have fixed formats which return a set
  302. of parameters stored in this routine.  Below are listed the format parameters
  303. for each of these other data file types.
  304. Format parameters for .spd data files:
  305.      format[0] = 1
  306.      format[1] = 1
  307.      format[2] = 1
  308.      format[3] = 512
  309.      vnames[0] = "speech_data"
  310. Returned value:
  311.      The returned value indicates the error status of the routine.  If no error
  312. occurs, the returned value is 0.  If an error occurs, the value is < 0.
  313. The following errors are detected:
  314.      - filename is too long
  315.      - invalid extension in filename
  316.      - no data file found, so can't determine format
  317.      - the format file could not be opened
  318.      - the format file is not complete
  319.      - invalid value read for file type
  320.      - invalid value read for variables/block
  321.      - invalid value read for data type
  322.      - invalid value read for values/block
  323. */
  324. read_format ( file, format, vnames )
  325. char file[], *vnames[];
  326. int format[];
  327. {
  328.    short frmt[2 + 2*MAX_VARS_PER_BLK];
  329.    int temp_fd, i, file_status;
  330.    char filename[MAX_FILENAME_LENG + sizeof(FFE)];
  331.    strcpy(ervar.routine, "read_format");
  332.    strncpy(ervar.name, file, MAX_FILENAME_LENG);
  333.    strcat(ervar.name, "");
  334.    if (strlen(file) > MAX_FILENAME_LENG)  /* filename too long */
  335.    {
  336.       if (auto_er) error_exit(-2);
  337.       return(-2);
  338.    }
  339. /*
  340.  *    check for filename extension options:
  341.  */
  342.    file_status = test_filename(file, filename, 2);
  343.    if (file_status == -2)                /* invalid extension */
  344.    {
  345.       if (auto_er) error_exit(-10);
  346.       return(-10);
  347.    }
  348.    if (file_status == -1)                /* no data file found */
  349.    {
  350.       if (auto_er) error_exit(-25);
  351.       return(-25);
  352.    }
  353.    if (file_status == 1)   /* the file is a .spd file */
  354.    {                          /* set default values */
  355.       format[0] = 1;
  356.       format[1] = 1;
  357.       format[2] = 1;
  358.       format[3] = 512;
  359.       strcpy( vnames[0], "speech_data" );
  360.       return(0);
  361.    }
  362. /*
  363.  *    the file is the usual .sg_format type.  open it:
  364.  */
  365.    if( (temp_fd = open(filename, O_RDONLY)) == -1) /* can't open format file */
  366.    {
  367.       perror("The system call error in disk read is");
  368.       if (auto_er) error_exit(-19);
  369.       return(-19);
  370.    }
  371. /*
  372.  *    read format[0] & format[1]:
  373.  */
  374.    if (read(temp_fd, (char *) frmt, 4) != 4) /* incomplete format file */
  375.    {
  376.       close(temp_fd);
  377.       if (auto_er) error_exit(-20);
  378.       return(-20);
  379.    }
  380. /*
  381.  *    check format[0] & format[1] for proper values:
  382.  */
  383.    if (frmt[0] < 0 || frmt[0] > 1)           /* invalid file type */
  384.    {
  385.       close(temp_fd);
  386.       ervar.param = frmt[0];
  387.       if (auto_er) error_exit(-21);
  388.       return(-21);
  389.    }
  390.    if (frmt[1] < 1 || frmt[1] > MAX_VARS_PER_BLK) /* invalid # of vars/block */
  391.    {
  392.       close(temp_fd);
  393.       ervar.param = frmt[1];
  394.       if (auto_er) error_exit(-22);
  395.       return(-22);
  396.    }
  397. /*
  398.  *    read the data type and number per block from format file:
  399.  */
  400.    if (4*frmt[1] != read(temp_fd, (char *) &frmt[2], (int) 4*frmt[1]))
  401.    {
  402.       close(temp_fd);
  403.       if (auto_er) error_exit(-20);
  404.       return(-20);
  405.    }
  406. /*
  407.  *    check the data type and number per block; and read the variable names:
  408.  */
  409.    for (i=1; i<=frmt[1]; ++i)
  410.    {
  411.       if (frmt[2*i] < 1 || frmt[2*i] > NUM_DATA_TYPES) /* invalid data type */
  412.       {
  413.          close(temp_fd);
  414.          ervar.param = frmt[2*i];
  415.          if (auto_er) error_exit(-23);
  416.          return(-23);
  417.       }
  418.       if (frmt[2*i+1] < 1 || frmt[2*i+1] > MAX_VALUES_PER_VAR) /* invalid # of vals per block */
  419.       {
  420.          close(temp_fd);
  421.          ervar.param = frmt[2*i+1];
  422.          if (auto_er) error_exit(-24);
  423.          return(-24);
  424.       }
  425.       *(vnames[i-1]+MAX_VARNAME_LENG) = '';  /* ensure null termination */
  426.       if (MAX_VARNAME_LENG != read(temp_fd, vnames[i-1], MAX_VARNAME_LENG) )
  427.       {
  428.          close(temp_fd);
  429.          if (auto_er) error_exit(-20);
  430.          return(-20);
  431.       }
  432.    }
  433. /*
  434.  *   everything OK, so transfer format info to int array and close format file:
  435.  */
  436.    for (i=0; i<2*MAX_VARS_PER_BLK + 2; i++) format[i] = frmt[i];
  437.    close(temp_fd);
  438.    return(0);
  439. }
  440. /*  ------------------------  FILE LENGTH ROUTINE  -------------------------  */
  441. /*   DESCRIPTION:
  442.      status = file_length ( chan_id, bytes, samples, blocks )
  443.      This routine returns the length of the file connected to "chan_id" in
  444. terms of bytes, samples and blocks.  I don't know what it should do with
  445. real-time data files yet.
  446. Returned value:
  447.      The returned value indicates the error status of the routine.  If no error
  448. occurs, the returned value is 0.  If an error occurs, the value is < 0.
  449. The following errors are detected:
  450.      - channel number is outside valid range
  451.      - specified channel is not open
  452. */
  453. file_length ( channel, bytes, samples, blocks )
  454. int channel, *bytes, *samples, *blocks;
  455. {
  456.    int length;
  457.    struct stat status;       /* for use with fstat */
  458.    strcpy(ervar.routine, "file_length");
  459.    strcpy(ervar.name, "UNKNOWN");  /* can't determine associated file name */
  460.    if (channel < 0 || channel >= MAX_CHANNELS)   /* bogus channel # */
  461.    {
  462.       ervar.param = channel;
  463.       if (auto_er) error_exit(-3);
  464.       return(-3);
  465.    }
  466.    if (fd[channel].open != 1)                    /* channel not open */
  467.    {
  468.       ervar.param = channel;
  469.       if (auto_er) error_exit(-4);
  470.       return(-4);
  471.    }
  472.    fstat(fd[channel].fd, &status);   /* unix library routine that returns */
  473.    length = status.st_size;          /* file length in structure "status" */
  474.    *bytes = length;
  475.    *blocks = length / fd[channel].byte_p_blk;
  476.    *samples = *blocks * fd[channel].samp_p_blk;
  477.    return(0);
  478. }
  479. /*  ------------------------  GOTO SAMPLE ROUTINE  -------------------------  */
  480. /*   DESCRIPTION:
  481.      position = goto_sample ( chan_id, sample_num, how )
  482.      This routine changes the sample number that the next call to read_variable
  483. on "chan_id" reads from.  When "how" is 0, "sample_num" is measured from the
  484. beginning of the file (i.e. absolute positioning).  When "how" is not 0,
  485. "sample_num" is measured from the current file position (i.e. relative
  486. positioning).  The first sample in the file is called sample 1.  This routine
  487. can be called only if the specified channel is a "variable channel", that is
  488. one opened via open_var_channel.  This routine does not return an error if the
  489. sample to be read is beyond the end of file; this condition is reported when
  490. reading.  
  491. Returned value:
  492.      If there are no errors, the returned value indicates the current file
  493. position (the sample number of the next sample to be read by read_variable).
  494. A valid sample number is 1 or greater.  If an error occurs, the value is < 0.
  495. The following errors are detected:
  496.      - channel number is outside valid range
  497.      - specified channel is not open
  498.      - this routine is for use only with variable channel types
  499.      - the file connected to this channel prohibits positioning
  500.      - effective sample_num is < 1
  501. */
  502. goto_sample ( channel, sample_num, how )
  503. int channel, sample_num, how;
  504. {
  505.    int samp_per_rec, skipped_rec, skipped_samp, next;
  506.    long p;
  507.    strcpy(ervar.routine, "goto_sample");
  508.    strcpy(ervar.name, "UNKNOWN");  /* the first 2 errors have no f or v name */
  509. /*
  510.  *    do the easy error checking:
  511.  */
  512.    if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
  513.    {
  514.       ervar.param = channel;
  515.       if (auto_er) error_exit(-3);
  516.       return(-3);
  517.    }
  518.    if (fd[channel].open != 1)                 /* channel not open */
  519.    {
  520.       ervar.param = channel;
  521.       if (auto_er) error_exit(-4);
  522.       return(-4);
  523.    }
  524.    strcpy(ervar.name, fd[channel].filename);
  525.    if (fd[channel].ch_type != 1)              /* not a "variable" chan type */
  526.    {
  527.       if (auto_er) error_exit(-7);
  528.       return(-7);
  529.    }
  530.    if (fd[channel].format[0] != 1)            /* file prohibits positioning */
  531.    {
  532.       if (auto_er) error_exit(-9);
  533.       return(-9);
  534.    }
  535.    next = (how == 0) ? sample_num : sample_num + fd[channel].next;
  536.    if (next < 1)                              /* invalid sample # */
  537.    {
  538.       ervar.param = next;
  539.       if (auto_er) error_exit(-27);
  540.       return(-27);
  541.    }
  542.    fd[channel].next = next;
  543.    samp_per_rec = fd[channel].format[2*fd[channel].v + 1];
  544.    skipped_rec  = (fd[channel].next - 1) / samp_per_rec;
  545.    skipped_samp = (fd[channel].next - 1) % samp_per_rec;
  546.    p = skipped_rec * fd[channel].byte_p_blk + fd[channel].gap_head
  547.          + skipped_samp * bytes_in[fd[channel].format[2*fd[channel].v] -1];
  548.    lseek(fd[channel].fd, p, 0);
  549.    fd[channel].samp_avail = samp_per_rec - skipped_samp;
  550.    return(next);
  551. }
  552. /*  -----------------------  READ VARIABLE ROUTINE  ------------------------  */
  553. /*   DESCRIPTION:
  554.      position = read_variable ( chan_id, values, num, num_read )
  555.      This routine returns the next "num" values of the variable connected to
  556. channel number "chan_id".  "values" is a pointer to an array where the returned
  557. values are placed.  In the calling routine, this array type should match that of
  558. the variable being returned.  The size of "n" is limited only by the array size
  559. in the calling routine.  The actual number of values read is returned via the
  560. pointer "num_read".  "num_read" will equal "num" unless an error (specified
  561. below) occurs; in this case, it may be zero to num-1.  This routine can be
  562. called only if the specified channel is a "variable channel", that is one
  563. opened via open_var_channel.
  564. Returned value:
  565.      If there are no errors, the returned value indicates the current file
  566. position (the sample number of the next sample to be read by read_variable).
  567. A valid sample number is 1 or greater.  If an error occurs, the value is < 0.
  568. The following errors are detected:
  569.      - error during the file read operation
  570.      - EOF encountered on the data file
  571.      - channel number is outside valid range
  572.      - specified channel is not open
  573.      - this routine is for use only with variable channel types
  574. */
  575. read_variable ( channel, values, n, n_read )
  576. int channel, n, *n_read;
  577. char values[];
  578. {
  579.    int bytes, b_read, s_read;
  580.    strcpy(ervar.routine, "read_variable");
  581.    strcpy(ervar.name, "UNKNOWN");  /* the first 2 errors have no f or v name */
  582.    *n_read = 0;   /*  set number read in case of an early error   */
  583. /*
  584.  *    do the easy error checking:
  585.  */
  586.    if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
  587.    {
  588.       ervar.param = channel;
  589.       if (auto_er) error_exit(-3);
  590.       return(-3);
  591.    }
  592.    if (fd[channel].open != 1)                  /* channel not open */
  593.    {
  594.       ervar.param = channel;
  595.       if (auto_er) error_exit(-4);
  596.       return(-4);
  597.    }
  598.    strcpy(ervar.name, fd[channel].filename);
  599.    if (fd[channel].ch_type != 1)               /* not a "variable" channel */
  600.    {
  601.       if (auto_er) error_exit(-7);
  602.       return(-7);
  603.    }
  604. /*
  605.  *    split into two cases, 1 variable or >1 variable in file:
  606.  */
  607.    if (fd[channel].format[1] == 1)   /* .sg_data file has only 1 variable */
  608.    {
  609.       bytes =  bytes_in[fd[channel].format[2] -1] * n;
  610.       b_read = read(fd[channel].fd, values, bytes);
  611.       if (b_read == -1)     /* error during read */
  612.       {
  613.          perror("The system call error in disk read is");
  614.          if (auto_er) error_exit(-6);
  615.          return(-6);
  616.       }
  617.       *n_read = b_read / bytes_in[fd[channel].format[2] -1];
  618.    }
  619.    else          /* .sg_data file has several variables, the general case */
  620.    {
  621.       s_read = read_sg(channel, values, n);
  622.       if (s_read == -1)     /* error during read */
  623.       {
  624.          perror("The system call error in disk read is");
  625.          if (auto_er) error_exit(-6);
  626.          return(-6);
  627.       }
  628.       *n_read = s_read;
  629.    }
  630.    fd[channel].next += *n_read;
  631.    if (*n_read != n)        /* EOF encountered */
  632.    {
  633.       if (auto_er) error_exit(-5);
  634.       return(-5);
  635.    }
  636.    return(fd[channel].next);
  637. }
  638. /*  ------------------------  GOTO BLOCK ROUTINE  --------------------------  */
  639. /*   DESCRIPTION:
  640.      position = goto_block ( chan_id, block_num, how )
  641.      This routine changes the place from which data is read in the file
  642. connected to "chan_id".  When 'how' is 0, 'block_num' is measured from the
  643. beginning of the file (i.e. absolute positioning).  When 'how' is not 0,
  644. 'block_num' is measured from the current file position (i.e. relative
  645. positioning).  It can be used on block channels and on variable channels.
  646. The first block in a file is called block 1.  This routine does not return an
  647. error if positioned beyond the end of file; this condition is reported when
  648. reading.
  649.      On block channels the repositioning is as follows:
  650.      If doing absolute positioning, the block number read by the next read_block
  651. is "block_num".
  652.      If doing relative positioning, the block number read by the next read_block
  653. is changed by "block_num" blocks.
  654.      On variable channels the repositioning is as follows:
  655.      If doing absolute positioning, the first sample read by the next
  656. read_variable is sample number:
  657. 1 + (block_num - 1) * (# of values of variable per block)
  658.      If doing relative positioning, the first sample read by the next
  659. read_variable is changed by "block_num" blocks.
  660. Returned value:
  661.      If there are no errors, the returned value indicates the current file
  662. position.  On variable channels, the returned value is the sample number of the
  663. next sample to be read by read_variable.  On block channels, the returned value
  664. is the block number of the next block to be read by read_block.  A valid sample
  665. number or block number is 1 or greater.  If an error occurs, the value is < 0.
  666. The following errors are detected:
  667.      - channel number is outside valid range
  668.      - specified channel is not open
  669.      - the file connected to this channel prohibits positioning
  670.      - effective block_num < 1
  671. */
  672. goto_block ( channel, block_num, how )
  673. int channel, block_num, how;
  674. {
  675.    int next;
  676.    long p;
  677.    strcpy(ervar.routine, "goto_block");
  678.    strcpy(ervar.name, "UNKNOWN");  /* the first 2 errors have no f or v name */
  679. /*
  680.  *    do the easy error checking:
  681.  */
  682.    if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
  683.    {
  684.       ervar.param = channel;
  685.       if (auto_er) error_exit(-3);
  686.       return(-3);
  687.    }
  688.    if (fd[channel].open != 1)                  /* channel not open */
  689.    {
  690.       ervar.param = channel;
  691.       if (auto_er) error_exit(-4);
  692.       return(-4);
  693.    }
  694.    strcpy(ervar.name, fd[channel].filename);
  695.    if (fd[channel].format[0] != 1)             /* file prohibits positioning */
  696.    {
  697.       if (auto_er) error_exit(-9);
  698.       return(-9);
  699.    }
  700. /*
  701.  *    partition according to positioning type:
  702.  */
  703.    if (how == 0)   /* absolute positioning */
  704.    {
  705.       next = (fd[channel].ch_type == 2) ? block_num :
  706.               1 + (block_num  - 1) * fd[channel].format[2*fd[channel].v+1];
  707.       if (next < 1)   /* invalid block # */
  708.       {
  709.          ervar.param = block_num;
  710.          if (auto_er) error_exit(-30);
  711.          return(-30);
  712.       }
  713.       p = (block_num - 1) * fd[channel].byte_p_blk;
  714.       lseek(fd[channel].fd, p, 0);
  715. /*
  716.  *    check for the general case and skip gap_head bytes, if so:
  717.  */
  718.       if (fd[channel].ch_type == 1 && fd[channel].format[1] > 1)
  719.       {
  720.          lseek(fd[channel].fd, (long) fd[channel].gap_head, 1);
  721.          fd[channel].samp_avail = fd[channel].format[2*fd[channel].v+1];
  722.       }
  723.    }
  724.    else           /* relative positioning */
  725.    {
  726.       next = (fd[channel].ch_type == 2) ? fd[channel].next + block_num :
  727.              fd[channel].next + block_num * fd[channel].format[2*fd[channel].v+1];
  728.       if (next < 1)   /* invalid block # */
  729.       {
  730.          ervar.param = (fd[channel].ch_type==2) ? next : (fd[channel].next-1) /
  731.                        fd[channel].format[2*fd[channel].v+1] + 1 + block_num;
  732.          if (auto_er) error_exit(-30);
  733.          return(-30);
  734.       }
  735.       p = block_num * fd[channel].byte_p_blk;
  736.       lseek(fd[channel].fd, p, 1);
  737.    }
  738.    fd[channel].next = next;
  739.    return(next);
  740. }
  741. /*  ------------------------  READ BLOCK ROUTINE  --------------------------  */
  742. /*   DESCRIPTION:
  743.      position = read_block ( chan_id, val_pntr )
  744.      This routine returns one block of values from the file connected to
  745. channel "chan_id".  "val_pntr" is an array of pointers having one element for
  746. each block variable.  The calling routine sets each pointer in the array to
  747. specify where the values for each block variable are to go.  Thus, val_pntr[0]
  748. is the address where the first value of the first block variable will be stored;
  749. val_pntr[1] is the address where the first value of the second block variable
  750. will be stored; etc.  Subsequent values of the variables are stored in
  751. sequential locations following the address of the first value.
  752. Returned value:
  753.      If there are no errors, the returned value indicates the current file
  754. position (the block number of the next block to be read by read_block).  A
  755. valid block number is 1 or greater.  If an error occurs, the value is < 0.
  756. The following errors are detected:
  757.      - channel number is outside valid range
  758.      - specified channel is not open
  759.      - this routine is for use only with block channel types
  760.      - error during the file read operation
  761.      - EOF encountered on the data file
  762. */
  763. read_block ( channel, val_pntr )
  764. char *val_pntr[];
  765. int channel;
  766. {
  767.    int i, err;
  768.    short num_left, num_to_read;
  769.    struct iovec {
  770.       char *iov_base;
  771.       int   iov_length;
  772.       };
  773.    struct iovec io_vector[MAX_VARS_PER_BLK];
  774.    strcpy(ervar.routine, "read_block");
  775.    strcpy(ervar.name, "UNKNOWN");  /* the first 2 errors have no f or v name */
  776. /*
  777.  *    do the easy error checking:
  778.  */
  779.    if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
  780.    {
  781.       ervar.param = channel;
  782.       if (auto_er) error_exit(-3);
  783.       return(-3);
  784.    }
  785.    if (fd[channel].open != 1)                  /* channel not open */
  786.    {
  787.       ervar.param = channel;
  788.       if (auto_er) error_exit(-4);
  789.       return(-4);
  790.    }
  791.    strcpy(ervar.name, fd[channel].filename);
  792.    if (fd[channel].ch_type != 2)               /* not a "block" channel */
  793.    {
  794.       if (auto_er) error_exit(-8);
  795.       return(-8);
  796.    }
  797. /*
  798.  *    write the input vector:
  799.  */
  800.    for (i=0; i<fd[channel].format[1]; i++)
  801.    {
  802.       io_vector[i].iov_base = val_pntr[i];
  803.       io_vector[i].iov_length = fd[channel].bytes[i];
  804.    }
  805. /*
  806.  *    read the block in chunks of 16 variables at a time (readv limitation):
  807.  */
  808.    i = 0;
  809.    num_left = fd[channel].format[1];
  810.    while (num_left > 0)
  811.    {
  812.       num_to_read = 16;
  813.       if (num_left < 16) num_to_read = num_left;
  814.       err = readv(fd[channel].fd, &io_vector[i], num_to_read);
  815.       if (err == -1)         /* error during read */
  816.       {
  817.          perror("The system call error in disk read is");
  818.          if (auto_er) error_exit(-6);
  819.          return(-6);
  820.       }
  821.       if (err == 0)          /* EOF encountered */
  822.       {
  823.          if (auto_er) error_exit(-5);
  824.          return(-5);
  825.       }
  826.       i += num_to_read;
  827.       num_left -= num_to_read;
  828.    }
  829.    return(++fd[channel].next);
  830. }
  831. /*  -----------------------  CLOSE CHANNEL ROUTINE  ------------------------  */
  832. /*   DESCRIPTION:
  833.      status = close_channel ( chan_id )
  834.      This routine closes the specified channel.  Doing so makes the channel id
  835. available for re-assignment.
  836. Returned value:
  837.      The returned value indicates the error status of the routine.  If no error
  838. occurs, the returned value is 0.  If an error occurs, the value is < 0.
  839. The following errors are detected:
  840.      - channel number is outside valid range
  841.      - specified channel is not open
  842. */
  843. close_channel ( channel )
  844. int channel;
  845. {
  846.    strcpy(ervar.routine, "close_channel");
  847.    strcpy(ervar.name, "UNKNOWN");  /* the first 2 errors have no f or v name */
  848.    if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
  849.    {
  850.       ervar.param = channel;
  851.       if (auto_er) error_exit(-3);
  852.       return(-3);
  853.    }
  854.    if (fd[channel].open != 1)                  /* channel not open */
  855.    {
  856.       ervar.param = channel;
  857.       if (auto_er) error_exit(-4);
  858.       return(-4);
  859.    }
  860.    fd[channel].open = 0;
  861.    close (fd[channel].fd);
  862.    return(0);
  863. }
  864. /*  -------------------  PRINT DISK READ ERROR ROUTINE  --------------------  */
  865. /*   DESCRIPTION:
  866.      print_disk_read_error ( err_num )
  867.      This routine prints an error message which corresponds to "err_num".
  868. It is printed on stderr.
  869. */
  870. print_disk_read_error ( err_num )
  871. int err_num;
  872. {
  873.    char *disk_read_error ();
  874.    if (err_num < 0)
  875.    {
  876.       fprintf(stderr, "Disk_IO error in routine '%s'.n", ervar.routine);
  877.       fprintf(stderr, "The filename or variable name associated with the offending call is:n");
  878.       fprintf(stderr, "%sn", ervar.name);
  879.       fprintf(stderr, disk_read_error(err_num) );
  880.       if (ervar.param != PARAM_OK)
  881.       {
  882.          fprintf(stderr, "Its value was: %dn", ervar.param);
  883.          ervar.param = PARAM_OK;
  884.       }
  885.    }
  886.    else fprintf(stderr, disk_read_error(err_num) );
  887.    return;
  888. }
  889. /*  ----------------------  DISK READ ERROR ROUTINE  -----------------------  */
  890. /*   DESCRIPTION:
  891.      error_string = disk_read_error ( err_num )
  892.      The disk_read_error routine returns a brief error message which
  893. corresponds to "err_num".
  894. */
  895. char *disk_read_error ( err_num )
  896. int err_num;
  897. {
  898.    static char err_string[70];
  899.    static char *err_msg[] = {
  900. "No error",                                                      /* 0 */
  901. /*
  902.  * COMMON ERRORS:
  903.  */
  904. "unassigned",                                                    /* 1 */
  905. "Filename is too long",                                          /* 2 */
  906. "Channel number is outside valid range",                         /* 3 */
  907. "Specified channel is not open",                                 /* 4 */
  908. "EOF encountered on the data file",                              /* 5 */
  909. "Error during the file read operation",                          /* 6 */
  910. "This routine is for use only with variable channel types",      /* 7 */
  911. "This routine is for use only with block channel types",         /* 8 */
  912. "The file connected to this channel prohibits positioning",      /* 9 */
  913. "Invalid extension in filename",                                /* 10 */
  914. "unassigned",                                                   /* 11 */
  915. /*
  916.  * OPEN CHANNEL ERRORS:
  917.  */
  918. "There is a format file problem",                               /* 12 */
  919. "The data file could not be opened",                            /* 13 */
  920. "All channels are open",                                        /* 14 */
  921. "The specified variable was not found",                         /* 15 */
  922. "No data file found",                                           /* 16 */
  923. "unassigned",                                                   /* 17 */
  924. "unassigned",                                                   /* 18 */
  925. /*
  926.  * READ FORMAT ERRORS:
  927.  */
  928. "The format file could not be opened",                          /* 19 */
  929. "The format file is not complete",                              /* 20 */
  930. "Invalid value read for file type",                             /* 21 */
  931. "Invalid value read for variables/block",                       /* 22 */
  932. "Invalid value read for data type",                             /* 23 */
  933. "Invalid value read for values/block",                          /* 24 */
  934. "No data file found, so can't determine format",                /* 25 */
  935. /*
  936.  * FILE LENGTH ERRORS:
  937.  */
  938. "unassigned",                                                   /* 26 */
  939. /*
  940.  * GOTO SAMPLE ERRORS:
  941.  */
  942. "Effective sample_num is < 1",                                  /* 27 */
  943. "unassigned",                                                   /* 28 */
  944. /*
  945.  * READ VARIABLE ERRORS:
  946.  */
  947. "unassigned",                                                   /* 29 */
  948. /*
  949.  * GOTO BLOCK ERRORS:
  950.  */
  951. "Effective block_num is < 1",                                   /* 30 */
  952. "unassigned",                                                   /* 31 */
  953. /*
  954.  * READ BLOCK ERRORS:
  955.  */
  956. "unassigned",                                                   /* 32 */
  957. /*
  958.  * CLOSE CHANNEL ERRORS:
  959.  */
  960. "unassigned",                                                   /* 33 */
  961. /*
  962.  * ALL OTHER ERRORS:
  963.  */
  964. "Bad value for error number"                                    /* 34 */
  965. };
  966. #define NUM 34
  967.    if (err_num > 0) err_num = 0; /* force positive arguments to give no error */
  968.    strcpy(err_string, (-err_num < NUM) ? err_msg[-err_num] : err_msg[NUM] );
  969.    strcat(err_string, ".n");
  970.    return(err_string);
  971. }
  972. /*  --------------------------  SUPPORT ROUTINES  --------------------------  */
  973. /*  -----------------------  TEST FILENAME ROUTINE  ------------------------  */
  974. /*   DESCRIPTION:
  975.      This routine examines the filename "in_file" and returns in "out_file" the
  976. data file or format file name which corresponds to "in_file".  "out_file_type"
  977. specifies whether to return the name of a data file (if 1) or the format file
  978. name (if 2).  This is the routine which implements the filename flexibility
  979. which read_format and the open channel routines have.
  980. The return value of the function indicates the following:
  981.      -2 - invalid extension
  982.      -1 - data file not found
  983.       0 - in_file is .sg file type
  984.       1 - in_file is .spd file type
  985.     ( value increases by 1 for each added data file type )
  986. */
  987. static test_filename ( in_file, out_file, out_file_type )
  988. char in_file[], out_file[];
  989. int out_file_type;
  990. {
  991.    char extn[MAX_FILENAME_LENG];
  992.    if (rindex(in_file, '.') == NULL) /* in_file does not have an extension */
  993.    {
  994.       strcpy(out_file, in_file);
  995.       strcat(out_file, DFE);           /* out_file = in_file.DFE */
  996.       if (access(out_file, 0) == 0)    /* out_file.DFE exists */
  997.       {
  998.          if (out_file_type == 2)       /* output the format file name instead */
  999.          {
  1000.             strcpy(out_file, in_file);
  1001.             strcat(out_file, FFE);     /* out_file = in_file.FFE */
  1002.          }
  1003.          return(0);                    /* .sg file type */
  1004.       }
  1005.       strcpy(out_file, in_file);
  1006.       strcat(out_file, ".spd");        /* out_file = in_file.spd */
  1007.       if (access(out_file, 0) == 0) return(1);  /* .spd file type */
  1008.       return(-1);                      /* could not find a data file */
  1009.    }
  1010.    else                                /* in_file has an extension */
  1011.    {
  1012.       strcpy(extn, rindex(in_file, '.') );  /* extn = the extension */
  1013.       strcpy(out_file, "");            /* out_file = extensionless in_file */
  1014.       strncat(out_file, in_file, strlen(in_file)-strlen(extn) );
  1015.       if (strcmp(extn, DFE) == 0)      /* the extension is DFE */
  1016.       {
  1017.          if (out_file_type == 1) strcat(out_file, DFE);
  1018.          if (out_file_type == 2) strcat(out_file, FFE);
  1019.          return(0);                    /* .sg file type */
  1020.       }
  1021.       if (strcmp(extn, FFE) == 0)      /* the extension is FFE */
  1022.       {
  1023.          if (out_file_type == 1) return(-2);
  1024.          if (out_file_type == 2) strcat(out_file, FFE);
  1025.          return(0);                    /* .sg file type */
  1026.       }
  1027.       if (strcmp(extn, ".spd") == 0)   /* the extension is .spd */
  1028.       {
  1029.          strcpy(out_file, in_file);
  1030.          return(1);                    /* .spd file type */
  1031.       }
  1032.       return(-2);                      /* invalid extension */
  1033.    }
  1034. }
  1035. /*  -----------------------  READ SUNGRAPH DATA FILE  ----------------------  */
  1036. /*   DESCRIPTION:
  1037.      This routine is like "read" but instead reads data files which are in the
  1038. SUNGRAPH format.  It operates with channels opened for single variable access.
  1039. It fetches the next "samp" samples of the variable that "channel" was opened to
  1040. read.  The function value is the actual number of samples read, unless "read"
  1041. or "lseek" returns -1, in which case -1 is the function value.
  1042. */
  1043. static read_sg ( channel, values, samp )
  1044. char values[];
  1045. int channel, samp;
  1046. {
  1047.    register int bytes_per_samp, index, left;
  1048.    int n, bytes, total;
  1049.    total = 0;
  1050.    index = 0;
  1051.    left = samp;
  1052.    bytes_per_samp = bytes_in[fd[channel].format[2*fd[channel].v] -1];
  1053.    while (left > 0)
  1054.    {
  1055.       if (left >= fd[channel].samp_avail)  /* read to end of current block */
  1056.       {
  1057.          bytes = bytes_per_samp * fd[channel].samp_avail;
  1058.          n = read(fd[channel].fd, &values[index], bytes);
  1059.          if (n == -1) return(-1);  /* read error */
  1060.          if (n != bytes)          /* EOF reached */
  1061.          {
  1062.             fd[channel].samp_avail -= n / bytes_per_samp;
  1063.             return(total + n/bytes_per_samp);
  1064.          }
  1065.          total += fd[channel].samp_avail;
  1066.          left  -= fd[channel].samp_avail;
  1067.          index += bytes;
  1068.          lseek(fd[channel].fd, (long) fd[channel].gap_total, 1);
  1069.          fd[channel].samp_avail = fd[channel].format[2*fd[channel].v + 1];
  1070.       }
  1071.       else     /* read just the number of samples left to fetch for this call */
  1072.       {
  1073.          bytes = bytes_per_samp * left;
  1074.          n = read(fd[channel].fd, &values[index], bytes);
  1075.          if (n == -1) return(-1);  /* read error */
  1076.          if (n != bytes)           /* EOF reached */
  1077.          {
  1078.             fd[channel].samp_avail -= n / bytes_per_samp;
  1079.             return(total + n/bytes_per_samp);
  1080.          }
  1081.          total += left;
  1082.          fd[channel].samp_avail -= left;
  1083.          left = 0;
  1084.       }
  1085.    }
  1086.    return(total);
  1087. }
  1088. /*  -----------------------------  ERROR_EXIT  -----------------------------  */
  1089. static error_exit(err_num)
  1090. int err_num;
  1091. {
  1092.    print_disk_read_error(err_num);
  1093.    exit(-1);
  1094. }