146be34b9SKris Kennaway /* buf.c: This file contains the scratch-file buffer routines for the 230154ac8SAndrew Moore ed line editor. */ 330154ac8SAndrew Moore /*- 495e6217eSAndrew Moore * Copyright (c) 1993 Andrew Moore, Talke Studio. 530154ac8SAndrew Moore * All rights reserved. 630154ac8SAndrew Moore * 730154ac8SAndrew Moore * Redistribution and use in source and binary forms, with or without 830154ac8SAndrew Moore * modification, are permitted provided that the following conditions 930154ac8SAndrew Moore * are met: 1030154ac8SAndrew Moore * 1. Redistributions of source code must retain the above copyright 1130154ac8SAndrew Moore * notice, this list of conditions and the following disclaimer. 1230154ac8SAndrew Moore * 2. Redistributions in binary form must reproduce the above copyright 1330154ac8SAndrew Moore * notice, this list of conditions and the following disclaimer in the 1430154ac8SAndrew Moore * documentation and/or other materials provided with the distribution. 1530154ac8SAndrew Moore * 1695e6217eSAndrew Moore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1730154ac8SAndrew Moore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1830154ac8SAndrew Moore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1995e6217eSAndrew Moore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2030154ac8SAndrew Moore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2130154ac8SAndrew Moore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2230154ac8SAndrew Moore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2330154ac8SAndrew Moore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2430154ac8SAndrew Moore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2530154ac8SAndrew Moore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2630154ac8SAndrew Moore * SUCH DAMAGE. 2730154ac8SAndrew Moore */ 285967604aSSteve Price 2930154ac8SAndrew Moore #ifndef lint 305967604aSSteve Price #if 0 3178b09ffeSSteve Price static char * const rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp"; 325967604aSSteve Price #else 335967604aSSteve Price static char * const rcsid = 3446be34b9SKris Kennaway "$Id: buf.c,v 1.15 1997/12/31 12:25:33 helbig Exp $"; 355967604aSSteve Price #endif 3630154ac8SAndrew Moore #endif /* not lint */ 3730154ac8SAndrew Moore 3830154ac8SAndrew Moore #include <sys/file.h> 39d165d4acSAndrew Moore #include <sys/stat.h> 4030154ac8SAndrew Moore 4130154ac8SAndrew Moore #include "ed.h" 4230154ac8SAndrew Moore 4330154ac8SAndrew Moore 4430154ac8SAndrew Moore FILE *sfp; /* scratch file pointer */ 4530154ac8SAndrew Moore off_t sfseek; /* scratch file position */ 4630154ac8SAndrew Moore int seek_write; /* seek before writing */ 4795e6217eSAndrew Moore line_t buffer_head; /* incore buffer */ 4830154ac8SAndrew Moore 4995e6217eSAndrew Moore /* get_sbuf_line: get a line of text from the scratch file; return pointer 5030154ac8SAndrew Moore to the text */ 5130154ac8SAndrew Moore char * 5295e6217eSAndrew Moore get_sbuf_line(lp) 5330154ac8SAndrew Moore line_t *lp; 5430154ac8SAndrew Moore { 5595e6217eSAndrew Moore static char *sfbuf = NULL; /* buffer */ 5695e6217eSAndrew Moore static int sfbufsz = 0; /* buffer size */ 5795e6217eSAndrew Moore 5830154ac8SAndrew Moore int len, ct; 5930154ac8SAndrew Moore 6095e6217eSAndrew Moore if (lp == &buffer_head) 6130154ac8SAndrew Moore return NULL; 6230154ac8SAndrew Moore seek_write = 1; /* force seek on write */ 6330154ac8SAndrew Moore /* out of position */ 6430154ac8SAndrew Moore if (sfseek != lp->seek) { 6530154ac8SAndrew Moore sfseek = lp->seek; 6630154ac8SAndrew Moore if (fseek(sfp, sfseek, SEEK_SET) < 0) { 6730154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 6830154ac8SAndrew Moore sprintf(errmsg, "cannot seek temp file"); 6930154ac8SAndrew Moore return NULL; 7030154ac8SAndrew Moore } 7130154ac8SAndrew Moore } 7295e6217eSAndrew Moore len = lp->len; 7395e6217eSAndrew Moore REALLOC(sfbuf, sfbufsz, len + 1, NULL); 7430154ac8SAndrew Moore if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) { 7530154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 7630154ac8SAndrew Moore sprintf(errmsg, "cannot read temp file"); 7730154ac8SAndrew Moore return NULL; 7830154ac8SAndrew Moore } 7930154ac8SAndrew Moore sfseek += len; /* update file position */ 8030154ac8SAndrew Moore sfbuf[len] = '\0'; 8130154ac8SAndrew Moore return sfbuf; 8230154ac8SAndrew Moore } 8330154ac8SAndrew Moore 8430154ac8SAndrew Moore 8595e6217eSAndrew Moore /* put_sbuf_line: write a line of text to the scratch file and add a line node 8630154ac8SAndrew Moore to the editor buffer; return a pointer to the end of the text */ 8730154ac8SAndrew Moore char * 8895e6217eSAndrew Moore put_sbuf_line(cs) 8930154ac8SAndrew Moore char *cs; 9030154ac8SAndrew Moore { 9130154ac8SAndrew Moore line_t *lp; 9230154ac8SAndrew Moore int len, ct; 9330154ac8SAndrew Moore char *s; 9430154ac8SAndrew Moore 9530154ac8SAndrew Moore if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 9630154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 9730154ac8SAndrew Moore sprintf(errmsg, "out of memory"); 9830154ac8SAndrew Moore return NULL; 9930154ac8SAndrew Moore } 10030154ac8SAndrew Moore /* assert: cs is '\n' terminated */ 10130154ac8SAndrew Moore for (s = cs; *s != '\n'; s++) 10230154ac8SAndrew Moore ; 10330154ac8SAndrew Moore if (s - cs >= LINECHARS) { 10430154ac8SAndrew Moore sprintf(errmsg, "line too long"); 10530154ac8SAndrew Moore return NULL; 10630154ac8SAndrew Moore } 10795e6217eSAndrew Moore len = s - cs; 10830154ac8SAndrew Moore /* out of position */ 10930154ac8SAndrew Moore if (seek_write) { 11030154ac8SAndrew Moore if (fseek(sfp, 0L, SEEK_END) < 0) { 11130154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 11230154ac8SAndrew Moore sprintf(errmsg, "cannot seek temp file"); 11330154ac8SAndrew Moore return NULL; 11430154ac8SAndrew Moore } 11530154ac8SAndrew Moore sfseek = ftell(sfp); 11630154ac8SAndrew Moore seek_write = 0; 11730154ac8SAndrew Moore } 11895e6217eSAndrew Moore /* assert: SPL1() */ 11930154ac8SAndrew Moore if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 12030154ac8SAndrew Moore sfseek = -1; 12130154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 12230154ac8SAndrew Moore sprintf(errmsg, "cannot write temp file"); 12330154ac8SAndrew Moore return NULL; 12430154ac8SAndrew Moore } 12530154ac8SAndrew Moore lp->len = len; 12630154ac8SAndrew Moore lp->seek = sfseek; 12795e6217eSAndrew Moore add_line_node(lp); 12830154ac8SAndrew Moore sfseek += len; /* update file position */ 12930154ac8SAndrew Moore return ++s; 13030154ac8SAndrew Moore } 13130154ac8SAndrew Moore 13230154ac8SAndrew Moore 13395e6217eSAndrew Moore /* add_line_node: add a line node in the editor buffer after the current line */ 13430154ac8SAndrew Moore void 13595e6217eSAndrew Moore add_line_node(lp) 13630154ac8SAndrew Moore line_t *lp; 13730154ac8SAndrew Moore { 13830154ac8SAndrew Moore line_t *cp; 13930154ac8SAndrew Moore 14095e6217eSAndrew Moore cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 141d165d4acSAndrew Moore INSQUE(lp, cp); 14295e6217eSAndrew Moore addr_last++; 14395e6217eSAndrew Moore current_addr++; 14430154ac8SAndrew Moore } 14530154ac8SAndrew Moore 14630154ac8SAndrew Moore 14795e6217eSAndrew Moore /* get_line_node_addr: return line number of pointer */ 14830154ac8SAndrew Moore long 14995e6217eSAndrew Moore get_line_node_addr(lp) 15030154ac8SAndrew Moore line_t *lp; 15130154ac8SAndrew Moore { 15295e6217eSAndrew Moore line_t *cp = &buffer_head; 15330154ac8SAndrew Moore long n = 0; 15430154ac8SAndrew Moore 15595e6217eSAndrew Moore while (cp != lp && (cp = cp->q_forw) != &buffer_head) 15630154ac8SAndrew Moore n++; 15795e6217eSAndrew Moore if (n && cp == &buffer_head) { 15810ca1c6cSAndrew Moore sprintf(errmsg, "invalid address"); 15910ca1c6cSAndrew Moore return ERR; 16010ca1c6cSAndrew Moore } 16110ca1c6cSAndrew Moore return n; 16230154ac8SAndrew Moore } 16330154ac8SAndrew Moore 16430154ac8SAndrew Moore 16595e6217eSAndrew Moore /* get_addressed_line_node: return pointer to a line node in the editor buffer */ 16630154ac8SAndrew Moore line_t * 16795e6217eSAndrew Moore get_addressed_line_node(n) 16830154ac8SAndrew Moore long n; 16930154ac8SAndrew Moore { 17095e6217eSAndrew Moore static line_t *lp = &buffer_head; 17130154ac8SAndrew Moore static long on = 0; 17230154ac8SAndrew Moore 17395e6217eSAndrew Moore SPL1(); 17430154ac8SAndrew Moore if (n > on) 17595e6217eSAndrew Moore if (n <= (on + addr_last) >> 1) 17630154ac8SAndrew Moore for (; on < n; on++) 17795e6217eSAndrew Moore lp = lp->q_forw; 17830154ac8SAndrew Moore else { 17995e6217eSAndrew Moore lp = buffer_head.q_back; 18095e6217eSAndrew Moore for (on = addr_last; on > n; on--) 18195e6217eSAndrew Moore lp = lp->q_back; 18230154ac8SAndrew Moore } 18330154ac8SAndrew Moore else 18430154ac8SAndrew Moore if (n >= on >> 1) 18530154ac8SAndrew Moore for (; on > n; on--) 18695e6217eSAndrew Moore lp = lp->q_back; 18730154ac8SAndrew Moore else { 18895e6217eSAndrew Moore lp = &buffer_head; 18930154ac8SAndrew Moore for (on = 0; on < n; on++) 19095e6217eSAndrew Moore lp = lp->q_forw; 19130154ac8SAndrew Moore } 19295e6217eSAndrew Moore SPL0(); 19330154ac8SAndrew Moore return lp; 19430154ac8SAndrew Moore } 19530154ac8SAndrew Moore 19630154ac8SAndrew Moore 19795e6217eSAndrew Moore extern int newline_added; 19895e6217eSAndrew Moore 19930154ac8SAndrew Moore char sfn[15] = ""; /* scratch file name */ 20030154ac8SAndrew Moore 20195e6217eSAndrew Moore /* open_sbuf: open scratch file */ 20295e6217eSAndrew Moore int 20395e6217eSAndrew Moore open_sbuf() 20430154ac8SAndrew Moore { 205e38b5013SWarner Losh int fd = -1; 206d165d4acSAndrew Moore int u; 207d165d4acSAndrew Moore 20895e6217eSAndrew Moore isbinary = newline_added = 0; 209d165d4acSAndrew Moore u = umask(077); 21030154ac8SAndrew Moore strcpy(sfn, "/tmp/ed.XXXXXX"); 211f8ce2ec9SEivind Eklund if ((fd = mkstemp(sfn)) == -1 || 212e38b5013SWarner Losh (sfp = fdopen(fd, "w+")) == NULL) { 213e38b5013SWarner Losh if (fd != -1) 214e38b5013SWarner Losh close(fd); 215e38b5013SWarner Losh perror(sfn); 216e38b5013SWarner Losh strcpy(errmsg, "cannot open temp file"); 217d165d4acSAndrew Moore umask(u); 21830154ac8SAndrew Moore return ERR; 21930154ac8SAndrew Moore } 220d165d4acSAndrew Moore umask(u); 22130154ac8SAndrew Moore return 0; 22230154ac8SAndrew Moore } 22330154ac8SAndrew Moore 22430154ac8SAndrew Moore 22595e6217eSAndrew Moore /* close_sbuf: close scratch file */ 22695e6217eSAndrew Moore int 22795e6217eSAndrew Moore close_sbuf() 22830154ac8SAndrew Moore { 22930154ac8SAndrew Moore if (sfp) { 23030154ac8SAndrew Moore if (fclose(sfp) < 0) { 23130154ac8SAndrew Moore fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 23230154ac8SAndrew Moore sprintf(errmsg, "cannot close temp file"); 23330154ac8SAndrew Moore return ERR; 23430154ac8SAndrew Moore } 23530154ac8SAndrew Moore sfp = NULL; 23630154ac8SAndrew Moore unlink(sfn); 23730154ac8SAndrew Moore } 23830154ac8SAndrew Moore sfseek = seek_write = 0; 23930154ac8SAndrew Moore return 0; 24030154ac8SAndrew Moore } 24130154ac8SAndrew Moore 24230154ac8SAndrew Moore 24395e6217eSAndrew Moore /* quit: remove_lines scratch file and exit */ 24430154ac8SAndrew Moore void 24530154ac8SAndrew Moore quit(n) 24630154ac8SAndrew Moore int n; 24730154ac8SAndrew Moore { 24830154ac8SAndrew Moore if (sfp) { 24930154ac8SAndrew Moore fclose(sfp); 25030154ac8SAndrew Moore unlink(sfn); 25130154ac8SAndrew Moore } 25230154ac8SAndrew Moore exit(n); 25330154ac8SAndrew Moore } 25495c745afSAndrew Moore 25595c745afSAndrew Moore 25695c745afSAndrew Moore unsigned char ctab[256]; /* character translation table */ 25795c745afSAndrew Moore 25895e6217eSAndrew Moore /* init_buffers: open scratch buffer; initialize line queue */ 25995c745afSAndrew Moore void 26095e6217eSAndrew Moore init_buffers() 26195c745afSAndrew Moore { 26295c745afSAndrew Moore int i = 0; 26395c745afSAndrew Moore 26495e6217eSAndrew Moore /* Read stdin one character at a time to avoid i/o contention 26595e6217eSAndrew Moore with shell escapes invoked by nonterminal input, e.g., 26695e6217eSAndrew Moore ed - <<EOF 26795e6217eSAndrew Moore !cat 26895e6217eSAndrew Moore hello, world 26995e6217eSAndrew Moore EOF */ 27095e6217eSAndrew Moore setbuffer(stdin, stdinbuf, 1); 271fd0e1c25SWolfgang Helbig 272fd0e1c25SWolfgang Helbig /* Ensure stdout is line buffered. This avoids bogus delays 273fd0e1c25SWolfgang Helbig of output if stdout is piped through utilities to a terminal. */ 274fd0e1c25SWolfgang Helbig setvbuf(stdout, NULL, _IOLBF, 0); 27595e6217eSAndrew Moore if (open_sbuf() < 0) 27695c745afSAndrew Moore quit(2); 27795e6217eSAndrew Moore REQUE(&buffer_head, &buffer_head); 27895c745afSAndrew Moore for (i = 0; i < 256; i++) 27995c745afSAndrew Moore ctab[i] = i; 28095c745afSAndrew Moore } 28195c745afSAndrew Moore 28295c745afSAndrew Moore 28395e6217eSAndrew Moore /* translit_text: translate characters in a string */ 28495c745afSAndrew Moore char * 28595e6217eSAndrew Moore translit_text(s, len, from, to) 28695c745afSAndrew Moore char *s; 28795c745afSAndrew Moore int len; 28895c745afSAndrew Moore int from; 28995c745afSAndrew Moore int to; 29095c745afSAndrew Moore { 29195c745afSAndrew Moore static int i = 0; 29295c745afSAndrew Moore 29395c745afSAndrew Moore unsigned char *us; 29495c745afSAndrew Moore 29595c745afSAndrew Moore ctab[i] = i; /* restore table to initial state */ 29695c745afSAndrew Moore ctab[i = from] = to; 29795c745afSAndrew Moore for (us = (unsigned char *) s; len-- > 0; us++) 29895c745afSAndrew Moore *us = ctab[*us]; 29995c745afSAndrew Moore return s; 30095c745afSAndrew Moore } 301