Merge branch 'vendor/OPENSSL'
[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  * @(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp
29  * $FreeBSD: src/bin/ed/buf.c,v 1.22 2002/06/30 05:13:53 obrien Exp $
30  * $DragonFly: src/bin/ed/buf.c,v 1.4 2007/04/06 23:36:54 pavalos Exp $
31  */
32
33 #include <sys/file.h>
34 #include <sys/stat.h>
35
36 #include "ed.h"
37
38
39 FILE *sfp;                              /* scratch file pointer */
40 off_t sfseek;                           /* scratch file position */
41 int seek_write;                         /* seek before writing */
42 line_t buffer_head;                     /* incore buffer */
43
44 /* get_sbuf_line: get a line of text from the scratch file; return pointer
45    to the text */
46 char *
47 get_sbuf_line(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 (fseeko(sfp, sfseek, SEEK_SET) < 0) {
61                         fprintf(stderr, "%s\n", strerror(errno));
62                         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                 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 const char *
82 put_sbuf_line(const char *cs)
83 {
84         line_t *lp;
85         int len, ct;
86         const char *s;
87
88         if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
89                 fprintf(stderr, "%s\n", strerror(errno));
90                 errmsg = "out of memory";
91                 return NULL;
92         }
93         /* assert: cs is '\n' terminated */
94         for (s = cs; *s != '\n'; s++)
95                 ;
96         if (s - cs >= LINECHARS) {
97                 errmsg = "line too long";
98                 return NULL;
99         }
100         len = s - cs;
101         /* out of position */
102         if (seek_write) {
103                 if (fseeko(sfp, (off_t)0, SEEK_END) < 0) {
104                         fprintf(stderr, "%s\n", strerror(errno));
105                         errmsg = "cannot seek temp file";
106                         return NULL;
107                 }
108                 sfseek = ftello(sfp);
109                 seek_write = 0;
110         }
111         /* assert: SPL1() */
112         if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
113                 sfseek = -1;
114                 fprintf(stderr, "%s\n", strerror(errno));
115                 errmsg = "cannot write temp file";
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
187 extern int newline_added;
188
189 char sfn[15] = "";                              /* scratch file name */
190
191 /* open_sbuf: open scratch file */
192 int
193 open_sbuf(void)
194 {
195         int fd;
196         int u;
197
198         isbinary = newline_added = 0;
199         u = umask(077);
200         strcpy(sfn, "/tmp/ed.XXXXXX");
201         if ((fd = mkstemp(sfn)) == -1 ||
202             (sfp = fdopen(fd, "w+")) == NULL) {
203                 if (fd != -1)
204                         close(fd);
205                 perror(sfn);
206                 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(void)
218 {
219         if (sfp) {
220                 if (fclose(sfp) < 0) {
221                         fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
222                         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(int n)
236 {
237         if (sfp) {
238                 fclose(sfp);
239                 unlink(sfn);
240         }
241         exit(n);
242 }
243
244
245 unsigned char ctab[256];                /* character translation table */
246
247 /* init_buffers: open scratch buffer; initialize line queue */
248 void
249 init_buffers(void)
250 {
251         int i = 0;
252
253         /* Read stdin one character at a time to avoid i/o contention
254            with shell escapes invoked by nonterminal input, e.g.,
255            ed - <<EOF
256            !cat
257            hello, world
258            EOF */
259         setbuffer(stdin, stdinbuf, 1);
260
261         /* Ensure stdout is line buffered. This avoids bogus delays
262            of output if stdout is piped through utilities to a terminal. */
263         setvbuf(stdout, NULL, _IOLBF, 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 */
273 char *
274 translit_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 }