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