1 /* $NetBSD: buf.c,v 1.15 1995/04/23 10:07:28 cgd Exp $ */ 2 3 /* buf.c: This file contains the scratch-file buffer rountines 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 #ifndef lint 32 #if 0 33 static char *rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp"; 34 #else 35 static char rcsid[] = "$NetBSD: buf.c,v 1.15 1995/04/23 10:07:28 cgd Exp $"; 36 #endif 37 #endif /* not lint */ 38 39 #include <sys/file.h> 40 #include <sys/stat.h> 41 42 #include "ed.h" 43 44 45 FILE *sfp; /* scratch file pointer */ 46 off_t sfseek; /* scratch file position */ 47 int seek_write; /* seek before writing */ 48 line_t buffer_head; /* incore buffer */ 49 50 /* get_sbuf_line: get a line of text from the scratch file; return pointer 51 to the text */ 52 char * 53 get_sbuf_line(lp) 54 line_t *lp; 55 { 56 static char *sfbuf = NULL; /* buffer */ 57 static int sfbufsz = 0; /* buffer size */ 58 59 int len, ct; 60 61 if (lp == &buffer_head) 62 return NULL; 63 seek_write = 1; /* force seek on write */ 64 /* out of position */ 65 if (sfseek != lp->seek) { 66 sfseek = lp->seek; 67 if (fseek(sfp, sfseek, SEEK_SET) < 0) { 68 fprintf(stderr, "%s\n", strerror(errno)); 69 sprintf(errmsg, "cannot seek temp file"); 70 return NULL; 71 } 72 } 73 len = lp->len; 74 REALLOC(sfbuf, sfbufsz, len + 1, NULL); 75 if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) { 76 fprintf(stderr, "%s\n", strerror(errno)); 77 sprintf(errmsg, "cannot read temp file"); 78 return NULL; 79 } 80 sfseek += len; /* update file position */ 81 sfbuf[len] = '\0'; 82 return sfbuf; 83 } 84 85 86 /* put_sbuf_line: write a line of text to the scratch file and add a line node 87 to the editor buffer; return a pointer to the end of the text */ 88 char * 89 put_sbuf_line(cs) 90 char *cs; 91 { 92 line_t *lp; 93 int len, ct; 94 char *s; 95 96 if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 97 fprintf(stderr, "%s\n", strerror(errno)); 98 sprintf(errmsg, "out of memory"); 99 return NULL; 100 } 101 /* assert: cs is '\n' terminated */ 102 for (s = cs; *s != '\n'; s++) 103 ; 104 if (s - cs >= LINECHARS) { 105 sprintf(errmsg, "line too long"); 106 return NULL; 107 } 108 len = s - cs; 109 /* out of position */ 110 if (seek_write) { 111 if (fseek(sfp, 0L, SEEK_END) < 0) { 112 fprintf(stderr, "%s\n", strerror(errno)); 113 sprintf(errmsg, "cannot seek temp file"); 114 return NULL; 115 } 116 sfseek = ftell(sfp); 117 seek_write = 0; 118 } 119 /* assert: SPL1() */ 120 if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 121 sfseek = -1; 122 fprintf(stderr, "%s\n", strerror(errno)); 123 sprintf(errmsg, "cannot write temp file"); 124 return NULL; 125 } 126 lp->len = len; 127 lp->seek = sfseek; 128 add_line_node(lp); 129 sfseek += len; /* update file position */ 130 return ++s; 131 } 132 133 134 /* add_line_node: add a line node in the editor buffer after the current line */ 135 void 136 add_line_node(lp) 137 line_t *lp; 138 { 139 line_t *cp; 140 141 cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 142 INSQUE(lp, cp); 143 addr_last++; 144 current_addr++; 145 } 146 147 148 /* get_line_node_addr: return line number of pointer */ 149 long 150 get_line_node_addr(lp) 151 line_t *lp; 152 { 153 line_t *cp = &buffer_head; 154 long n = 0; 155 156 while (cp != lp && (cp = cp->q_forw) != &buffer_head) 157 n++; 158 if (n && cp == &buffer_head) { 159 sprintf(errmsg, "invalid address"); 160 return ERR; 161 } 162 return n; 163 } 164 165 166 /* get_addressed_line_node: return pointer to a line node in the editor buffer */ 167 line_t * 168 get_addressed_line_node(n) 169 long n; 170 { 171 static line_t *lp = &buffer_head; 172 static long on = 0; 173 174 SPL1(); 175 if (n > on) 176 if (n <= (on + addr_last) >> 1) 177 for (; on < n; on++) 178 lp = lp->q_forw; 179 else { 180 lp = buffer_head.q_back; 181 for (on = addr_last; on > n; on--) 182 lp = lp->q_back; 183 } 184 else 185 if (n >= on >> 1) 186 for (; on > n; on--) 187 lp = lp->q_back; 188 else { 189 lp = &buffer_head; 190 for (on = 0; on < n; on++) 191 lp = lp->q_forw; 192 } 193 SPL0(); 194 return lp; 195 } 196 197 198 extern int newline_added; 199 200 char sfn[15] = ""; /* scratch file name */ 201 202 /* open_sbuf: open scratch file */ 203 int 204 open_sbuf() 205 { 206 int u; 207 208 isbinary = newline_added = 0; 209 u = umask(077); 210 strcpy(sfn, "/tmp/ed.XXXXXX"); 211 if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) { 212 fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 213 sprintf(errmsg, "cannot open temp file"); 214 umask(u); 215 return ERR; 216 } 217 umask(u); 218 return 0; 219 } 220 221 222 /* close_sbuf: close scratch file */ 223 int 224 close_sbuf() 225 { 226 if (sfp) { 227 if (fclose(sfp) < 0) { 228 fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 229 sprintf(errmsg, "cannot close temp file"); 230 return ERR; 231 } 232 sfp = NULL; 233 unlink(sfn); 234 } 235 sfseek = seek_write = 0; 236 return 0; 237 } 238 239 240 /* quit: remove_lines scratch file and exit */ 241 void 242 quit(n) 243 int n; 244 { 245 if (sfp) { 246 fclose(sfp); 247 unlink(sfn); 248 } 249 exit(n); 250 } 251 252 253 unsigned char ctab[256]; /* character translation table */ 254 255 /* init_buffers: open scratch buffer; initialize line queue */ 256 void 257 init_buffers() 258 { 259 int i = 0; 260 261 /* Read stdin one character at a time to avoid i/o contention 262 with shell escapes invoked by nonterminal input, e.g., 263 ed - <<EOF 264 !cat 265 hello, world 266 EOF */ 267 setbuffer(stdin, stdinbuf, 1); 268 if (open_sbuf() < 0) 269 quit(2); 270 REQUE(&buffer_head, &buffer_head); 271 for (i = 0; i < 256; i++) 272 ctab[i] = i; 273 } 274 275 276 /* translit_text: translate characters in a string */ 277 char * 278 translit_text(s, len, from, to) 279 char *s; 280 int len; 281 int from; 282 int to; 283 { 284 static int i = 0; 285 286 unsigned char *us; 287 288 ctab[i] = i; /* restore table to initial state */ 289 ctab[i = from] = to; 290 for (us = (unsigned char *) s; len-- > 0; us++) 291 *us = ctab[*us]; 292 return s; 293 } 294