/* @(#)osa.c 17.1.1.1 (ES0-DMD) 01/25/02 17:35:24 */ /*=========================================================================== 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 osa .LANGUAGE C .AUTHOR IPG-ESO Garching .CATEGORY Host operating system interfaces. Record i/o on disk files. .ENVIRONMENT VAX / VMS .COMMENTS Handling of RECORD io's. All files are referenced by the physical name in the open function. A file identifier (number) is returned by open functions to be used in later i/o operations. \begin{TeX} The routines return always a non-negative integer number on successful return. Otherwise, a value of -1 is set to indicate an error condition or the End of File; the variable ``oserror'' contains the numeric error code ($0$ for EOF), which can be converted to a character pointer via osmsg routine. Access to permanent (terminal) files ia made via QIO's. \end{TeX} .VERSION 0.0 25-Aug-1986 Definition J. D. Ponz .VERSION 1.6 22-Oct-1987 Written for VMS. Merge with UNIX. Tested on Ultrix. (F. Ochsenbein) .VERSION 2.0 13-Oct-1988 Compatibility. .VERSION 2.1 24-Aug-1990 Small simplifications. (F. Ochsenbein) ------------------------------------------------------------*/ #define DEBUG 0 #include #include #include #include #include /* System */ #include /* System */ # define fab$l_fna name # define fab$b_fns lname # define rab$l_ctx last_op /* 1 if $FIND */ # define fab$l_ctx file_no #include /* System */ #include /* System */ #include /* System */ MID_EXTERN vmserror; /* VMS-specific error code */ MID_EXTERN int oserror; MID_EXTERN char *oserrmsg; #define FINISH goto FIN /* Variables shared in local subroutines */ static struct FAB *fap; static struct XABFHC *fhp; static struct RAB *fp; static int TheFile = 0; static unsigned short old_rfa[3]; /* record's file address */ static unsigned short chan; #define pos_to_rfa(pos) fp->rab$w_rfa[2] = pos % fap->fab$w_bls,\ *(long *)(fp->rab$w_rfa) = 1 + pos / fap->fab$w_bls struct RAB *vmsrab(); long vmsize(); /**************************** * General Utility Routines * ****************************/ /*==========================================================================*/ static int getfile(fid) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Retrieves the file pointer. .RETURNS Number of file; the static fp (file pointer) is also defined. ------------------------------------------------------------*/ int fid; /* IN : file identifier */ { if (!(fp = vmsrab(fid))) FINISH; fap = fp->rab$l_fab; fhp = (struct XABFHC *)(fap->fab$l_xab); TheFile = fap->file_no; if (fp->rab$l_ctx == 0xffffffff) chan = fp->rab$w_isi; else chan = 0; FIN: return ( oserror ? -1 : fid ); } /*========================================================================== Routines dealing with VMS record-oriented i/o *==========================================================================*/ /*==========================================================================*/ static int vmsget(pbuf, nochar) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Interface to SYS$GET .RETURNS Number of characters of the record / -1 for error ------------------------------------------------------------*/ char *pbuf; /* IN : pointer to i/o buffer */ long nochar; /* IN : number of i/o characters */ { register int len; short ba[3]; fp->rab$l_ubf = pbuf, fp->rab$w_usz = nochar; ba[0] = fp->rab$w_rfa[0], ba[1] = fp->rab$w_rfa[1], ba[2] = fp->rab$w_rfa[2]; vmserror = SYS$GET(fp); fp->last_op &= ~1; /* Last operation is NOT a find */ switch(vmserror) { case RMS$_NORMAL: len = fp->rab$w_rsz; /* Length of read block */ break; case RMS$_EOF: len = -1; fp->rab$b_rac = RAB$C_SEQ; fp->rab$w_rfa[0] = ba[0], fp->rab$w_rfa[1] = ba[1], fp->rab$w_rfa[2] = ba[2]; break; case RMS$_RTB: len = fp->rab$l_stv; /* Actual Record Length */ break; default: len = -1; oserror = EIO; FINISH; } if (fp->rab$b_rac == RAB$C_RFA) /* Set RFA to NEXT record */ { fp->rab$b_rac = RAB$C_SEQ; /* Random access: Must modify RFA */ if (fap->fab$b_fac & FAB$M_PUT) if (SYS$FIND(fp) &1) fp->rab$b_rac = RAB$C_RFA, fp->last_op |= 1; } FIN: return(len); /* Length of read block */ } /*==========================================================================*/ static int toeof(pos) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Positions the file to END. .RETURNS Upon successful completion, the file size measured in characters, or -1 on error. .REMARKS The position is the one of the NEXT record. .METHOD SYS$FIND on sequential, then SYS$FIND on random access. ------------------------------------------------------------*/ long pos; /* IN: The EOF position */ { if ((fap->fab$b_fac & FAB$M_PUT) && ((fp->rab$l_rop & RAB$M_EOF) == 0)) { SYS$FLUSH(fp); SYS$DISCONNECT(fp); fp->rab$l_rop |= RAB$M_EOF; SYS$CONNECT(fp); fp->rab$b_rac = RAB$C_SEQ; } else fp->rab$b_rac = RAB$C_RFA; pos_to_rfa(pos); return(0); } /*==========================================================================*/ static long vmstell() /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Computes the current byte position in the file. .RETURNS Upon successful completion, the resulting pointer position measured in characters, or -1 on error. .REMARKS The position is the one of the NEXT record. .METHOD SYS$FIND on sequential, then SYS$FIND on random access. ------------------------------------------------------------*/ { long pos; if (*(long *)(fp->rab$w_rfa) == 0) return(0); if ((fp->rab$b_rac == RAB$C_SEQ) && !(fp->last_op & 1)) { vmserror = SYS$FIND(fp); /* Tells position of NEXT record */ if (vmserror&1) /* Randomly resets the pointer */ fp->last_op |= 1; } else vmserror = RMS$_NORMAL; switch(vmserror) { case RMS$_EOF: pos = vmsize(TheFile); pos_to_rfa(pos); break; case RMS$_NORMAL: pos = (*(long *)(fp->rab$w_rfa))-1; pos = pos * fap->fab$w_bls + fp->rab$w_rfa[2]; break; default: oserror = ESPIPE; break; } FIN: return(oserror ? -1 : pos); } /*==========================================================================*/ static int vmsput(pbuf, nochar) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Interface to SYS$PUT .RETURNS Number of characters actually written. -1 is returned in case of error (error in oserror). .REMARKS Use SYS$UPDATE service to write in the middle of a file... ------------------------------------------------------------*/ char *pbuf; /* IN : pointer to i/o buffer */ long nochar; /* IN : number of i/o characters */ { register int len; #if DEBUG printf("rfm is %d, rat is %d\n", fap->fab$b_rfm, fap->fab$b_rat); #endif len = nochar; if (fp->rab$b_rac == RAB$C_RFA) /* Put within the file */ { switch(vmserror = SYS$FIND(fp)) { case RMS$_EOF: toeof(vmsize(TheFile)); goto Append; case RMS$_NORMAL: break; default: FINISH; } fp->rab$l_rbf = pbuf, fp->rab$w_rsz = nochar; vmserror = SYS$UPDATE(fp); if (vmserror&1) /* This updates the RFA to NEXT record */ { fp->rab$b_rac = RAB$C_SEQ; if (SYS$FIND(fp) &1) fp->rab$b_rac = RAB$C_RFA, fp->last_op |= 1; } FINISH; } Append: fp->rab$l_rbf = pbuf, fp->rab$w_rsz = nochar; vmserror = SYS$PUT(fp); FIN: if (!(vmserror&1)) oserror = EIO; return(oserror ? -1 : len); } /*==========================================================================*/ static long vmsseek(address, mode) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE moves read/write pointer to text file. The address defines the pointer position in characters relative to: start of the file, current position or end of the file as defined by the variable mode (FILE_START, FILE_CURRENT, FILE_END). .RETURNS Upon successful completion, the resulting pointer position measured in characters is returned or -1 on error. .REMARKS use of File Record Address ------------------------------------------------------------*/ long address; /* IN : offset to seek to */ int mode; /* IN : mode of addressing */ { register long pos; switch (mode) { case FILE_CURRENT : /* seek to file_current + address */ pos = vmstell(); if (address == 0) FINISH; pos += address; /* Absolute address, continue */ break; case FILE_START : /* seek to file_start + address */ pos = address; break; case FILE_END : /* seek to file_end + address */ pos = vmsize(TheFile) + address; break; default: oserror = EINVAL; break; } if (oserror) FINISH; /* Convert now pos to RFA (Record File Address), and find this * record ... */ pos_to_rfa(pos); fp->rab$b_rac = RAB$C_RFA; /* First seek randomly... */ vmserror = SYS$FIND(fp); if (vmserror & 1) fp->last_op |= 1; /* Last operation = $FIND */ FIN: fp->rab$l_rop &= ~RAB$M_EOF; /* We're not any more at EOF */ /* Note: RMS apparently provides an EOF message when * the RFA is bad... Let's assume that we go to EOF. */ switch(vmserror) { case RMS$_EOF: pos = vmsize(TheFile); toeof(pos); break; default: oserror = ESPIPE; break; case RMS$_NORMAL: case 0: break; } return( ( oserror ? -1 : pos)); } /************************ * OSA Routines * ************************/ /*==========================================================================*/ int osaopen(phname, mode) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Opens disk file for read or write, and positions at file beginning (at end for APPEND mode). The variable `mode' defines the way of opening the file as READ_ONLY, WRITE_ONLY, READ_WRITE and APPEND. (see midas/osparms.h). .RETURNS Upon successful completion a file descriptor is returned. -1 is returned on error. .REMARKS File is opened with buffering. The mode is a combination of the following options (defined is osparms): \begin{TeX} \begin{itemize} \item {\em READ WRITE READ\_WRITE APPEND} \item {\em NOATTR} (record without attributes, i.e. without linefeed) \end{itemize} The routine {\em osfop}, if called before {\em osaopen}, allows to create non STMLF--format files. \end{TeX} ------------------------------------------------------------*/ char *phname; /* IN : physical filename */ int mode; /* IN : open mode (see remarks) */ { register int i; i = vmsopen(phname, mode); /* Call system-dependent part */ if ((i > 0) && ((mode&3) == READ_WRITE)) { getfile(i); if (SYS$FIND(fp) &1) fp->rab$b_rac = RAB$C_RFA, fp->last_op |= 1; } return( i); } /*==========================================================================*/ int osaclose(fid) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Closes a disk file. The argument fid is the file identification obtained from osdopen. .RETURNS 0 (success) / -1 (failure) .REMARKS ------------------------------------------------------------*/ int fid; /* IN : file identifier */ { oserror = 0; vmsclose(fid); return(oserror ? -1 : 0); } /*==========================================================================*/ int osawait(fid) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Force the physical writing on disk of modified buffers. The argument fid is the file identification obtained from osdopen. .RETURNS 0 (success) / -1 (failure) .REMARKS ------------------------------------------------------------*/ int fid; /* IN : file identifier */ { if (getfile(fid) < 0) FINISH; if (chan) FINISH; vmserror = SYS$FLUSH(fp); if (!(vmserror&1)) oserror = EIO; FIN: return(oserror ? -1 : 0); } /*==========================================================================*/ int osaread(fid, pbuf, nochar) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Synchronous RECORD read from disk file. The argument fid is the file identification obtained from osdopen. The routine reads 1 record from the current file position and stores up to nochar characters into the buffer pointed by pbuf. If the buffer is too small, the remainder of the record is IGNORED, BUT the function returns the actual record size. The end-of-record character is never returned, but replaced with the end-of-string character. The buffer returned is always null terminated. .RETURNS --- Number of characters actually read, excluding the end-of-string terminator (e.g. 0 for an empty record). This number may be larger than (nobuf-1) in case of truncation. --- -1 if an error is encountered or if the end of file is reached. In case of error, oserror is set to the relevant error number; oserror is set to 0 in case of EOF. .REMARKS ------------------------------------------------------------*/ int fid; /* IN : file identifier */ char *pbuf; /* OUT : pointer to i/o buffer */ unsigned int nochar; /* IN : size of buffer */ { register int len; len = 0; if (nochar < 2) FINISH; if (getfile(fid) < 0) FINISH; if (chan) len = vmsrlb(chan, pbuf, nochar-1); else len = vmsget(pbuf, nochar-1); if (len < 0) FINISH; *(pbuf + MIN(len,nochar-1)) = EOS; FIN: return(oserror ? -1 : len); } /*==========================================================================*/ int osawrite(fid, pbuf, nochar) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Synchronous write to a file a string of characters followed by a newline (end of record). The argument fid is the file identification obtained from osdopen. .RETURNS Number of characters actually written -1 for error (oserror provides an explanation) .REMARKS ------------------------------------------------------------*/ int fid; /* IN : file identifier */ char *pbuf; /* IN : EOS-terminated string to write */ unsigned int nochar; /* IN : Number of bytes to write */ { register char *p; register int i; if (getfile(fid) < 0) FINISH; i = nochar; if (i == 0) FINISH; p = pbuf + i - 1; /* Suppress last linefeed */ if (chan) { /* Output via QIO */ i = vmsqio(chan, IO$_WRITELBLK, pbuf, i, 0); if (*p == '\n') i += vmsqio(chan, IO$_WRITELBLK, "\r", 1, 0); } else { if (*(p) == '\n') i--; i = vmsput(pbuf, i); } FIN: return(oserror ? -1 : i); } /*==========================================================================*/ long osaseek(fid, address, mode) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Moves read/write pointer to a specified byte position. Bytes are numbered from 0 at the file beginning. The address is a displacement in BYTES from start of the file, current position or end of the file as defined by the variable mode (FILE_START, FILE_CURRENT, FILE_END). The argument fid is the file identification obtained from osdopen. .RETURNS Upon successful completion, the resulting sector number; -1 on error (oserror explains the error). .REMARKS ------------------------------------------------------------*/ int fid; /* IN : file identifier */ long address; /* IN : Move in bytes */ int mode; /* IN : mode of addressing */ { register int i; register long pos; if (getfile(fid) < 0) FINISH; if (chan) oserror = ESPIPE; else pos = vmsseek(address, mode); FIN: return(oserror ? -1 : pos); } /*==========================================================================*/ long osasize(fid) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Tells the size of an opened file without moving the file pointer. .RETURNS Upon successful completion, the file size; -1 on error (oserror explains the error). .REMARKS ------------------------------------------------------------*/ int fid; /* IN : file identifier */ { return(vmsize(fid)); } /*==========================================================================*/ int osaunix(fid) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Tells if the opened file is Unix-compatible .RETURNS 0 if non-unix, 1 if Unix, -1 on error (oserror explains the error). .REMARKS VMS only ------------------------------------------------------------*/ int fid; /* IN : file identifier */ { register int isunix; if (getfile(fid) < 0) return(-1); return(fap->fab$b_rfm == FAB$C_STMLF ? 1 : 0); }