/* buf.c: This file contains the scratch-file buffer routines for the1ed line editor. */2/*-3* Copyright (c) 1993 Andrew Moore, Talke Studio.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/cdefs.h>29#include <sys/file.h>30#include <sys/stat.h>3132#include "ed.h"333435static FILE *sfp; /* scratch file pointer */36static off_t sfseek; /* scratch file position */37static int seek_write; /* seek before writing */38static line_t buffer_head; /* incore buffer */3940/* get_sbuf_line: get a line of text from the scratch file; return pointer41to the text */42char *43get_sbuf_line(line_t *lp)44{45static char *sfbuf = NULL; /* buffer */46static size_t sfbufsz; /* buffer size */4748size_t len;4950if (lp == &buffer_head)51return NULL;52seek_write = 1; /* force seek on write */53/* out of position */54if (sfseek != lp->seek) {55sfseek = lp->seek;56if (fseeko(sfp, sfseek, SEEK_SET) < 0) {57fprintf(stderr, "%s\n", strerror(errno));58errmsg = "cannot seek temp file";59return NULL;60}61}62len = lp->len;63REALLOC(sfbuf, sfbufsz, len + 1, NULL);64if (fread(sfbuf, sizeof(char), len, sfp) != len) {65fprintf(stderr, "%s\n", strerror(errno));66errmsg = "cannot read temp file";67return NULL;68}69sfseek += len; /* update file position */70sfbuf[len] = '\0';71return sfbuf;72}737475/* put_sbuf_line: write a line of text to the scratch file and add a line node76to the editor buffer; return a pointer to the end of the text */77const char *78put_sbuf_line(const char *cs)79{80line_t *lp;81size_t len;82const char *s;8384if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {85fprintf(stderr, "%s\n", strerror(errno));86errmsg = "out of memory";87return NULL;88}89/* assert: cs is '\n' terminated */90for (s = cs; *s != '\n'; s++)91;92if (s - cs >= LINECHARS) {93errmsg = "line too long";94free(lp);95return NULL;96}97len = s - cs;98/* out of position */99if (seek_write) {100if (fseeko(sfp, (off_t)0, SEEK_END) < 0) {101fprintf(stderr, "%s\n", strerror(errno));102errmsg = "cannot seek temp file";103free(lp);104return NULL;105}106sfseek = ftello(sfp);107seek_write = 0;108}109/* assert: SPL1() */110if (fwrite(cs, sizeof(char), len, sfp) != len) {111sfseek = -1;112fprintf(stderr, "%s\n", strerror(errno));113errmsg = "cannot write temp file";114free(lp);115return NULL;116}117lp->len = len;118lp->seek = sfseek;119add_line_node(lp);120sfseek += len; /* update file position */121return ++s;122}123124125/* add_line_node: add a line node in the editor buffer after the current line */126void127add_line_node(line_t *lp)128{129line_t *cp;130131cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */132INSQUE(lp, cp);133addr_last++;134current_addr++;135}136137138/* get_line_node_addr: return line number of pointer */139long140get_line_node_addr(line_t *lp)141{142line_t *cp = &buffer_head;143long n = 0;144145while (cp != lp && (cp = cp->q_forw) != &buffer_head)146n++;147if (n && cp == &buffer_head) {148errmsg = "invalid address";149return ERR;150}151return n;152}153154155/* get_addressed_line_node: return pointer to a line node in the editor buffer */156line_t *157get_addressed_line_node(long n)158{159static line_t *lp = &buffer_head;160static long on = 0;161162SPL1();163if (n > on)164if (n <= (on + addr_last) >> 1)165for (; on < n; on++)166lp = lp->q_forw;167else {168lp = buffer_head.q_back;169for (on = addr_last; on > n; on--)170lp = lp->q_back;171}172else173if (n >= on >> 1)174for (; on > n; on--)175lp = lp->q_back;176else {177lp = &buffer_head;178for (on = 0; on < n; on++)179lp = lp->q_forw;180}181SPL0();182return lp;183}184185static char sfn[15] = ""; /* scratch file name */186187/* open_sbuf: open scratch file */188int189open_sbuf(void)190{191int fd;192int u;193194isbinary = newline_added = 0;195u = umask(077);196strcpy(sfn, "/tmp/ed.XXXXXX");197if ((fd = mkstemp(sfn)) == -1 ||198(sfp = fdopen(fd, "w+")) == NULL) {199if (fd != -1)200close(fd);201perror(sfn);202errmsg = "cannot open temp file";203umask(u);204return ERR;205}206umask(u);207return 0;208}209210211/* close_sbuf: close scratch file */212int213close_sbuf(void)214{215if (sfp) {216if (fclose(sfp) < 0) {217fprintf(stderr, "%s: %s\n", sfn, strerror(errno));218errmsg = "cannot close temp file";219return ERR;220}221sfp = NULL;222unlink(sfn);223}224sfseek = seek_write = 0;225return 0;226}227228229/* quit: remove_lines scratch file and exit */230void231quit(int n)232{233if (sfp) {234fclose(sfp);235unlink(sfn);236}237exit(n);238}239240241static unsigned char ctab[256]; /* character translation table */242243/* init_buffers: open scratch buffer; initialize line queue */244void245init_buffers(void)246{247int i = 0;248249/* Read stdin one character at a time to avoid i/o contention250with shell escapes invoked by nonterminal input, e.g.,251ed - <<EOF252!cat253hello, world254EOF */255setbuffer(stdin, stdinbuf, 1);256257/* Ensure stdout is line buffered. This avoids bogus delays258of output if stdout is piped through utilities to a terminal. */259setvbuf(stdout, NULL, _IOLBF, 0);260if (open_sbuf() < 0)261quit(2);262REQUE(&buffer_head, &buffer_head);263for (i = 0; i < 256; i++)264ctab[i] = i;265}266267268/* translit_text: translate characters in a string */269char *270translit_text(char *s, int len, int from, int to)271{272static int i = 0;273274unsigned char *us;275276ctab[i] = i; /* restore table to initial state */277ctab[i = from] = to;278for (us = (unsigned char *) s; len-- > 0; us++)279*us = ctab[*us];280return s;281}282283284