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