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