11057Salm/* io.c: This file contains the i/o routines for the ed line editor */ 21057Salm/*- 31057Salm * Copyright (c) 1993 Andrew Moore, Talke Studio. 41057Salm * All rights reserved. 51057Salm * 61057Salm * Redistribution and use in source and binary forms, with or without 71057Salm * modification, are permitted provided that the following conditions 81057Salm * are met: 91057Salm * 1. Redistributions of source code must retain the above copyright 101057Salm * notice, this list of conditions and the following disclaimer. 111057Salm * 2. Redistributions in binary form must reproduce the above copyright 121057Salm * notice, this list of conditions and the following disclaimer in the 131057Salm * documentation and/or other materials provided with the distribution. 141057Salm * 151057Salm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 161057Salm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 171057Salm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 181057Salm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 191057Salm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 201057Salm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 211057Salm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 221057Salm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 231057Salm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 241057Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 251057Salm * SUCH DAMAGE. 261057Salm */ 271057Salm 2899109Sobrien#include <sys/cdefs.h> 2999109Sobrien__FBSDID("$FreeBSD$"); 301057Salm 311057Salm#include "ed.h" 321057Salm 331057Salm/* read_file: read a named file/pipe into the buffer; return line count */ 341057Salmlong 3590109Simpread_file(char *fn, long n) 361057Salm{ 371057Salm FILE *fp; 381057Salm long size; 391057Salm 401057Salm 411057Salm fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r"); 421057Salm if (fp == NULL) { 431057Salm fprintf(stderr, "%s: %s\n", fn, strerror(errno)); 4481220Smike errmsg = "cannot open input file"; 451057Salm return ERR; 461057Salm } else if ((size = read_stream(fp, n)) < 0) 471057Salm return ERR; 481057Salm else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) { 491057Salm fprintf(stderr, "%s: %s\n", fn, strerror(errno)); 5081220Smike errmsg = "cannot close input file"; 511057Salm return ERR; 521057Salm } 53228595Sdim if (!scripted) 54228595Sdim fprintf(stdout, "%lu\n", size); 551057Salm return current_addr - n; 561057Salm} 571057Salm 58241720Sedstatic char *sbuf; /* file i/o buffer */ 59241720Sedstatic int sbufsz; /* file i/o buffer size */ 601057Salmint newline_added; /* if set, newline appended to input file */ 611057Salm 621057Salm/* read_stream: read a stream into the editor buffer; return status */ 631057Salmlong 6490109Simpread_stream(FILE *fp, long n) 651057Salm{ 661057Salm line_t *lp = get_addressed_line_node(n); 671057Salm undo_t *up = NULL; 681057Salm unsigned long size = 0; 691057Salm int o_newline_added = newline_added; 701057Salm int o_isbinary = isbinary; 711057Salm int appended = (n == addr_last); 721057Salm int len; 731057Salm 741057Salm isbinary = newline_added = 0; 751057Salm if (des) 761057Salm init_des_cipher(); 771057Salm for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) { 781057Salm SPL1(); 791057Salm if (put_sbuf_line(sbuf) == NULL) { 801057Salm SPL0(); 811057Salm return ERR; 821057Salm } 831057Salm lp = lp->q_forw; 841057Salm if (up) 851057Salm up->t = lp; 861057Salm else if ((up = push_undo_stack(UADD, current_addr, 871057Salm current_addr)) == NULL) { 881057Salm SPL0(); 891057Salm return ERR; 901057Salm } 911057Salm SPL0(); 921057Salm } 931057Salm if (len < 0) 941057Salm return ERR; 951057Salm if (appended && size && o_isbinary && o_newline_added) 961057Salm fputs("newline inserted\n", stderr); 977165Sjoerg else if (newline_added && (!appended || (!isbinary && !o_isbinary))) 981057Salm fputs("newline appended\n", stderr); 991057Salm if (isbinary && newline_added && !appended) 1001057Salm size += 1; 1011057Salm if (!size) 1021057Salm newline_added = 1; 1031057Salm newline_added = appended ? newline_added : o_newline_added; 1041057Salm isbinary = isbinary | o_isbinary; 1051057Salm if (des) 1061057Salm size += 8 - size % 8; /* adjust DES size */ 1071057Salm return size; 1081057Salm} 1091057Salm 1101057Salm 1111057Salm/* get_stream_line: read a line of text from a stream; return line length */ 1121057Salmint 11390109Simpget_stream_line(FILE *fp) 1141057Salm{ 11581220Smike int c; 11681220Smike int i = 0; 1171057Salm 1187165Sjoerg while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || (!feof(fp) && 1197165Sjoerg !ferror(fp))) && c != '\n') { 1201057Salm REALLOC(sbuf, sbufsz, i + 1, ERR); 1211057Salm if (!(sbuf[i++] = c)) 1221057Salm isbinary = 1; 1231057Salm } 1241057Salm REALLOC(sbuf, sbufsz, i + 2, ERR); 1251057Salm if (c == '\n') 1261057Salm sbuf[i++] = c; 1271057Salm else if (ferror(fp)) { 1281057Salm fprintf(stderr, "%s\n", strerror(errno)); 12981220Smike errmsg = "cannot read input file"; 1301057Salm return ERR; 1311057Salm } else if (i) { 1321057Salm sbuf[i++] = '\n'; 1331057Salm newline_added = 1; 1341057Salm } 1351057Salm sbuf[i] = '\0'; 1361057Salm return (isbinary && newline_added && i) ? --i : i; 1371057Salm} 1381057Salm 1391057Salm 1401057Salm/* write_file: write a range of lines to a named file/pipe; return line count */ 1411057Salmlong 14290109Simpwrite_file(char *fn, const char *mode, long n, long m) 1431057Salm{ 1441057Salm FILE *fp; 1451057Salm long size; 1461057Salm 1471057Salm fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode); 1481057Salm if (fp == NULL) { 1491057Salm fprintf(stderr, "%s: %s\n", fn, strerror(errno)); 15081220Smike errmsg = "cannot open output file"; 1511057Salm return ERR; 1521057Salm } else if ((size = write_stream(fp, n, m)) < 0) 1531057Salm return ERR; 1541057Salm else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) { 1551057Salm fprintf(stderr, "%s: %s\n", fn, strerror(errno)); 15681220Smike errmsg = "cannot close output file"; 1571057Salm return ERR; 1581057Salm } 159228595Sdim if (!scripted) 160228595Sdim fprintf(stdout, "%lu\n", size); 1611057Salm return n ? m - n + 1 : 0; 1621057Salm} 1631057Salm 1641057Salm 1651057Salm/* write_stream: write a range of lines to a stream; return status */ 1661057Salmlong 16790109Simpwrite_stream(FILE *fp, long n, long m) 1681057Salm{ 1691057Salm line_t *lp = get_addressed_line_node(n); 1701057Salm unsigned long size = 0; 1711057Salm char *s; 1721057Salm int len; 1731057Salm 1741057Salm if (des) 1751057Salm init_des_cipher(); 1761057Salm for (; n && n <= m; n++, lp = lp->q_forw) { 1771057Salm if ((s = get_sbuf_line(lp)) == NULL) 1781057Salm return ERR; 1791057Salm len = lp->len; 1801057Salm if (n != addr_last || !isbinary || !newline_added) 1811057Salm s[len++] = '\n'; 1821057Salm if (put_stream_line(fp, s, len) < 0) 1831057Salm return ERR; 1841057Salm size += len; 1851057Salm } 1861057Salm if (des) { 1871057Salm flush_des_file(fp); /* flush buffer */ 1881057Salm size += 8 - size % 8; /* adjust DES size */ 1891057Salm } 1901057Salm return size; 1911057Salm} 1921057Salm 1931057Salm 1941057Salm/* put_stream_line: write a line of text to a stream; return status */ 1951057Salmint 19690109Simpput_stream_line(FILE *fp, const char *s, int len) 1971057Salm{ 1981057Salm while (len--) 1991057Salm if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) { 2001057Salm fprintf(stderr, "%s\n", strerror(errno)); 20181220Smike errmsg = "cannot write file"; 2021057Salm return ERR; 2031057Salm } 2041057Salm return 0; 2051057Salm} 2061057Salm 207108533Sschweikh/* get_extended_line: get an extended line from stdin */ 2081057Salmchar * 20990109Simpget_extended_line(int *sizep, int nonl) 2101057Salm{ 2111057Salm static char *cvbuf = NULL; /* buffer */ 2121057Salm static int cvbufsz = 0; /* buffer size */ 2131057Salm 2141057Salm int l, n; 2151057Salm char *t = ibufp; 2161057Salm 2171057Salm while (*t++ != '\n') 2181057Salm ; 2191057Salm if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) { 2201057Salm *sizep = l; 2211057Salm return ibufp; 2221057Salm } 2231057Salm *sizep = -1; 2241057Salm REALLOC(cvbuf, cvbufsz, l, NULL); 2251057Salm memcpy(cvbuf, ibufp, l); 2261057Salm *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ 2271057Salm if (nonl) l--; /* strip newline */ 2281057Salm for (;;) { 2291057Salm if ((n = get_tty_line()) < 0) 2301057Salm return NULL; 2311057Salm else if (n == 0 || ibuf[n - 1] != '\n') { 23281220Smike errmsg = "unexpected end-of-file"; 2331057Salm return NULL; 2341057Salm } 2351057Salm REALLOC(cvbuf, cvbufsz, l + n, NULL); 2361057Salm memcpy(cvbuf + l, ibuf, n); 2371057Salm l += n; 2381057Salm if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1)) 2391057Salm break; 2401057Salm *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ 2411057Salm if (nonl) l--; /* strip newline */ 2421057Salm } 2431057Salm REALLOC(cvbuf, cvbufsz, l + 1, NULL); 2441057Salm cvbuf[l] = '\0'; 2451057Salm *sizep = l; 2461057Salm return cvbuf; 2471057Salm} 2481057Salm 2491057Salm 2501057Salm/* get_tty_line: read a line of text from stdin; return line length */ 2511057Salmint 25290109Simpget_tty_line(void) 2531057Salm{ 25481220Smike int oi = 0; 25581220Smike int i = 0; 2561057Salm int c; 2571057Salm 2581057Salm for (;;) 2591057Salm switch (c = getchar()) { 2601057Salm default: 2611057Salm oi = 0; 2621057Salm REALLOC(ibuf, ibufsz, i + 2, ERR); 2631057Salm if (!(ibuf[i++] = c)) isbinary = 1; 2641057Salm if (c != '\n') 2651057Salm continue; 2661057Salm lineno++; 2671057Salm ibuf[i] = '\0'; 2681057Salm ibufp = ibuf; 2691057Salm return i; 2701057Salm case EOF: 2711057Salm if (ferror(stdin)) { 2721057Salm fprintf(stderr, "stdin: %s\n", strerror(errno)); 27381220Smike errmsg = "cannot read stdin"; 2741057Salm clearerr(stdin); 2751057Salm ibufp = NULL; 2761057Salm return ERR; 2771057Salm } else { 2781057Salm clearerr(stdin); 2791057Salm if (i != oi) { 2801057Salm oi = i; 2811057Salm continue; 2821057Salm } else if (i) 2831057Salm ibuf[i] = '\0'; 2841057Salm ibufp = ibuf; 2851057Salm return i; 2861057Salm } 2871057Salm } 2881057Salm} 2891057Salm 2901057Salm 2911057Salm 2921057Salm#define ESCAPES "\a\b\f\n\r\t\v\\" 2931057Salm#define ESCCHARS "abfnrtv\\" 2941057Salm 2951057Salm/* put_tty_line: print text to stdout */ 2961057Salmint 29790109Simpput_tty_line(const char *s, int l, long n, int gflag) 2981057Salm{ 2991057Salm int col = 0; 3001057Salm int lc = 0; 3011057Salm char *cp; 3021057Salm 3031057Salm if (gflag & GNP) { 3041057Salm printf("%ld\t", n); 3051057Salm col = 8; 3061057Salm } 3071057Salm for (; l--; s++) { 3081057Salm if ((gflag & GLS) && ++col > cols) { 3091057Salm fputs("\\\n", stdout); 3101057Salm col = 1; 3111057Salm#ifndef BACKWARDS 3121057Salm if (!scripted && !isglobal && ++lc > rows) { 3131057Salm lc = 0; 3141057Salm fputs("Press <RETURN> to continue... ", stdout); 3151057Salm fflush(stdout); 3161057Salm if (get_tty_line() < 0) 3171057Salm return ERR; 3181057Salm } 3191057Salm#endif 3201057Salm } 3211057Salm if (gflag & GLS) { 3221057Salm if (31 < *s && *s < 127 && *s != '\\') 3231057Salm putchar(*s); 3241057Salm else { 3251057Salm putchar('\\'); 3261057Salm col++; 3271057Salm if (*s && (cp = strchr(ESCAPES, *s)) != NULL) 3281057Salm putchar(ESCCHARS[cp - ESCAPES]); 3291057Salm else { 3301057Salm putchar((((unsigned char) *s & 0300) >> 6) + '0'); 3311057Salm putchar((((unsigned char) *s & 070) >> 3) + '0'); 3321057Salm putchar(((unsigned char) *s & 07) + '0'); 3331057Salm col += 2; 3341057Salm } 3351057Salm } 3361057Salm 3371057Salm } else 3381057Salm putchar(*s); 3391057Salm } 3401057Salm#ifndef BACKWARDS 3411057Salm if (gflag & GLS) 3421057Salm putchar('$'); 3431057Salm#endif 3441057Salm putchar('\n'); 3451057Salm return 0; 3461057Salm} 347