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>
3030154ac8SAndrew Moore #include <sys/file.h>
31d165d4acSAndrew Moore #include <sys/stat.h>
3230154ac8SAndrew Moore
3330154ac8SAndrew Moore #include "ed.h"
3430154ac8SAndrew Moore
3530154ac8SAndrew Moore
36ae824d80SEd Schouten static FILE *sfp; /* scratch file pointer */
37ae824d80SEd Schouten static off_t sfseek; /* scratch file position */
38ae824d80SEd Schouten static int seek_write; /* seek before writing */
39ae824d80SEd Schouten static line_t buffer_head; /* incore buffer */
4030154ac8SAndrew Moore
4195e6217eSAndrew Moore /* get_sbuf_line: get a line of text from the scratch file; return pointer
4230154ac8SAndrew Moore to the text */
4330154ac8SAndrew Moore char *
get_sbuf_line(line_t * lp)447669d0fcSWarner Losh get_sbuf_line(line_t *lp)
4530154ac8SAndrew Moore {
4695e6217eSAndrew Moore static char *sfbuf = NULL; /* buffer */
478bd856deSPedro F. Giffuni static size_t sfbufsz; /* buffer size */
4895e6217eSAndrew Moore
498bd856deSPedro F. Giffuni size_t len;
5030154ac8SAndrew Moore
5195e6217eSAndrew Moore if (lp == &buffer_head)
5230154ac8SAndrew Moore return NULL;
5330154ac8SAndrew Moore seek_write = 1; /* force seek on write */
5430154ac8SAndrew Moore /* out of position */
5530154ac8SAndrew Moore if (sfseek != lp->seek) {
5630154ac8SAndrew Moore sfseek = lp->seek;
577cbfe4d8SAndrey A. Chernov if (fseeko(sfp, sfseek, SEEK_SET) < 0) {
5830154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno));
59a4616748SMike Barcroft errmsg = "cannot seek temp file";
6030154ac8SAndrew Moore return NULL;
6130154ac8SAndrew Moore }
6230154ac8SAndrew Moore }
6395e6217eSAndrew Moore len = lp->len;
6495e6217eSAndrew Moore REALLOC(sfbuf, sfbufsz, len + 1, NULL);
65*f50fae31SPedro F. Giffuni if (fread(sfbuf, sizeof(char), len, sfp) != len) {
6630154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno));
67a4616748SMike Barcroft errmsg = "cannot read temp file";
6830154ac8SAndrew Moore return NULL;
6930154ac8SAndrew Moore }
7030154ac8SAndrew Moore sfseek += len; /* update file position */
7130154ac8SAndrew Moore sfbuf[len] = '\0';
7230154ac8SAndrew Moore return sfbuf;
7330154ac8SAndrew Moore }
7430154ac8SAndrew Moore
7530154ac8SAndrew Moore
7695e6217eSAndrew Moore /* put_sbuf_line: write a line of text to the scratch file and add a line node
7730154ac8SAndrew Moore to the editor buffer; return a pointer to the end of the text */
78a4616748SMike Barcroft const char *
put_sbuf_line(const char * cs)797669d0fcSWarner Losh put_sbuf_line(const char *cs)
8030154ac8SAndrew Moore {
8130154ac8SAndrew Moore line_t *lp;
828bd856deSPedro F. Giffuni size_t len;
83a4616748SMike Barcroft const char *s;
8430154ac8SAndrew Moore
8530154ac8SAndrew Moore if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
8630154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno));
87a4616748SMike Barcroft errmsg = "out of memory";
8830154ac8SAndrew Moore return NULL;
8930154ac8SAndrew Moore }
9030154ac8SAndrew Moore /* assert: cs is '\n' terminated */
9130154ac8SAndrew Moore for (s = cs; *s != '\n'; s++)
9230154ac8SAndrew Moore ;
9330154ac8SAndrew Moore if (s - cs >= LINECHARS) {
94a4616748SMike Barcroft errmsg = "line too long";
95ae568477SChristian Brueffer free(lp);
9630154ac8SAndrew Moore return NULL;
9730154ac8SAndrew Moore }
9895e6217eSAndrew Moore len = s - cs;
9930154ac8SAndrew Moore /* out of position */
10030154ac8SAndrew Moore if (seek_write) {
1017cbfe4d8SAndrey A. Chernov if (fseeko(sfp, (off_t)0, SEEK_END) < 0) {
10230154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno));
103a4616748SMike Barcroft errmsg = "cannot seek temp file";
104ae568477SChristian Brueffer free(lp);
10530154ac8SAndrew Moore return NULL;
10630154ac8SAndrew Moore }
1077cbfe4d8SAndrey A. Chernov sfseek = ftello(sfp);
10830154ac8SAndrew Moore seek_write = 0;
10930154ac8SAndrew Moore }
11095e6217eSAndrew Moore /* assert: SPL1() */
111*f50fae31SPedro F. Giffuni if (fwrite(cs, sizeof(char), len, sfp) != len) {
11230154ac8SAndrew Moore sfseek = -1;
11330154ac8SAndrew Moore fprintf(stderr, "%s\n", strerror(errno));
114a4616748SMike Barcroft errmsg = "cannot write temp file";
115ae568477SChristian Brueffer free(lp);
11630154ac8SAndrew Moore return NULL;
11730154ac8SAndrew Moore }
11830154ac8SAndrew Moore lp->len = len;
11930154ac8SAndrew Moore lp->seek = sfseek;
12095e6217eSAndrew Moore add_line_node(lp);
12130154ac8SAndrew Moore sfseek += len; /* update file position */
12230154ac8SAndrew Moore return ++s;
12330154ac8SAndrew Moore }
12430154ac8SAndrew Moore
12530154ac8SAndrew Moore
12695e6217eSAndrew Moore /* add_line_node: add a line node in the editor buffer after the current line */
12730154ac8SAndrew Moore void
add_line_node(line_t * lp)1287669d0fcSWarner Losh add_line_node(line_t *lp)
12930154ac8SAndrew Moore {
13030154ac8SAndrew Moore line_t *cp;
13130154ac8SAndrew Moore
13295e6217eSAndrew Moore cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */
133d165d4acSAndrew Moore INSQUE(lp, cp);
13495e6217eSAndrew Moore addr_last++;
13595e6217eSAndrew Moore current_addr++;
13630154ac8SAndrew Moore }
13730154ac8SAndrew Moore
13830154ac8SAndrew Moore
13995e6217eSAndrew Moore /* get_line_node_addr: return line number of pointer */
14030154ac8SAndrew Moore long
get_line_node_addr(line_t * lp)1417669d0fcSWarner Losh get_line_node_addr(line_t *lp)
14230154ac8SAndrew Moore {
14395e6217eSAndrew Moore line_t *cp = &buffer_head;
14430154ac8SAndrew Moore long n = 0;
14530154ac8SAndrew Moore
14695e6217eSAndrew Moore while (cp != lp && (cp = cp->q_forw) != &buffer_head)
14730154ac8SAndrew Moore n++;
14895e6217eSAndrew Moore if (n && cp == &buffer_head) {
149a4616748SMike Barcroft errmsg = "invalid address";
15010ca1c6cSAndrew Moore return ERR;
15110ca1c6cSAndrew Moore }
15210ca1c6cSAndrew Moore return n;
15330154ac8SAndrew Moore }
15430154ac8SAndrew Moore
15530154ac8SAndrew Moore
15695e6217eSAndrew Moore /* get_addressed_line_node: return pointer to a line node in the editor buffer */
15730154ac8SAndrew Moore line_t *
get_addressed_line_node(long n)1587669d0fcSWarner Losh get_addressed_line_node(long n)
15930154ac8SAndrew Moore {
16095e6217eSAndrew Moore static line_t *lp = &buffer_head;
16130154ac8SAndrew Moore static long on = 0;
16230154ac8SAndrew Moore
16395e6217eSAndrew Moore SPL1();
16430154ac8SAndrew Moore if (n > on)
16595e6217eSAndrew Moore if (n <= (on + addr_last) >> 1)
16630154ac8SAndrew Moore for (; on < n; on++)
16795e6217eSAndrew Moore lp = lp->q_forw;
16830154ac8SAndrew Moore else {
16995e6217eSAndrew Moore lp = buffer_head.q_back;
17095e6217eSAndrew Moore for (on = addr_last; on > n; on--)
17195e6217eSAndrew Moore lp = lp->q_back;
17230154ac8SAndrew Moore }
17330154ac8SAndrew Moore else
17430154ac8SAndrew Moore if (n >= on >> 1)
17530154ac8SAndrew Moore for (; on > n; on--)
17695e6217eSAndrew Moore lp = lp->q_back;
17730154ac8SAndrew Moore else {
17895e6217eSAndrew Moore lp = &buffer_head;
17930154ac8SAndrew Moore for (on = 0; on < n; on++)
18095e6217eSAndrew Moore lp = lp->q_forw;
18130154ac8SAndrew Moore }
18295e6217eSAndrew Moore SPL0();
18330154ac8SAndrew Moore return lp;
18430154ac8SAndrew Moore }
18530154ac8SAndrew Moore
186ae824d80SEd Schouten static char sfn[15] = ""; /* scratch file name */
18730154ac8SAndrew Moore
18895e6217eSAndrew Moore /* open_sbuf: open scratch file */
18995e6217eSAndrew Moore int
open_sbuf(void)1907669d0fcSWarner Losh open_sbuf(void)
19130154ac8SAndrew Moore {
19249d54362SJuli Mallett int fd;
193d165d4acSAndrew Moore int u;
194d165d4acSAndrew Moore
19595e6217eSAndrew Moore isbinary = newline_added = 0;
196d165d4acSAndrew Moore u = umask(077);
19730154ac8SAndrew Moore strcpy(sfn, "/tmp/ed.XXXXXX");
198f8ce2ec9SEivind Eklund if ((fd = mkstemp(sfn)) == -1 ||
199e38b5013SWarner Losh (sfp = fdopen(fd, "w+")) == NULL) {
200e38b5013SWarner Losh if (fd != -1)
201e38b5013SWarner Losh close(fd);
202e38b5013SWarner Losh perror(sfn);
203a4616748SMike Barcroft errmsg = "cannot open temp file";
204d165d4acSAndrew Moore umask(u);
20530154ac8SAndrew Moore return ERR;
20630154ac8SAndrew Moore }
207d165d4acSAndrew Moore umask(u);
20830154ac8SAndrew Moore return 0;
20930154ac8SAndrew Moore }
21030154ac8SAndrew Moore
21130154ac8SAndrew Moore
21295e6217eSAndrew Moore /* close_sbuf: close scratch file */
21395e6217eSAndrew Moore int
close_sbuf(void)2147669d0fcSWarner Losh close_sbuf(void)
21530154ac8SAndrew Moore {
21630154ac8SAndrew Moore if (sfp) {
21730154ac8SAndrew Moore if (fclose(sfp) < 0) {
21830154ac8SAndrew Moore fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
219a4616748SMike Barcroft errmsg = "cannot close temp file";
22030154ac8SAndrew Moore return ERR;
22130154ac8SAndrew Moore }
22230154ac8SAndrew Moore sfp = NULL;
22330154ac8SAndrew Moore unlink(sfn);
22430154ac8SAndrew Moore }
22530154ac8SAndrew Moore sfseek = seek_write = 0;
22630154ac8SAndrew Moore return 0;
22730154ac8SAndrew Moore }
22830154ac8SAndrew Moore
22930154ac8SAndrew Moore
23095e6217eSAndrew Moore /* quit: remove_lines scratch file and exit */
23130154ac8SAndrew Moore void
quit(int n)2327669d0fcSWarner Losh quit(int n)
23330154ac8SAndrew Moore {
23430154ac8SAndrew Moore if (sfp) {
23530154ac8SAndrew Moore fclose(sfp);
23630154ac8SAndrew Moore unlink(sfn);
23730154ac8SAndrew Moore }
23830154ac8SAndrew Moore exit(n);
23930154ac8SAndrew Moore }
24095c745afSAndrew Moore
24195c745afSAndrew Moore
242ae824d80SEd Schouten static unsigned char ctab[256]; /* character translation table */
24395c745afSAndrew Moore
24495e6217eSAndrew Moore /* init_buffers: open scratch buffer; initialize line queue */
24595c745afSAndrew Moore void
init_buffers(void)2467669d0fcSWarner Losh init_buffers(void)
24795c745afSAndrew Moore {
24895c745afSAndrew Moore int i = 0;
24995c745afSAndrew Moore
25095e6217eSAndrew Moore /* Read stdin one character at a time to avoid i/o contention
25195e6217eSAndrew Moore with shell escapes invoked by nonterminal input, e.g.,
25295e6217eSAndrew Moore ed - <<EOF
25395e6217eSAndrew Moore !cat
25495e6217eSAndrew Moore hello, world
25595e6217eSAndrew Moore EOF */
25695e6217eSAndrew Moore setbuffer(stdin, stdinbuf, 1);
257fd0e1c25SWolfgang Helbig
258fd0e1c25SWolfgang Helbig /* Ensure stdout is line buffered. This avoids bogus delays
259fd0e1c25SWolfgang Helbig of output if stdout is piped through utilities to a terminal. */
260fd0e1c25SWolfgang Helbig setvbuf(stdout, NULL, _IOLBF, 0);
26195e6217eSAndrew Moore if (open_sbuf() < 0)
26295c745afSAndrew Moore quit(2);
26395e6217eSAndrew Moore REQUE(&buffer_head, &buffer_head);
26495c745afSAndrew Moore for (i = 0; i < 256; i++)
26595c745afSAndrew Moore ctab[i] = i;
26695c745afSAndrew Moore }
26795c745afSAndrew Moore
26895c745afSAndrew Moore
26995e6217eSAndrew Moore /* translit_text: translate characters in a string */
27095c745afSAndrew Moore char *
translit_text(char * s,int len,int from,int to)2717669d0fcSWarner Losh translit_text(char *s, int len, int from, int to)
27295c745afSAndrew Moore {
27395c745afSAndrew Moore static int i = 0;
27495c745afSAndrew Moore
27595c745afSAndrew Moore unsigned char *us;
27695c745afSAndrew Moore
27795c745afSAndrew Moore ctab[i] = i; /* restore table to initial state */
27895c745afSAndrew Moore ctab[i = from] = to;
27995c745afSAndrew Moore for (us = (unsigned char *) s; len-- > 0; us++)
28095c745afSAndrew Moore *us = ctab[*us];
28195c745afSAndrew Moore return s;
28295c745afSAndrew Moore }
283