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