1218885Sdim/* buf.c: This file contains the scratch-file buffer routines for the 2218885Sdim ed line editor. */ 3218885Sdim/*- 4218885Sdim * Copyright (c) 1993 Andrew Moore, Talke Studio. 5218885Sdim * All rights reserved. 6218885Sdim * 7218885Sdim * Redistribution and use in source and binary forms, with or without 8218885Sdim * modification, are permitted provided that the following conditions 9218885Sdim * are met: 10218885Sdim * 1. Redistributions of source code must retain the above copyright 11218885Sdim * notice, this list of conditions and the following disclaimer. 12218885Sdim * 2. Redistributions in binary form must reproduce the above copyright 13218885Sdim * notice, this list of conditions and the following disclaimer in the 14218885Sdim * documentation and/or other materials provided with the distribution. 15218885Sdim * 16218885Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17218885Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18218885Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19218885Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20218885Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21218885Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22226633Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23226633Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24226633Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25218885Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26218885Sdim * SUCH DAMAGE. 27263508Sdim */ 28263508Sdim 29218885Sdim#include <sys/cdefs.h> 30263508Sdim__FBSDID("$FreeBSD$"); 31263508Sdim 32218885Sdim#include <sys/file.h> 33234353Sdim#include <sys/stat.h> 34218885Sdim 35218885Sdim#include "ed.h" 36263508Sdim 37218885Sdim 38218885Sdimstatic FILE *sfp; /* scratch file pointer */ 39218885Sdimstatic off_t sfseek; /* scratch file position */ 40218885Sdimstatic int seek_write; /* seek before writing */ 41218885Sdimstatic line_t buffer_head; /* incore buffer */ 42263508Sdim 43263508Sdim/* get_sbuf_line: get a line of text from the scratch file; return pointer 44263508Sdim to the text */ 45263508Sdimchar * 46263508Sdimget_sbuf_line(line_t *lp) 47263508Sdim{ 48263508Sdim static char *sfbuf = NULL; /* buffer */ 49263508Sdim static int sfbufsz = 0; /* buffer size */ 50218885Sdim 51263508Sdim int len, ct; 52218885Sdim 53218885Sdim if (lp == &buffer_head) 54234353Sdim return NULL; 55234353Sdim seek_write = 1; /* force seek on write */ 56234353Sdim /* out of position */ 57234353Sdim if (sfseek != lp->seek) { 58218885Sdim sfseek = lp->seek; 59234353Sdim if (fseeko(sfp, sfseek, SEEK_SET) < 0) { 60234353Sdim fprintf(stderr, "%s\n", strerror(errno)); 61218885Sdim errmsg = "cannot seek temp file"; 62234353Sdim return NULL; 63234353Sdim } 64218885Sdim } 65234353Sdim len = lp->len; 66234353Sdim REALLOC(sfbuf, sfbufsz, len + 1, NULL); 67234353Sdim if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) { 68234353Sdim fprintf(stderr, "%s\n", strerror(errno)); 69234353Sdim errmsg = "cannot read temp file"; 70234353Sdim return NULL; 71218885Sdim } 72218885Sdim sfseek += len; /* update file position */ 73234353Sdim sfbuf[len] = '\0'; 74234353Sdim return sfbuf; 75234353Sdim} 76234353Sdim 77218885Sdim 78218885Sdim/* put_sbuf_line: write a line of text to the scratch file and add a line node 79234353Sdim to the editor buffer; return a pointer to the end of the text */ 80234353Sdimconst char * 81234353Sdimput_sbuf_line(const char *cs) 82234353Sdim{ 83218885Sdim line_t *lp; 84218885Sdim int len, ct; 85234353Sdim const char *s; 86234353Sdim 87263508Sdim if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 88234353Sdim fprintf(stderr, "%s\n", strerror(errno)); 89234353Sdim errmsg = "out of memory"; 90234353Sdim return NULL; 91234353Sdim } 92234353Sdim /* assert: cs is '\n' terminated */ 93234353Sdim for (s = cs; *s != '\n'; s++) 94218885Sdim ; 95218885Sdim if (s - cs >= LINECHARS) { 96234353Sdim errmsg = "line too long"; 97234353Sdim free(lp); 98218885Sdim return NULL; 99234353Sdim } 100234353Sdim len = s - cs; 101234353Sdim /* out of position */ 102218885Sdim if (seek_write) { 103234353Sdim if (fseeko(sfp, (off_t)0, SEEK_END) < 0) { 104234353Sdim fprintf(stderr, "%s\n", strerror(errno)); 105218885Sdim errmsg = "cannot seek temp file"; 106218885Sdim free(lp); 107234353Sdim return NULL; 108234353Sdim } 109218885Sdim sfseek = ftello(sfp); 110234353Sdim seek_write = 0; 111218885Sdim } 112234353Sdim /* assert: SPL1() */ 113234353Sdim if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 114234353Sdim sfseek = -1; 115234353Sdim fprintf(stderr, "%s\n", strerror(errno)); 116234353Sdim errmsg = "cannot write temp file"; 117218885Sdim free(lp); 118234353Sdim return NULL; 119234353Sdim } 120234353Sdim lp->len = len; 121234353Sdim lp->seek = sfseek; 122234353Sdim add_line_node(lp); 123218885Sdim sfseek += len; /* update file position */ 124218885Sdim return ++s; 125234353Sdim} 126234353Sdim 127234353Sdim 128218885Sdim/* add_line_node: add a line node in the editor buffer after the current line */ 129234353Sdimvoid 130234353Sdimadd_line_node(line_t *lp) 131218885Sdim{ 132234353Sdim line_t *cp; 133218885Sdim 134234353Sdim cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 135234353Sdim INSQUE(lp, cp); 136234353Sdim addr_last++; 137218885Sdim current_addr++; 138218885Sdim} 139218885Sdim 140234353Sdim 141218885Sdim/* get_line_node_addr: return line number of pointer */ 142234353Sdimlong 143234353Sdimget_line_node_addr(line_t *lp) 144234353Sdim{ 145234353Sdim line_t *cp = &buffer_head; 146234353Sdim long n = 0; 147234353Sdim 148218885Sdim while (cp != lp && (cp = cp->q_forw) != &buffer_head) 149218885Sdim n++; 150218885Sdim if (n && cp == &buffer_head) { 151218885Sdim errmsg = "invalid address"; 152218885Sdim return ERR; 153218885Sdim } 154218885Sdim return n; 155218885Sdim} 156218885Sdim 157218885Sdim 158218885Sdim/* get_addressed_line_node: return pointer to a line node in the editor buffer */ 159263508Sdimline_t * 160263508Sdimget_addressed_line_node(long n) 161263508Sdim{ 162263508Sdim static line_t *lp = &buffer_head; 163263508Sdim static long on = 0; 164263508Sdim 165263508Sdim SPL1(); 166263508Sdim if (n > on) 167263508Sdim if (n <= (on + addr_last) >> 1) 168218885Sdim for (; on < n; on++) 169 lp = lp->q_forw; 170 else { 171 lp = buffer_head.q_back; 172 for (on = addr_last; on > n; on--) 173 lp = lp->q_back; 174 } 175 else 176 if (n >= on >> 1) 177 for (; on > n; on--) 178 lp = lp->q_back; 179 else { 180 lp = &buffer_head; 181 for (on = 0; on < n; on++) 182 lp = lp->q_forw; 183 } 184 SPL0(); 185 return lp; 186} 187 188static char sfn[15] = ""; /* scratch file name */ 189 190/* open_sbuf: open scratch file */ 191int 192open_sbuf(void) 193{ 194 int fd; 195 int u; 196 197 isbinary = newline_added = 0; 198 u = umask(077); 199 strcpy(sfn, "/tmp/ed.XXXXXX"); 200 if ((fd = mkstemp(sfn)) == -1 || 201 (sfp = fdopen(fd, "w+")) == NULL) { 202 if (fd != -1) 203 close(fd); 204 perror(sfn); 205 errmsg = "cannot open temp file"; 206 umask(u); 207 return ERR; 208 } 209 umask(u); 210 return 0; 211} 212 213 214/* close_sbuf: close scratch file */ 215int 216close_sbuf(void) 217{ 218 if (sfp) { 219 if (fclose(sfp) < 0) { 220 fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 221 errmsg = "cannot close temp file"; 222 return ERR; 223 } 224 sfp = NULL; 225 unlink(sfn); 226 } 227 sfseek = seek_write = 0; 228 return 0; 229} 230 231 232/* quit: remove_lines scratch file and exit */ 233void 234quit(int n) 235{ 236 if (sfp) { 237 fclose(sfp); 238 unlink(sfn); 239 } 240 exit(n); 241} 242 243 244static unsigned char ctab[256]; /* character translation table */ 245 246/* init_buffers: open scratch buffer; initialize line queue */ 247void 248init_buffers(void) 249{ 250 int i = 0; 251 252 /* Read stdin one character at a time to avoid i/o contention 253 with shell escapes invoked by nonterminal input, e.g., 254 ed - <<EOF 255 !cat 256 hello, world 257 EOF */ 258 setbuffer(stdin, stdinbuf, 1); 259 260 /* Ensure stdout is line buffered. This avoids bogus delays 261 of output if stdout is piped through utilities to a terminal. */ 262 setvbuf(stdout, NULL, _IOLBF, 0); 263 if (open_sbuf() < 0) 264 quit(2); 265 REQUE(&buffer_head, &buffer_head); 266 for (i = 0; i < 256; i++) 267 ctab[i] = i; 268} 269 270 271/* translit_text: translate characters in a string */ 272char * 273translit_text(char *s, int len, int from, int to) 274{ 275 static int i = 0; 276 277 unsigned char *us; 278 279 ctab[i] = i; /* restore table to initial state */ 280 ctab[i = from] = to; 281 for (us = (unsigned char *) s; len-- > 0; us++) 282 *us = ctab[*us]; 283 return s; 284} 285