/* * Routines to open/close/read/write the local file. * For "binary" (octet) transmissions, we use the UNIX open/read/write * system calls (or their equivalent). * For "ascii" (netascii) transmissions, we use the UNIX standard i/o routines * fopen/getc/putc (or their equivalent). */ #include "defs.h" /* * The following are used by the functions in this file only. */ static int lastcr = 0; /* 1 if last character was a carriage-return */ static int nextchar = 0; /* * Open the local file for reading or writing. * Return a FILE pointer, or NULL on error. */ FILE * file_open(fname, mode, initblknum) char *fname; char *mode; /* for fopen() - "r" or "w" */ int initblknum; { register FILE *fp; if (strcmp(fname, "-") == 0) fp = stdout; else if ( (fp = fopen(fname, mode)) == NULL) return((FILE *) 0); nextblknum = initblknum; /* for first data packet or first ACK */ lastcr = 0; /* for file_write() */ nextchar = -1; /* for file_read() */ DEBUG2("file_open: opened %s, mode = %s", fname, mode); return(fp); } /* * Close the local file. * This causes the standard i/o system to flush its buffers for this file. */ file_close(fp) FILE *fp; { if (lastcr) err_dump("final character was a CR"); if (nextchar >= 0) err_dump("nextchar >= 0"); if (fp == stdout) return; /* don't close standard output */ else if (fclose(fp) == EOF) err_dump("fclose error"); } /* * Read data from the local file. * Here is where we handle any conversion between the file's mode * on the local system and the network mode. * * Return the number of bytes read (between 1 and maxnbytes, inclusive) * or 0 on EOF. */ int file_read(fp, ptr, maxnbytes, mode) FILE *fp; register char *ptr; register int maxnbytes; int mode; { register int c, count; if (mode == MODE_BINARY) { count = read(fileno(fp), ptr, maxnbytes); if (count < 0) err_dump("read error on local file"); return(count); /* will be 0 on EOF */ } else if (mode == MODE_ASCII) { /* * For files that are transferred in netascii, we must * perform the reverse conversions that file_write() does. * Note that we have to use the global "nextchar" to * remember if the next character to output is a linefeed * or a null, since the second byte of a 2-byte sequence * may not fit in the current buffer, and may have to go * as the first byte of the next buffer (i.e., we have to * remember this fact from one call to the next). */ for (count = 0; count < maxnbytes; count++) { if (nextchar >= 0) { *ptr++ = nextchar; nextchar = -1; continue; } c = getc(fp); if (c == EOF) { /* EOF return means eof or error */ if (ferror(fp)) err_dump("read err from getc on local file"); return(count); } else if (c == '\n') { c = '\r'; /* newline -> CR,LF */ nextchar = '\n'; } else if (c == '\r') { nextchar = '\0'; /* CR -> CR,NULL */ } else nextchar = -1; *ptr++ = c; } return(count); } else err_dump("unknown MODE value"); /* NOTREACHED */ } /* * Write data to the local file. * Here is where we handle any conversion between the mode of the * file on the network and the local system's conventions. */ file_write(fp, ptr, nbytes, mode) FILE *fp; register char *ptr; register int nbytes; int mode; { register int c, i; if (mode == MODE_BINARY) { /* * For binary mode files, no conversion is required. */ i = write(fileno(fp), ptr, nbytes); if (i != nbytes) err_dump("write error to local file, i = %d", i); } else if (mode == MODE_ASCII) { /* * For files that are transferred in netascii, we must * perform the following conversions: * * CR,LF -> newline = '\n' * CR,NULL -> CR = '\r' * CR,anything_else -> undefined (we don't allow this) * * Note that we have to use the global "lastcr" to remember * if the last character was a carriage-return or not, * since if the last character of a buffer is a CR, we have * to remember that when we're called for the next buffer. */ for (i = 0; i < nbytes; i++) { c = *ptr++; if (lastcr) { if (c == '\n') c = '\n'; else if (c == '\0') c = '\r'; else err_dump("CR followed by 0x%02x", c); lastcr = 0; } else if (c == '\r') { lastcr = 1; continue; /* get next character */ } if (putc(c, fp) == EOF) err_dump("write error from putc to local file"); } } else err_dump("unknown MODE value"); }