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