io.c revision 1.3 1 /* $NetBSD: io.c,v 1.3 1997/01/09 16:34:27 tls Exp $ */
2
3 /* io.c: This file contains the i/o routines for the ed line editor */
4 /*-
5 * Copyright (c) 1993 Andrew Moore, Talke Studio.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #ifndef lint
31 #if 0
32 static char *rcsid = "@(#)io.c,v 1.1 1994/02/01 00:34:41 alm Exp";
33 #else
34 static char rcsid[] = "$NetBSD: io.c,v 1.3 1997/01/09 16:34:27 tls Exp $";
35 #endif
36 #endif /* not lint */
37
38 #include "ed.h"
39
40
41 extern int scripted;
42
43 /* read_file: read a named file/pipe into the buffer; return line count */
44 long
45 read_file(fn, n)
46 char *fn;
47 long n;
48 {
49 FILE *fp;
50 long size;
51
52
53 fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r");
54 if (fp == NULL) {
55 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
56 sprintf(errmsg, "cannot open input file");
57 return ERR;
58 } else if ((size = read_stream(fp, n)) < 0)
59 return ERR;
60 else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
61 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
62 sprintf(errmsg, "cannot close input file");
63 return ERR;
64 }
65 fprintf(stderr, !scripted ? "%lu\n" : "", size);
66 return current_addr - n;
67 }
68
69
70 extern int des;
71
72 char *sbuf; /* file i/o buffer */
73 int sbufsz; /* file i/o buffer size */
74 int newline_added; /* if set, newline appended to input file */
75
76 /* read_stream: read a stream into the editor buffer; return status */
77 long
78 read_stream(fp, n)
79 FILE *fp;
80 long n;
81 {
82 line_t *lp = get_addressed_line_node(n);
83 undo_t *up = NULL;
84 unsigned long size = 0;
85 int o_newline_added = newline_added;
86 int o_isbinary = isbinary;
87 int appended = (n == addr_last);
88 int len;
89
90 isbinary = newline_added = 0;
91 if (des)
92 init_des_cipher();
93 for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) {
94 SPL1();
95 if (put_sbuf_line(sbuf) == NULL) {
96 SPL0();
97 return ERR;
98 }
99 lp = lp->q_forw;
100 if (up)
101 up->t = lp;
102 else if ((up = push_undo_stack(UADD, current_addr,
103 current_addr)) == NULL) {
104 SPL0();
105 return ERR;
106 }
107 SPL0();
108 }
109 if (len < 0)
110 return ERR;
111 if (appended && size && o_isbinary && o_newline_added)
112 fputs("newline inserted\n", stderr);
113 else if (newline_added && (!appended || !isbinary && !o_isbinary))
114 fputs("newline appended\n", stderr);
115 if (isbinary && newline_added && !appended)
116 size += 1;
117 if (!size)
118 newline_added = 1;
119 newline_added = appended ? newline_added : o_newline_added;
120 isbinary = isbinary | o_isbinary;
121 if (des)
122 size += 8 - size % 8; /* adjust DES size */
123 return size;
124 }
125
126
127 /* get_stream_line: read a line of text from a stream; return line length */
128 int
129 get_stream_line(fp)
130 FILE *fp;
131 {
132 int c;
133 int i = 0;
134
135 while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || !feof(fp) &&
136 !ferror(fp)) && c != '\n') {
137 REALLOC(sbuf, sbufsz, i + 1, ERR);
138 if (!(sbuf[i++] = c))
139 isbinary = 1;
140 }
141 REALLOC(sbuf, sbufsz, i + 2, ERR);
142 if (c == '\n')
143 sbuf[i++] = c;
144 else if (ferror(fp)) {
145 fprintf(stderr, "%s\n", strerror(errno));
146 sprintf(errmsg, "cannot read input file");
147 return ERR;
148 } else if (i) {
149 sbuf[i++] = '\n';
150 newline_added = 1;
151 }
152 sbuf[i] = '\0';
153 return (isbinary && newline_added && i) ? --i : i;
154 }
155
156
157 /* write_file: write a range of lines to a named file/pipe; return line count */
158 long
159 write_file(fn, mode, n, m)
160 char *fn;
161 char *mode;
162 long n;
163 long m;
164 {
165 FILE *fp;
166 long size;
167
168 fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode);
169 if (fp == NULL) {
170 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
171 sprintf(errmsg, "cannot open output file");
172 return ERR;
173 } else if ((size = write_stream(fp, n, m)) < 0)
174 return ERR;
175 else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
176 fprintf(stderr, "%s: %s\n", fn, strerror(errno));
177 sprintf(errmsg, "cannot close output file");
178 return ERR;
179 }
180 fprintf(stderr, !scripted ? "%lu\n" : "", size);
181 return n ? m - n + 1 : 0;
182 }
183
184
185 /* write_stream: write a range of lines to a stream; return status */
186 long
187 write_stream(fp, n, m)
188 FILE *fp;
189 long n;
190 long m;
191 {
192 line_t *lp = get_addressed_line_node(n);
193 unsigned long size = 0;
194 char *s;
195 int len;
196
197 if (des)
198 init_des_cipher();
199 for (; n && n <= m; n++, lp = lp->q_forw) {
200 if ((s = get_sbuf_line(lp)) == NULL)
201 return ERR;
202 len = lp->len;
203 if (n != addr_last || !isbinary || !newline_added)
204 s[len++] = '\n';
205 if (put_stream_line(fp, s, len) < 0)
206 return ERR;
207 size += len;
208 }
209 if (des) {
210 flush_des_file(fp); /* flush buffer */
211 size += 8 - size % 8; /* adjust DES size */
212 }
213 return size;
214 }
215
216
217 /* put_stream_line: write a line of text to a stream; return status */
218 int
219 put_stream_line(fp, s, len)
220 FILE *fp;
221 char *s;
222 int len;
223 {
224 while (len--)
225 if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) {
226 fprintf(stderr, "%s\n", strerror(errno));
227 sprintf(errmsg, "cannot write file");
228 return ERR;
229 }
230 return 0;
231 }
232
233 /* get_extended_line: get a an extended line from stdin */
234 char *
235 get_extended_line(sizep, nonl)
236 int *sizep;
237 int nonl;
238 {
239 static char *cvbuf = NULL; /* buffer */
240 static int cvbufsz = 0; /* buffer size */
241
242 int l, n;
243 char *t = ibufp;
244
245 while (*t++ != '\n')
246 ;
247 if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) {
248 *sizep = l;
249 return ibufp;
250 }
251 *sizep = -1;
252 REALLOC(cvbuf, cvbufsz, l, NULL);
253 memcpy(cvbuf, ibufp, l);
254 *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
255 if (nonl) l--; /* strip newline */
256 for (;;) {
257 if ((n = get_tty_line()) < 0)
258 return NULL;
259 else if (n == 0 || ibuf[n - 1] != '\n') {
260 sprintf(errmsg, "unexpected end-of-file");
261 return NULL;
262 }
263 REALLOC(cvbuf, cvbufsz, l + n, NULL);
264 memcpy(cvbuf + l, ibuf, n);
265 l += n;
266 if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1))
267 break;
268 *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
269 if (nonl) l--; /* strip newline */
270 }
271 REALLOC(cvbuf, cvbufsz, l + 1, NULL);
272 cvbuf[l] = '\0';
273 *sizep = l;
274 return cvbuf;
275 }
276
277
278 /* get_tty_line: read a line of text from stdin; return line length */
279 int
280 get_tty_line()
281 {
282 int oi = 0;
283 int i = 0;
284 int c;
285
286 for (;;)
287 switch (c = getchar()) {
288 default:
289 oi = 0;
290 REALLOC(ibuf, ibufsz, i + 2, ERR);
291 if (!(ibuf[i++] = c)) isbinary = 1;
292 if (c != '\n')
293 continue;
294 lineno++;
295 ibuf[i] = '\0';
296 ibufp = ibuf;
297 return i;
298 case EOF:
299 if (ferror(stdin)) {
300 fprintf(stderr, "stdin: %s\n", strerror(errno));
301 sprintf(errmsg, "cannot read stdin");
302 clearerr(stdin);
303 ibufp = NULL;
304 return ERR;
305 } else {
306 clearerr(stdin);
307 if (i != oi) {
308 oi = i;
309 continue;
310 } else if (i)
311 ibuf[i] = '\0';
312 ibufp = ibuf;
313 return i;
314 }
315 }
316 }
317
318
319
320 #define ESCAPES "\a\b\f\n\r\t\v\\"
321 #define ESCCHARS "abfnrtv\\"
322
323 extern int rows;
324 extern int cols;
325
326 /* put_tty_line: print text to stdout */
327 int
328 put_tty_line(s, l, n, gflag)
329 char *s;
330 int l;
331 long n;
332 int gflag;
333 {
334 int col = 0;
335 int lc = 0;
336 char *cp;
337
338 if (gflag & GNP) {
339 printf("%ld\t", n);
340 col = 8;
341 }
342 for (; l--; s++) {
343 if ((gflag & GLS) && ++col > cols) {
344 fputs("\\\n", stdout);
345 col = 1;
346 #ifndef BACKWARDS
347 if (!scripted && !isglobal && ++lc > rows) {
348 lc = 0;
349 fputs("Press <RETURN> to continue... ", stdout);
350 fflush(stdout);
351 if (get_tty_line() < 0)
352 return ERR;
353 }
354 #endif
355 }
356 if (gflag & GLS) {
357 if (31 < *s && *s < 127 && *s != '\\')
358 putchar(*s);
359 else {
360 putchar('\\');
361 col++;
362 if (*s && (cp = strchr(ESCAPES, *s)) != NULL)
363 putchar(ESCCHARS[cp - ESCAPES]);
364 else {
365 putchar((((unsigned char) *s & 0300) >> 6) + '0');
366 putchar((((unsigned char) *s & 070) >> 3) + '0');
367 putchar(((unsigned char) *s & 07) + '0');
368 col += 2;
369 }
370 }
371
372 } else
373 putchar(*s);
374 }
375 #ifndef BACKWARDS
376 if (gflag & GLS)
377 putchar('$');
378 #endif
379 putchar('\n');
380 return 0;
381 }
382