1 /* $OpenBSD: buf.c,v 1.19 2009/10/27 23:59:21 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 routines 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 #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 perror(NULL); 61 seterrmsg("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 perror(NULL); 69 seterrmsg("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 char * 81 put_sbuf_line(char *cs) 82 { 83 line_t *lp; 84 int len, ct; 85 char *s; 86 87 if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 88 perror(NULL); 89 seterrmsg("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 seterrmsg("line too long"); 97 free(lp); 98 return NULL; 99 } 100 len = s - cs; 101 /* out of position */ 102 if (seek_write) { 103 if (fseek(sfp, 0L, SEEK_END) < 0) { 104 perror(NULL); 105 seterrmsg("cannot seek temp file"); 106 free(lp); 107 return NULL; 108 } 109 sfseek = ftello(sfp); 110 seek_write = 0; 111 } 112 /* assert: SPL1() */ 113 if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 114 sfseek = -1; 115 perror(NULL); 116 seterrmsg("cannot write temp file"); 117 free(lp); 118 return NULL; 119 } 120 lp->len = len; 121 lp->seek = sfseek; 122 add_line_node(lp); 123 sfseek += len; /* update file position */ 124 return ++s; 125 } 126 127 128 /* add_line_node: add a line node in the editor buffer after the current line */ 129 void 130 add_line_node(line_t *lp) 131 { 132 line_t *cp; 133 134 /* this get_addressed_line_node last! */ 135 cp = get_addressed_line_node(current_addr); 136 INSQUE(lp, cp); 137 addr_last++; 138 current_addr++; 139 } 140 141 142 /* get_line_node_addr: return line number of pointer */ 143 int 144 get_line_node_addr(line_t *lp) 145 { 146 line_t *cp = &buffer_head; 147 int n = 0; 148 149 while (cp != lp && (cp = cp->q_forw) != &buffer_head) 150 n++; 151 if (n && cp == &buffer_head) { 152 seterrmsg("invalid address"); 153 return ERR; 154 } 155 return n; 156 } 157 158 159 /* get_addressed_line_node: return pointer to a line node in the editor buffer */ 160 line_t * 161 get_addressed_line_node(int n) 162 { 163 static line_t *lp = &buffer_head; 164 static int on = 0; 165 166 SPL1(); 167 if (n > on) { 168 if (n <= (on + addr_last) >> 1) 169 for (; on < n; on++) 170 lp = lp->q_forw; 171 else { 172 lp = buffer_head.q_back; 173 for (on = addr_last; on > n; on--) 174 lp = lp->q_back; 175 } 176 } else { 177 if (n >= on >> 1) 178 for (; on > n; on--) 179 lp = lp->q_back; 180 else { 181 lp = &buffer_head; 182 for (on = 0; on < n; on++) 183 lp = lp->q_forw; 184 } 185 } 186 SPL0(); 187 return lp; 188 } 189 190 191 extern int newline_added; 192 193 #define SCRATCH_TEMPLATE "/tmp/ed.XXXXXXXXXX" 194 char sfn[sizeof(SCRATCH_TEMPLATE)+1] = ""; /* scratch file name */ 195 196 /* open_sbuf: open scratch file */ 197 int 198 open_sbuf(void) 199 { 200 int fd = -1; 201 202 isbinary = newline_added = 0; 203 strlcpy(sfn, SCRATCH_TEMPLATE, sizeof sfn); 204 if ((fd = mkstemp(sfn)) == -1 || 205 (sfp = fdopen(fd, "w+")) == NULL) { 206 if (fd != -1) 207 close(fd); 208 perror(sfn); 209 seterrmsg("cannot open temp file"); 210 return ERR; 211 } 212 return 0; 213 } 214 215 216 /* close_sbuf: close scratch file */ 217 int 218 close_sbuf(void) 219 { 220 if (sfp) { 221 if (fclose(sfp) < 0) { 222 perror(sfn); 223 seterrmsg("cannot close temp file"); 224 return ERR; 225 } 226 sfp = NULL; 227 unlink(sfn); 228 } 229 sfseek = seek_write = 0; 230 return 0; 231 } 232 233 234 /* quit: remove_lines scratch file and exit */ 235 void 236 quit(int n) 237 { 238 if (sfp) { 239 fclose(sfp); 240 unlink(sfn); 241 } 242 exit(n); 243 } 244 245 246 unsigned char ctab[256]; /* character translation table */ 247 248 /* init_buffers: open scratch buffer; initialize line queue */ 249 void 250 init_buffers(void) 251 { 252 int i = 0; 253 254 /* Read stdin one character at a time to avoid i/o contention 255 with shell escapes invoked by nonterminal input, e.g., 256 ed - <<EOF 257 !cat 258 hello, world 259 EOF */ 260 setbuffer(stdin, stdinbuf, 1); 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