sync
[bitrig.git] / bin / ed / buf.c
blobfc1ae7f4ffec5935901063426e01b554480cad80
1 /* $OpenBSD: buf.c,v 1.19 2009/10/27 23:59:21 deraadt Exp $ */
2 /* $NetBSD: buf.c,v 1.15 1995/04/23 10:07:28 cgd Exp $ */
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.
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.
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.
32 #include <sys/file.h>
33 #include <sys/stat.h>
35 #include "ed.h"
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 */
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(line_t *lp)
48 static char *sfbuf = NULL; /* buffer */
49 static int sfbufsz = 0; /* buffer size */
51 int len, ct;
53 if (lp == &buffer_head)
54 return NULL;
55 seek_write = 1; /* force seek on write */
56 /* out of position */
57 if (sfseek != lp->seek) {
58 sfseek = lp->seek;
59 if (fseeko(sfp, sfseek, SEEK_SET) < 0) {
60 perror(NULL);
61 seterrmsg("cannot seek temp file");
62 return NULL;
65 len = lp->len;
66 REALLOC(sfbuf, sfbufsz, len + 1, NULL);
67 if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) {
68 perror(NULL);
69 seterrmsg("cannot read temp file");
70 return NULL;
72 sfseek += len; /* update file position */
73 sfbuf[len] = '\0';
74 return sfbuf;
78 /* put_sbuf_line: write a line of text to the scratch file and add a line node
79 to the editor buffer; return a pointer to the end of the text */
80 char *
81 put_sbuf_line(char *cs)
83 line_t *lp;
84 int len, ct;
85 char *s;
87 if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
88 perror(NULL);
89 seterrmsg("out of memory");
90 return NULL;
92 /* assert: cs is '\n' terminated */
93 for (s = cs; *s != '\n'; s++)
95 if (s - cs >= LINECHARS) {
96 seterrmsg("line too long");
97 free(lp);
98 return NULL;
100 len = s - cs;
101 /* out of position */
102 if (seek_write) {
103 if (fseek(sfp, 0L, SEEK_END) < 0) {
104 perror(NULL);
105 seterrmsg("cannot seek temp file");
106 free(lp);
107 return NULL;
109 sfseek = ftello(sfp);
110 seek_write = 0;
112 /* assert: SPL1() */
113 if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
114 sfseek = -1;
115 perror(NULL);
116 seterrmsg("cannot write temp file");
117 free(lp);
118 return NULL;
120 lp->len = len;
121 lp->seek = sfseek;
122 add_line_node(lp);
123 sfseek += len; /* update file position */
124 return ++s;
128 /* add_line_node: add a line node in the editor buffer after the current line */
129 void
130 add_line_node(line_t *lp)
132 line_t *cp;
134 /* this get_addressed_line_node last! */
135 cp = get_addressed_line_node(current_addr);
136 INSQUE(lp, cp);
137 addr_last++;
138 current_addr++;
142 /* get_line_node_addr: return line number of pointer */
144 get_line_node_addr(line_t *lp)
146 line_t *cp = &buffer_head;
147 int n = 0;
149 while (cp != lp && (cp = cp->q_forw) != &buffer_head)
150 n++;
151 if (n && cp == &buffer_head) {
152 seterrmsg("invalid address");
153 return ERR;
155 return n;
159 /* get_addressed_line_node: return pointer to a line node in the editor buffer */
160 line_t *
161 get_addressed_line_node(int n)
163 static line_t *lp = &buffer_head;
164 static int on = 0;
166 SPL1();
167 if (n > on) {
168 if (n <= (on + addr_last) >> 1)
169 for (; on < n; on++)
170 lp = lp->q_forw;
171 else {
172 lp = buffer_head.q_back;
173 for (on = addr_last; on > n; on--)
174 lp = lp->q_back;
176 } else {
177 if (n >= on >> 1)
178 for (; on > n; on--)
179 lp = lp->q_back;
180 else {
181 lp = &buffer_head;
182 for (on = 0; on < n; on++)
183 lp = lp->q_forw;
186 SPL0();
187 return lp;
191 extern int newline_added;
193 #define SCRATCH_TEMPLATE "/tmp/ed.XXXXXXXXXX"
194 char sfn[sizeof(SCRATCH_TEMPLATE)+1] = ""; /* scratch file name */
196 /* open_sbuf: open scratch file */
198 open_sbuf(void)
200 int fd = -1;
202 isbinary = newline_added = 0;
203 strlcpy(sfn, SCRATCH_TEMPLATE, sizeof sfn);
204 if ((fd = mkstemp(sfn)) == -1 ||
205 (sfp = fdopen(fd, "w+")) == NULL) {
206 if (fd != -1)
207 close(fd);
208 perror(sfn);
209 seterrmsg("cannot open temp file");
210 return ERR;
212 return 0;
216 /* close_sbuf: close scratch file */
218 close_sbuf(void)
220 if (sfp) {
221 if (fclose(sfp) < 0) {
222 perror(sfn);
223 seterrmsg("cannot close temp file");
224 return ERR;
226 sfp = NULL;
227 unlink(sfn);
229 sfseek = seek_write = 0;
230 return 0;
234 /* quit: remove_lines scratch file and exit */
235 void
236 quit(int n)
238 if (sfp) {
239 fclose(sfp);
240 unlink(sfn);
242 exit(n);
246 unsigned char ctab[256]; /* character translation table */
248 /* init_buffers: open scratch buffer; initialize line queue */
249 void
250 init_buffers(void)
252 int i = 0;
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;
269 /* translit_text: translate characters in a string */
270 char *
271 translit_text(char *s, int len, int from, int to)
273 static int i = 0;
275 unsigned char *us;
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;