/* @(#)file.c 17.1.1.1 (ES0-DMD) 01/25/02 17:47:37 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .NAME file.c .LANGUAGE C .AUTHOR Alan Richmond [ST-ECF], Francois Ochsenbein [ESO-IPG] .CATEGORY Interface to disk file access .ENVIRONMENT .COMMENTS To improve file handling independance. The UNIX i/o functions are used; for output, creat generates standard C (i.e. byte stream) files. \begin{TeX} The basic operations are performed by means of \begin{itemize} \item fi\_open(filename,mode) to open a file, with mode values defined in \item fi\_close to close a file \item fi\_name to retrieve the name of a file \item fi\_load to load efficiently ascii text from a file \item fi\_seek to position to a specified byte position (from the file beginning, end, or current position) \item fi\_tell to return the current byte location within a file. \item to read records, use \begin{itemize} \item fi\_read reads a specified amount of bytes \item fi\_gets reads a record, terminating the record with an EOS; a returned status indicates if a full record was read \end{itemize} \item to write records, use \begin{itemize} \item fi\_write writes a specified amount of bytes \item fi\_put writes an EOS-terminated ASCII string \item fi\_puts writes a record (the EOS terminator is replaced by an EOL character) \end{itemize} \end{itemize} \end{TeX} .VERSION 1.0 Creation Alan Richmond .VERSION 2.0 01-Aug-1986: VMS dependancies are grouped within #if VMS blocks. Buffering is used for byte stream files. .VERSION 2.1 30-Sep-1986: Be sure that the last character is not lost, even on VMS-files. .VERSION 2.2 16-Dec-1986: Defined internal functions as static .VERSION 2.3 17-Feb-1987: Added fi_wopen .VERSION 3.0 13-Oct-1988: Use os interfaces .VERSION 3.1 07-Dec-1988: Re-added fi_wopen... .VERSION 3.2 20-Jun-1989: Translate file name before Open .VERSION 3.3 20-Nov-1989: Be sure that fi_load ends with EOS. .VERSION 3.4 14-Dec-1989: Removed buf in fi_close when file is 0, 1 , 2 -------------------------------------------------------------*/ #define PM_LEVEL LEVEL_FI /* The Monitoring level for this file */ #define DEBUG 0 /* Debugging option */ #include #include #include #include #include #include #include #define _NFILES_ 32 /* Maximal number of Files */ static char opened_mode[_NFILES_] = {0,0,0,0}; static char *filenames [_NFILES_] = {"stdin", "stdout", "stderr"}; static int mode; char *osmsg(); #define set_mode(f) mode = (f>=0 && f < _NFILES_ ? opened_mode[f] : 0); #define FINISH goto FIN /*======================================================================*/ static char *save (name) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Copy the filename to a new piece of memory .RETURNS Address of name -------------------------------------------------------------*/ char *name; /* IN: File name */ { char *p, *mm_alloc(); int l; l = strlen(name) + 1; if (p = mm_alloc(l)) oscopy(p, name, l); return(p); } /*======================================================================*/ static int fi_error (msg, fid) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Write error message. .RETURNS 0 -------------------------------------------------------------*/ char *msg; /* IN: Message associated */ int fid; /* IN: File Identification */ { if ( (fid < 0) || (fid > _NFILES_) || (!filenames[fid])) ERR_ED_I(msg, fid); else ERR_ED_STRING(msg, filenames[fid]); return(0); } /*======================================================================*/ int fi_wopen (name) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Open file for special output mode (Variable) .RETURNS File number, or NOK if error .REMARKS Mode is variable-length, max = 2048 bytes. Useless on Unix. -----------*/ char *name; /* IN: File name */ { osfop('V', 2048); return(fi_open(name,WRITE|RECORD_MODE)); } /*======================================================================*/ int fi_open (name, mode) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Open file for specified access mode. .RETURNS File number, or NOK if error .REMARKS Mode may include the optional parameter RECORD_MODE. generating variable-length files on VMS. -----------*/ char *name; /* IN: File name */ int mode; /* IN: Access mode 0, 1 or 2 */ { static char trace[] = "Open file[I ] "; static char mop[4] = {'I', 'O', 'M', 'A'}; int status, rec_mode; char *phname; ENTER("fi_open"); status = NOK; if (name) { trace[10] = mop[mode&3]; rec_mode = mode & RECORD_MODE; trace[11] = (rec_mode ? 'R' : ' '); TRACE_ED_STRING(trace,name); status = mode & ~RECORD_MODE; phname = osftr(name); /* Physical Name */ status = (rec_mode ? osaopen(phname, status) : osdopen(phname, status) ); if (status < 0) ERR_ED_STRING(osmsg(), name), status = NOK; else if (status < _NFILES_) opened_mode[status] = (mode & RECORD_MODE ? 1 : 0), filenames[status] = save(name); } else ERROR("Invalid File Name (NULL)"); EXIT(status); } /*======================================================================*/ long fi_seek (file, offset, direction) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Set file position. .RETURNS New byte position, or EOF (impossible) .REMARKS See osdseek. -------------------------------------------------------------*/ int file; /* IN: File number */ long offset; /* IN: byte offset */ int direction; /* IN: FILE_START, FILE_CURRENT, FILE_END */ { register long pos; ENTER(".fi_seek"); set_mode(file); pos = ( mode ? osaseek(file,offset,direction) : osdseek(file,offset,direction) ); if (pos == -1) fi_error(osmsg(), file); EXITl ( pos ); } /*======================================================================*/ int fi_load (name, offset, buf, nbytes) /*++++++++++ .PURPOSE Load the ascii file `name', starting at position `offset', up to nbytes. .RETURNS Actual number of bytes read (0 for error) .REMARKS The most efficient way to load the file is used. -----------*/ char *name; /* IN: File name */ long offset; /* IN: Where to start the reading */ char *buf; /* OUT: Buffer to get read bytes */ unsigned int nbytes; /* IN: Size of buffer */ { int status, fid; char *p, *pe; ENTER("+fi_load"); p = buf, pe = buf + nbytes; *p = EOS; status = osfunix(name); if_not(fid = fi_open(name, (status ? READ : READ|RECORD_MODE))) FINISH; fi_seek(fid, offset, FILE_START); if (status) /* Unix file */ { status = fi_read(fid, p, pe-p); if (status > 0) p += status; } else /* Use Record Mode */ { while (p < pe) { status = osaread(fid, p, pe-p); if (status < 0) break; p += status; if (p < pe) *(p++) = '\n'; } if (p > pe) p = pe; } status = p - buf; if (status < nbytes) *p = EOS; fi_close(fid); FIN: EXIT(status); } /*======================================================================*/ int fi_close (file) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Close file. .RETURNS NOK if failure, OK otherwise .REMARKS See close. -------------------------------------------------------------*/ int file; /* IN: File number */ { int status; ENTER("fi_close"); set_mode(file); status = ( mode ? osaclose(file) : osdclose(file)); if (status<0) fi_error(osmsg(), file), status = NOK; else if (file > 2) mm_free(filenames[file]), status = OK, filenames[file] = NULL_PTR(char); EXIT(status); } /*======================================================================*/ char *fi_name (file) /*++++++++++++++++ .PURPOSE Retrieve name of an opened file .RETURNS Address of name (NULL if not opened) .REMARKS Not traced. ------------------*/ int file; /* IN: File number */ { char *p; if ((file >= 0) && (file < _NFILES_)) p = filenames[file]; else p = NULL_PTR(char); return(p); } /*======================================================================*/ int fi_read (file, record, nbytes) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Read up to nbytes from a file. .RETURNS Actual number of bytes read, or EOF / NOK (error) .REMARKS File must have been opened without RECORD_MODE option. -------------------------------------------------------------*/ int file; /* IN: File number */ char *record; /* OUT: record buffer */ unsigned int nbytes; /* IN: size of buffer */ { int lrec; ENTER("+fi_read"); set_mode(file); lrec = NOK; if(mode) /* Was opened with RECORD_MODE */ lrec = osaread(file, record, nbytes); else lrec = osdread(file, record, nbytes); if ((lrec == -1) && (*osmsg())) fi_error(osmsg(), file); EXIT (lrec); } /*======================================================================*/ int fi_write (file, record, nbytes) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Write nbytes to file. .RETURNS Number of bytes actually written, or NOK for errors .REMARKS -------------------------------------------------------------*/ int file; /* IN: File number */ char *record; /* IN: record buffer */ unsigned int nbytes; /* IN: size of buffer */ { int status; ENTER("+fi_write"); set_mode(file); status = (mode ? osawrite(file,record,nbytes) : osdwrite(file,record,nbytes) ); if (status<0) fi_error(osmsg(), file), status = NOK; else status = OK; EXIT (status); } /*======================================================================*/ long fi_tell (file) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Tells the current file position .RETURNS Byte position, or EOF (impossible) .REMARKS -------------------------------------------------------------*/ int file; /* IN: File number */ { return(fi_seek(file, 0L, FILE_CURRENT)); } /*======================================================================*/ int fi_gets (file, record, nbytes) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Read a record from a file, with insertion of EOS .RETURNS OK if buffer large enough, EOF (end of file), NOK if record larger than nbytes or an error occured. .REMARKS Record is always terminated by EOS; if record is larger than nbytes, the remainder is ignored. The file muast have been opened with RECORD_MODE option. -------------------------------------------------------------*/ int file; /* IN: File number */ char *record; /* OUT: record buffer */ unsigned int nbytes; /* IN: size of buffer */ { register int lrec; ENTER("fi_gets"); set_mode(file); lrec = NOK; if ((!mode) && file) /* Not an error for stdin */ fi_error("File was not opened with RECORD_MODE: ", file); else { lrec = osaread(file, record, nbytes); if (lrec >= 0) { lrec = (lrec >= nbytes ? NOK : OK); TRACE(record); } else if (*osmsg()) lrec = NOK, fi_error(osmsg(), file); } EXIT(lrec); } /*======================================================================*/ int fi_put (file, record) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Write an EOS-terminated string (without adding EOL indicator) .RETURNS OK if all bytes written, NOK if only a part of record was written or an error occured. .REMARKS The string must be terminated with EOL followed by EOS for writing a complete record (or use fi_puts function) -------------------------------------------------------------*/ int file; /* IN: File number */ char *record; /* IN: EOS-terminated record buffer */ { int length, status; ENTER("fi_put"); TRACE(record); length = strlen(record); status = ( fi_write(file,record,length) == length ? OK : NOK); EXIT (status); } /*======================================================================*/ int fi_puts (file, record) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Write up an EOS-terminated string as a new record .RETURNS OK if all bytes written, NOK if part of record is written or an error occured. .REMARKS -------------------------------------------------------------*/ int file; /* IN: File number */ char *record; /* IN: EOS-terminated record buffer */ { int status; ENTER("fi_puts"); TRACE(record); set_mode(file); status = ( mode ? osaput(file,record) : osdputs(file,record)); if (status < 0) fi_error(osmsg(), file), status = NOK; else status = OK; EXIT (status); } /*======================================================================*/ int fi_flush (file) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Flush (ensure that buffers are copied to disk) .RETURNS OK / NOK .REMARKS -------------------------------------------------------------*/ int file; /* IN: File number */ { int status; ENTER("fi_flush"); set_mode(file); status = ( mode ? osaflush(file) : osdflush(file)); if (status < 0) fi_error(osmsg(), file), status = NOK; else status = OK; EXIT (status); }