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