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