xref: /freebsd/bin/ed/io.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
195e6217eSAndrew Moore /* io.c: This file contains the i/o routines for the ed line editor */
295e6217eSAndrew Moore /*-
395e6217eSAndrew Moore  * Copyright (c) 1993 Andrew Moore, Talke Studio.
495e6217eSAndrew Moore  * All rights reserved.
595e6217eSAndrew Moore  *
695e6217eSAndrew Moore  * Redistribution and use in source and binary forms, with or without
795e6217eSAndrew Moore  * modification, are permitted provided that the following conditions
895e6217eSAndrew Moore  * are met:
995e6217eSAndrew Moore  * 1. Redistributions of source code must retain the above copyright
1095e6217eSAndrew Moore  *    notice, this list of conditions and the following disclaimer.
1195e6217eSAndrew Moore  * 2. Redistributions in binary form must reproduce the above copyright
1295e6217eSAndrew Moore  *    notice, this list of conditions and the following disclaimer in the
1395e6217eSAndrew Moore  *    documentation and/or other materials provided with the distribution.
1495e6217eSAndrew Moore  *
1595e6217eSAndrew Moore  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1695e6217eSAndrew Moore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1795e6217eSAndrew Moore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1895e6217eSAndrew Moore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1995e6217eSAndrew Moore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2095e6217eSAndrew Moore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2195e6217eSAndrew Moore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2295e6217eSAndrew Moore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2395e6217eSAndrew Moore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2495e6217eSAndrew Moore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2595e6217eSAndrew Moore  * SUCH DAMAGE.
2695e6217eSAndrew Moore  */
2795e6217eSAndrew Moore 
285eb43ac2SDavid E. O'Brien #include <sys/cdefs.h>
2995e6217eSAndrew Moore #include "ed.h"
3095e6217eSAndrew Moore 
3195e6217eSAndrew Moore /* read_file: read a named file/pipe into the buffer; return line count */
3295e6217eSAndrew Moore long
read_file(char * fn,long n)337669d0fcSWarner Losh read_file(char *fn, long n)
3495e6217eSAndrew Moore {
3595e6217eSAndrew Moore 	FILE *fp;
3695e6217eSAndrew Moore 	long size;
3792a58a92SDon Lewis 	int cs;
3895e6217eSAndrew Moore 
3995e6217eSAndrew Moore 	fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r");
4095e6217eSAndrew Moore 	if (fp == NULL) {
4195e6217eSAndrew Moore 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
42a4616748SMike Barcroft 		errmsg = "cannot open input file";
4395e6217eSAndrew Moore 		return ERR;
4492a58a92SDon Lewis 	}
4592a58a92SDon Lewis 	if ((size = read_stream(fp, n)) < 0) {
4692a58a92SDon Lewis 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
4792a58a92SDon Lewis 		errmsg = "error reading input file";
4892a58a92SDon Lewis 	}
4992a58a92SDon Lewis 	if ((cs = (*fn == '!') ?  pclose(fp) : fclose(fp)) < 0) {
5095e6217eSAndrew Moore 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
51a4616748SMike Barcroft 		errmsg = "cannot close input file";
5295e6217eSAndrew Moore 	}
5392a58a92SDon Lewis 	if (size < 0 || cs < 0)
5492a58a92SDon Lewis 		return ERR;
554bfc2007SDimitry Andric 	if (!scripted)
564bfc2007SDimitry Andric 		fprintf(stdout, "%lu\n", size);
5795e6217eSAndrew Moore 	return current_addr - n;
5895e6217eSAndrew Moore }
5995e6217eSAndrew Moore 
60ae824d80SEd Schouten static char *sbuf;		/* file i/o buffer */
61ae824d80SEd Schouten static int sbufsz;		/* file i/o buffer size */
6295e6217eSAndrew Moore int newline_added;		/* if set, newline appended to input file */
6395e6217eSAndrew Moore 
6495e6217eSAndrew Moore /* read_stream: read a stream into the editor buffer; return status */
6595e6217eSAndrew Moore long
read_stream(FILE * fp,long n)667669d0fcSWarner Losh read_stream(FILE *fp, long n)
6795e6217eSAndrew Moore {
6895e6217eSAndrew Moore 	line_t *lp = get_addressed_line_node(n);
6995e6217eSAndrew Moore 	undo_t *up = NULL;
7095e6217eSAndrew Moore 	unsigned long size = 0;
7195e6217eSAndrew Moore 	int o_newline_added = newline_added;
7295e6217eSAndrew Moore 	int o_isbinary = isbinary;
7395e6217eSAndrew Moore 	int appended = (n == addr_last);
7495e6217eSAndrew Moore 	int len;
7595e6217eSAndrew Moore 
7695e6217eSAndrew Moore 	isbinary = newline_added = 0;
7795e6217eSAndrew Moore 	for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) {
7895e6217eSAndrew Moore 		SPL1();
7995e6217eSAndrew Moore 		if (put_sbuf_line(sbuf) == NULL) {
8095e6217eSAndrew Moore 			SPL0();
8195e6217eSAndrew Moore 			return ERR;
8295e6217eSAndrew Moore 		}
8395e6217eSAndrew Moore 		lp = lp->q_forw;
8495e6217eSAndrew Moore 		if (up)
8595e6217eSAndrew Moore 			up->t = lp;
8695e6217eSAndrew Moore 		else if ((up = push_undo_stack(UADD, current_addr,
8795e6217eSAndrew Moore 		    current_addr)) == NULL) {
8895e6217eSAndrew Moore 			SPL0();
8995e6217eSAndrew Moore 			return ERR;
9095e6217eSAndrew Moore 		}
9195e6217eSAndrew Moore 		SPL0();
9295e6217eSAndrew Moore 	}
9395e6217eSAndrew Moore 	if (len < 0)
9495e6217eSAndrew Moore 		return ERR;
9595e6217eSAndrew Moore 	if (appended && size && o_isbinary && o_newline_added)
9695e6217eSAndrew Moore 		fputs("newline inserted\n", stderr);
970fd510b7SJoerg Wunsch 	else if (newline_added && (!appended || (!isbinary && !o_isbinary)))
9895e6217eSAndrew Moore 		fputs("newline appended\n", stderr);
9995e6217eSAndrew Moore 	if (isbinary && newline_added && !appended)
10095e6217eSAndrew Moore 	    	size += 1;
10195e6217eSAndrew Moore 	if (!size)
10295e6217eSAndrew Moore 		newline_added = 1;
10395e6217eSAndrew Moore 	newline_added = appended ? newline_added : o_newline_added;
10495e6217eSAndrew Moore 	isbinary = isbinary | o_isbinary;
10595e6217eSAndrew Moore 	return size;
10695e6217eSAndrew Moore }
10795e6217eSAndrew Moore 
10895e6217eSAndrew Moore 
10995e6217eSAndrew Moore /* get_stream_line: read a line of text from a stream; return line length */
11095e6217eSAndrew Moore int
get_stream_line(FILE * fp)1117669d0fcSWarner Losh get_stream_line(FILE *fp)
11295e6217eSAndrew Moore {
113a4616748SMike Barcroft 	int c;
114a4616748SMike Barcroft 	int i = 0;
11595e6217eSAndrew Moore 
116*d83db3fbSConrad Meyer 	while (((c = getc(fp)) != EOF || (!feof(fp) && !ferror(fp))) &&
117*d83db3fbSConrad Meyer 	    c != '\n') {
11895e6217eSAndrew Moore 		REALLOC(sbuf, sbufsz, i + 1, ERR);
11995e6217eSAndrew Moore 		if (!(sbuf[i++] = c))
12095e6217eSAndrew Moore 			isbinary = 1;
12195e6217eSAndrew Moore 	}
12295e6217eSAndrew Moore 	REALLOC(sbuf, sbufsz, i + 2, ERR);
12395e6217eSAndrew Moore 	if (c == '\n')
12495e6217eSAndrew Moore 		sbuf[i++] = c;
12595e6217eSAndrew Moore 	else if (ferror(fp)) {
12695e6217eSAndrew Moore 		fprintf(stderr, "%s\n", strerror(errno));
127a4616748SMike Barcroft 		errmsg = "cannot read input file";
12895e6217eSAndrew Moore 		return ERR;
12995e6217eSAndrew Moore 	} else if (i) {
13095e6217eSAndrew Moore 		sbuf[i++] = '\n';
13195e6217eSAndrew Moore 		newline_added = 1;
13295e6217eSAndrew Moore 	}
13395e6217eSAndrew Moore 	sbuf[i] = '\0';
13495e6217eSAndrew Moore 	return (isbinary && newline_added && i) ? --i : i;
13595e6217eSAndrew Moore }
13695e6217eSAndrew Moore 
13795e6217eSAndrew Moore 
13895e6217eSAndrew Moore /* write_file: write a range of lines to a named file/pipe; return line count */
13995e6217eSAndrew Moore long
write_file(char * fn,const char * mode,long n,long m)1407669d0fcSWarner Losh write_file(char *fn, const char *mode, long n, long m)
14195e6217eSAndrew Moore {
14295e6217eSAndrew Moore 	FILE *fp;
14395e6217eSAndrew Moore 	long size;
14492a58a92SDon Lewis 	int cs;
14595e6217eSAndrew Moore 
14695e6217eSAndrew Moore 	fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode);
14795e6217eSAndrew Moore 	if (fp == NULL) {
14895e6217eSAndrew Moore 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
149a4616748SMike Barcroft 		errmsg = "cannot open output file";
15095e6217eSAndrew Moore 		return ERR;
15192a58a92SDon Lewis 	}
15292a58a92SDon Lewis 	if ((size = write_stream(fp, n, m)) < 0) {
15392a58a92SDon Lewis 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
15492a58a92SDon Lewis 		errmsg = "error writing output file";
15592a58a92SDon Lewis 	}
15692a58a92SDon Lewis 	if ((cs = (*fn == '!') ?  pclose(fp) : fclose(fp)) < 0) {
15795e6217eSAndrew Moore 		fprintf(stderr, "%s: %s\n", fn, strerror(errno));
158a4616748SMike Barcroft 		errmsg = "cannot close output file";
15995e6217eSAndrew Moore 	}
16092a58a92SDon Lewis 	if (size < 0 || cs < 0)
16192a58a92SDon Lewis 		return ERR;
1624bfc2007SDimitry Andric 	if (!scripted)
1634bfc2007SDimitry Andric 		fprintf(stdout, "%lu\n", size);
16495e6217eSAndrew Moore 	return n ? m - n + 1 : 0;
16595e6217eSAndrew Moore }
16695e6217eSAndrew Moore 
16795e6217eSAndrew Moore 
16895e6217eSAndrew Moore /* write_stream: write a range of lines to a stream; return status */
16995e6217eSAndrew Moore long
write_stream(FILE * fp,long n,long m)1707669d0fcSWarner Losh write_stream(FILE *fp, long n, long m)
17195e6217eSAndrew Moore {
17295e6217eSAndrew Moore 	line_t *lp = get_addressed_line_node(n);
17395e6217eSAndrew Moore 	unsigned long size = 0;
17495e6217eSAndrew Moore 	char *s;
17595e6217eSAndrew Moore 	int len;
17695e6217eSAndrew Moore 
17795e6217eSAndrew Moore 	for (; n && n <= m; n++, lp = lp->q_forw) {
17895e6217eSAndrew Moore 		if ((s = get_sbuf_line(lp)) == NULL)
17995e6217eSAndrew Moore 			return ERR;
18095e6217eSAndrew Moore 		len = lp->len;
18195e6217eSAndrew Moore 		if (n != addr_last || !isbinary || !newline_added)
18295e6217eSAndrew Moore 			s[len++] = '\n';
18395e6217eSAndrew Moore 		if (put_stream_line(fp, s, len) < 0)
18495e6217eSAndrew Moore 			return ERR;
18595e6217eSAndrew Moore 		size += len;
18695e6217eSAndrew Moore 	}
18795e6217eSAndrew Moore 	return size;
18895e6217eSAndrew Moore }
18995e6217eSAndrew Moore 
19095e6217eSAndrew Moore 
19195e6217eSAndrew Moore /* put_stream_line: write a line of text to a stream; return status */
19295e6217eSAndrew Moore int
put_stream_line(FILE * fp,const char * s,int len)1937669d0fcSWarner Losh put_stream_line(FILE *fp, const char *s, int len)
19495e6217eSAndrew Moore {
19595e6217eSAndrew Moore 	while (len--)
196*d83db3fbSConrad Meyer 		if (fputc(*s++, fp) < 0) {
19795e6217eSAndrew Moore 			fprintf(stderr, "%s\n", strerror(errno));
198a4616748SMike Barcroft 			errmsg = "cannot write file";
19995e6217eSAndrew Moore 			return ERR;
20095e6217eSAndrew Moore 		}
20195e6217eSAndrew Moore 	return 0;
20295e6217eSAndrew Moore }
20395e6217eSAndrew Moore 
2049d5abbddSJens Schweikhardt /* get_extended_line: get an extended line from stdin */
20595e6217eSAndrew Moore char *
get_extended_line(int * sizep,int nonl)2067669d0fcSWarner Losh get_extended_line(int *sizep, int nonl)
20795e6217eSAndrew Moore {
20895e6217eSAndrew Moore 	static char *cvbuf = NULL;		/* buffer */
20995e6217eSAndrew Moore 	static int cvbufsz = 0;			/* buffer size */
21095e6217eSAndrew Moore 
21195e6217eSAndrew Moore 	int l, n;
21295e6217eSAndrew Moore 	char *t = ibufp;
21395e6217eSAndrew Moore 
21495e6217eSAndrew Moore 	while (*t++ != '\n')
21595e6217eSAndrew Moore 		;
21695e6217eSAndrew Moore 	if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) {
21795e6217eSAndrew Moore 		*sizep = l;
21895e6217eSAndrew Moore 		return ibufp;
21995e6217eSAndrew Moore 	}
22095e6217eSAndrew Moore 	*sizep = -1;
22195e6217eSAndrew Moore 	REALLOC(cvbuf, cvbufsz, l, NULL);
22295e6217eSAndrew Moore 	memcpy(cvbuf, ibufp, l);
22395e6217eSAndrew Moore 	*(cvbuf + --l - 1) = '\n'; 	/* strip trailing esc */
22495e6217eSAndrew Moore 	if (nonl) l--; 			/* strip newline */
22595e6217eSAndrew Moore 	for (;;) {
22695e6217eSAndrew Moore 		if ((n = get_tty_line()) < 0)
22795e6217eSAndrew Moore 			return NULL;
22895e6217eSAndrew Moore 		else if (n == 0 || ibuf[n - 1] != '\n') {
229a4616748SMike Barcroft 			errmsg = "unexpected end-of-file";
23095e6217eSAndrew Moore 			return NULL;
23195e6217eSAndrew Moore 		}
23295e6217eSAndrew Moore 		REALLOC(cvbuf, cvbufsz, l + n, NULL);
23395e6217eSAndrew Moore 		memcpy(cvbuf + l, ibuf, n);
23495e6217eSAndrew Moore 		l += n;
23595e6217eSAndrew Moore 		if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1))
23695e6217eSAndrew Moore 			break;
23795e6217eSAndrew Moore 		*(cvbuf + --l - 1) = '\n'; 	/* strip trailing esc */
23895e6217eSAndrew Moore 		if (nonl) l--; 			/* strip newline */
23995e6217eSAndrew Moore 	}
24095e6217eSAndrew Moore 	REALLOC(cvbuf, cvbufsz, l + 1, NULL);
24195e6217eSAndrew Moore 	cvbuf[l] = '\0';
24295e6217eSAndrew Moore 	*sizep = l;
24395e6217eSAndrew Moore 	return cvbuf;
24495e6217eSAndrew Moore }
24595e6217eSAndrew Moore 
24695e6217eSAndrew Moore 
24795e6217eSAndrew Moore /* get_tty_line: read a line of text from stdin; return line length */
24895e6217eSAndrew Moore int
get_tty_line(void)2497669d0fcSWarner Losh get_tty_line(void)
25095e6217eSAndrew Moore {
251a4616748SMike Barcroft 	int oi = 0;
252a4616748SMike Barcroft 	int i = 0;
25395e6217eSAndrew Moore 	int c;
25495e6217eSAndrew Moore 
25595e6217eSAndrew Moore 	for (;;)
25695e6217eSAndrew Moore 		switch (c = getchar()) {
25795e6217eSAndrew Moore 		default:
25895e6217eSAndrew Moore 			oi = 0;
25995e6217eSAndrew Moore 			REALLOC(ibuf, ibufsz, i + 2, ERR);
26095e6217eSAndrew Moore 			if (!(ibuf[i++] = c)) isbinary = 1;
26195e6217eSAndrew Moore 			if (c != '\n')
26295e6217eSAndrew Moore 				continue;
26395e6217eSAndrew Moore 			lineno++;
26495e6217eSAndrew Moore 			ibuf[i] = '\0';
26595e6217eSAndrew Moore 			ibufp = ibuf;
26695e6217eSAndrew Moore 			return i;
26795e6217eSAndrew Moore 		case EOF:
26895e6217eSAndrew Moore 			if (ferror(stdin)) {
26995e6217eSAndrew Moore 				fprintf(stderr, "stdin: %s\n", strerror(errno));
270a4616748SMike Barcroft 				errmsg = "cannot read stdin";
27195e6217eSAndrew Moore 				clearerr(stdin);
27295e6217eSAndrew Moore 				ibufp = NULL;
27395e6217eSAndrew Moore 				return ERR;
27495e6217eSAndrew Moore 			} else {
27595e6217eSAndrew Moore 				clearerr(stdin);
27695e6217eSAndrew Moore 				if (i != oi) {
27795e6217eSAndrew Moore 					oi = i;
27895e6217eSAndrew Moore 					continue;
27995e6217eSAndrew Moore 				} else if (i)
28095e6217eSAndrew Moore 					ibuf[i] = '\0';
28195e6217eSAndrew Moore 				ibufp = ibuf;
28295e6217eSAndrew Moore 				return i;
28395e6217eSAndrew Moore 			}
28495e6217eSAndrew Moore 		}
28595e6217eSAndrew Moore }
28695e6217eSAndrew Moore 
28795e6217eSAndrew Moore 
28895e6217eSAndrew Moore 
28995e6217eSAndrew Moore #define ESCAPES "\a\b\f\n\r\t\v\\"
29095e6217eSAndrew Moore #define ESCCHARS "abfnrtv\\"
29195e6217eSAndrew Moore 
29295e6217eSAndrew Moore /* put_tty_line: print text to stdout */
29395e6217eSAndrew Moore int
put_tty_line(const char * s,int l,long n,int gflag)2947669d0fcSWarner Losh put_tty_line(const char *s, int l, long n, int gflag)
29595e6217eSAndrew Moore {
29695e6217eSAndrew Moore 	int col = 0;
29795e6217eSAndrew Moore 	int lc = 0;
29895e6217eSAndrew Moore 	char *cp;
29995e6217eSAndrew Moore 
30095e6217eSAndrew Moore 	if (gflag & GNP) {
30195e6217eSAndrew Moore 		printf("%ld\t", n);
30295e6217eSAndrew Moore 		col = 8;
30395e6217eSAndrew Moore 	}
30495e6217eSAndrew Moore 	for (; l--; s++) {
30595e6217eSAndrew Moore 		if ((gflag & GLS) && ++col > cols) {
30695e6217eSAndrew Moore 			fputs("\\\n", stdout);
30795e6217eSAndrew Moore 			col = 1;
30895e6217eSAndrew Moore #ifndef BACKWARDS
30995e6217eSAndrew Moore 			if (!scripted && !isglobal && ++lc > rows) {
31095e6217eSAndrew Moore 				lc = 0;
31195e6217eSAndrew Moore 				fputs("Press <RETURN> to continue... ", stdout);
31295e6217eSAndrew Moore 				fflush(stdout);
31395e6217eSAndrew Moore 				if (get_tty_line() < 0)
31495e6217eSAndrew Moore 					return ERR;
31595e6217eSAndrew Moore 			}
31695e6217eSAndrew Moore #endif
31795e6217eSAndrew Moore 		}
31895e6217eSAndrew Moore 		if (gflag & GLS) {
31995e6217eSAndrew Moore 			if (31 < *s && *s < 127 && *s != '\\')
32095e6217eSAndrew Moore 				putchar(*s);
32195e6217eSAndrew Moore 			else {
32295e6217eSAndrew Moore 				putchar('\\');
32395e6217eSAndrew Moore 				col++;
32495e6217eSAndrew Moore 				if (*s && (cp = strchr(ESCAPES, *s)) != NULL)
32595e6217eSAndrew Moore 					putchar(ESCCHARS[cp - ESCAPES]);
32695e6217eSAndrew Moore 				else {
32795e6217eSAndrew Moore 					putchar((((unsigned char) *s & 0300) >> 6) + '0');
32895e6217eSAndrew Moore 					putchar((((unsigned char) *s & 070) >> 3) + '0');
32995e6217eSAndrew Moore 					putchar(((unsigned char) *s & 07) + '0');
33095e6217eSAndrew Moore 					col += 2;
33195e6217eSAndrew Moore 				}
33295e6217eSAndrew Moore 			}
33395e6217eSAndrew Moore 
33495e6217eSAndrew Moore 		} else
33595e6217eSAndrew Moore 			putchar(*s);
33695e6217eSAndrew Moore 	}
33795e6217eSAndrew Moore #ifndef BACKWARDS
33895e6217eSAndrew Moore 	if (gflag & GLS)
33995e6217eSAndrew Moore 		putchar('$');
34095e6217eSAndrew Moore #endif
34195e6217eSAndrew Moore 	putchar('\n');
34295e6217eSAndrew Moore 	return 0;
34395e6217eSAndrew Moore }
344