xref: /dragonfly/bin/ed/buf.c (revision 6e285212)
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  * @(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp
29  * $FreeBSD: src/bin/ed/buf.c,v 1.17 1999/08/27 23:14:12 peter Exp $
30  * $DragonFly: src/bin/ed/buf.c,v 1.2 2003/06/17 04:22:49 dillon Exp $
31  */
32 
33 #include <sys/file.h>
34 #include <sys/stat.h>
35 
36 #include "ed.h"
37 
38 
39 FILE *sfp;				/* scratch file pointer */
40 off_t sfseek;				/* scratch file position */
41 int seek_write;				/* seek before writing */
42 line_t buffer_head;			/* incore buffer */
43 
44 /* get_sbuf_line: get a line of text from the scratch file; return pointer
45    to the text */
46 char *
47 get_sbuf_line(lp)
48 	line_t *lp;
49 {
50 	static char *sfbuf = NULL;	/* buffer */
51 	static int sfbufsz = 0;		/* buffer size */
52 
53 	int len, ct;
54 
55 	if (lp == &buffer_head)
56 		return NULL;
57 	seek_write = 1;				/* force seek on write */
58 	/* out of position */
59 	if (sfseek != lp->seek) {
60 		sfseek = lp->seek;
61 		if (fseek(sfp, sfseek, SEEK_SET) < 0) {
62 			fprintf(stderr, "%s\n", strerror(errno));
63 			sprintf(errmsg, "cannot seek temp file");
64 			return NULL;
65 		}
66 	}
67 	len = lp->len;
68 	REALLOC(sfbuf, sfbufsz, len + 1, NULL);
69 	if ((ct = fread(sfbuf, sizeof(char), len, sfp)) <  0 || ct != len) {
70 		fprintf(stderr, "%s\n", strerror(errno));
71 		sprintf(errmsg, "cannot read temp file");
72 		return NULL;
73 	}
74 	sfseek += len;				/* update file position */
75 	sfbuf[len] = '\0';
76 	return sfbuf;
77 }
78 
79 
80 /* put_sbuf_line: write a line of text to the scratch file and add a line node
81    to the editor buffer;  return a pointer to the end of the text */
82 char *
83 put_sbuf_line(cs)
84 	char *cs;
85 {
86 	line_t *lp;
87 	int len, ct;
88 	char *s;
89 
90 	if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
91 		fprintf(stderr, "%s\n", strerror(errno));
92 		sprintf(errmsg, "out of memory");
93 		return NULL;
94 	}
95 	/* assert: cs is '\n' terminated */
96 	for (s = cs; *s != '\n'; s++)
97 		;
98 	if (s - cs >= LINECHARS) {
99 		sprintf(errmsg, "line too long");
100 		return NULL;
101 	}
102 	len = s - cs;
103 	/* out of position */
104 	if (seek_write) {
105 		if (fseek(sfp, 0L, SEEK_END) < 0) {
106 			fprintf(stderr, "%s\n", strerror(errno));
107 			sprintf(errmsg, "cannot seek temp file");
108 			return NULL;
109 		}
110 		sfseek = ftell(sfp);
111 		seek_write = 0;
112 	}
113 	/* assert: SPL1() */
114 	if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
115 		sfseek = -1;
116 		fprintf(stderr, "%s\n", strerror(errno));
117 		sprintf(errmsg, "cannot write temp file");
118 		return NULL;
119 	}
120 	lp->len = len;
121 	lp->seek  = sfseek;
122 	add_line_node(lp);
123 	sfseek += len;			/* update file position */
124 	return ++s;
125 }
126 
127 
128 /* add_line_node: add a line node in the editor buffer after the current line */
129 void
130 add_line_node(lp)
131 	line_t *lp;
132 {
133 	line_t *cp;
134 
135 	cp = get_addressed_line_node(current_addr);				/* this get_addressed_line_node last! */
136 	INSQUE(lp, cp);
137 	addr_last++;
138 	current_addr++;
139 }
140 
141 
142 /* get_line_node_addr: return line number of pointer */
143 long
144 get_line_node_addr(lp)
145 	line_t *lp;
146 {
147 	line_t *cp = &buffer_head;
148 	long n = 0;
149 
150 	while (cp != lp && (cp = cp->q_forw) != &buffer_head)
151 		n++;
152 	if (n && cp == &buffer_head) {
153 		sprintf(errmsg, "invalid address");
154 		return ERR;
155 	 }
156 	 return n;
157 }
158 
159 
160 /* get_addressed_line_node: return pointer to a line node in the editor buffer */
161 line_t *
162 get_addressed_line_node(n)
163 	long n;
164 {
165 	static line_t *lp = &buffer_head;
166 	static long on = 0;
167 
168 	SPL1();
169 	if (n > on)
170 		if (n <= (on + addr_last) >> 1)
171 			for (; on < n; on++)
172 				lp = lp->q_forw;
173 		else {
174 			lp = buffer_head.q_back;
175 			for (on = addr_last; on > n; on--)
176 				lp = lp->q_back;
177 		}
178 	else
179 		if (n >= on >> 1)
180 			for (; on > n; on--)
181 				lp = lp->q_back;
182 		else {
183 			lp = &buffer_head;
184 			for (on = 0; on < n; on++)
185 				lp = lp->q_forw;
186 		}
187 	SPL0();
188 	return lp;
189 }
190 
191 
192 extern int newline_added;
193 
194 char sfn[15] = "";				/* scratch file name */
195 
196 /* open_sbuf: open scratch file */
197 int
198 open_sbuf()
199 {
200 	int fd = -1;
201 	int u;
202 
203 	isbinary = newline_added = 0;
204 	u = umask(077);
205 	strcpy(sfn, "/tmp/ed.XXXXXX");
206 	if ((fd = mkstemp(sfn)) == -1 ||
207 	    (sfp = fdopen(fd, "w+")) == NULL) {
208 		if (fd != -1)
209 			close(fd);
210 		perror(sfn);
211 		strcpy(errmsg, "cannot open temp file");
212 		umask(u);
213 		return ERR;
214 	}
215 	umask(u);
216 	return 0;
217 }
218 
219 
220 /* close_sbuf: close scratch file */
221 int
222 close_sbuf()
223 {
224 	if (sfp) {
225 		if (fclose(sfp) < 0) {
226 			fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
227 			sprintf(errmsg, "cannot close temp file");
228 			return ERR;
229 		}
230 		sfp = NULL;
231 		unlink(sfn);
232 	}
233 	sfseek = seek_write = 0;
234 	return 0;
235 }
236 
237 
238 /* quit: remove_lines scratch file and exit */
239 void
240 quit(n)
241 	int n;
242 {
243 	if (sfp) {
244 		fclose(sfp);
245 		unlink(sfn);
246 	}
247 	exit(n);
248 }
249 
250 
251 unsigned char ctab[256];		/* character translation table */
252 
253 /* init_buffers: open scratch buffer; initialize line queue */
254 void
255 init_buffers()
256 {
257 	int i = 0;
258 
259 	/* Read stdin one character at a time to avoid i/o contention
260 	   with shell escapes invoked by nonterminal input, e.g.,
261 	   ed - <<EOF
262 	   !cat
263 	   hello, world
264 	   EOF */
265 	setbuffer(stdin, stdinbuf, 1);
266 
267 	/* Ensure stdout is line buffered. This avoids bogus delays
268 	   of output if stdout is piped through utilities to a terminal. */
269 	setvbuf(stdout, NULL, _IOLBF, 0);
270 	if (open_sbuf() < 0)
271 		quit(2);
272 	REQUE(&buffer_head, &buffer_head);
273 	for (i = 0; i < 256; i++)
274 		ctab[i] = i;
275 }
276 
277 
278 /* translit_text: translate characters in a string */
279 char *
280 translit_text(s, len, from, to)
281 	char *s;
282 	int len;
283 	int from;
284 	int to;
285 {
286 	static int i = 0;
287 
288 	unsigned char *us;
289 
290 	ctab[i] = i;			/* restore table to initial state */
291 	ctab[i = from] = to;
292 	for (us = (unsigned char *) s; len-- > 0; us++)
293 		*us = ctab[*us];
294 	return s;
295 }
296