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 29 #ifndef lint 30 static const char rcsid[] = 31 "$FreeBSD$"; 32 #endif /* not lint */ 33 34 #include <sys/file.h> 35 #include <sys/stat.h> 36 37 #include "ed.h" 38 39 40 FILE *sfp; /* scratch file pointer */ 41 off_t sfseek; /* scratch file position */ 42 int seek_write; /* seek before writing */ 43 line_t buffer_head; /* incore buffer */ 44 45 /* get_sbuf_line: get a line of text from the scratch file; return pointer 46 to the text */ 47 char * 48 get_sbuf_line(lp) 49 line_t *lp; 50 { 51 static char *sfbuf = NULL; /* buffer */ 52 static int sfbufsz = 0; /* buffer size */ 53 54 int len, ct; 55 56 if (lp == &buffer_head) 57 return NULL; 58 seek_write = 1; /* force seek on write */ 59 /* out of position */ 60 if (sfseek != lp->seek) { 61 sfseek = lp->seek; 62 if (fseeko(sfp, sfseek, SEEK_SET) < 0) { 63 fprintf(stderr, "%s\n", strerror(errno)); 64 errmsg = "cannot seek temp file"; 65 return NULL; 66 } 67 } 68 len = lp->len; 69 REALLOC(sfbuf, sfbufsz, len + 1, NULL); 70 if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) { 71 fprintf(stderr, "%s\n", strerror(errno)); 72 errmsg = "cannot read temp file"; 73 return NULL; 74 } 75 sfseek += len; /* update file position */ 76 sfbuf[len] = '\0'; 77 return sfbuf; 78 } 79 80 81 /* put_sbuf_line: write a line of text to the scratch file and add a line node 82 to the editor buffer; return a pointer to the end of the text */ 83 const char * 84 put_sbuf_line(cs) 85 const char *cs; 86 { 87 line_t *lp; 88 int len, ct; 89 const char *s; 90 91 if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 92 fprintf(stderr, "%s\n", strerror(errno)); 93 errmsg = "out of memory"; 94 return NULL; 95 } 96 /* assert: cs is '\n' terminated */ 97 for (s = cs; *s != '\n'; s++) 98 ; 99 if (s - cs >= LINECHARS) { 100 errmsg = "line too long"; 101 return NULL; 102 } 103 len = s - cs; 104 /* out of position */ 105 if (seek_write) { 106 if (fseeko(sfp, (off_t)0, SEEK_END) < 0) { 107 fprintf(stderr, "%s\n", strerror(errno)); 108 errmsg = "cannot seek temp file"; 109 return NULL; 110 } 111 sfseek = ftello(sfp); 112 seek_write = 0; 113 } 114 /* assert: SPL1() */ 115 if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 116 sfseek = -1; 117 fprintf(stderr, "%s\n", strerror(errno)); 118 errmsg = "cannot write temp file"; 119 return NULL; 120 } 121 lp->len = len; 122 lp->seek = sfseek; 123 add_line_node(lp); 124 sfseek += len; /* update file position */ 125 return ++s; 126 } 127 128 129 /* add_line_node: add a line node in the editor buffer after the current line */ 130 void 131 add_line_node(lp) 132 line_t *lp; 133 { 134 line_t *cp; 135 136 cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 137 INSQUE(lp, cp); 138 addr_last++; 139 current_addr++; 140 } 141 142 143 /* get_line_node_addr: return line number of pointer */ 144 long 145 get_line_node_addr(lp) 146 line_t *lp; 147 { 148 line_t *cp = &buffer_head; 149 long n = 0; 150 151 while (cp != lp && (cp = cp->q_forw) != &buffer_head) 152 n++; 153 if (n && cp == &buffer_head) { 154 errmsg = "invalid address"; 155 return ERR; 156 } 157 return n; 158 } 159 160 161 /* get_addressed_line_node: return pointer to a line node in the editor buffer */ 162 line_t * 163 get_addressed_line_node(n) 164 long n; 165 { 166 static line_t *lp = &buffer_head; 167 static long on = 0; 168 169 SPL1(); 170 if (n > on) 171 if (n <= (on + addr_last) >> 1) 172 for (; on < n; on++) 173 lp = lp->q_forw; 174 else { 175 lp = buffer_head.q_back; 176 for (on = addr_last; on > n; on--) 177 lp = lp->q_back; 178 } 179 else 180 if (n >= on >> 1) 181 for (; on > n; on--) 182 lp = lp->q_back; 183 else { 184 lp = &buffer_head; 185 for (on = 0; on < n; on++) 186 lp = lp->q_forw; 187 } 188 SPL0(); 189 return lp; 190 } 191 192 193 extern int newline_added; 194 195 char sfn[15] = ""; /* scratch file name */ 196 197 /* open_sbuf: open scratch file */ 198 int 199 open_sbuf() 200 { 201 int fd = -1; 202 int u; 203 204 isbinary = newline_added = 0; 205 u = umask(077); 206 strcpy(sfn, "/tmp/ed.XXXXXX"); 207 if ((fd = mkstemp(sfn)) == -1 || 208 (sfp = fdopen(fd, "w+")) == NULL) { 209 if (fd != -1) 210 close(fd); 211 perror(sfn); 212 errmsg = "cannot open temp file"; 213 umask(u); 214 return ERR; 215 } 216 umask(u); 217 return 0; 218 } 219 220 221 /* close_sbuf: close scratch file */ 222 int 223 close_sbuf() 224 { 225 if (sfp) { 226 if (fclose(sfp) < 0) { 227 fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 228 errmsg = "cannot close temp file"; 229 return ERR; 230 } 231 sfp = NULL; 232 unlink(sfn); 233 } 234 sfseek = seek_write = 0; 235 return 0; 236 } 237 238 239 /* quit: remove_lines scratch file and exit */ 240 void 241 quit(n) 242 int n; 243 { 244 if (sfp) { 245 fclose(sfp); 246 unlink(sfn); 247 } 248 exit(n); 249 } 250 251 252 unsigned char ctab[256]; /* character translation table */ 253 254 /* init_buffers: open scratch buffer; initialize line queue */ 255 void 256 init_buffers() 257 { 258 int i = 0; 259 260 /* Read stdin one character at a time to avoid i/o contention 261 with shell escapes invoked by nonterminal input, e.g., 262 ed - <<EOF 263 !cat 264 hello, world 265 EOF */ 266 setbuffer(stdin, stdinbuf, 1); 267 268 /* Ensure stdout is line buffered. This avoids bogus delays 269 of output if stdout is piped through utilities to a terminal. */ 270 setvbuf(stdout, NULL, _IOLBF, 0); 271 if (open_sbuf() < 0) 272 quit(2); 273 REQUE(&buffer_head, &buffer_head); 274 for (i = 0; i < 256; i++) 275 ctab[i] = i; 276 } 277 278 279 /* translit_text: translate characters in a string */ 280 char * 281 translit_text(s, len, from, to) 282 char *s; 283 int len; 284 int from; 285 int to; 286 { 287 static int i = 0; 288 289 unsigned char *us; 290 291 ctab[i] = i; /* restore table to initial state */ 292 ctab[i = from] = to; 293 for (us = (unsigned char *) s; len-- > 0; us++) 294 *us = ctab[*us]; 295 return s; 296 } 297