buf.c revision 50471
1/* buf.c: This file contains the scratch-file buffer routines for the
2   ed line editor. */
3/*-
4 * Copyright (c) 1993 Andrew Moore, Talke Studio.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#ifndef lint
30#if 0
31static char * const rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp";
32#else
33static char * const rcsid =
34  "$FreeBSD: head/bin/ed/buf.c 50471 1999-08-27 23:15:48Z peter $";
35#endif
36#endif /* not lint */
37
38#include <sys/file.h>
39#include <sys/stat.h>
40
41#include "ed.h"
42
43
44FILE *sfp;				/* scratch file pointer */
45off_t sfseek;				/* scratch file position */
46int seek_write;				/* seek before writing */
47line_t buffer_head;			/* incore buffer */
48
49/* get_sbuf_line: get a line of text from the scratch file; return pointer
50   to the text */
51char *
52get_sbuf_line(lp)
53	line_t *lp;
54{
55	static char *sfbuf = NULL;	/* buffer */
56	static int sfbufsz = 0;		/* buffer size */
57
58	int len, ct;
59
60	if (lp == &buffer_head)
61		return NULL;
62	seek_write = 1;				/* force seek on write */
63	/* out of position */
64	if (sfseek != lp->seek) {
65		sfseek = lp->seek;
66		if (fseek(sfp, sfseek, SEEK_SET) < 0) {
67			fprintf(stderr, "%s\n", strerror(errno));
68			sprintf(errmsg, "cannot seek temp file");
69			return NULL;
70		}
71	}
72	len = lp->len;
73	REALLOC(sfbuf, sfbufsz, len + 1, NULL);
74	if ((ct = fread(sfbuf, sizeof(char), len, sfp)) <  0 || ct != len) {
75		fprintf(stderr, "%s\n", strerror(errno));
76		sprintf(errmsg, "cannot read temp file");
77		return NULL;
78	}
79	sfseek += len;				/* update file position */
80	sfbuf[len] = '\0';
81	return sfbuf;
82}
83
84
85/* put_sbuf_line: write a line of text to the scratch file and add a line node
86   to the editor buffer;  return a pointer to the end of the text */
87char *
88put_sbuf_line(cs)
89	char *cs;
90{
91	line_t *lp;
92	int len, ct;
93	char *s;
94
95	if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
96		fprintf(stderr, "%s\n", strerror(errno));
97		sprintf(errmsg, "out of memory");
98		return NULL;
99	}
100	/* assert: cs is '\n' terminated */
101	for (s = cs; *s != '\n'; s++)
102		;
103	if (s - cs >= LINECHARS) {
104		sprintf(errmsg, "line too long");
105		return NULL;
106	}
107	len = s - cs;
108	/* out of position */
109	if (seek_write) {
110		if (fseek(sfp, 0L, SEEK_END) < 0) {
111			fprintf(stderr, "%s\n", strerror(errno));
112			sprintf(errmsg, "cannot seek temp file");
113			return NULL;
114		}
115		sfseek = ftell(sfp);
116		seek_write = 0;
117	}
118	/* assert: SPL1() */
119	if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
120		sfseek = -1;
121		fprintf(stderr, "%s\n", strerror(errno));
122		sprintf(errmsg, "cannot write temp file");
123		return NULL;
124	}
125	lp->len = len;
126	lp->seek  = sfseek;
127	add_line_node(lp);
128	sfseek += len;			/* update file position */
129	return ++s;
130}
131
132
133/* add_line_node: add a line node in the editor buffer after the current line */
134void
135add_line_node(lp)
136	line_t *lp;
137{
138	line_t *cp;
139
140	cp = get_addressed_line_node(current_addr);				/* this get_addressed_line_node last! */
141	INSQUE(lp, cp);
142	addr_last++;
143	current_addr++;
144}
145
146
147/* get_line_node_addr: return line number of pointer */
148long
149get_line_node_addr(lp)
150	line_t *lp;
151{
152	line_t *cp = &buffer_head;
153	long n = 0;
154
155	while (cp != lp && (cp = cp->q_forw) != &buffer_head)
156		n++;
157	if (n && cp == &buffer_head) {
158		sprintf(errmsg, "invalid address");
159		return ERR;
160	 }
161	 return n;
162}
163
164
165/* get_addressed_line_node: return pointer to a line node in the editor buffer */
166line_t *
167get_addressed_line_node(n)
168	long n;
169{
170	static line_t *lp = &buffer_head;
171	static long on = 0;
172
173	SPL1();
174	if (n > on)
175		if (n <= (on + addr_last) >> 1)
176			for (; on < n; on++)
177				lp = lp->q_forw;
178		else {
179			lp = buffer_head.q_back;
180			for (on = addr_last; on > n; on--)
181				lp = lp->q_back;
182		}
183	else
184		if (n >= on >> 1)
185			for (; on > n; on--)
186				lp = lp->q_back;
187		else {
188			lp = &buffer_head;
189			for (on = 0; on < n; on++)
190				lp = lp->q_forw;
191		}
192	SPL0();
193	return lp;
194}
195
196
197extern int newline_added;
198
199char sfn[15] = "";				/* scratch file name */
200
201/* open_sbuf: open scratch file */
202int
203open_sbuf()
204{
205	int fd = -1;
206	int u;
207
208	isbinary = newline_added = 0;
209	u = umask(077);
210	strcpy(sfn, "/tmp/ed.XXXXXX");
211	if ((fd = mkstemp(sfn)) == -1 ||
212	    (sfp = fdopen(fd, "w+")) == NULL) {
213		if (fd != -1)
214			close(fd);
215		perror(sfn);
216		strcpy(errmsg, "cannot open temp file");
217		umask(u);
218		return ERR;
219	}
220	umask(u);
221	return 0;
222}
223
224
225/* close_sbuf: close scratch file */
226int
227close_sbuf()
228{
229	if (sfp) {
230		if (fclose(sfp) < 0) {
231			fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
232			sprintf(errmsg, "cannot close temp file");
233			return ERR;
234		}
235		sfp = NULL;
236		unlink(sfn);
237	}
238	sfseek = seek_write = 0;
239	return 0;
240}
241
242
243/* quit: remove_lines scratch file and exit */
244void
245quit(n)
246	int n;
247{
248	if (sfp) {
249		fclose(sfp);
250		unlink(sfn);
251	}
252	exit(n);
253}
254
255
256unsigned char ctab[256];		/* character translation table */
257
258/* init_buffers: open scratch buffer; initialize line queue */
259void
260init_buffers()
261{
262	int i = 0;
263
264	/* Read stdin one character at a time to avoid i/o contention
265	   with shell escapes invoked by nonterminal input, e.g.,
266	   ed - <<EOF
267	   !cat
268	   hello, world
269	   EOF */
270	setbuffer(stdin, stdinbuf, 1);
271
272	/* Ensure stdout is line buffered. This avoids bogus delays
273	   of output if stdout is piped through utilities to a terminal. */
274	setvbuf(stdout, NULL, _IOLBF, 0);
275	if (open_sbuf() < 0)
276		quit(2);
277	REQUE(&buffer_head, &buffer_head);
278	for (i = 0; i < 256; i++)
279		ctab[i] = i;
280}
281
282
283/* translit_text: translate characters in a string */
284char *
285translit_text(s, len, from, to)
286	char *s;
287	int len;
288	int from;
289	int to;
290{
291	static int i = 0;
292
293	unsigned char *us;
294
295	ctab[i] = i;			/* restore table to initial state */
296	ctab[i = from] = to;
297	for (us = (unsigned char *) s; len-- > 0; us++)
298		*us = ctab[*us];
299	return s;
300}
301