1 /* buf.c: This file contains the scratch-file buffer routines for the 2 ed line editor. */ 3 /*- 4 * Copyright (c) 1993 Andrew Moore, Talke Studio. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * @(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp 29 * $FreeBSD: src/bin/ed/buf.c,v 1.17 1999/08/27 23:14:12 peter Exp $ 30 * $DragonFly: src/bin/ed/buf.c,v 1.2 2003/06/17 04:22:49 dillon Exp $ 31 */ 32 33 #include <sys/file.h> 34 #include <sys/stat.h> 35 36 #include "ed.h" 37 38 39 FILE *sfp; /* scratch file pointer */ 40 off_t sfseek; /* scratch file position */ 41 int seek_write; /* seek before writing */ 42 line_t buffer_head; /* incore buffer */ 43 44 /* get_sbuf_line: get a line of text from the scratch file; return pointer 45 to the text */ 46 char * 47 get_sbuf_line(lp) 48 line_t *lp; 49 { 50 static char *sfbuf = NULL; /* buffer */ 51 static int sfbufsz = 0; /* buffer size */ 52 53 int len, ct; 54 55 if (lp == &buffer_head) 56 return NULL; 57 seek_write = 1; /* force seek on write */ 58 /* out of position */ 59 if (sfseek != lp->seek) { 60 sfseek = lp->seek; 61 if (fseek(sfp, sfseek, SEEK_SET) < 0) { 62 fprintf(stderr, "%s\n", strerror(errno)); 63 sprintf(errmsg, "cannot seek temp file"); 64 return NULL; 65 } 66 } 67 len = lp->len; 68 REALLOC(sfbuf, sfbufsz, len + 1, NULL); 69 if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) { 70 fprintf(stderr, "%s\n", strerror(errno)); 71 sprintf(errmsg, "cannot read temp file"); 72 return NULL; 73 } 74 sfseek += len; /* update file position */ 75 sfbuf[len] = '\0'; 76 return sfbuf; 77 } 78 79 80 /* put_sbuf_line: write a line of text to the scratch file and add a line node 81 to the editor buffer; return a pointer to the end of the text */ 82 char * 83 put_sbuf_line(cs) 84 char *cs; 85 { 86 line_t *lp; 87 int len, ct; 88 char *s; 89 90 if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 91 fprintf(stderr, "%s\n", strerror(errno)); 92 sprintf(errmsg, "out of memory"); 93 return NULL; 94 } 95 /* assert: cs is '\n' terminated */ 96 for (s = cs; *s != '\n'; s++) 97 ; 98 if (s - cs >= LINECHARS) { 99 sprintf(errmsg, "line too long"); 100 return NULL; 101 } 102 len = s - cs; 103 /* out of position */ 104 if (seek_write) { 105 if (fseek(sfp, 0L, SEEK_END) < 0) { 106 fprintf(stderr, "%s\n", strerror(errno)); 107 sprintf(errmsg, "cannot seek temp file"); 108 return NULL; 109 } 110 sfseek = ftell(sfp); 111 seek_write = 0; 112 } 113 /* assert: SPL1() */ 114 if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 115 sfseek = -1; 116 fprintf(stderr, "%s\n", strerror(errno)); 117 sprintf(errmsg, "cannot write temp file"); 118 return NULL; 119 } 120 lp->len = len; 121 lp->seek = sfseek; 122 add_line_node(lp); 123 sfseek += len; /* update file position */ 124 return ++s; 125 } 126 127 128 /* add_line_node: add a line node in the editor buffer after the current line */ 129 void 130 add_line_node(lp) 131 line_t *lp; 132 { 133 line_t *cp; 134 135 cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 136 INSQUE(lp, cp); 137 addr_last++; 138 current_addr++; 139 } 140 141 142 /* get_line_node_addr: return line number of pointer */ 143 long 144 get_line_node_addr(lp) 145 line_t *lp; 146 { 147 line_t *cp = &buffer_head; 148 long n = 0; 149 150 while (cp != lp && (cp = cp->q_forw) != &buffer_head) 151 n++; 152 if (n && cp == &buffer_head) { 153 sprintf(errmsg, "invalid address"); 154 return ERR; 155 } 156 return n; 157 } 158 159 160 /* get_addressed_line_node: return pointer to a line node in the editor buffer */ 161 line_t * 162 get_addressed_line_node(n) 163 long n; 164 { 165 static line_t *lp = &buffer_head; 166 static long on = 0; 167 168 SPL1(); 169 if (n > on) 170 if (n <= (on + addr_last) >> 1) 171 for (; on < n; on++) 172 lp = lp->q_forw; 173 else { 174 lp = buffer_head.q_back; 175 for (on = addr_last; on > n; on--) 176 lp = lp->q_back; 177 } 178 else 179 if (n >= on >> 1) 180 for (; on > n; on--) 181 lp = lp->q_back; 182 else { 183 lp = &buffer_head; 184 for (on = 0; on < n; on++) 185 lp = lp->q_forw; 186 } 187 SPL0(); 188 return lp; 189 } 190 191 192 extern int newline_added; 193 194 char sfn[15] = ""; /* scratch file name */ 195 196 /* open_sbuf: open scratch file */ 197 int 198 open_sbuf() 199 { 200 int fd = -1; 201 int u; 202 203 isbinary = newline_added = 0; 204 u = umask(077); 205 strcpy(sfn, "/tmp/ed.XXXXXX"); 206 if ((fd = mkstemp(sfn)) == -1 || 207 (sfp = fdopen(fd, "w+")) == NULL) { 208 if (fd != -1) 209 close(fd); 210 perror(sfn); 211 strcpy(errmsg, "cannot open temp file"); 212 umask(u); 213 return ERR; 214 } 215 umask(u); 216 return 0; 217 } 218 219 220 /* close_sbuf: close scratch file */ 221 int 222 close_sbuf() 223 { 224 if (sfp) { 225 if (fclose(sfp) < 0) { 226 fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 227 sprintf(errmsg, "cannot close temp file"); 228 return ERR; 229 } 230 sfp = NULL; 231 unlink(sfn); 232 } 233 sfseek = seek_write = 0; 234 return 0; 235 } 236 237 238 /* quit: remove_lines scratch file and exit */ 239 void 240 quit(n) 241 int n; 242 { 243 if (sfp) { 244 fclose(sfp); 245 unlink(sfn); 246 } 247 exit(n); 248 } 249 250 251 unsigned char ctab[256]; /* character translation table */ 252 253 /* init_buffers: open scratch buffer; initialize line queue */ 254 void 255 init_buffers() 256 { 257 int i = 0; 258 259 /* Read stdin one character at a time to avoid i/o contention 260 with shell escapes invoked by nonterminal input, e.g., 261 ed - <<EOF 262 !cat 263 hello, world 264 EOF */ 265 setbuffer(stdin, stdinbuf, 1); 266 267 /* Ensure stdout is line buffered. This avoids bogus delays 268 of output if stdout is piped through utilities to a terminal. */ 269 setvbuf(stdout, NULL, _IOLBF, 0); 270 if (open_sbuf() < 0) 271 quit(2); 272 REQUE(&buffer_head, &buffer_head); 273 for (i = 0; i < 256; i++) 274 ctab[i] = i; 275 } 276 277 278 /* translit_text: translate characters in a string */ 279 char * 280 translit_text(s, len, from, to) 281 char *s; 282 int len; 283 int from; 284 int to; 285 { 286 static int i = 0; 287 288 unsigned char *us; 289 290 ctab[i] = i; /* restore table to initial state */ 291 ctab[i = from] = to; 292 for (us = (unsigned char *) s; len-- > 0; us++) 293 *us = ctab[*us]; 294 return s; 295 } 296