xref: /freebsd/bin/ed/buf.c (revision f50fae318d6dd4028b6aca25436053c28b07b0ea)
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