/* C K V F I O object module transfer */ /********************************************************************** * * * IVS / MCS-Kermit REL 2 * * source code * * * * Change History: * * * * 1. Modify C-Kermit(4E) source code to * * produce new module for MCS/IVS-Kermit * * ORIGINAL RELEASE * * June 22, 1990 * * * * * ***********************************************************************/ /* update May 10, 1990 PEG Modified error handling to reflect changes to other modules to use errhdlr() update May 23, 1990 OBJECT FILE message flawed PEG VKOFIO - Object file I/O for VKERMIT. This module interfaces to and does buffering for VRX/E object files. In order for object file transfer to work, the file type must be set to binary for both sides of the kermit file transfer. No translation of CR or LF can be allowed. Vkermit can only receive and create object files which have been sent previously by vkermit. It cannot handle object files transferred to the remote system by some other means. Nor is the format of a vkermit sent object file suitable for ANY use other than being transferred back to a VRX system by vkermit. FCL is necessary to properly open the object file. The default file reference name is OBJFILE. The VRX file type must be set to object and the record size must be set to 1/490. The following routines are to be called by the ckufio module when it detects that a VRX object file is being transported. voopeni - to open an object file for input (download) Called by zopeni. voopeno - to open an object file for output (upload) Called by zopeno. vogetc - to get the next character from a VRX object file. Called by zchin. voputc - to put the next character to a vrx object. Called by zchout. voclose - to close a VRX object file. Called by zclose. This module contains data structures to buffer the characters and keep track of the object file(s) currently open. In this implementation, there is only one VRX object file open at a time. Since VRX object files are variable length, a two byte VLI is prepended to each data record. This module creates the VLI for downloading and interprets the VLI for uploading. The rest of kermit does not even know these VLIs are there and treats them as data. Since binary file type transfer is being used, the non-ASCII nature of these VLIs is unimportant. Using VLIs as part of the data stream is the only way to recreate the object file on VRX. Object files must be written with variable length records. When an object file is written, the VLI is stripped off of the buffer and the rest of the buffer is written as the record. The implicit length of the string determines the record size and VRX file management takes care of the internals necessary for variable length records. Although buffering is done by this module, the actual I/O's are done by a separate module written in NCRL which uses NCRL IO. */ #include #include "ckcker.h" /* March 2, 1990 */ #include /* * Constants used by this module */ /* * Errors returned by NCRL I/O service routines */ #define NIOOK 0 #define NIOBAD 1 #define NIOEOF 2 /* * Sizes of various structures and strings */ #define LEGRECSIZ 200 /* The size of the NCRL legible type */ /* Actual size is probably less - e.g. 134 bytes on 4-85, but the size is not guaranteed to remain constant from release to release. */ #define MAXOBJDAT 490 /* Max size of object record data */ #define REFSIZ 31 /* Standard size for VRX file reference */ #define OBJREFSIZ 7 /* Size of default reference name */ #define VLISIZE 2 /* The size of the added VLIs */ #define MAXOBJREC MAXOBJDAT+VLISIZE /* The maximum size of the buffer used for objects including the vli * / /* dummy type for access() */ #define file_EXIST 0 /* * Types declared for this module */ /* legible - This is an NCRL type used for I/O. */ typedef char legible[LEGRECSIZ]; /* objrec - This type allows access of the buffer as a string and also direct reference of the VLI and data portions of the buffer. The NCRL IO routines actually fill in the VLI and data, but this module must have access of the number of bytes in order to determine when a new record must be read or written. */ typedef union objrec { char buffer[MAXOBJREC]; struct { short vli; /* does not include size of the vli itself */ /* must be on a two byte boundary */ char data[MAXOBJREC - VLISIZE]; } vlianddata; }; /* * This series of types is declared so that variable length strings can be passed to an NCRL routine. A NCRL string consists of a four byte length indicator and a pointer to the text of the string. The C strings passed as parameters must be translated into this form in order for NCRL IO to work properly. NCRLptr - a definition of NCRL's 3 byte pointers. ptr_param - a definition of the 4 byte pointer format of NCRL pointers used when passing pointers as parameters (the first byte is ignored as serves only to align the pointer). c2vrx_ptr - a union constructs that allows casting of integers into the four byte pointer format. ncrl_string - a definition of NCRL variable strings as a four byte length and a four byte pointer. */ struct NCRLptr { char byte1; char byte2; char byte3; }; struct ptr_param { char zero_fill; struct NCRLptr ptr; }; union c2vrx_ptr { int *int_ptr; struct ptr_param ncr_ptr; }; struct ncrl_string { int len; union c2vrx_ptr ptr; }; /* * Global variables - * These variables are directly referenced only be this module but * must retain their values until changed (if at all) by this module. */ /* objref - The default reference name. A different reference name can be passed in as part of the name parameter of the open routines. An FCL file reference must be used on the invocation of vkermit in order to open the file correctly. */ char objref[OBJREFSIZ+1] = "OBJFILE"; /* The default reference name */ union objrec buf; /* The buffer used for object IO */ struct ncrl_string buffer_string; /* The NCRL string used to pass the buffer to the NCRL IO routines (see discussion under types). */ int nBufSiz, nBufNdx; /* Current buffer size (including VLI) and current char in buffer being accessed */ legible objf; /* The object file definition structure The legible construct is filled in by the NCRL OPEN and is then used to refer to the file for all subsequent IO operations. */ /* There is only ONE object file open at a time */ /* * Declaration of all procedures in the NCRL IO service module. * This module must be compiled with COPT='-Xv' to avoid * adding an additional return parameter to these void declared * procedures. */ extern void OBJOPENI(); extern void OBJOPENO(); extern void OBJCLOSE(); extern void OBJRECIN(); /* Reads an entire object record, prepending data with a VLI. */ extern void OBJRECOUT(); /* Writes one variable record */ extern int errhdlr(); extern int access(); int ERRCELL; /* set in VKNCRLIO by bad vrxoutcome */ /* forward procedure declaration */ setupvbuf(); voopeni(n, in_name) int n; /* file number*/ char *in_name; /* voopeni - prepare for open of VRX object file by NCRL I/O refandname may be of the form "fileref(NAME=filename)" or may just contain the file name. If the complex form is present, it must be broken into its components for usage by NCRL I/O. The n parameter is the file number and is ignored since only one object file is opened at a time. Return values: 0 if open successful -1 if unsuccessful */ { char result; struct ncrl_string ncrl_name, ncrl_refname; char name[REFSIZ+1]; char refname[REFSIZ+1]; char refandname[REFSIZ+4]; char *temp; int i; /* before we go through several levels of code, parsing the final file name, etc, etc. Let's save some processing time and some nasty errors by verifying the file is present. In order for this to work the FCL reference OBJFILE must exist. Otherwise we maybe back at square one. PEG March 7, 1990 */ if (in_name != NULL) strcpy(refandname,in_name); else return(-1); if ((i = access(refandname, file_EXIST)) != 0) return(-1); if (in_name != NULL) strcpy(refandname,in_name); else return(-1); /* determine type of format of refandname and parse it */ if ((temp = strrchr(refandname, ')')) != NULL) { /* complex form */ /* eliminate final parenthesis */ temp[0] = '\0'; if ((temp = strrchr(refandname, '=')) != NULL) { /* now temp points just before file name */ temp++; strcpy(name, temp); /* continue to parse for refname */ if ((temp = strchr(refandname, '(')) != NULL) { /* eliminate first parenthesis - what is left is refname */ temp[0] = '\0'; strcpy(refname, refandname); } else { /* error! */ errhdlr("voopeni"); fprintf(stderr,"voopeni: name format1 error: %s", refandname); return(-1); } } else { /* error ! */ errhdlr("voopeni"); fprintf(stderr, "name format2 error: %s", refandname); return(-1); } } else { /* must be in simple format - use parameter as filename and use default refname */ strcpy(name, refandname); strcpy(refname, objref); } ncrl_name.len = strlen(name); ncrl_name.ptr.int_ptr = (int *) name; ncrl_refname.len = strlen(refname); ncrl_refname.ptr.int_ptr = (int *) refname; OBJOPENI(&ncrl_name, &ncrl_refname, objf, &result); if (result != NIOOK) { /* When a lousy outcome is returned from VKNCRLIO we output an error message PEG March 6, 1990 */ errhdlr("voopeni"); fprintf(stderr, "objfile (i)open failure outcome: %d\n", ERRCELL); return(-1); } setupvbuf(); return(0); } voopeno(n, in_name) int n; /* file number*/ char *in_name; /* voopeno - prepare for open of VRX object file by NCRL I/O refandname may be of the form "fileref(NAME=filename)" or may just contain the file name. If the complex form is present, it must be broken into its components for usage by NCRL I/O. The n parameter is the file number and is ignored since file numbers are not used when files are opend by NCRL IO. Return values: 0 if open successful -1 if unsuccessful */ { char result; struct ncrl_string ncrl_name, ncrl_refname; char name[REFSIZ+1]; char refname[REFSIZ+1]; char refandname[REFSIZ+1]; char *temp; if (in_name != NULL) strcpy(refandname,in_name); else return(-1); /* determine type of format of refandname and parse it */ if ((temp = strrchr(refandname, ')')) != NULL) { /* complex form */ /* eliminate final parenthesis */ temp[0] = '\0'; if ((temp = strrchr(refandname, '=')) != NULL) { /* now temp points just before file name */ temp++; strcpy(name, temp); /* continue to parse for refname */ if ((temp = strchr(refandname, '(')) != NULL) { /* eliminate first parenthesis - what is left is refname */ temp[0] = '\0'; strcpy(refname, refandname); } else { /* error! */ errhdlr("voopeno"); fprintf(stderr, "name format1 error: %s\n", refandname); return(-1); } } else { /* error ! */ errhdlr("voopeno"); fprintf(stderr, "name format2 error: %s\n", refandname); return(-1); } } else { /* must be in simple format - use parameter as filename and use default refname */ strcpy(name, refandname); strcpy(refname, objref); } ncrl_name.len = strlen(name); ncrl_name.ptr.int_ptr = (int *) name; ncrl_refname.len = strlen(refname); ncrl_refname.ptr.int_ptr = (int *) refname; OBJOPENO(&ncrl_name, &ncrl_refname, objf, &result); if (result != NIOOK) { /* When a lousy outcome is returned from VKNCRLIO we output an error message PEG March 6, 1990 */ errhdlr("voopeno"); fprintf(stderr,"object (o)file failure outcome: %d\n",ERRCELL); return(-1); } setupvbuf(); return(0); } setupvbuf() { /* SETUPVBUF - * Initialize buffer variables in preparation for IO */ buffer_string.len = MAXOBJREC; buffer_string.ptr.int_ptr = (int *) & buf; nBufSiz = nBufNdx = 0; } /* VOGETC - * Return the next characters from the object file. * In most cases, this just returns the next character in the object * record buffer. When the last character in the buffer has been * used, objrecin is called to read in another record. Note that * the VLI itself is returned to the caller as part of the data. * The calling kermit routine does not need to know this. * The VLI must be made part of the data in order to reconstruct * an object file when the file is later received by vkermit (see voputc). * * Return values: * -1 if error or EOF * otherwise the character read */ vogetc(n) int n; { char result; if (nBufNdx < nBufSiz) { nBufNdx++; return(buf.buffer[nBufNdx-1]); } else { /* get new buffer */ OBJRECIN(objf, &buffer_string, &nBufSiz, &result); if (result != NIOOK) { if (result != NIOEOF) { /* When a lousy outcome is returned from VKNCRLIO we output an error message PEG March 6, 1990 */ errhdlr("vogetc"); fprintf(stderr,"READ FAILURE OUTCOME: %d\n",ERRCELL); return(-1); } else /* end of file */ return(-1); /* DRE 030990 */ } else { /* good i-o */ if (buf.vlianddata.vli > MAXOBJDAT) { /* March 2, 1990 */ char errbuf[40]; sprintf(errbuf,"vogetc: obj vli exceeds max: %#X", buf.vlianddata.vli); errhdlr(errbuf); fprintf(stderr,"current vli maximum: %#X\n", MAXOBJDAT); return(-1); } nBufNdx = 1; nBufSiz += VLISIZE; return(buf.buffer[0]); } } } /* VOPUTC - * Put a single character into the destination object file. * The first two characters are used to calculate the size of * the record next to be written. When that many characters have * been transferred into the buffer, the buffer is written using * OBJRECOUT. A ncrl_string type must be used to create a string * with a known (to NCRL) length. * * Return values: * 0 if successful * -1 if failure */ voputc(c, n) char c; int n; { char result; /* check if we just got a full vli */ if (nBufNdx == 1) { /*calculate size of record to write */ /* Note that the buffer size includes the size of the VLI but the VLI itself does not include the size of the VLI */ buf.buffer[1] = c; if (buf.vlianddata.vli > MAXOBJDAT) { /* March 2, 1990 */ char errbuf[40]; sprintf(errbuf,"voputc: obj vli exceeds max: %#X", buf.vlianddata.vli); errhdlr(errbuf); fprintf(stderr,"current vli maximum: %#X\n", MAXOBJDAT); return(-1); } nBufSiz = buf.vlianddata.vli + VLISIZE; } buf.buffer[nBufNdx] = c; /* when nBufNdx = 1 c is written twice */ nBufNdx++; if (nBufNdx >= nBufSiz) { /* clear the current buffer by writing it out */ /* unless it is the first time */ if (nBufSiz > 0) { /* March 2, 1990 */ OBJRECOUT(objf, &buffer_string, &result); if (result != NIOOK) { /* When a lousy outcome is returned from VKNCRLIO we output an error message PEG March 6, 1990 */ errhdlr("voputc"); fprintf(stderr,"write failure outcome: %d\n",ERRCELL); return(-1); } nBufNdx = 0; /* Note actual size of buffer is not calculated until second byte arrives. */ } } return(0); } voclose(n) int n; { char result; OBJCLOSE(objf, result); if (result == NIOBAD) { /* When a lousy outcome is returned from VKNCRLIO we output an error message PEG March 6, 1990 */ errhdlr("voclose"); fprintf(stderr,"error closing file outcome: %d\n",ERRCELL); return(-1); } else return(0); }