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 3830154ac8SAndrew Moore FILE *sfp; /* scratch file pointer */ 3930154ac8SAndrew Moore off_t sfseek; /* scratch file position */ 4030154ac8SAndrew Moore int seek_write; /* seek before writing */ 4195e6217eSAndrew Moore 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 */ 4995e6217eSAndrew Moore static int sfbufsz = 0; /* buffer size */ 5095e6217eSAndrew Moore 5130154ac8SAndrew Moore int len, ct; 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); 6730154ac8SAndrew Moore if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != 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; 8430154ac8SAndrew Moore int len, ct; 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"; 9730154ac8SAndrew Moore return NULL; 9830154ac8SAndrew Moore } 9995e6217eSAndrew Moore len = s - cs; 10030154ac8SAndrew Moore /* out of position */ 10130154ac8SAndrew Moore if (seek_write) { 1027cbfe4d8SAndrey A. Chernov if (fseeko(sfp, (off_t)0, SEEK_END) < 0) { 10330154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 104a4616748SMike Barcroft errmsg = "cannot seek temp file"; 10530154ac8SAndrew Moore return NULL; 10630154ac8SAndrew Moore } 1077cbfe4d8SAndrey A. Chernov sfseek = ftello(sfp); 10830154ac8SAndrew Moore seek_write = 0; 10930154ac8SAndrew Moore } 11095e6217eSAndrew Moore /* assert: SPL1() */ 11130154ac8SAndrew Moore if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 11230154ac8SAndrew Moore sfseek = -1; 11330154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno)); 114a4616748SMike Barcroft errmsg = "cannot write temp file"; 11530154ac8SAndrew Moore return NULL; 11630154ac8SAndrew Moore } 11730154ac8SAndrew Moore lp->len = len; 11830154ac8SAndrew Moore lp->seek = sfseek; 11995e6217eSAndrew Moore add_line_node(lp); 12030154ac8SAndrew Moore sfseek += len; /* update file position */ 12130154ac8SAndrew Moore return ++s; 12230154ac8SAndrew Moore } 12330154ac8SAndrew Moore 12430154ac8SAndrew Moore 12595e6217eSAndrew Moore /* add_line_node: add a line node in the editor buffer after the current line */ 12630154ac8SAndrew Moore void 1277669d0fcSWarner Losh add_line_node(line_t *lp) 12830154ac8SAndrew Moore { 12930154ac8SAndrew Moore line_t *cp; 13030154ac8SAndrew Moore 13195e6217eSAndrew Moore cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 132d165d4acSAndrew Moore INSQUE(lp, cp); 13395e6217eSAndrew Moore addr_last++; 13495e6217eSAndrew Moore current_addr++; 13530154ac8SAndrew Moore } 13630154ac8SAndrew Moore 13730154ac8SAndrew Moore 13895e6217eSAndrew Moore /* get_line_node_addr: return line number of pointer */ 13930154ac8SAndrew Moore long 1407669d0fcSWarner Losh get_line_node_addr(line_t *lp) 14130154ac8SAndrew Moore { 14295e6217eSAndrew Moore line_t *cp = &buffer_head; 14330154ac8SAndrew Moore long n = 0; 14430154ac8SAndrew Moore 14595e6217eSAndrew Moore while (cp != lp && (cp = cp->q_forw) != &buffer_head) 14630154ac8SAndrew Moore n++; 14795e6217eSAndrew Moore if (n && cp == &buffer_head) { 148a4616748SMike Barcroft errmsg = "invalid address"; 14910ca1c6cSAndrew Moore return ERR; 15010ca1c6cSAndrew Moore } 15110ca1c6cSAndrew Moore return n; 15230154ac8SAndrew Moore } 15330154ac8SAndrew Moore 15430154ac8SAndrew Moore 15595e6217eSAndrew Moore /* get_addressed_line_node: return pointer to a line node in the editor buffer */ 15630154ac8SAndrew Moore line_t * 1577669d0fcSWarner Losh get_addressed_line_node(long n) 15830154ac8SAndrew Moore { 15995e6217eSAndrew Moore static line_t *lp = &buffer_head; 16030154ac8SAndrew Moore static long on = 0; 16130154ac8SAndrew Moore 16295e6217eSAndrew Moore SPL1(); 16330154ac8SAndrew Moore if (n > on) 16495e6217eSAndrew Moore if (n <= (on + addr_last) >> 1) 16530154ac8SAndrew Moore for (; on < n; on++) 16695e6217eSAndrew Moore lp = lp->q_forw; 16730154ac8SAndrew Moore else { 16895e6217eSAndrew Moore lp = buffer_head.q_back; 16995e6217eSAndrew Moore for (on = addr_last; on > n; on--) 17095e6217eSAndrew Moore lp = lp->q_back; 17130154ac8SAndrew Moore } 17230154ac8SAndrew Moore else 17330154ac8SAndrew Moore if (n >= on >> 1) 17430154ac8SAndrew Moore for (; on > n; on--) 17595e6217eSAndrew Moore lp = lp->q_back; 17630154ac8SAndrew Moore else { 17795e6217eSAndrew Moore lp = &buffer_head; 17830154ac8SAndrew Moore for (on = 0; on < n; on++) 17995e6217eSAndrew Moore lp = lp->q_forw; 18030154ac8SAndrew Moore } 18195e6217eSAndrew Moore SPL0(); 18230154ac8SAndrew Moore return lp; 18330154ac8SAndrew Moore } 18430154ac8SAndrew Moore 18530154ac8SAndrew Moore 18695e6217eSAndrew Moore extern int newline_added; 18795e6217eSAndrew Moore 18830154ac8SAndrew Moore 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 24495c745afSAndrew Moore 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