diskread.c
上传用户:szhypcb168
上传日期:2007-01-06
资源大小:2187k
文件大小:42k
- /* ---------------------- DATA FILE READ ROUTINES ----------------------- */
- /* --------------------- designed and coded by rpc ---------------------- */
- /* ---------------------- Version 1.5 July 1988 ----------------------- */
- /* ------------------------------------------------------------------------ */
- /* RELEASE NOTES:
- Version 1.0: The original version for the SUNGRAPH signal data input
- module.
- Version 1.1: Modified the argument list of some routines. Other changes?
- Version 1.2: Added the auto error reporting feature. This feature is
- enabled or disabled via disk_io_erh(flag) which is in its own source file.
- Also changed dfe[] & ffe[] to DFE & FFE.
- Version 1.3: Added relative positioning to goto_block & goto_sample.
- Deleted all checking for lseek errors since they can't occur.
- Version 1.4: Increased the amount of text in error reporting and changed
- it to print on stderr instead of stdout.
- Version 1.5: Made goto_sample, read_variable, goto_block and read_block
- return the sample or block number to be read next, i.e. the current position.
- */
- #include "diskio.h"
- #include <stdio.h>
- #include <strings.h>
- #include <sys/file.h>
- #include <sys/types.h> /* these two files are included for the call */
- #include <sys/stat.h> /* to fstat in file length routine */
- /* variable type definitions:
- *
- * TYPE # | C TYPE | # of BYTES | FORTRAN TYPE
- * --------------------------------------------------
- * 1 | short | 2 | integer*2
- * 2 | int | 4 | integer*4
- * 3 | float | 4 | real*4
- */
- static short bytes_in[] = { 2, 4, 4 }; /* number of bytes in the data types */
- #define NUM_DATA_TYPES sizeof(bytes_in)/sizeof(bytes_in[0]) /* elements in bytes_in */
- struct file_data {
- char filename[MAX_FILENAME_LENG+1];/* file connected to this channel */
- int fd; /* file descriptor assigned to above */
- int format[2+2*MAX_VARS_PER_BLK]; /* the format of the data file */
- short open; /* channel's status: 0-closed, 1-open */
- short ch_type; /* channel type */
- short v; /* variable # read on type 1 channels */
- int next; /* next sample to read on type 1 chan */
- /* next block to read on type 2 chan */
- short samp_p_blk; /* total # of samples/block */
- int byte_p_blk; /* total # of bytes/block */
- int bytes[MAX_VARS_PER_BLK]; /* # of bytes/block for each variable */
- short samp_avail; /* # of unread samples in current block */
- int gap_head; /* # of bytes in block before selected variable */
- int gap_total; /* # of block bytes not in selected variable */
- };
- static struct file_data fd[MAX_CHANNELS];
- #define PARAM_OK -999
- struct errs {
- char routine[20]; /* name of routine where error was */
- char name[MAX_FILENAME_LENG+1]; /* filename or variable name */
- int param; /* illegal argument of call in error */
- };
- static struct errs ervar = { "", "", PARAM_OK };
- #define DFE ".sg_data"
- #define FFE ".sg_format"
- extern int errno;
- extern short auto_er; /* flag to enable/disable auto error report & halt */
- extern long lseek();
- extern char *strcpy(), *strcat(), *strncat(), *rindex();
- /* -------------------- OPEN VARIABLE CHANNEL ROUTINE ------------------- */
- /* DESCRIPTION:
- chan_id = open_var_channel ( filename, var_name )
- This routine is called to establish a new channel to access the values of
- one of the variables in a data file. "filename" is the name of the file and
- "var_name" is the name of the variable whose values are to be read. The
- variable's values are accessed with the read_variable routine. This function
- returns a channel id ("chan_id") which is used to identify the opened channel
- when calling other disk read routines. "filename" can have an extension, but
- it is not mandatory.
- If "filename" has an extension:
- a) The extension is tested for validity. (eg. Is it .sg_data or one of
- the other types that can be read by these routines?) Valid extensions
- are these: .sg_data; .spd
- b) If the extension is valid, open_var_channel tries to open "filename".
- If the extension is not valid, an error is returned.
- If "filename" does not have an extension:
- a) Each valid extension is concatenated with a copy of filename and the
- resulting filename is tested for existance.
- b) If this file exists, open_var_channel tries to open it.
- If none of these files exist, an error is returned.
- If the file to be opened has the .sg_data extension, the format information
- must reside in a corresponding .sg_format file.
- Returned value:
- If there are no errors, the returned value is a channel id which is used to
- identify the open channel when using other disk read routines. A valid channel
- id is >= 0. If an error occurs, the returned value is < 0.
- The following errors are detected:
- - filename is too long
- - all channels are open
- - there is a format file problem
- - the specified variable was not found
- - invalid extension in filename
- - no data file found
- - the data file could not be opened
- */
- open_var_channel ( filename, var_name )
- char filename[], var_name[];
- {
- int chan_id;
- chan_id = open_channel(filename, 1, var_name);
- strcpy(ervar.routine, "open_var_channel");
- strncpy(ervar.name, filename, MAX_FILENAME_LENG);
- if (chan_id == -15) strncpy(ervar.name, var_name, MAX_FILENAME_LENG);
- strcat(ervar.name, "");
- if (chan_id < 0 && auto_er) error_exit(chan_id);
- return(chan_id);
- }
- /* --------------------- OPEN BLOCK CHANNEL ROUTINE --------------------- */
- /* DESCRIPTION:
- chan_id = open_block_channel ( filename )
- This routine is called to establish a new channel to access the values of
- all of the variables in a data file. The values of the data file variables are
- accessed with the read_block routine. This function returns a channel id
- ("chan_id") which is used to identify the opened channel when calling other
- disk read routines. "filename" can have an extension, but it is not mandatory.
- If "filename" has an extension:
- a) The extension is tested for validity. (eg. Is it .sg_data or one of
- the other types that can be read by these routines?) Valid extensions
- are these: .sg_data; .spd
- b) If the extension is valid, open_var_channel tries to open "filename".
- If the extension is not valid, an error is returned.
- If "filename" does not have an extension:
- a) Each valid extension is concatenated with a copy of filename and the
- resulting filename is tested for existance.
- b) If this file exists, open_var_channel tries to open it.
- If none of these files exist, an error is returned.
- If the file to be opened has the .sg_data extension, the format information
- must reside in a corresponding .sg_format file.
- Returned value:
- If there are no errors, the returned value is a channel id which is used to
- identify the open channel when using other disk read routines. A valid channel
- id is >= 0. If an error occurs, the returned value is < 0.
- The following errors are detected:
- - filename is too long
- - all channels are open
- - there is a format file problem
- - invalid extension in filename
- - no data file found
- - the data file could not be opened
- */
- open_block_channel ( filename )
- char filename[];
- {
- int chan_id;
- chan_id = open_channel(filename, 2, "");
- strcpy(ervar.routine, "open_block_channel");
- strncpy(ervar.name, filename, MAX_FILENAME_LENG);
- strcat(ervar.name, "");
- if (chan_id < 0 && auto_er) error_exit(chan_id);
- return(chan_id);
- }
- /* ------------------------ OPEN CHANNEL ROUTINE ------------------------ */
- /* DESCRIPTION:
- chan_id = open_channel ( file, chan_type, vname )
- This routine is for use only by the disk_read module; it cannot be called
- from anywhere else. It does the actual channel opening operations for each
- channel type. "chan_type" indicates the type of channel being requested. Two
- channel types are currently defined according to the type of access desired:
- 1 - single variable access
- 2 - block access (all block variables)
- "vname" is the name of the variable accessed on type 1 channels.
- */
- static open_channel ( file, chan_type, vname )
- char file[], vname[];
- int chan_type;
- {
- int format[2 + 2*MAX_VARS_PER_BLK], var_num, i, temp_fd, chan, file_status;
- char filename[MAX_FILENAME_LENG + sizeof(DFE)];
- static char varnames[MAX_VARS_PER_BLK][MAX_VARNAME_LENG + 1];
- static char *vnames[MAX_VARS_PER_BLK] = {
- varnames[ 0], varnames[ 1], varnames[ 2], varnames[ 3],
- varnames[ 4], varnames[ 5], varnames[ 6], varnames[ 7],
- varnames[ 8], varnames[ 9], varnames[10], varnames[11],
- varnames[12], varnames[13], varnames[14], varnames[15],
- varnames[16], varnames[17], varnames[18], varnames[19],
- varnames[20], varnames[21], varnames[22], varnames[23],
- varnames[24], varnames[25], varnames[26], varnames[27],
- varnames[28], varnames[29], varnames[30], varnames[31],
- varnames[32], varnames[33], varnames[34], varnames[35] };
- /*
- * do the easy error checking:
- */
- if (strlen(file) > MAX_FILENAME_LENG) return(-2);
- /*
- * look for first available channel:
- */
- chan = -1;
- for (i=0; i<MAX_CHANNELS; i++)
- {
- if (fd[i].open == 0)
- {
- chan = i;
- break;
- }
- }
- if (chan == -1) return(-14);
- /*
- * read format file:
- */
- if (read_format( file, format, vnames ) < 0) return(-12);
- /*
- * if type 1 channel, find the variable number from the variable name:
- */
- var_num = 0;
- if (chan_type==1)
- {
- for (i=0; i<format[1]; i++)
- {
- if (strcmp(vname, vnames[i]) == 0)
- {
- var_num = i+1;
- break;
- }
- }
- if (var_num == 0) return(-15);
- }
- /*
- * check for filename extension options and open the data file:
- */
- file_status = test_filename(file, filename, 1);
- if (file_status == -2) return(-10); /* invalid extension */
- if (file_status == -1) return(-16); /* no data file found */
- if( (temp_fd = open(filename, O_RDONLY)) == -1) /* couldn't open */
- {
- perror("The system call error in disk read is");
- return(-13);
- }
- /*
- * write the data file structure variables:
- */
- fd[chan].open = 1;
- strcpy( fd[chan].filename, file );
- for (i=0; i < 2*format[1]+2; i++) fd[chan].format[i] = format[i];
- fd[chan].fd = temp_fd;
- fd[chan].ch_type = chan_type;
- fd[chan].v = var_num;
- fd[chan].next = 1;
- fd[chan].samp_p_blk = 0;
- fd[chan].byte_p_blk = 0;
- for (i=1; i<=format[1]; i++)
- {
- fd[chan].samp_p_blk += format[2*i+1];
- fd[chan].byte_p_blk += bytes_in[format[2*i] -1] * format[2*i+1];
- fd[chan].bytes[i-1] = bytes_in[format[2*i] -1] * format[2*i+1];
- }
- fd[chan].gap_head = 0;
- fd[chan].gap_total = 0;
- if (chan_type == 1 && format[1] > 1) /* the general case */
- {
- fd[chan].samp_avail = format[2*var_num + 1];
- fd[chan].gap_total = fd[chan].byte_p_blk
- - bytes_in[format[2*var_num] -1] * format[2*var_num + 1];
- for (i=1; i<var_num; i++)
- fd[chan].gap_head += bytes_in[format[2*i] -1] * format[2*i+1];
- lseek(fd[chan].fd, (long) fd[chan].gap_head, 1);
- /*
- * for testing only, print gap_head & gap_total:
- *
- printf("n%d gap_headn%d gap_totaln",
- fd[chan].gap_head, fd[chan].gap_total );
- */
- }
- /*
- * for testing only, print samples/block & bytes/block:
- *
- printf("n%d samples/blockn%d bytes/blocknn",
- fd[chan].samp_p_blk, fd[chan].byte_p_blk );
- */
- return(chan);
- }
- /* ------------------------ READ FORMAT ROUTINE ------------------------- */
- /* DESCRIPTION:
- status = read_format ( filename, format, vnames )
- This routine determines the format associated with file "filename" and
- returns this information. As with the filename argument in the open channel
- routines, read_format accepts filenames with or without extensions. It uses the
- same process that the open channel routines use to determine for what data file
- the format information is sought. Hence, for a given filename, read_format
- always gets the format which corresponds to the data file opened by an open
- channel routine. (However, read_format accepts filenames that end with
- .sg_format. Such a filename would cause an error if given to an open channel
- routine.)
- The format array contains the following information:
- format[0] - file type indicator
- current meaning (will be expanded later):
- 1 if .sg_data file allows sample & block positioning;
- 0 if this is NOT allowed
- format[1] - number of variables/block in .sg_data file
- format[2*n] - data type of variable n in .sg_data file
- 1 - short; 2 - int; 3 - float
- format[2*n+1] - number of entries/block of variable n in .sg_data file
- "vnames" is an array of pointers to the names of variables saved in the data
- file. Thus, vnames[0] points to the name of the first variable, vnames[1]
- points to the name of the second variable, etc.
- The format information comes from a .sg_format file when the data file is
- a .sg_data file. Other data file types have fixed formats which return a set
- of parameters stored in this routine. Below are listed the format parameters
- for each of these other data file types.
- Format parameters for .spd data files:
- format[0] = 1
- format[1] = 1
- format[2] = 1
- format[3] = 512
- vnames[0] = "speech_data"
- Returned value:
- The returned value indicates the error status of the routine. If no error
- occurs, the returned value is 0. If an error occurs, the value is < 0.
- The following errors are detected:
- - filename is too long
- - invalid extension in filename
- - no data file found, so can't determine format
- - the format file could not be opened
- - the format file is not complete
- - invalid value read for file type
- - invalid value read for variables/block
- - invalid value read for data type
- - invalid value read for values/block
- */
- read_format ( file, format, vnames )
- char file[], *vnames[];
- int format[];
- {
- short frmt[2 + 2*MAX_VARS_PER_BLK];
- int temp_fd, i, file_status;
- char filename[MAX_FILENAME_LENG + sizeof(FFE)];
- strcpy(ervar.routine, "read_format");
- strncpy(ervar.name, file, MAX_FILENAME_LENG);
- strcat(ervar.name, "");
- if (strlen(file) > MAX_FILENAME_LENG) /* filename too long */
- {
- if (auto_er) error_exit(-2);
- return(-2);
- }
- /*
- * check for filename extension options:
- */
- file_status = test_filename(file, filename, 2);
- if (file_status == -2) /* invalid extension */
- {
- if (auto_er) error_exit(-10);
- return(-10);
- }
- if (file_status == -1) /* no data file found */
- {
- if (auto_er) error_exit(-25);
- return(-25);
- }
- if (file_status == 1) /* the file is a .spd file */
- { /* set default values */
- format[0] = 1;
- format[1] = 1;
- format[2] = 1;
- format[3] = 512;
- strcpy( vnames[0], "speech_data" );
- return(0);
- }
- /*
- * the file is the usual .sg_format type. open it:
- */
- if( (temp_fd = open(filename, O_RDONLY)) == -1) /* can't open format file */
- {
- perror("The system call error in disk read is");
- if (auto_er) error_exit(-19);
- return(-19);
- }
- /*
- * read format[0] & format[1]:
- */
- if (read(temp_fd, (char *) frmt, 4) != 4) /* incomplete format file */
- {
- close(temp_fd);
- if (auto_er) error_exit(-20);
- return(-20);
- }
- /*
- * check format[0] & format[1] for proper values:
- */
- if (frmt[0] < 0 || frmt[0] > 1) /* invalid file type */
- {
- close(temp_fd);
- ervar.param = frmt[0];
- if (auto_er) error_exit(-21);
- return(-21);
- }
- if (frmt[1] < 1 || frmt[1] > MAX_VARS_PER_BLK) /* invalid # of vars/block */
- {
- close(temp_fd);
- ervar.param = frmt[1];
- if (auto_er) error_exit(-22);
- return(-22);
- }
- /*
- * read the data type and number per block from format file:
- */
- if (4*frmt[1] != read(temp_fd, (char *) &frmt[2], (int) 4*frmt[1]))
- {
- close(temp_fd);
- if (auto_er) error_exit(-20);
- return(-20);
- }
- /*
- * check the data type and number per block; and read the variable names:
- */
- for (i=1; i<=frmt[1]; ++i)
- {
- if (frmt[2*i] < 1 || frmt[2*i] > NUM_DATA_TYPES) /* invalid data type */
- {
- close(temp_fd);
- ervar.param = frmt[2*i];
- if (auto_er) error_exit(-23);
- return(-23);
- }
- if (frmt[2*i+1] < 1 || frmt[2*i+1] > MAX_VALUES_PER_VAR) /* invalid # of vals per block */
- {
- close(temp_fd);
- ervar.param = frmt[2*i+1];
- if (auto_er) error_exit(-24);
- return(-24);
- }
- *(vnames[i-1]+MAX_VARNAME_LENG) = ' '; /* ensure null termination */
- if (MAX_VARNAME_LENG != read(temp_fd, vnames[i-1], MAX_VARNAME_LENG) )
- {
- close(temp_fd);
- if (auto_er) error_exit(-20);
- return(-20);
- }
- }
- /*
- * everything OK, so transfer format info to int array and close format file:
- */
- for (i=0; i<2*MAX_VARS_PER_BLK + 2; i++) format[i] = frmt[i];
- close(temp_fd);
- return(0);
- }
- /* ------------------------ FILE LENGTH ROUTINE ------------------------- */
- /* DESCRIPTION:
- status = file_length ( chan_id, bytes, samples, blocks )
- This routine returns the length of the file connected to "chan_id" in
- terms of bytes, samples and blocks. I don't know what it should do with
- real-time data files yet.
- Returned value:
- The returned value indicates the error status of the routine. If no error
- occurs, the returned value is 0. If an error occurs, the value is < 0.
- The following errors are detected:
- - channel number is outside valid range
- - specified channel is not open
- */
- file_length ( channel, bytes, samples, blocks )
- int channel, *bytes, *samples, *blocks;
- {
- int length;
- struct stat status; /* for use with fstat */
- strcpy(ervar.routine, "file_length");
- strcpy(ervar.name, "UNKNOWN"); /* can't determine associated file name */
- if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-3);
- return(-3);
- }
- if (fd[channel].open != 1) /* channel not open */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-4);
- return(-4);
- }
- fstat(fd[channel].fd, &status); /* unix library routine that returns */
- length = status.st_size; /* file length in structure "status" */
- *bytes = length;
- *blocks = length / fd[channel].byte_p_blk;
- *samples = *blocks * fd[channel].samp_p_blk;
- return(0);
- }
- /* ------------------------ GOTO SAMPLE ROUTINE ------------------------- */
- /* DESCRIPTION:
- position = goto_sample ( chan_id, sample_num, how )
- This routine changes the sample number that the next call to read_variable
- on "chan_id" reads from. When "how" is 0, "sample_num" is measured from the
- beginning of the file (i.e. absolute positioning). When "how" is not 0,
- "sample_num" is measured from the current file position (i.e. relative
- positioning). The first sample in the file is called sample 1. This routine
- can be called only if the specified channel is a "variable channel", that is
- one opened via open_var_channel. This routine does not return an error if the
- sample to be read is beyond the end of file; this condition is reported when
- reading.
- Returned value:
- If there are no errors, the returned value indicates the current file
- position (the sample number of the next sample to be read by read_variable).
- A valid sample number is 1 or greater. If an error occurs, the value is < 0.
- The following errors are detected:
- - channel number is outside valid range
- - specified channel is not open
- - this routine is for use only with variable channel types
- - the file connected to this channel prohibits positioning
- - effective sample_num is < 1
- */
- goto_sample ( channel, sample_num, how )
- int channel, sample_num, how;
- {
- int samp_per_rec, skipped_rec, skipped_samp, next;
- long p;
- strcpy(ervar.routine, "goto_sample");
- strcpy(ervar.name, "UNKNOWN"); /* the first 2 errors have no f or v name */
- /*
- * do the easy error checking:
- */
- if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-3);
- return(-3);
- }
- if (fd[channel].open != 1) /* channel not open */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-4);
- return(-4);
- }
- strcpy(ervar.name, fd[channel].filename);
- if (fd[channel].ch_type != 1) /* not a "variable" chan type */
- {
- if (auto_er) error_exit(-7);
- return(-7);
- }
- if (fd[channel].format[0] != 1) /* file prohibits positioning */
- {
- if (auto_er) error_exit(-9);
- return(-9);
- }
- next = (how == 0) ? sample_num : sample_num + fd[channel].next;
- if (next < 1) /* invalid sample # */
- {
- ervar.param = next;
- if (auto_er) error_exit(-27);
- return(-27);
- }
- fd[channel].next = next;
- samp_per_rec = fd[channel].format[2*fd[channel].v + 1];
- skipped_rec = (fd[channel].next - 1) / samp_per_rec;
- skipped_samp = (fd[channel].next - 1) % samp_per_rec;
- p = skipped_rec * fd[channel].byte_p_blk + fd[channel].gap_head
- + skipped_samp * bytes_in[fd[channel].format[2*fd[channel].v] -1];
- lseek(fd[channel].fd, p, 0);
- fd[channel].samp_avail = samp_per_rec - skipped_samp;
- return(next);
- }
- /* ----------------------- READ VARIABLE ROUTINE ------------------------ */
- /* DESCRIPTION:
- position = read_variable ( chan_id, values, num, num_read )
- This routine returns the next "num" values of the variable connected to
- channel number "chan_id". "values" is a pointer to an array where the returned
- values are placed. In the calling routine, this array type should match that of
- the variable being returned. The size of "n" is limited only by the array size
- in the calling routine. The actual number of values read is returned via the
- pointer "num_read". "num_read" will equal "num" unless an error (specified
- below) occurs; in this case, it may be zero to num-1. This routine can be
- called only if the specified channel is a "variable channel", that is one
- opened via open_var_channel.
- Returned value:
- If there are no errors, the returned value indicates the current file
- position (the sample number of the next sample to be read by read_variable).
- A valid sample number is 1 or greater. If an error occurs, the value is < 0.
- The following errors are detected:
- - error during the file read operation
- - EOF encountered on the data file
- - channel number is outside valid range
- - specified channel is not open
- - this routine is for use only with variable channel types
- */
- read_variable ( channel, values, n, n_read )
- int channel, n, *n_read;
- char values[];
- {
- int bytes, b_read, s_read;
- strcpy(ervar.routine, "read_variable");
- strcpy(ervar.name, "UNKNOWN"); /* the first 2 errors have no f or v name */
- *n_read = 0; /* set number read in case of an early error */
- /*
- * do the easy error checking:
- */
- if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-3);
- return(-3);
- }
- if (fd[channel].open != 1) /* channel not open */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-4);
- return(-4);
- }
- strcpy(ervar.name, fd[channel].filename);
- if (fd[channel].ch_type != 1) /* not a "variable" channel */
- {
- if (auto_er) error_exit(-7);
- return(-7);
- }
- /*
- * split into two cases, 1 variable or >1 variable in file:
- */
- if (fd[channel].format[1] == 1) /* .sg_data file has only 1 variable */
- {
- bytes = bytes_in[fd[channel].format[2] -1] * n;
- b_read = read(fd[channel].fd, values, bytes);
- if (b_read == -1) /* error during read */
- {
- perror("The system call error in disk read is");
- if (auto_er) error_exit(-6);
- return(-6);
- }
- *n_read = b_read / bytes_in[fd[channel].format[2] -1];
- }
- else /* .sg_data file has several variables, the general case */
- {
- s_read = read_sg(channel, values, n);
- if (s_read == -1) /* error during read */
- {
- perror("The system call error in disk read is");
- if (auto_er) error_exit(-6);
- return(-6);
- }
- *n_read = s_read;
- }
- fd[channel].next += *n_read;
- if (*n_read != n) /* EOF encountered */
- {
- if (auto_er) error_exit(-5);
- return(-5);
- }
- return(fd[channel].next);
- }
- /* ------------------------ GOTO BLOCK ROUTINE -------------------------- */
- /* DESCRIPTION:
- position = goto_block ( chan_id, block_num, how )
- This routine changes the place from which data is read in the file
- connected to "chan_id". When 'how' is 0, 'block_num' is measured from the
- beginning of the file (i.e. absolute positioning). When 'how' is not 0,
- 'block_num' is measured from the current file position (i.e. relative
- positioning). It can be used on block channels and on variable channels.
- The first block in a file is called block 1. This routine does not return an
- error if positioned beyond the end of file; this condition is reported when
- reading.
- On block channels the repositioning is as follows:
- If doing absolute positioning, the block number read by the next read_block
- is "block_num".
- If doing relative positioning, the block number read by the next read_block
- is changed by "block_num" blocks.
- On variable channels the repositioning is as follows:
- If doing absolute positioning, the first sample read by the next
- read_variable is sample number:
- 1 + (block_num - 1) * (# of values of variable per block)
- If doing relative positioning, the first sample read by the next
- read_variable is changed by "block_num" blocks.
- Returned value:
- If there are no errors, the returned value indicates the current file
- position. On variable channels, the returned value is the sample number of the
- next sample to be read by read_variable. On block channels, the returned value
- is the block number of the next block to be read by read_block. A valid sample
- number or block number is 1 or greater. If an error occurs, the value is < 0.
- The following errors are detected:
- - channel number is outside valid range
- - specified channel is not open
- - the file connected to this channel prohibits positioning
- - effective block_num < 1
- */
- goto_block ( channel, block_num, how )
- int channel, block_num, how;
- {
- int next;
- long p;
- strcpy(ervar.routine, "goto_block");
- strcpy(ervar.name, "UNKNOWN"); /* the first 2 errors have no f or v name */
- /*
- * do the easy error checking:
- */
- if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-3);
- return(-3);
- }
- if (fd[channel].open != 1) /* channel not open */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-4);
- return(-4);
- }
- strcpy(ervar.name, fd[channel].filename);
- if (fd[channel].format[0] != 1) /* file prohibits positioning */
- {
- if (auto_er) error_exit(-9);
- return(-9);
- }
- /*
- * partition according to positioning type:
- */
- if (how == 0) /* absolute positioning */
- {
- next = (fd[channel].ch_type == 2) ? block_num :
- 1 + (block_num - 1) * fd[channel].format[2*fd[channel].v+1];
- if (next < 1) /* invalid block # */
- {
- ervar.param = block_num;
- if (auto_er) error_exit(-30);
- return(-30);
- }
- p = (block_num - 1) * fd[channel].byte_p_blk;
- lseek(fd[channel].fd, p, 0);
- /*
- * check for the general case and skip gap_head bytes, if so:
- */
- if (fd[channel].ch_type == 1 && fd[channel].format[1] > 1)
- {
- lseek(fd[channel].fd, (long) fd[channel].gap_head, 1);
- fd[channel].samp_avail = fd[channel].format[2*fd[channel].v+1];
- }
- }
- else /* relative positioning */
- {
- next = (fd[channel].ch_type == 2) ? fd[channel].next + block_num :
- fd[channel].next + block_num * fd[channel].format[2*fd[channel].v+1];
- if (next < 1) /* invalid block # */
- {
- ervar.param = (fd[channel].ch_type==2) ? next : (fd[channel].next-1) /
- fd[channel].format[2*fd[channel].v+1] + 1 + block_num;
- if (auto_er) error_exit(-30);
- return(-30);
- }
- p = block_num * fd[channel].byte_p_blk;
- lseek(fd[channel].fd, p, 1);
- }
- fd[channel].next = next;
- return(next);
- }
- /* ------------------------ READ BLOCK ROUTINE -------------------------- */
- /* DESCRIPTION:
- position = read_block ( chan_id, val_pntr )
- This routine returns one block of values from the file connected to
- channel "chan_id". "val_pntr" is an array of pointers having one element for
- each block variable. The calling routine sets each pointer in the array to
- specify where the values for each block variable are to go. Thus, val_pntr[0]
- is the address where the first value of the first block variable will be stored;
- val_pntr[1] is the address where the first value of the second block variable
- will be stored; etc. Subsequent values of the variables are stored in
- sequential locations following the address of the first value.
- Returned value:
- If there are no errors, the returned value indicates the current file
- position (the block number of the next block to be read by read_block). A
- valid block number is 1 or greater. If an error occurs, the value is < 0.
- The following errors are detected:
- - channel number is outside valid range
- - specified channel is not open
- - this routine is for use only with block channel types
- - error during the file read operation
- - EOF encountered on the data file
- */
- read_block ( channel, val_pntr )
- char *val_pntr[];
- int channel;
- {
- int i, err;
- short num_left, num_to_read;
- struct iovec {
- char *iov_base;
- int iov_length;
- };
- struct iovec io_vector[MAX_VARS_PER_BLK];
- strcpy(ervar.routine, "read_block");
- strcpy(ervar.name, "UNKNOWN"); /* the first 2 errors have no f or v name */
- /*
- * do the easy error checking:
- */
- if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-3);
- return(-3);
- }
- if (fd[channel].open != 1) /* channel not open */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-4);
- return(-4);
- }
- strcpy(ervar.name, fd[channel].filename);
- if (fd[channel].ch_type != 2) /* not a "block" channel */
- {
- if (auto_er) error_exit(-8);
- return(-8);
- }
- /*
- * write the input vector:
- */
- for (i=0; i<fd[channel].format[1]; i++)
- {
- io_vector[i].iov_base = val_pntr[i];
- io_vector[i].iov_length = fd[channel].bytes[i];
- }
- /*
- * read the block in chunks of 16 variables at a time (readv limitation):
- */
- i = 0;
- num_left = fd[channel].format[1];
- while (num_left > 0)
- {
- num_to_read = 16;
- if (num_left < 16) num_to_read = num_left;
- err = readv(fd[channel].fd, &io_vector[i], num_to_read);
- if (err == -1) /* error during read */
- {
- perror("The system call error in disk read is");
- if (auto_er) error_exit(-6);
- return(-6);
- }
- if (err == 0) /* EOF encountered */
- {
- if (auto_er) error_exit(-5);
- return(-5);
- }
- i += num_to_read;
- num_left -= num_to_read;
- }
- return(++fd[channel].next);
- }
- /* ----------------------- CLOSE CHANNEL ROUTINE ------------------------ */
- /* DESCRIPTION:
- status = close_channel ( chan_id )
- This routine closes the specified channel. Doing so makes the channel id
- available for re-assignment.
- Returned value:
- The returned value indicates the error status of the routine. If no error
- occurs, the returned value is 0. If an error occurs, the value is < 0.
- The following errors are detected:
- - channel number is outside valid range
- - specified channel is not open
- */
- close_channel ( channel )
- int channel;
- {
- strcpy(ervar.routine, "close_channel");
- strcpy(ervar.name, "UNKNOWN"); /* the first 2 errors have no f or v name */
- if (channel < 0 || channel >= MAX_CHANNELS) /* bogus channel # */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-3);
- return(-3);
- }
- if (fd[channel].open != 1) /* channel not open */
- {
- ervar.param = channel;
- if (auto_er) error_exit(-4);
- return(-4);
- }
- fd[channel].open = 0;
- close (fd[channel].fd);
- return(0);
- }
- /* ------------------- PRINT DISK READ ERROR ROUTINE -------------------- */
- /* DESCRIPTION:
- print_disk_read_error ( err_num )
- This routine prints an error message which corresponds to "err_num".
- It is printed on stderr.
- */
- print_disk_read_error ( err_num )
- int err_num;
- {
- char *disk_read_error ();
- if (err_num < 0)
- {
- fprintf(stderr, "Disk_IO error in routine '%s'.n", ervar.routine);
- fprintf(stderr, "The filename or variable name associated with the offending call is:n");
- fprintf(stderr, "%sn", ervar.name);
- fprintf(stderr, disk_read_error(err_num) );
- if (ervar.param != PARAM_OK)
- {
- fprintf(stderr, "Its value was: %dn", ervar.param);
- ervar.param = PARAM_OK;
- }
- }
- else fprintf(stderr, disk_read_error(err_num) );
- return;
- }
- /* ---------------------- DISK READ ERROR ROUTINE ----------------------- */
- /* DESCRIPTION:
- error_string = disk_read_error ( err_num )
- The disk_read_error routine returns a brief error message which
- corresponds to "err_num".
- */
- char *disk_read_error ( err_num )
- int err_num;
- {
- static char err_string[70];
- static char *err_msg[] = {
- "No error", /* 0 */
- /*
- * COMMON ERRORS:
- */
- "unassigned", /* 1 */
- "Filename is too long", /* 2 */
- "Channel number is outside valid range", /* 3 */
- "Specified channel is not open", /* 4 */
- "EOF encountered on the data file", /* 5 */
- "Error during the file read operation", /* 6 */
- "This routine is for use only with variable channel types", /* 7 */
- "This routine is for use only with block channel types", /* 8 */
- "The file connected to this channel prohibits positioning", /* 9 */
- "Invalid extension in filename", /* 10 */
- "unassigned", /* 11 */
- /*
- * OPEN CHANNEL ERRORS:
- */
- "There is a format file problem", /* 12 */
- "The data file could not be opened", /* 13 */
- "All channels are open", /* 14 */
- "The specified variable was not found", /* 15 */
- "No data file found", /* 16 */
- "unassigned", /* 17 */
- "unassigned", /* 18 */
- /*
- * READ FORMAT ERRORS:
- */
- "The format file could not be opened", /* 19 */
- "The format file is not complete", /* 20 */
- "Invalid value read for file type", /* 21 */
- "Invalid value read for variables/block", /* 22 */
- "Invalid value read for data type", /* 23 */
- "Invalid value read for values/block", /* 24 */
- "No data file found, so can't determine format", /* 25 */
- /*
- * FILE LENGTH ERRORS:
- */
- "unassigned", /* 26 */
- /*
- * GOTO SAMPLE ERRORS:
- */
- "Effective sample_num is < 1", /* 27 */
- "unassigned", /* 28 */
- /*
- * READ VARIABLE ERRORS:
- */
- "unassigned", /* 29 */
- /*
- * GOTO BLOCK ERRORS:
- */
- "Effective block_num is < 1", /* 30 */
- "unassigned", /* 31 */
- /*
- * READ BLOCK ERRORS:
- */
- "unassigned", /* 32 */
- /*
- * CLOSE CHANNEL ERRORS:
- */
- "unassigned", /* 33 */
- /*
- * ALL OTHER ERRORS:
- */
- "Bad value for error number" /* 34 */
- };
- #define NUM 34
- if (err_num > 0) err_num = 0; /* force positive arguments to give no error */
- strcpy(err_string, (-err_num < NUM) ? err_msg[-err_num] : err_msg[NUM] );
- strcat(err_string, ".n");
- return(err_string);
- }
- /* -------------------------- SUPPORT ROUTINES -------------------------- */
- /* ----------------------- TEST FILENAME ROUTINE ------------------------ */
- /* DESCRIPTION:
- This routine examines the filename "in_file" and returns in "out_file" the
- data file or format file name which corresponds to "in_file". "out_file_type"
- specifies whether to return the name of a data file (if 1) or the format file
- name (if 2). This is the routine which implements the filename flexibility
- which read_format and the open channel routines have.
- The return value of the function indicates the following:
- -2 - invalid extension
- -1 - data file not found
- 0 - in_file is .sg file type
- 1 - in_file is .spd file type
- ( value increases by 1 for each added data file type )
- */
- static test_filename ( in_file, out_file, out_file_type )
- char in_file[], out_file[];
- int out_file_type;
- {
- char extn[MAX_FILENAME_LENG];
- if (rindex(in_file, '.') == NULL) /* in_file does not have an extension */
- {
- strcpy(out_file, in_file);
- strcat(out_file, DFE); /* out_file = in_file.DFE */
- if (access(out_file, 0) == 0) /* out_file.DFE exists */
- {
- if (out_file_type == 2) /* output the format file name instead */
- {
- strcpy(out_file, in_file);
- strcat(out_file, FFE); /* out_file = in_file.FFE */
- }
- return(0); /* .sg file type */
- }
- strcpy(out_file, in_file);
- strcat(out_file, ".spd"); /* out_file = in_file.spd */
- if (access(out_file, 0) == 0) return(1); /* .spd file type */
- return(-1); /* could not find a data file */
- }
- else /* in_file has an extension */
- {
- strcpy(extn, rindex(in_file, '.') ); /* extn = the extension */
- strcpy(out_file, ""); /* out_file = extensionless in_file */
- strncat(out_file, in_file, strlen(in_file)-strlen(extn) );
- if (strcmp(extn, DFE) == 0) /* the extension is DFE */
- {
- if (out_file_type == 1) strcat(out_file, DFE);
- if (out_file_type == 2) strcat(out_file, FFE);
- return(0); /* .sg file type */
- }
- if (strcmp(extn, FFE) == 0) /* the extension is FFE */
- {
- if (out_file_type == 1) return(-2);
- if (out_file_type == 2) strcat(out_file, FFE);
- return(0); /* .sg file type */
- }
- if (strcmp(extn, ".spd") == 0) /* the extension is .spd */
- {
- strcpy(out_file, in_file);
- return(1); /* .spd file type */
- }
- return(-2); /* invalid extension */
- }
- }
- /* ----------------------- READ SUNGRAPH DATA FILE ---------------------- */
- /* DESCRIPTION:
- This routine is like "read" but instead reads data files which are in the
- SUNGRAPH format. It operates with channels opened for single variable access.
- It fetches the next "samp" samples of the variable that "channel" was opened to
- read. The function value is the actual number of samples read, unless "read"
- or "lseek" returns -1, in which case -1 is the function value.
- */
- static read_sg ( channel, values, samp )
- char values[];
- int channel, samp;
- {
- register int bytes_per_samp, index, left;
- int n, bytes, total;
- total = 0;
- index = 0;
- left = samp;
- bytes_per_samp = bytes_in[fd[channel].format[2*fd[channel].v] -1];
- while (left > 0)
- {
- if (left >= fd[channel].samp_avail) /* read to end of current block */
- {
- bytes = bytes_per_samp * fd[channel].samp_avail;
- n = read(fd[channel].fd, &values[index], bytes);
- if (n == -1) return(-1); /* read error */
- if (n != bytes) /* EOF reached */
- {
- fd[channel].samp_avail -= n / bytes_per_samp;
- return(total + n/bytes_per_samp);
- }
- total += fd[channel].samp_avail;
- left -= fd[channel].samp_avail;
- index += bytes;
- lseek(fd[channel].fd, (long) fd[channel].gap_total, 1);
- fd[channel].samp_avail = fd[channel].format[2*fd[channel].v + 1];
- }
- else /* read just the number of samples left to fetch for this call */
- {
- bytes = bytes_per_samp * left;
- n = read(fd[channel].fd, &values[index], bytes);
- if (n == -1) return(-1); /* read error */
- if (n != bytes) /* EOF reached */
- {
- fd[channel].samp_avail -= n / bytes_per_samp;
- return(total + n/bytes_per_samp);
- }
- total += left;
- fd[channel].samp_avail -= left;
- left = 0;
- }
- }
- return(total);
- }
- /* ----------------------------- ERROR_EXIT ----------------------------- */
- static error_exit(err_num)
- int err_num;
- {
- print_disk_read_error(err_num);
- exit(-1);
- }