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