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