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