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