1 /* $NetBSD: buf.c,v 1.23 2003/10/19 01:52:45 wiz Exp $ */ 2 3 /* buf.c: This file contains the scratch-file buffer routines for the 4 ed line editor. */ 5 /*- 6 * Copyright (c) 1993 Andrew Moore, Talke Studio. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 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 __RCSID("$NetBSD: buf.c,v 1.23 2003/10/19 01:52:45 wiz Exp $"); 37 #endif 38 #endif /* not lint */ 39 40 #include <sys/file.h> 41 #include <sys/stat.h> 42 43 #include <paths.h> 44 #include <stdio.h> 45 #include <err.h> 46 47 #include "ed.h" 48 49 50 FILE *sfp; /* scratch file pointer */ 51 off_t sfseek; /* scratch file position */ 52 int seek_write; /* seek before writing */ 53 line_t buffer_head; /* incore buffer */ 54 55 /* get_sbuf_line: get a line of text from the scratch file; return pointer 56 to the text */ 57 char * 58 get_sbuf_line(lp) 59 line_t *lp; 60 { 61 static char *sfbuf = NULL; /* buffer */ 62 static int sfbufsz = 0; /* buffer size */ 63 64 int len, ct; 65 66 if (lp == &buffer_head) 67 return NULL; 68 seek_write = 1; /* force seek on write */ 69 /* out of position */ 70 if (sfseek != lp->seek) { 71 sfseek = lp->seek; 72 if (fseek(sfp, sfseek, SEEK_SET) < 0) { 73 fprintf(stderr, "%s\n", strerror(errno)); 74 sprintf(errmsg, "cannot seek temp file"); 75 return NULL; 76 } 77 } 78 len = lp->len; 79 REALLOC(sfbuf, sfbufsz, len + 1, NULL); 80 if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) { 81 fprintf(stderr, "%s\n", strerror(errno)); 82 sprintf(errmsg, "cannot read temp file"); 83 return NULL; 84 } 85 sfseek += len; /* update file position */ 86 sfbuf[len] = '\0'; 87 return sfbuf; 88 } 89 90 91 /* put_sbuf_line: write a line of text to the scratch file and add a line node 92 to the editor buffer; return a pointer to the end of the text */ 93 char * 94 put_sbuf_line(cs) 95 char *cs; 96 { 97 line_t *lp; 98 int len, ct; 99 char *s; 100 101 if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 102 fprintf(stderr, "%s\n", strerror(errno)); 103 sprintf(errmsg, "out of memory"); 104 return NULL; 105 } 106 /* assert: cs is '\n' terminated */ 107 for (s = cs; *s != '\n'; s++) 108 ; 109 if (s - cs >= LINECHARS) { 110 sprintf(errmsg, "line too long"); 111 free(lp); 112 return NULL; 113 } 114 len = s - cs; 115 /* out of position */ 116 if (seek_write) { 117 if (fseek(sfp, 0L, SEEK_END) < 0) { 118 fprintf(stderr, "%s\n", strerror(errno)); 119 sprintf(errmsg, "cannot seek temp file"); 120 free(lp); 121 return NULL; 122 } 123 sfseek = ftell(sfp); 124 seek_write = 0; 125 } 126 /* assert: SPL1() */ 127 if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 128 sfseek = -1; 129 fprintf(stderr, "%s\n", strerror(errno)); 130 sprintf(errmsg, "cannot write temp file"); 131 free(lp); 132 return NULL; 133 } 134 lp->len = len; 135 lp->seek = sfseek; 136 add_line_node(lp); 137 sfseek += len; /* update file position */ 138 return ++s; 139 } 140 141 142 /* add_line_node: add a line node in the editor buffer after the current line */ 143 void 144 add_line_node(lp) 145 line_t *lp; 146 { 147 line_t *cp; 148 149 cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 150 INSQUE(lp, cp); 151 addr_last++; 152 current_addr++; 153 } 154 155 156 /* get_line_node_addr: return line number of pointer */ 157 long 158 get_line_node_addr(lp) 159 line_t *lp; 160 { 161 line_t *cp = &buffer_head; 162 long n = 0; 163 164 while (cp != lp && (cp = cp->q_forw) != &buffer_head) 165 n++; 166 if (n && cp == &buffer_head) { 167 sprintf(errmsg, "invalid address"); 168 return ERR; 169 } 170 return n; 171 } 172 173 174 /* get_addressed_line_node: return pointer to a line node in the editor buffer */ 175 line_t * 176 get_addressed_line_node(n) 177 long n; 178 { 179 static line_t *lp = &buffer_head; 180 static long on = 0; 181 182 SPL1(); 183 if (n > on) { 184 if (n <= (on + addr_last) >> 1) { 185 for (; on < n; on++) 186 lp = lp->q_forw; 187 } else { 188 lp = buffer_head.q_back; 189 for (on = addr_last; on > n; on--) 190 lp = lp->q_back; 191 } 192 } else { 193 if (n >= on >> 1) { 194 for (; on > n; on--) 195 lp = lp->q_back; 196 } else { 197 lp = &buffer_head; 198 for (on = 0; on < n; on++) 199 lp = lp->q_forw; 200 } 201 } 202 SPL0(); 203 return lp; 204 } 205 206 207 char *sfn = NULL; /* scratch file name */ 208 209 /* open_sbuf: open scratch file */ 210 int 211 open_sbuf() 212 { 213 int u, fd; 214 char *tmp; 215 size_t s; 216 217 isbinary = newline_added = 0; 218 fd = -1; 219 u = umask(077); 220 221 if ((tmp = getenv("TMPDIR")) == NULL) 222 tmp = _PATH_TMP; 223 224 if ((s = strlen(tmp)) == 0 || tmp[s - 1] == '/') 225 (void)asprintf(&sfn, "%sed.XXXXXX", tmp); 226 else 227 (void)asprintf(&sfn, "%s/ed.XXXXXX", tmp); 228 229 if ((fd = mkstemp(sfn)) == -1 || (sfp = fdopen(fd, "w+")) == NULL) { 230 if (fd != -1) 231 close(fd); 232 warn("%s", sfn); 233 sprintf(errmsg, "cannot open temp file"); 234 umask(u); 235 return ERR; 236 } 237 umask(u); 238 return 0; 239 } 240 241 242 /* close_sbuf: close scratch file */ 243 int 244 close_sbuf() 245 { 246 if (sfp) { 247 if (fclose(sfp) < 0) { 248 fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 249 sprintf(errmsg, "cannot close temp file"); 250 return ERR; 251 } 252 sfp = NULL; 253 if (sfn) { 254 unlink(sfn); 255 free(sfn); 256 sfn = NULL; 257 } 258 } 259 sfseek = seek_write = 0; 260 return 0; 261 } 262 263 264 /* quit: remove_lines scratch file and exit */ 265 void 266 quit(n) 267 int n; 268 { 269 if (sfp) { 270 fclose(sfp); 271 if (sfn) { 272 unlink(sfn); 273 free(sfn); 274 sfn = NULL; 275 } 276 } 277 exit(n); 278 /* NOTREACHED */ 279 } 280 281 282 unsigned char ctab[256]; /* character translation table */ 283 284 /* init_buffers: open scratch buffer; initialize line queue */ 285 void 286 init_buffers() 287 { 288 int i = 0; 289 290 /* Read stdin one character at a time to avoid i/o contention 291 with shell escapes invoked by nonterminal input, e.g., 292 ed - <<EOF 293 !cat 294 hello, world 295 EOF */ 296 setbuffer(stdin, stdinbuf, 1); 297 if (open_sbuf() < 0) 298 quit(2); 299 REQUE(&buffer_head, &buffer_head); 300 for (i = 0; i < 256; i++) 301 ctab[i] = i; 302 } 303 304 305 /* translit_text: translate characters in a string */ 306 char * 307 translit_text(s, len, from, to) 308 char *s; 309 int len; 310 int from; 311 int to; 312 { 313 static int i = 0; 314 315 unsigned char *us; 316 317 ctab[i] = i; /* restore table to initial state */ 318 ctab[i = from] = to; 319 for (us = (unsigned char *) s; len-- > 0; us++) 320 *us = ctab[*us]; 321 return s; 322 } 323