1*0a6a1f1dSLionel Sambuc /* $NetBSD: io.c,v 1.10 2014/03/23 05:06:42 dholland Exp $ */
27e81b07cSAndy Kosela
37e81b07cSAndy Kosela /* io.c: This file contains the i/o routines for the ed line editor */
47e81b07cSAndy Kosela /*-
57e81b07cSAndy Kosela * Copyright (c) 1993 Andrew Moore, Talke Studio.
67e81b07cSAndy Kosela * All rights reserved.
77e81b07cSAndy Kosela *
87e81b07cSAndy Kosela * Redistribution and use in source and binary forms, with or without
97e81b07cSAndy Kosela * modification, are permitted provided that the following conditions
107e81b07cSAndy Kosela * are met:
117e81b07cSAndy Kosela * 1. Redistributions of source code must retain the above copyright
127e81b07cSAndy Kosela * notice, this list of conditions and the following disclaimer.
137e81b07cSAndy Kosela * 2. Redistributions in binary form must reproduce the above copyright
147e81b07cSAndy Kosela * notice, this list of conditions and the following disclaimer in the
157e81b07cSAndy Kosela * documentation and/or other materials provided with the distribution.
167e81b07cSAndy Kosela *
177e81b07cSAndy Kosela * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
187e81b07cSAndy Kosela * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
197e81b07cSAndy Kosela * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
207e81b07cSAndy Kosela * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
217e81b07cSAndy Kosela * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
227e81b07cSAndy Kosela * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
237e81b07cSAndy Kosela * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
247e81b07cSAndy Kosela * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
257e81b07cSAndy Kosela * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
267e81b07cSAndy Kosela * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
277e81b07cSAndy Kosela * SUCH DAMAGE.
287e81b07cSAndy Kosela */
297e81b07cSAndy Kosela
307e81b07cSAndy Kosela #include <sys/cdefs.h>
317e81b07cSAndy Kosela #ifndef lint
327e81b07cSAndy Kosela #if 0
337e81b07cSAndy Kosela static char *rcsid = "@(#)io.c,v 1.1 1994/02/01 00:34:41 alm Exp";
347e81b07cSAndy Kosela #else
35*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: io.c,v 1.10 2014/03/23 05:06:42 dholland Exp $");
367e81b07cSAndy Kosela #endif
377e81b07cSAndy Kosela #endif /* not lint */
387e81b07cSAndy Kosela
397e81b07cSAndy Kosela #include "ed.h"
407e81b07cSAndy Kosela
417e81b07cSAndy Kosela
427e81b07cSAndy Kosela /* read_file: read a named file/pipe into the buffer; return line count */
437e81b07cSAndy Kosela long
read_file(char * fn,long n)447e81b07cSAndy Kosela read_file(char *fn, long n)
457e81b07cSAndy Kosela {
467e81b07cSAndy Kosela FILE *fp;
477e81b07cSAndy Kosela long size;
487e81b07cSAndy Kosela
497e81b07cSAndy Kosela
507e81b07cSAndy Kosela fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r");
517e81b07cSAndy Kosela if (fp == NULL) {
527e81b07cSAndy Kosela fprintf(stderr, "%s: %s\n", fn, strerror(errno));
53*0a6a1f1dSLionel Sambuc seterrmsg("cannot open input file");
547e81b07cSAndy Kosela return ERR;
557e81b07cSAndy Kosela } else if ((size = read_stream(fp, n)) < 0)
567e81b07cSAndy Kosela return ERR;
577e81b07cSAndy Kosela else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
587e81b07cSAndy Kosela fprintf(stderr, "%s: %s\n", fn, strerror(errno));
59*0a6a1f1dSLionel Sambuc seterrmsg("cannot close input file");
607e81b07cSAndy Kosela return ERR;
617e81b07cSAndy Kosela }
627e81b07cSAndy Kosela if (!scripted)
637e81b07cSAndy Kosela fprintf(stderr, "%lu\n", size);
647e81b07cSAndy Kosela return current_addr - n;
657e81b07cSAndy Kosela }
667e81b07cSAndy Kosela
677e81b07cSAndy Kosela
687e81b07cSAndy Kosela char *sbuf; /* file i/o buffer */
697e81b07cSAndy Kosela int sbufsz; /* file i/o buffer size */
707e81b07cSAndy Kosela int newline_added; /* if set, newline appended to input file */
717e81b07cSAndy Kosela
727e81b07cSAndy Kosela /* read_stream: read a stream into the editor buffer; return status */
737e81b07cSAndy Kosela long
read_stream(FILE * fp,long n)747e81b07cSAndy Kosela read_stream(FILE *fp, long n)
757e81b07cSAndy Kosela {
767e81b07cSAndy Kosela line_t *lp = get_addressed_line_node(n);
777e81b07cSAndy Kosela undo_t *up = NULL;
787e81b07cSAndy Kosela unsigned long size = 0;
797e81b07cSAndy Kosela int o_newline_added = newline_added;
807e81b07cSAndy Kosela int o_isbinary = isbinary;
817e81b07cSAndy Kosela int appended = (n == addr_last);
827e81b07cSAndy Kosela int len;
837e81b07cSAndy Kosela
847e81b07cSAndy Kosela isbinary = newline_added = 0;
857e81b07cSAndy Kosela if (des)
867e81b07cSAndy Kosela init_des_cipher();
877e81b07cSAndy Kosela for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) {
887e81b07cSAndy Kosela SPL1();
897e81b07cSAndy Kosela if (put_sbuf_line(sbuf) == NULL) {
907e81b07cSAndy Kosela SPL0();
917e81b07cSAndy Kosela return ERR;
927e81b07cSAndy Kosela }
937e81b07cSAndy Kosela lp = lp->q_forw;
947e81b07cSAndy Kosela if (up)
957e81b07cSAndy Kosela up->t = lp;
967e81b07cSAndy Kosela else if ((up = push_undo_stack(UADD, current_addr,
977e81b07cSAndy Kosela current_addr)) == NULL) {
987e81b07cSAndy Kosela SPL0();
997e81b07cSAndy Kosela return ERR;
1007e81b07cSAndy Kosela }
1017e81b07cSAndy Kosela SPL0();
1027e81b07cSAndy Kosela }
1037e81b07cSAndy Kosela if (len < 0)
1047e81b07cSAndy Kosela return ERR;
1057e81b07cSAndy Kosela if (appended && size && o_isbinary && o_newline_added)
1067e81b07cSAndy Kosela fputs("newline inserted\n", stderr);
1077e81b07cSAndy Kosela else if (newline_added && (!appended || (!isbinary && !o_isbinary)))
1087e81b07cSAndy Kosela fputs("newline appended\n", stderr);
1097e81b07cSAndy Kosela if (isbinary && newline_added && !appended)
1107e81b07cSAndy Kosela size += 1;
1117e81b07cSAndy Kosela if (!size)
1127e81b07cSAndy Kosela newline_added = 1;
1137e81b07cSAndy Kosela newline_added = appended ? newline_added : o_newline_added;
1147e81b07cSAndy Kosela isbinary = isbinary | o_isbinary;
1157e81b07cSAndy Kosela if (des)
1167e81b07cSAndy Kosela size += 8 - size % 8; /* adjust DES size */
1177e81b07cSAndy Kosela return size;
1187e81b07cSAndy Kosela }
1197e81b07cSAndy Kosela
1207e81b07cSAndy Kosela
1217e81b07cSAndy Kosela /* get_stream_line: read a line of text from a stream; return line length */
1227e81b07cSAndy Kosela int
get_stream_line(FILE * fp)1237e81b07cSAndy Kosela get_stream_line(FILE *fp)
1247e81b07cSAndy Kosela {
1257e81b07cSAndy Kosela int c;
1267e81b07cSAndy Kosela int i = 0;
1277e81b07cSAndy Kosela
1287e81b07cSAndy Kosela while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || (!feof(fp) &&
1297e81b07cSAndy Kosela !ferror(fp))) && c != '\n') {
1307e81b07cSAndy Kosela REALLOC(sbuf, sbufsz, i + 1, ERR);
1317e81b07cSAndy Kosela if (!(sbuf[i++] = c))
1327e81b07cSAndy Kosela isbinary = 1;
1337e81b07cSAndy Kosela }
1347e81b07cSAndy Kosela REALLOC(sbuf, sbufsz, i + 2, ERR);
1357e81b07cSAndy Kosela if (c == '\n')
1367e81b07cSAndy Kosela sbuf[i++] = c;
1377e81b07cSAndy Kosela else if (ferror(fp)) {
1387e81b07cSAndy Kosela fprintf(stderr, "%s\n", strerror(errno));
139*0a6a1f1dSLionel Sambuc seterrmsg("cannot read input file");
1407e81b07cSAndy Kosela return ERR;
1417e81b07cSAndy Kosela } else if (i) {
1427e81b07cSAndy Kosela sbuf[i++] = '\n';
1437e81b07cSAndy Kosela newline_added = 1;
1447e81b07cSAndy Kosela }
1457e81b07cSAndy Kosela sbuf[i] = '\0';
1467e81b07cSAndy Kosela return (isbinary && newline_added && i) ? --i : i;
1477e81b07cSAndy Kosela }
1487e81b07cSAndy Kosela
1497e81b07cSAndy Kosela
1507e81b07cSAndy Kosela /* write_file: write a range of lines to a named file/pipe; return line count */
1517e81b07cSAndy Kosela long
write_file(const char * fn,const char * mode,long n,long m)1527e81b07cSAndy Kosela write_file(const char *fn, const char *mode, long n, long m)
1537e81b07cSAndy Kosela {
1547e81b07cSAndy Kosela FILE *fp;
1557e81b07cSAndy Kosela long size;
1567e81b07cSAndy Kosela
1577e81b07cSAndy Kosela fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode);
1587e81b07cSAndy Kosela if (fp == NULL) {
1597e81b07cSAndy Kosela fprintf(stderr, "%s: %s\n", fn, strerror(errno));
160*0a6a1f1dSLionel Sambuc seterrmsg("cannot open output file");
1617e81b07cSAndy Kosela return ERR;
1627e81b07cSAndy Kosela } else if ((size = write_stream(fp, n, m)) < 0)
1637e81b07cSAndy Kosela return ERR;
1647e81b07cSAndy Kosela else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
1657e81b07cSAndy Kosela fprintf(stderr, "%s: %s\n", fn, strerror(errno));
166*0a6a1f1dSLionel Sambuc seterrmsg("cannot close output file");
1677e81b07cSAndy Kosela return ERR;
1687e81b07cSAndy Kosela }
1697e81b07cSAndy Kosela if (!scripted)
1707e81b07cSAndy Kosela fprintf(stderr, "%lu\n", size);
1717e81b07cSAndy Kosela return n ? m - n + 1 : 0;
1727e81b07cSAndy Kosela }
1737e81b07cSAndy Kosela
1747e81b07cSAndy Kosela
1757e81b07cSAndy Kosela /* write_stream: write a range of lines to a stream; return status */
1767e81b07cSAndy Kosela long
write_stream(FILE * fp,long n,long m)1777e81b07cSAndy Kosela write_stream(FILE *fp, long n, long m)
1787e81b07cSAndy Kosela {
1797e81b07cSAndy Kosela line_t *lp = get_addressed_line_node(n);
1807e81b07cSAndy Kosela unsigned long size = 0;
1817e81b07cSAndy Kosela char *s;
1827e81b07cSAndy Kosela int len;
1837e81b07cSAndy Kosela
1847e81b07cSAndy Kosela if (des)
1857e81b07cSAndy Kosela init_des_cipher();
1867e81b07cSAndy Kosela for (; n && n <= m; n++, lp = lp->q_forw) {
1877e81b07cSAndy Kosela if ((s = get_sbuf_line(lp)) == NULL)
1887e81b07cSAndy Kosela return ERR;
1897e81b07cSAndy Kosela len = lp->len;
1907e81b07cSAndy Kosela if (n != addr_last || !isbinary || !newline_added)
1917e81b07cSAndy Kosela s[len++] = '\n';
1927e81b07cSAndy Kosela if (put_stream_line(fp, s, len) < 0)
1937e81b07cSAndy Kosela return ERR;
1947e81b07cSAndy Kosela size += len;
1957e81b07cSAndy Kosela }
1967e81b07cSAndy Kosela if (des) {
1977e81b07cSAndy Kosela flush_des_file(fp); /* flush buffer */
1987e81b07cSAndy Kosela size += 8 - size % 8; /* adjust DES size */
1997e81b07cSAndy Kosela }
2007e81b07cSAndy Kosela return size;
2017e81b07cSAndy Kosela }
2027e81b07cSAndy Kosela
2037e81b07cSAndy Kosela
2047e81b07cSAndy Kosela /* put_stream_line: write a line of text to a stream; return status */
2057e81b07cSAndy Kosela int
put_stream_line(FILE * fp,char * s,int len)2067e81b07cSAndy Kosela put_stream_line(FILE *fp, char *s, int len)
2077e81b07cSAndy Kosela {
2087e81b07cSAndy Kosela while (len--)
2097e81b07cSAndy Kosela if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) {
2107e81b07cSAndy Kosela fprintf(stderr, "%s\n", strerror(errno));
211*0a6a1f1dSLionel Sambuc seterrmsg("cannot write file");
2127e81b07cSAndy Kosela return ERR;
2137e81b07cSAndy Kosela }
2147e81b07cSAndy Kosela return 0;
2157e81b07cSAndy Kosela }
2167e81b07cSAndy Kosela
2177e81b07cSAndy Kosela /* get_extended_line: get a an extended line from stdin */
2187e81b07cSAndy Kosela char *
get_extended_line(int * sizep,int nonl)2197e81b07cSAndy Kosela get_extended_line(int *sizep, int nonl)
2207e81b07cSAndy Kosela {
2217e81b07cSAndy Kosela static char *cvbuf = NULL; /* buffer */
2227e81b07cSAndy Kosela static int cvbufsz = 0; /* buffer size */
2237e81b07cSAndy Kosela
2247e81b07cSAndy Kosela int l, n;
2257e81b07cSAndy Kosela char *t = ibufp;
2267e81b07cSAndy Kosela
2277e81b07cSAndy Kosela while (*t++ != '\n')
2287e81b07cSAndy Kosela ;
2297e81b07cSAndy Kosela if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) {
2307e81b07cSAndy Kosela *sizep = l;
2317e81b07cSAndy Kosela return ibufp;
2327e81b07cSAndy Kosela }
2337e81b07cSAndy Kosela *sizep = -1;
2347e81b07cSAndy Kosela REALLOC(cvbuf, cvbufsz, l, NULL);
2357e81b07cSAndy Kosela memcpy(cvbuf, ibufp, l);
2367e81b07cSAndy Kosela *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
2377e81b07cSAndy Kosela if (nonl) l--; /* strip newline */
2387e81b07cSAndy Kosela for (;;) {
2397e81b07cSAndy Kosela if ((n = get_tty_line()) < 0)
2407e81b07cSAndy Kosela return NULL;
2417e81b07cSAndy Kosela else if (n == 0 || ibuf[n - 1] != '\n') {
242*0a6a1f1dSLionel Sambuc seterrmsg("unexpected end-of-file");
2437e81b07cSAndy Kosela return NULL;
2447e81b07cSAndy Kosela }
2457e81b07cSAndy Kosela REALLOC(cvbuf, cvbufsz, l + n, NULL);
2467e81b07cSAndy Kosela memcpy(cvbuf + l, ibuf, n);
2477e81b07cSAndy Kosela l += n;
2487e81b07cSAndy Kosela if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1))
2497e81b07cSAndy Kosela break;
2507e81b07cSAndy Kosela *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
2517e81b07cSAndy Kosela if (nonl) l--; /* strip newline */
2527e81b07cSAndy Kosela }
2537e81b07cSAndy Kosela REALLOC(cvbuf, cvbufsz, l + 1, NULL);
2547e81b07cSAndy Kosela cvbuf[l] = '\0';
2557e81b07cSAndy Kosela *sizep = l;
2567e81b07cSAndy Kosela return cvbuf;
2577e81b07cSAndy Kosela }
2587e81b07cSAndy Kosela
2597e81b07cSAndy Kosela
2607e81b07cSAndy Kosela /* get_tty_line: read a line of text from stdin; return line length */
2617e81b07cSAndy Kosela int
get_tty_line(void)2627e81b07cSAndy Kosela get_tty_line(void)
2637e81b07cSAndy Kosela {
2647e81b07cSAndy Kosela int oi = 0;
2657e81b07cSAndy Kosela int i = 0;
2667e81b07cSAndy Kosela int c;
2677e81b07cSAndy Kosela
2687e81b07cSAndy Kosela for (;;)
2697e81b07cSAndy Kosela switch (c = getchar()) {
2707e81b07cSAndy Kosela default:
2717e81b07cSAndy Kosela oi = 0;
2727e81b07cSAndy Kosela REALLOC(ibuf, ibufsz, i + 2, ERR);
2737e81b07cSAndy Kosela if (!(ibuf[i++] = c)) isbinary = 1;
2747e81b07cSAndy Kosela if (c != '\n')
2757e81b07cSAndy Kosela continue;
2767e81b07cSAndy Kosela lineno++;
2777e81b07cSAndy Kosela ibuf[i] = '\0';
2787e81b07cSAndy Kosela ibufp = ibuf;
2797e81b07cSAndy Kosela return i;
2807e81b07cSAndy Kosela case EOF:
2817e81b07cSAndy Kosela if (ferror(stdin)) {
2827e81b07cSAndy Kosela fprintf(stderr, "stdin: %s\n", strerror(errno));
283*0a6a1f1dSLionel Sambuc seterrmsg("cannot read stdin");
2847e81b07cSAndy Kosela clearerr(stdin);
2857e81b07cSAndy Kosela ibufp = NULL;
2867e81b07cSAndy Kosela return ERR;
2877e81b07cSAndy Kosela } else {
2887e81b07cSAndy Kosela clearerr(stdin);
2897e81b07cSAndy Kosela if (i != oi) {
2907e81b07cSAndy Kosela oi = i;
2917e81b07cSAndy Kosela continue;
2927e81b07cSAndy Kosela } else if (i)
2937e81b07cSAndy Kosela ibuf[i] = '\0';
2947e81b07cSAndy Kosela ibufp = ibuf;
2957e81b07cSAndy Kosela return i;
2967e81b07cSAndy Kosela }
2977e81b07cSAndy Kosela }
2987e81b07cSAndy Kosela }
2997e81b07cSAndy Kosela
3007e81b07cSAndy Kosela
3017e81b07cSAndy Kosela
3027e81b07cSAndy Kosela #define ESCAPES "\a\b\f\n\r\t\v\\"
3037e81b07cSAndy Kosela #define ESCCHARS "abfnrtv\\"
3047e81b07cSAndy Kosela
3057e81b07cSAndy Kosela /* put_tty_line: print text to stdout */
3067e81b07cSAndy Kosela int
put_tty_line(char * s,int l,long n,int gflag)3077e81b07cSAndy Kosela put_tty_line(char *s, int l, long n, int gflag)
3087e81b07cSAndy Kosela {
3097e81b07cSAndy Kosela int col = 0;
3107e81b07cSAndy Kosela char *cp;
3117e81b07cSAndy Kosela #ifndef BACKWARDS
3127e81b07cSAndy Kosela int lc = 0;
3137e81b07cSAndy Kosela #endif
3147e81b07cSAndy Kosela
3157e81b07cSAndy Kosela if (gflag & GNP) {
3167e81b07cSAndy Kosela printf("%ld\t", n);
3177e81b07cSAndy Kosela col = 8;
3187e81b07cSAndy Kosela }
3197e81b07cSAndy Kosela for (; l--; s++) {
3207e81b07cSAndy Kosela if ((gflag & GLS) && ++col > cols) {
3217e81b07cSAndy Kosela fputs("\\\n", stdout);
3227e81b07cSAndy Kosela col = 1;
3237e81b07cSAndy Kosela #ifndef BACKWARDS
3247e81b07cSAndy Kosela if (!scripted && !isglobal && ++lc > rows) {
3257e81b07cSAndy Kosela lc = 0;
3267e81b07cSAndy Kosela fputs("Press <RETURN> to continue... ", stdout);
3277e81b07cSAndy Kosela fflush(stdout);
3287e81b07cSAndy Kosela if (get_tty_line() < 0)
3297e81b07cSAndy Kosela return ERR;
3307e81b07cSAndy Kosela }
3317e81b07cSAndy Kosela #endif
3327e81b07cSAndy Kosela }
3337e81b07cSAndy Kosela if (gflag & GLS) {
3347e81b07cSAndy Kosela if (31 < *s && *s < 127 && *s != '\\')
3357e81b07cSAndy Kosela putchar(*s);
3367e81b07cSAndy Kosela else {
3377e81b07cSAndy Kosela putchar('\\');
3387e81b07cSAndy Kosela col++;
3397e81b07cSAndy Kosela if (*s && (cp = strchr(ESCAPES, *s)) != NULL)
3407e81b07cSAndy Kosela putchar(ESCCHARS[cp - ESCAPES]);
3417e81b07cSAndy Kosela else {
3427e81b07cSAndy Kosela putchar((((unsigned char) *s & 0300) >> 6) + '0');
3437e81b07cSAndy Kosela putchar((((unsigned char) *s & 070) >> 3) + '0');
3447e81b07cSAndy Kosela putchar(((unsigned char) *s & 07) + '0');
3457e81b07cSAndy Kosela col += 2;
3467e81b07cSAndy Kosela }
3477e81b07cSAndy Kosela }
3487e81b07cSAndy Kosela
3497e81b07cSAndy Kosela } else
3507e81b07cSAndy Kosela putchar(*s);
3517e81b07cSAndy Kosela }
3527e81b07cSAndy Kosela #ifndef BACKWARDS
3537e81b07cSAndy Kosela if (gflag & GLS)
3547e81b07cSAndy Kosela putchar('$');
3557e81b07cSAndy Kosela #endif
3567e81b07cSAndy Kosela putchar('\n');
3577e81b07cSAndy Kosela return 0;
3587e81b07cSAndy Kosela }
359