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