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