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 295eb43ac2SDavid E. O'Brien #include <sys/cdefs.h> 305eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3130154ac8SAndrew Moore 3230154ac8SAndrew Moore #include <sys/file.h> 33d165d4acSAndrew Moore #include <sys/stat.h> 3430154ac8SAndrew Moore 3530154ac8SAndrew Moore #include "ed.h" 3630154ac8SAndrew Moore 3730154ac8SAndrew Moore 38ae824d80SEd Schouten static FILE *sfp; /* scratch file pointer */ 39ae824d80SEd Schouten static off_t sfseek; /* scratch file position */ 40ae824d80SEd Schouten static int seek_write; /* seek before writing */ 41ae824d80SEd Schouten static line_t buffer_head; /* incore buffer */ 4230154ac8SAndrew Moore 4395e6217eSAndrew Moore /* get_sbuf_line: get a line of text from the scratch file; return pointer 4430154ac8SAndrew Moore to the text */ 4530154ac8SAndrew Moore char * 467669d0fcSWarner Losh get_sbuf_line(line_t *lp) 4730154ac8SAndrew Moore { 4895e6217eSAndrew Moore static char *sfbuf = NULL; /* buffer */ 498bd856deSPedro F. Giffuni static size_t sfbufsz; /* buffer size */ 5095e6217eSAndrew Moore 518bd856deSPedro F. Giffuni size_t len; 5230154ac8SAndrew Moore 5395e6217eSAndrew Moore if (lp == &buffer_head) 5430154ac8SAndrew Moore return NULL; 5530154ac8SAndrew Moore seek_write = 1; /* force seek on write */ 5630154ac8SAndrew Moore /* out of position */ 5730154ac8SAndrew Moore if (sfseek != lp->seek) { 5830154ac8SAndrew Moore sfseek = lp->seek; 597cbfe4d8SAndrey A. Chernov if (fseeko(sfp, sfseek, SEEK_SET) < 0) { 6030154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 61a4616748SMike Barcroft errmsg = "cannot seek temp file"; 6230154ac8SAndrew Moore return NULL; 6330154ac8SAndrew Moore } 6430154ac8SAndrew Moore } 6595e6217eSAndrew Moore len = lp->len; 6695e6217eSAndrew Moore REALLOC(sfbuf, sfbufsz, len + 1, NULL); 67*f50fae31SPedro F. Giffuni if (fread(sfbuf, sizeof(char), len, sfp) != len) { 6830154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 69a4616748SMike Barcroft errmsg = "cannot read temp file"; 7030154ac8SAndrew Moore return NULL; 7130154ac8SAndrew Moore } 7230154ac8SAndrew Moore sfseek += len; /* update file position */ 7330154ac8SAndrew Moore sfbuf[len] = '\0'; 7430154ac8SAndrew Moore return sfbuf; 7530154ac8SAndrew Moore } 7630154ac8SAndrew Moore 7730154ac8SAndrew Moore 7895e6217eSAndrew Moore /* put_sbuf_line: write a line of text to the scratch file and add a line node 7930154ac8SAndrew Moore to the editor buffer; return a pointer to the end of the text */ 80a4616748SMike Barcroft const char * 817669d0fcSWarner Losh put_sbuf_line(const char *cs) 8230154ac8SAndrew Moore { 8330154ac8SAndrew Moore line_t *lp; 848bd856deSPedro F. Giffuni size_t len; 85a4616748SMike Barcroft const char *s; 8630154ac8SAndrew Moore 8730154ac8SAndrew Moore if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 8830154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 89a4616748SMike Barcroft errmsg = "out of memory"; 9030154ac8SAndrew Moore return NULL; 9130154ac8SAndrew Moore } 9230154ac8SAndrew Moore /* assert: cs is '\n' terminated */ 9330154ac8SAndrew Moore for (s = cs; *s != '\n'; s++) 9430154ac8SAndrew Moore ; 9530154ac8SAndrew Moore if (s - cs >= LINECHARS) { 96a4616748SMike Barcroft errmsg = "line too long"; 97ae568477SChristian Brueffer free(lp); 9830154ac8SAndrew Moore return NULL; 9930154ac8SAndrew Moore } 10095e6217eSAndrew Moore len = s - cs; 10130154ac8SAndrew Moore /* out of position */ 10230154ac8SAndrew Moore if (seek_write) { 1037cbfe4d8SAndrey A. Chernov if (fseeko(sfp, (off_t)0, SEEK_END) < 0) { 10430154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 105a4616748SMike Barcroft errmsg = "cannot seek temp file"; 106ae568477SChristian Brueffer free(lp); 10730154ac8SAndrew Moore return NULL; 10830154ac8SAndrew Moore } 1097cbfe4d8SAndrey A. Chernov sfseek = ftello(sfp); 11030154ac8SAndrew Moore seek_write = 0; 11130154ac8SAndrew Moore } 11295e6217eSAndrew Moore /* assert: SPL1() */ 113*f50fae31SPedro F. Giffuni if (fwrite(cs, sizeof(char), len, sfp) != len) { 11430154ac8SAndrew Moore sfseek = -1; 11530154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 116a4616748SMike Barcroft errmsg = "cannot write temp file"; 117ae568477SChristian Brueffer free(lp); 11830154ac8SAndrew Moore return NULL; 11930154ac8SAndrew Moore } 12030154ac8SAndrew Moore lp->len = len; 12130154ac8SAndrew Moore lp->seek = sfseek; 12295e6217eSAndrew Moore add_line_node(lp); 12330154ac8SAndrew Moore sfseek += len; /* update file position */ 12430154ac8SAndrew Moore return ++s; 12530154ac8SAndrew Moore } 12630154ac8SAndrew Moore 12730154ac8SAndrew Moore 12895e6217eSAndrew Moore /* add_line_node: add a line node in the editor buffer after the current line */ 12930154ac8SAndrew Moore void 1307669d0fcSWarner Losh add_line_node(line_t *lp) 13130154ac8SAndrew Moore { 13230154ac8SAndrew Moore line_t *cp; 13330154ac8SAndrew Moore 13495e6217eSAndrew Moore cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 135d165d4acSAndrew Moore INSQUE(lp, cp); 13695e6217eSAndrew Moore addr_last++; 13795e6217eSAndrew Moore current_addr++; 13830154ac8SAndrew Moore } 13930154ac8SAndrew Moore 14030154ac8SAndrew Moore 14195e6217eSAndrew Moore /* get_line_node_addr: return line number of pointer */ 14230154ac8SAndrew Moore long 1437669d0fcSWarner Losh get_line_node_addr(line_t *lp) 14430154ac8SAndrew Moore { 14595e6217eSAndrew Moore line_t *cp = &buffer_head; 14630154ac8SAndrew Moore long n = 0; 14730154ac8SAndrew Moore 14895e6217eSAndrew Moore while (cp != lp && (cp = cp->q_forw) != &buffer_head) 14930154ac8SAndrew Moore n++; 15095e6217eSAndrew Moore if (n && cp == &buffer_head) { 151a4616748SMike Barcroft errmsg = "invalid address"; 15210ca1c6cSAndrew Moore return ERR; 15310ca1c6cSAndrew Moore } 15410ca1c6cSAndrew Moore return n; 15530154ac8SAndrew Moore } 15630154ac8SAndrew Moore 15730154ac8SAndrew Moore 15895e6217eSAndrew Moore /* get_addressed_line_node: return pointer to a line node in the editor buffer */ 15930154ac8SAndrew Moore line_t * 1607669d0fcSWarner Losh get_addressed_line_node(long n) 16130154ac8SAndrew Moore { 16295e6217eSAndrew Moore static line_t *lp = &buffer_head; 16330154ac8SAndrew Moore static long on = 0; 16430154ac8SAndrew Moore 16595e6217eSAndrew Moore SPL1(); 16630154ac8SAndrew Moore if (n > on) 16795e6217eSAndrew Moore if (n <= (on + addr_last) >> 1) 16830154ac8SAndrew Moore for (; on < n; on++) 16995e6217eSAndrew Moore lp = lp->q_forw; 17030154ac8SAndrew Moore else { 17195e6217eSAndrew Moore lp = buffer_head.q_back; 17295e6217eSAndrew Moore for (on = addr_last; on > n; on--) 17395e6217eSAndrew Moore lp = lp->q_back; 17430154ac8SAndrew Moore } 17530154ac8SAndrew Moore else 17630154ac8SAndrew Moore if (n >= on >> 1) 17730154ac8SAndrew Moore for (; on > n; on--) 17895e6217eSAndrew Moore lp = lp->q_back; 17930154ac8SAndrew Moore else { 18095e6217eSAndrew Moore lp = &buffer_head; 18130154ac8SAndrew Moore for (on = 0; on < n; on++) 18295e6217eSAndrew Moore lp = lp->q_forw; 18330154ac8SAndrew Moore } 18495e6217eSAndrew Moore SPL0(); 18530154ac8SAndrew Moore return lp; 18630154ac8SAndrew Moore } 18730154ac8SAndrew Moore 188ae824d80SEd Schouten static char sfn[15] = ""; /* scratch file name */ 18930154ac8SAndrew Moore 19095e6217eSAndrew Moore /* open_sbuf: open scratch file */ 19195e6217eSAndrew Moore int 1927669d0fcSWarner Losh open_sbuf(void) 19330154ac8SAndrew Moore { 19449d54362SJuli Mallett int fd; 195d165d4acSAndrew Moore int u; 196d165d4acSAndrew Moore 19795e6217eSAndrew Moore isbinary = newline_added = 0; 198d165d4acSAndrew Moore u = umask(077); 19930154ac8SAndrew Moore strcpy(sfn, "/tmp/ed.XXXXXX"); 200f8ce2ec9SEivind Eklund if ((fd = mkstemp(sfn)) == -1 || 201e38b5013SWarner Losh (sfp = fdopen(fd, "w+")) == NULL) { 202e38b5013SWarner Losh if (fd != -1) 203e38b5013SWarner Losh close(fd); 204e38b5013SWarner Losh perror(sfn); 205a4616748SMike Barcroft errmsg = "cannot open temp file"; 206d165d4acSAndrew Moore umask(u); 20730154ac8SAndrew Moore return ERR; 20830154ac8SAndrew Moore } 209d165d4acSAndrew Moore umask(u); 21030154ac8SAndrew Moore return 0; 21130154ac8SAndrew Moore } 21230154ac8SAndrew Moore 21330154ac8SAndrew Moore 21495e6217eSAndrew Moore /* close_sbuf: close scratch file */ 21595e6217eSAndrew Moore int 2167669d0fcSWarner Losh close_sbuf(void) 21730154ac8SAndrew Moore { 21830154ac8SAndrew Moore if (sfp) { 21930154ac8SAndrew Moore if (fclose(sfp) < 0) { 22030154ac8SAndrew Moore fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 221a4616748SMike Barcroft errmsg = "cannot close temp file"; 22230154ac8SAndrew Moore return ERR; 22330154ac8SAndrew Moore } 22430154ac8SAndrew Moore sfp = NULL; 22530154ac8SAndrew Moore unlink(sfn); 22630154ac8SAndrew Moore } 22730154ac8SAndrew Moore sfseek = seek_write = 0; 22830154ac8SAndrew Moore return 0; 22930154ac8SAndrew Moore } 23030154ac8SAndrew Moore 23130154ac8SAndrew Moore 23295e6217eSAndrew Moore /* quit: remove_lines scratch file and exit */ 23330154ac8SAndrew Moore void 2347669d0fcSWarner Losh quit(int n) 23530154ac8SAndrew Moore { 23630154ac8SAndrew Moore if (sfp) { 23730154ac8SAndrew Moore fclose(sfp); 23830154ac8SAndrew Moore unlink(sfn); 23930154ac8SAndrew Moore } 24030154ac8SAndrew Moore exit(n); 24130154ac8SAndrew Moore } 24295c745afSAndrew Moore 24395c745afSAndrew Moore 244ae824d80SEd Schouten static unsigned char ctab[256]; /* character translation table */ 24595c745afSAndrew Moore 24695e6217eSAndrew Moore /* init_buffers: open scratch buffer; initialize line queue */ 24795c745afSAndrew Moore void 2487669d0fcSWarner Losh init_buffers(void) 24995c745afSAndrew Moore { 25095c745afSAndrew Moore int i = 0; 25195c745afSAndrew Moore 25295e6217eSAndrew Moore /* Read stdin one character at a time to avoid i/o contention 25395e6217eSAndrew Moore with shell escapes invoked by nonterminal input, e.g., 25495e6217eSAndrew Moore ed - <<EOF 25595e6217eSAndrew Moore !cat 25695e6217eSAndrew Moore hello, world 25795e6217eSAndrew Moore EOF */ 25895e6217eSAndrew Moore setbuffer(stdin, stdinbuf, 1); 259fd0e1c25SWolfgang Helbig 260fd0e1c25SWolfgang Helbig /* Ensure stdout is line buffered. This avoids bogus delays 261fd0e1c25SWolfgang Helbig of output if stdout is piped through utilities to a terminal. */ 262fd0e1c25SWolfgang Helbig setvbuf(stdout, NULL, _IOLBF, 0); 26395e6217eSAndrew Moore if (open_sbuf() < 0) 26495c745afSAndrew Moore quit(2); 26595e6217eSAndrew Moore REQUE(&buffer_head, &buffer_head); 26695c745afSAndrew Moore for (i = 0; i < 256; i++) 26795c745afSAndrew Moore ctab[i] = i; 26895c745afSAndrew Moore } 26995c745afSAndrew Moore 27095c745afSAndrew Moore 27195e6217eSAndrew Moore /* translit_text: translate characters in a string */ 27295c745afSAndrew Moore char * 2737669d0fcSWarner Losh translit_text(char *s, int len, int from, int to) 27495c745afSAndrew Moore { 27595c745afSAndrew Moore static int i = 0; 27695c745afSAndrew Moore 27795c745afSAndrew Moore unsigned char *us; 27895c745afSAndrew Moore 27995c745afSAndrew Moore ctab[i] = i; /* restore table to initial state */ 28095c745afSAndrew Moore ctab[i = from] = to; 28195c745afSAndrew Moore for (us = (unsigned char *) s; len-- > 0; us++) 28295c745afSAndrew Moore *us = ctab[*us]; 28395c745afSAndrew Moore return s; 28495c745afSAndrew Moore } 285