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