Home | History | Annotate | Line # | Download | only in ed
buf.c revision 1.15
      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