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