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