xref: /freebsd/bin/ed/buf.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
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
31 static char * const rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp";
32 #else
33 static char * const rcsid =
34 	"$Id: buf.c,v 1.15 1997/12/31 12:25:33 helbig Exp $";
35 #endif
36 #endif /* not lint */
37 
38 #include <sys/file.h>
39 #include <sys/stat.h>
40 
41 #include "ed.h"
42 
43 
44 FILE *sfp;				/* scratch file pointer */
45 off_t sfseek;				/* scratch file position */
46 int seek_write;				/* seek before writing */
47 line_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 */
51 char *
52 get_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 */
87 char *
88 put_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 */
134 void
135 add_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 */
148 long
149 get_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 */
166 line_t *
167 get_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 
197 extern int newline_added;
198 
199 char sfn[15] = "";				/* scratch file name */
200 
201 /* open_sbuf: open scratch file */
202 int
203 open_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 */
226 int
227 close_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 */
244 void
245 quit(n)
246 	int n;
247 {
248 	if (sfp) {
249 		fclose(sfp);
250 		unlink(sfn);
251 	}
252 	exit(n);
253 }
254 
255 
256 unsigned char ctab[256];		/* character translation table */
257 
258 /* init_buffers: open scratch buffer; initialize line queue */
259 void
260 init_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 */
284 char *
285 translit_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