# define INCLUDE_FILE_IO # include "ed.h" # include "buffer.h" # include "path.h" # include "fileio.h" /* * The file I/O operations of the editor. */ typedef struct { char *filename; /* file name */ int fd; /* read/write file descriptor */ char *buffer; /* file buffer */ char *bufp; /* buffer pointer */ unsigned int inbuf; /* # bytes in buffer */ char *lbuf; /* line buffer */ char *lbuflast; /* end of line buffer */ io *iostat; /* I/O status */ } fiocontext; /* * NAME: getline() * DESCRIPTION: read a line from the input, return as '\0'-terminated string * without '\n' */ static char *getline(ptr) char *ptr; { register fiocontext *x; register char c, *p, *bp; register int i; x = (fiocontext *) ptr; if (x->iostat->ill) { /* previous line was incomplete, therefore the last */ return (char *) NULL; } p = x->lbuf; bp = x->bufp; i = x->inbuf; do { if (i == 0) { /* buffer empty */ i = read(x->fd, x->buffer, BUF_SIZE); if (i <= 0) { /* eof or error */ if (i < 0) { error("error while reading file \"/%s\"", x->filename); } if (p == x->lbuf) { return (char *) NULL; } else { p++; /* make room for terminating '\0' */ x->iostat->ill = TRUE; break; } } bp = x->buffer; } --i; c = *bp++; if (c == '\0') { x->iostat->zero++; /* skip zeroes */ } else { if (p == x->lbuflast && c != LF) { x->iostat->split++; i++; --bp; c = LF; } *p++ = c; } } while (c != LF); /* eoln */ x->iostat->lines++; x->iostat->chars += p - x->lbuf; /* including terminating '\0' */ x->bufp = bp; x->inbuf = i; *--p = '\0'; return x->lbuf; } /* * NAME: io_load() * DESCRIPTION: append block read from file after a line */ bool io_load(eb, filename, l, iobuf) editbuf *eb; char *filename; Int l; io *iobuf; { char b[MAX_LINE_SIZE], buf[BUF_SIZE]; struct stat sbuf; fiocontext x; /* open file */ x.filename = path_ed_read(filename); if (x.filename == (char *) NULL || stat(x.filename, &sbuf) < 0 || (sbuf.st_mode & S_IFMT) != S_IFREG) { return FALSE; } x.fd = open(x.filename, O_RDONLY | O_BINARY, 0); if (x.fd < 0) { return FALSE; } /* initialize buffers */ x.buffer = buf; x.inbuf = 0; x.lbuf = b; x.lbuflast = &b[MAX_LINE_SIZE - 1]; /* initialize statistics */ x.iostat = iobuf; x.iostat->lines = 0; x.iostat->chars = 0; x.iostat->zero = 0; x.iostat->split = 0; x.iostat->ill = FALSE; /* add the block to the edit buffer */ if (ec_push((ec_ftn) NULL)) { close(x.fd); error((char *) NULL); /* pass on error */ } eb_add(eb, l, getline, (char *) &x); ec_pop(); close(x.fd); return TRUE; } /* * NAME: putline() * DESCRIPTION: write a line to a file */ static void putline(ptr, text) char *ptr; register char *text; { register fiocontext *x; register unsigned int len; x = (fiocontext *) ptr; len = strlen(text); x->iostat->lines += 1; x->iostat->chars += len + 1; while (x->inbuf + len >= BUF_SIZE) { /* flush buffer */ if (x->inbuf != BUF_SIZE) { /* room left for a piece of line */ register unsigned int chunk; chunk = BUF_SIZE - x->inbuf; memcpy(x->buffer + x->inbuf, text, chunk); text += chunk; len -= chunk; } if (write(x->fd, x->buffer, BUF_SIZE) != BUF_SIZE) { error("error while writing file \"/%s\"", x->filename); } x->inbuf = 0; } if (len > 0) { /* piece of line left */ memcpy(x->buffer + x->inbuf, text, len); x->inbuf += len; } x->buffer[x->inbuf++] = LF; } /* * NAME: io_save() * DESCRIPTION: write a range of lines to a file */ bool io_save(eb, filename, first, last, append, iobuf) editbuf *eb; char *filename; Int first, last; int append; io *iobuf; { char buf[BUF_SIZE]; fiocontext x; x.filename = path_ed_write(filename); if (x.filename == (char *) NULL) { return FALSE; } /* create file */ x.fd = open(x.filename, (append) ? O_CREAT | O_APPEND | O_WRONLY | O_BINARY : O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0664); if (x.fd < 0) { return FALSE; } /* initialize buffer */ x.buffer = buf; x.inbuf = 0; /* initialize statistics */ x.iostat = iobuf; x.iostat->lines = 0; x.iostat->chars = 0; x.iostat->zero = 0; x.iostat->split = 0; x.iostat->ill = FALSE; /* write range */ if (ec_push((ec_ftn) NULL)) { close(x.fd); error((char *) NULL); /* pass on error */ } eb_range(eb, first, last, putline, (char *) &x, FALSE); if (write(x.fd, x.buffer, x.inbuf) != x.inbuf) { error("error while writing file \"/%s\"", x.filename); } ec_pop(); close(x.fd); return TRUE; }