1 /* $NetBSD: io.c,v 1.2 1995/03/21 09:04:43 cgd 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 #ifndef lint 31 #if 0 32 static char *rcsid = "@(#)io.c,v 1.1 1994/02/01 00:34:41 alm Exp"; 33 #else 34 static char rcsid[] = "$NetBSD: io.c,v 1.2 1995/03/21 09:04:43 cgd Exp $"; 35 #endif 36 #endif /* not lint */ 37 38 #include "ed.h" 39 40 41 extern int scripted; 42 43 /* read_file: read a named file/pipe into the buffer; return line count */ 44 long 45 read_file(fn, n) 46 char *fn; 47 long n; 48 { 49 FILE *fp; 50 long size; 51 52 53 fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r"); 54 if (fp == NULL) { 55 fprintf(stderr, "%s: %s\n", fn, strerror(errno)); 56 sprintf(errmsg, "cannot open input file"); 57 return ERR; 58 } else if ((size = read_stream(fp, n)) < 0) 59 return ERR; 60 else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) { 61 fprintf(stderr, "%s: %s\n", fn, strerror(errno)); 62 sprintf(errmsg, "cannot close input file"); 63 return ERR; 64 } 65 fprintf(stderr, !scripted ? "%lu\n" : "", size); 66 return current_addr - n; 67 } 68 69 70 extern int des; 71 72 char *sbuf; /* file i/o buffer */ 73 int sbufsz; /* file i/o buffer size */ 74 int newline_added; /* if set, newline appended to input file */ 75 76 /* read_stream: read a stream into the editor buffer; return status */ 77 long 78 read_stream(fp, n) 79 FILE *fp; 80 long n; 81 { 82 line_t *lp = get_addressed_line_node(n); 83 undo_t *up = NULL; 84 unsigned long size = 0; 85 int o_newline_added = newline_added; 86 int o_isbinary = isbinary; 87 int appended = (n == addr_last); 88 int len; 89 90 isbinary = newline_added = 0; 91 if (des) 92 init_des_cipher(); 93 for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) { 94 SPL1(); 95 if (put_sbuf_line(sbuf) == NULL) { 96 SPL0(); 97 return ERR; 98 } 99 lp = lp->q_forw; 100 if (up) 101 up->t = lp; 102 else if ((up = push_undo_stack(UADD, current_addr, 103 current_addr)) == NULL) { 104 SPL0(); 105 return ERR; 106 } 107 SPL0(); 108 } 109 if (len < 0) 110 return ERR; 111 if (appended && size && o_isbinary && o_newline_added) 112 fputs("newline inserted\n", stderr); 113 else if (newline_added && (!appended || !isbinary && !o_isbinary)) 114 fputs("newline appended\n", stderr); 115 if (isbinary && newline_added && !appended) 116 size += 1; 117 if (!size) 118 newline_added = 1; 119 newline_added = appended ? newline_added : o_newline_added; 120 isbinary = isbinary | o_isbinary; 121 if (des) 122 size += 8 - size % 8; /* adjust DES size */ 123 return size; 124 } 125 126 127 /* get_stream_line: read a line of text from a stream; return line length */ 128 int 129 get_stream_line(fp) 130 FILE *fp; 131 { 132 register int c; 133 register int i = 0; 134 135 while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || !feof(fp) && 136 !ferror(fp)) && c != '\n') { 137 REALLOC(sbuf, sbufsz, i + 1, ERR); 138 if (!(sbuf[i++] = c)) 139 isbinary = 1; 140 } 141 REALLOC(sbuf, sbufsz, i + 2, ERR); 142 if (c == '\n') 143 sbuf[i++] = c; 144 else if (ferror(fp)) { 145 fprintf(stderr, "%s\n", strerror(errno)); 146 sprintf(errmsg, "cannot read input file"); 147 return ERR; 148 } else if (i) { 149 sbuf[i++] = '\n'; 150 newline_added = 1; 151 } 152 sbuf[i] = '\0'; 153 return (isbinary && newline_added && i) ? --i : i; 154 } 155 156 157 /* write_file: write a range of lines to a named file/pipe; return line count */ 158 long 159 write_file(fn, mode, n, m) 160 char *fn; 161 char *mode; 162 long n; 163 long m; 164 { 165 FILE *fp; 166 long size; 167 168 fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode); 169 if (fp == NULL) { 170 fprintf(stderr, "%s: %s\n", fn, strerror(errno)); 171 sprintf(errmsg, "cannot open output file"); 172 return ERR; 173 } else if ((size = write_stream(fp, n, m)) < 0) 174 return ERR; 175 else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) { 176 fprintf(stderr, "%s: %s\n", fn, strerror(errno)); 177 sprintf(errmsg, "cannot close output file"); 178 return ERR; 179 } 180 fprintf(stderr, !scripted ? "%lu\n" : "", size); 181 return n ? m - n + 1 : 0; 182 } 183 184 185 /* write_stream: write a range of lines to a stream; return status */ 186 long 187 write_stream(fp, n, m) 188 FILE *fp; 189 long n; 190 long m; 191 { 192 line_t *lp = get_addressed_line_node(n); 193 unsigned long size = 0; 194 char *s; 195 int len; 196 197 if (des) 198 init_des_cipher(); 199 for (; n && n <= m; n++, lp = lp->q_forw) { 200 if ((s = get_sbuf_line(lp)) == NULL) 201 return ERR; 202 len = lp->len; 203 if (n != addr_last || !isbinary || !newline_added) 204 s[len++] = '\n'; 205 if (put_stream_line(fp, s, len) < 0) 206 return ERR; 207 size += len; 208 } 209 if (des) { 210 flush_des_file(fp); /* flush buffer */ 211 size += 8 - size % 8; /* adjust DES size */ 212 } 213 return size; 214 } 215 216 217 /* put_stream_line: write a line of text to a stream; return status */ 218 int 219 put_stream_line(fp, s, len) 220 FILE *fp; 221 char *s; 222 int len; 223 { 224 while (len--) 225 if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) { 226 fprintf(stderr, "%s\n", strerror(errno)); 227 sprintf(errmsg, "cannot write file"); 228 return ERR; 229 } 230 return 0; 231 } 232 233 /* get_extended_line: get a an extended line from stdin */ 234 char * 235 get_extended_line(sizep, nonl) 236 int *sizep; 237 int nonl; 238 { 239 static char *cvbuf = NULL; /* buffer */ 240 static int cvbufsz = 0; /* buffer size */ 241 242 int l, n; 243 char *t = ibufp; 244 245 while (*t++ != '\n') 246 ; 247 if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) { 248 *sizep = l; 249 return ibufp; 250 } 251 *sizep = -1; 252 REALLOC(cvbuf, cvbufsz, l, NULL); 253 memcpy(cvbuf, ibufp, l); 254 *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ 255 if (nonl) l--; /* strip newline */ 256 for (;;) { 257 if ((n = get_tty_line()) < 0) 258 return NULL; 259 else if (n == 0 || ibuf[n - 1] != '\n') { 260 sprintf(errmsg, "unexpected end-of-file"); 261 return NULL; 262 } 263 REALLOC(cvbuf, cvbufsz, l + n, NULL); 264 memcpy(cvbuf + l, ibuf, n); 265 l += n; 266 if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1)) 267 break; 268 *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */ 269 if (nonl) l--; /* strip newline */ 270 } 271 REALLOC(cvbuf, cvbufsz, l + 1, NULL); 272 cvbuf[l] = '\0'; 273 *sizep = l; 274 return cvbuf; 275 } 276 277 278 /* get_tty_line: read a line of text from stdin; return line length */ 279 int 280 get_tty_line() 281 { 282 register int oi = 0; 283 register int i = 0; 284 int c; 285 286 for (;;) 287 switch (c = getchar()) { 288 default: 289 oi = 0; 290 REALLOC(ibuf, ibufsz, i + 2, ERR); 291 if (!(ibuf[i++] = c)) isbinary = 1; 292 if (c != '\n') 293 continue; 294 lineno++; 295 ibuf[i] = '\0'; 296 ibufp = ibuf; 297 return i; 298 case EOF: 299 if (ferror(stdin)) { 300 fprintf(stderr, "stdin: %s\n", strerror(errno)); 301 sprintf(errmsg, "cannot read stdin"); 302 clearerr(stdin); 303 ibufp = NULL; 304 return ERR; 305 } else { 306 clearerr(stdin); 307 if (i != oi) { 308 oi = i; 309 continue; 310 } else if (i) 311 ibuf[i] = '\0'; 312 ibufp = ibuf; 313 return i; 314 } 315 } 316 } 317 318 319 320 #define ESCAPES "\a\b\f\n\r\t\v\\" 321 #define ESCCHARS "abfnrtv\\" 322 323 extern int rows; 324 extern int cols; 325 326 /* put_tty_line: print text to stdout */ 327 int 328 put_tty_line(s, l, n, gflag) 329 char *s; 330 int l; 331 long n; 332 int gflag; 333 { 334 int col = 0; 335 int lc = 0; 336 char *cp; 337 338 if (gflag & GNP) { 339 printf("%ld\t", n); 340 col = 8; 341 } 342 for (; l--; s++) { 343 if ((gflag & GLS) && ++col > cols) { 344 fputs("\\\n", stdout); 345 col = 1; 346 #ifndef BACKWARDS 347 if (!scripted && !isglobal && ++lc > rows) { 348 lc = 0; 349 fputs("Press <RETURN> to continue... ", stdout); 350 fflush(stdout); 351 if (get_tty_line() < 0) 352 return ERR; 353 } 354 #endif 355 } 356 if (gflag & GLS) { 357 if (31 < *s && *s < 127 && *s != '\\') 358 putchar(*s); 359 else { 360 putchar('\\'); 361 col++; 362 if (*s && (cp = strchr(ESCAPES, *s)) != NULL) 363 putchar(ESCCHARS[cp - ESCAPES]); 364 else { 365 putchar((((unsigned char) *s & 0300) >> 6) + '0'); 366 putchar((((unsigned char) *s & 070) >> 3) + '0'); 367 putchar(((unsigned char) *s & 07) + '0'); 368 col += 2; 369 } 370 } 371 372 } else 373 putchar(*s); 374 } 375 #ifndef BACKWARDS 376 if (gflag & GLS) 377 putchar('$'); 378 #endif 379 putchar('\n'); 380 return 0; 381 } 382