1 /* $OpenBSD: buf.c,v 1.11 2001/01/16 03:04:45 deraadt Exp $ */ 2 /* $NetBSD: buf.c,v 1.15 1995/04/23 10:07:28 cgd Exp $ */ 3 4 /* buf.c: This file contains the scratch-file buffer rountines for the 5 ed line editor. */ 6 /*- 7 * Copyright (c) 1993 Andrew Moore, Talke Studio. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 #if 0 34 static char *rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp"; 35 #else 36 static char rcsid[] = "$OpenBSD: buf.c,v 1.11 2001/01/16 03:04:45 deraadt Exp $"; 37 #endif 38 #endif /* not lint */ 39 40 #include <sys/file.h> 41 #include <sys/stat.h> 42 43 #include "ed.h" 44 45 46 FILE *sfp; /* scratch file pointer */ 47 off_t sfseek; /* scratch file position */ 48 int seek_write; /* seek before writing */ 49 line_t buffer_head; /* incore buffer */ 50 51 /* get_sbuf_line: get a line of text from the scratch file; return pointer 52 to the text */ 53 char * 54 get_sbuf_line(lp) 55 line_t *lp; 56 { 57 static char *sfbuf = NULL; /* buffer */ 58 static int sfbufsz = 0; /* buffer size */ 59 60 int len, ct; 61 62 if (lp == &buffer_head) 63 return NULL; 64 seek_write = 1; /* force seek on write */ 65 /* out of position */ 66 if (sfseek != lp->seek) { 67 sfseek = lp->seek; 68 if (fseek(sfp, sfseek, SEEK_SET) < 0) { 69 perror(NULL); 70 seterrmsg("cannot seek temp file"); 71 return NULL; 72 } 73 } 74 len = lp->len; 75 REALLOC(sfbuf, sfbufsz, len + 1, NULL); 76 if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) { 77 perror(NULL); 78 seterrmsg("cannot read temp file"); 79 return NULL; 80 } 81 sfseek += len; /* update file position */ 82 sfbuf[len] = '\0'; 83 return sfbuf; 84 } 85 86 87 /* put_sbuf_line: write a line of text to the scratch file and add a line node 88 to the editor buffer; return a pointer to the end of the text */ 89 char * 90 put_sbuf_line(cs) 91 char *cs; 92 { 93 line_t *lp; 94 int len, ct; 95 char *s; 96 97 if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 98 perror(NULL); 99 seterrmsg("out of memory"); 100 return NULL; 101 } 102 /* assert: cs is '\n' terminated */ 103 for (s = cs; *s != '\n'; s++) 104 ; 105 if (s - cs >= LINECHARS) { 106 seterrmsg("line too long"); 107 return NULL; 108 } 109 len = s - cs; 110 /* out of position */ 111 if (seek_write) { 112 if (fseek(sfp, 0L, SEEK_END) < 0) { 113 perror(NULL); 114 seterrmsg("cannot seek temp file"); 115 return NULL; 116 } 117 sfseek = ftell(sfp); 118 seek_write = 0; 119 } 120 /* assert: SPL1() */ 121 if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 122 sfseek = -1; 123 perror(NULL); 124 seterrmsg("cannot write temp file"); 125 return NULL; 126 } 127 lp->len = len; 128 lp->seek = sfseek; 129 add_line_node(lp); 130 sfseek += len; /* update file position */ 131 return ++s; 132 } 133 134 135 /* add_line_node: add a line node in the editor buffer after the current line */ 136 void 137 add_line_node(lp) 138 line_t *lp; 139 { 140 line_t *cp; 141 142 cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 143 INSQUE(lp, cp); 144 addr_last++; 145 current_addr++; 146 } 147 148 149 /* get_line_node_addr: return line number of pointer */ 150 long 151 get_line_node_addr(lp) 152 line_t *lp; 153 { 154 line_t *cp = &buffer_head; 155 long n = 0; 156 157 while (cp != lp && (cp = cp->q_forw) != &buffer_head) 158 n++; 159 if (n && cp == &buffer_head) { 160 seterrmsg("invalid address"); 161 return ERR; 162 } 163 return n; 164 } 165 166 167 /* get_addressed_line_node: return pointer to a line node in the editor buffer */ 168 line_t * 169 get_addressed_line_node(n) 170 long n; 171 { 172 static line_t *lp = &buffer_head; 173 static long on = 0; 174 175 SPL1(); 176 if (n > on) { 177 if (n <= (on + addr_last) >> 1) 178 for (; on < n; on++) 179 lp = lp->q_forw; 180 else { 181 lp = buffer_head.q_back; 182 for (on = addr_last; on > n; on--) 183 lp = lp->q_back; 184 } 185 } else { 186 if (n >= on >> 1) 187 for (; on > n; on--) 188 lp = lp->q_back; 189 else { 190 lp = &buffer_head; 191 for (on = 0; on < n; on++) 192 lp = lp->q_forw; 193 } 194 } 195 SPL0(); 196 return lp; 197 } 198 199 200 extern int newline_added; 201 202 #define SCRATCH_TEMPLATE "/tmp/ed.XXXXXXXXXX" 203 char sfn[sizeof(SCRATCH_TEMPLATE)+1] = ""; /* scratch file name */ 204 205 /* open_sbuf: open scratch file */ 206 int 207 open_sbuf() 208 { 209 int fd = -1; 210 211 isbinary = newline_added = 0; 212 strlcpy(sfn, SCRATCH_TEMPLATE, sizeof sfn); 213 if ((fd = mkstemp(sfn)) == -1 || 214 (sfp = fdopen(fd, "w+")) == NULL) { 215 if (fd != -1) 216 close(fd); 217 perror(sfn); 218 seterrmsg("cannot open temp file"); 219 return ERR; 220 } 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 perror(sfn); 232 seterrmsg("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 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