Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/bin/ed/buf.c
39477 views
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 *
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 *
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
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
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 *
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
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
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
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
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 *
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
284