1 /* buf.c: This file contains the scratch-file buffer rountines 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 #ifndef lint 29 static char *rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp"; 30 #endif /* not lint */ 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(lp) 47 line_t *lp; 48 { 49 static char *sfbuf = NULL; /* buffer */ 50 static int sfbufsz = 0; /* buffer size */ 51 52 int len, ct; 53 54 if (lp == &buffer_head) 55 return NULL; 56 seek_write = 1; /* force seek on write */ 57 /* out of position */ 58 if (sfseek != lp->seek) { 59 sfseek = lp->seek; 60 if (fseek(sfp, sfseek, SEEK_SET) < 0) { 61 fprintf(stderr, "%s\n", strerror(errno)); 62 sprintf(errmsg, "cannot seek temp file"); 63 return NULL; 64 } 65 } 66 len = lp->len; 67 REALLOC(sfbuf, sfbufsz, len + 1, NULL); 68 if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) { 69 fprintf(stderr, "%s\n", strerror(errno)); 70 sprintf(errmsg, "cannot read temp file"); 71 return NULL; 72 } 73 sfseek += len; /* update file position */ 74 sfbuf[len] = '\0'; 75 return sfbuf; 76 } 77 78 79 /* put_sbuf_line: write a line of text to the scratch file and add a line node 80 to the editor buffer; return a pointer to the end of the text */ 81 char * 82 put_sbuf_line(cs) 83 char *cs; 84 { 85 line_t *lp; 86 int len, ct; 87 char *s; 88 89 if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 90 fprintf(stderr, "%s\n", strerror(errno)); 91 sprintf(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 sprintf(errmsg, "line too long"); 99 return NULL; 100 } 101 len = s - cs; 102 /* out of position */ 103 if (seek_write) { 104 if (fseek(sfp, 0L, SEEK_END) < 0) { 105 fprintf(stderr, "%s\n", strerror(errno)); 106 sprintf(errmsg, "cannot seek temp file"); 107 return NULL; 108 } 109 sfseek = ftell(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 sprintf(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 */ 128 void 129 add_line_node(lp) 130 line_t *lp; 131 { 132 line_t *cp; 133 134 cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 135 INSQUE(lp, cp); 136 addr_last++; 137 current_addr++; 138 } 139 140 141 /* get_line_node_addr: return line number of pointer */ 142 long 143 get_line_node_addr(lp) 144 line_t *lp; 145 { 146 line_t *cp = &buffer_head; 147 long n = 0; 148 149 while (cp != lp && (cp = cp->q_forw) != &buffer_head) 150 n++; 151 if (n && cp == &buffer_head) { 152 sprintf(errmsg, "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(n) 162 long n; 163 { 164 static line_t *lp = &buffer_head; 165 static long on = 0; 166 167 SPL1(); 168 if (n > on) 169 if (n <= (on + addr_last) >> 1) 170 for (; on < n; on++) 171 lp = lp->q_forw; 172 else { 173 lp = buffer_head.q_back; 174 for (on = addr_last; on > n; on--) 175 lp = lp->q_back; 176 } 177 else 178 if (n >= on >> 1) 179 for (; on > n; on--) 180 lp = lp->q_back; 181 else { 182 lp = &buffer_head; 183 for (on = 0; on < n; on++) 184 lp = lp->q_forw; 185 } 186 SPL0(); 187 return lp; 188 } 189 190 191 extern int newline_added; 192 193 char sfn[15] = ""; /* scratch file name */ 194 195 /* open_sbuf: open scratch file */ 196 int 197 open_sbuf() 198 { 199 int u; 200 201 isbinary = newline_added = 0; 202 u = umask(077); 203 strcpy(sfn, "/tmp/ed.XXXXXX"); 204 if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) { 205 fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 206 sprintf(errmsg, "cannot open temp file"); 207 umask(u); 208 return ERR; 209 } 210 umask(u); 211 return 0; 212 } 213 214 215 /* close_sbuf: close scratch file */ 216 int 217 close_sbuf() 218 { 219 if (sfp) { 220 if (fclose(sfp) < 0) { 221 fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 222 sprintf(errmsg, "cannot close temp file"); 223 return ERR; 224 } 225 sfp = NULL; 226 unlink(sfn); 227 } 228 sfseek = seek_write = 0; 229 return 0; 230 } 231 232 233 /* quit: remove_lines scratch file and exit */ 234 void 235 quit(n) 236 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() 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(s, len, from, to) 272 char *s; 273 int len; 274 int from; 275 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