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