buf.c revision 1.14 1 /* $NetBSD: buf.c,v 1.14 1995/03/21 09:04:35 cgd 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 #ifndef lint
31 #if 0
32 static char *rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp";
33 #else
34 static char rcsid[] = "$NetBSD: buf.c,v 1.14 1995/03/21 09:04:35 cgd 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 u;
206
207 isbinary = newline_added = 0;
208 u = umask(077);
209 strcpy(sfn, "/tmp/ed.XXXXXX");
210 if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) {
211 fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
212 sprintf(errmsg, "cannot open temp file");
213 umask(u);
214 return ERR;
215 }
216 umask(u);
217 return 0;
218 }
219
220
221 /* close_sbuf: close scratch file */
222 int
223 close_sbuf()
224 {
225 if (sfp) {
226 if (fclose(sfp) < 0) {
227 fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
228 sprintf(errmsg, "cannot close temp file");
229 return ERR;
230 }
231 sfp = NULL;
232 unlink(sfn);
233 }
234 sfseek = seek_write = 0;
235 return 0;
236 }
237
238
239 /* quit: remove_lines scratch file and exit */
240 void
241 quit(n)
242 int n;
243 {
244 if (sfp) {
245 fclose(sfp);
246 unlink(sfn);
247 }
248 exit(n);
249 }
250
251
252 unsigned char ctab[256]; /* character translation table */
253
254 /* init_buffers: open scratch buffer; initialize line queue */
255 void
256 init_buffers()
257 {
258 int i = 0;
259
260 /* Read stdin one character at a time to avoid i/o contention
261 with shell escapes invoked by nonterminal input, e.g.,
262 ed - <<EOF
263 !cat
264 hello, world
265 EOF */
266 setbuffer(stdin, stdinbuf, 1);
267 if (open_sbuf() < 0)
268 quit(2);
269 REQUE(&buffer_head, &buffer_head);
270 for (i = 0; i < 256; i++)
271 ctab[i] = i;
272 }
273
274
275 /* translit_text: translate characters in a string */
276 char *
277 translit_text(s, len, from, to)
278 char *s;
279 int len;
280 int from;
281 int to;
282 {
283 static int i = 0;
284
285 unsigned char *us;
286
287 ctab[i] = i; /* restore table to initial state */
288 ctab[i = from] = to;
289 for (us = (unsigned char *) s; len-- > 0; us++)
290 *us = ctab[*us];
291 return s;
292 }
293