xref: /minix3/bin/ed/buf.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: buf.c,v 1.27 2014/03/23 05:06:42 dholland Exp $	*/
27e81b07cSAndy Kosela 
37e81b07cSAndy Kosela /* buf.c: This file contains the scratch-file buffer routines for the
47e81b07cSAndy Kosela    ed line editor. */
57e81b07cSAndy Kosela /*-
67e81b07cSAndy Kosela  * Copyright (c) 1993 Andrew Moore, Talke Studio.
77e81b07cSAndy Kosela  * All rights reserved.
87e81b07cSAndy Kosela  *
97e81b07cSAndy Kosela  * Redistribution and use in source and binary forms, with or without
107e81b07cSAndy Kosela  * modification, are permitted provided that the following conditions
117e81b07cSAndy Kosela  * are met:
127e81b07cSAndy Kosela  * 1. Redistributions of source code must retain the above copyright
137e81b07cSAndy Kosela  *    notice, this list of conditions and the following disclaimer.
147e81b07cSAndy Kosela  * 2. Redistributions in binary form must reproduce the above copyright
157e81b07cSAndy Kosela  *    notice, this list of conditions and the following disclaimer in the
167e81b07cSAndy Kosela  *    documentation and/or other materials provided with the distribution.
177e81b07cSAndy Kosela  *
187e81b07cSAndy Kosela  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
197e81b07cSAndy Kosela  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
207e81b07cSAndy Kosela  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
217e81b07cSAndy Kosela  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
227e81b07cSAndy Kosela  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
237e81b07cSAndy Kosela  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
247e81b07cSAndy Kosela  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
257e81b07cSAndy Kosela  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
267e81b07cSAndy Kosela  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
277e81b07cSAndy Kosela  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
287e81b07cSAndy Kosela  * SUCH DAMAGE.
297e81b07cSAndy Kosela  */
307e81b07cSAndy Kosela 
317e81b07cSAndy Kosela #include <sys/cdefs.h>
327e81b07cSAndy Kosela #ifndef lint
337e81b07cSAndy Kosela #if 0
347e81b07cSAndy Kosela static char *rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp";
357e81b07cSAndy Kosela #else
36*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: buf.c,v 1.27 2014/03/23 05:06:42 dholland Exp $");
377e81b07cSAndy Kosela #endif
387e81b07cSAndy Kosela #endif /* not lint */
397e81b07cSAndy Kosela 
407e81b07cSAndy Kosela #include <sys/file.h>
417e81b07cSAndy Kosela #include <sys/stat.h>
427e81b07cSAndy Kosela 
437e81b07cSAndy Kosela #include <paths.h>
447e81b07cSAndy Kosela #include <stdio.h>
457e81b07cSAndy Kosela #include <err.h>
467e81b07cSAndy Kosela 
477e81b07cSAndy Kosela #include "ed.h"
487e81b07cSAndy Kosela 
497e81b07cSAndy Kosela 
507e81b07cSAndy Kosela FILE *sfp;				/* scratch file pointer */
517e81b07cSAndy Kosela off_t sfseek;				/* scratch file position */
527e81b07cSAndy Kosela int seek_write;				/* seek before writing */
537e81b07cSAndy Kosela line_t buffer_head;			/* incore buffer */
547e81b07cSAndy Kosela 
557e81b07cSAndy Kosela /* get_sbuf_line: get a line of text from the scratch file; return pointer
567e81b07cSAndy Kosela    to the text */
577e81b07cSAndy Kosela char *
get_sbuf_line(line_t * lp)587e81b07cSAndy Kosela get_sbuf_line(line_t *lp)
597e81b07cSAndy Kosela {
607e81b07cSAndy Kosela 	static char *sfbuf = NULL;	/* buffer */
617e81b07cSAndy Kosela 	static int sfbufsz = 0;		/* buffer size */
627e81b07cSAndy Kosela 
637e81b07cSAndy Kosela 	int len, ct;
647e81b07cSAndy Kosela 
657e81b07cSAndy Kosela 	if (lp == &buffer_head)
667e81b07cSAndy Kosela 		return NULL;
677e81b07cSAndy Kosela 	seek_write = 1;				/* force seek on write */
687e81b07cSAndy Kosela 	/* out of position */
697e81b07cSAndy Kosela 	if (sfseek != lp->seek) {
707e81b07cSAndy Kosela 		sfseek = lp->seek;
717e81b07cSAndy Kosela 		if (fseek(sfp, sfseek, SEEK_SET) < 0) {
727e81b07cSAndy Kosela 			fprintf(stderr, "%s\n", strerror(errno));
73*0a6a1f1dSLionel Sambuc 			seterrmsg("cannot seek temp file");
747e81b07cSAndy Kosela 			return NULL;
757e81b07cSAndy Kosela 		}
767e81b07cSAndy Kosela 	}
777e81b07cSAndy Kosela 	len = lp->len;
787e81b07cSAndy Kosela 	REALLOC(sfbuf, sfbufsz, len + 1, NULL);
797e81b07cSAndy Kosela 	if ((ct = fread(sfbuf, sizeof(char), len, sfp)) <  0 || ct != len) {
807e81b07cSAndy Kosela 		fprintf(stderr, "%s\n", strerror(errno));
81*0a6a1f1dSLionel Sambuc 		seterrmsg("cannot read temp file");
827e81b07cSAndy Kosela 		return NULL;
837e81b07cSAndy Kosela 	}
847e81b07cSAndy Kosela 	sfseek += len;				/* update file position */
857e81b07cSAndy Kosela 	sfbuf[len] = '\0';
867e81b07cSAndy Kosela 	return sfbuf;
877e81b07cSAndy Kosela }
887e81b07cSAndy Kosela 
897e81b07cSAndy Kosela 
907e81b07cSAndy Kosela /* put_sbuf_line: write a line of text to the scratch file and add a line node
917e81b07cSAndy Kosela    to the editor buffer;  return a pointer to the end of the text */
927e81b07cSAndy Kosela char *
put_sbuf_line(char * cs)937e81b07cSAndy Kosela put_sbuf_line(char *cs)
947e81b07cSAndy Kosela {
957e81b07cSAndy Kosela 	line_t *lp;
967e81b07cSAndy Kosela 	int len, ct;
977e81b07cSAndy Kosela 	char *s;
987e81b07cSAndy Kosela 
997e81b07cSAndy Kosela 	if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
1007e81b07cSAndy Kosela 		fprintf(stderr, "%s\n", strerror(errno));
101*0a6a1f1dSLionel Sambuc 		seterrmsg("out of memory");
1027e81b07cSAndy Kosela 		return NULL;
1037e81b07cSAndy Kosela 	}
1047e81b07cSAndy Kosela 	/* assert: cs is '\n' terminated */
1057e81b07cSAndy Kosela 	for (s = cs; *s != '\n'; s++)
1067e81b07cSAndy Kosela 		;
1077e81b07cSAndy Kosela 	if (s - cs >= LINECHARS) {
108*0a6a1f1dSLionel Sambuc 		seterrmsg("line too long");
1097e81b07cSAndy Kosela 		free(lp);
1107e81b07cSAndy Kosela 		return NULL;
1117e81b07cSAndy Kosela 	}
1127e81b07cSAndy Kosela 	len = s - cs;
1137e81b07cSAndy Kosela 	/* out of position */
1147e81b07cSAndy Kosela 	if (seek_write) {
1157e81b07cSAndy Kosela 		if (fseek(sfp, 0L, SEEK_END) < 0) {
1167e81b07cSAndy Kosela 			fprintf(stderr, "%s\n", strerror(errno));
117*0a6a1f1dSLionel Sambuc 			seterrmsg("cannot seek temp file");
1187e81b07cSAndy Kosela 			free(lp);
1197e81b07cSAndy Kosela 			return NULL;
1207e81b07cSAndy Kosela 		}
1217e81b07cSAndy Kosela 		sfseek = ftell(sfp);
1227e81b07cSAndy Kosela 		seek_write = 0;
1237e81b07cSAndy Kosela 	}
1247e81b07cSAndy Kosela 	/* assert: SPL1() */
1257e81b07cSAndy Kosela 	if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
1267e81b07cSAndy Kosela 		sfseek = -1;
1277e81b07cSAndy Kosela 		fprintf(stderr, "%s\n", strerror(errno));
128*0a6a1f1dSLionel Sambuc 		seterrmsg("cannot write temp file");
1297e81b07cSAndy Kosela 		free(lp);
1307e81b07cSAndy Kosela 		return NULL;
1317e81b07cSAndy Kosela 	}
1327e81b07cSAndy Kosela 	lp->len = len;
1337e81b07cSAndy Kosela 	lp->seek  = sfseek;
1347e81b07cSAndy Kosela 	add_line_node(lp);
1357e81b07cSAndy Kosela 	sfseek += len;			/* update file position */
1367e81b07cSAndy Kosela 	return ++s;
1377e81b07cSAndy Kosela }
1387e81b07cSAndy Kosela 
1397e81b07cSAndy Kosela 
1407e81b07cSAndy Kosela /* add_line_node: add a line node in the editor buffer after the current line */
1417e81b07cSAndy Kosela void
add_line_node(line_t * lp)1427e81b07cSAndy Kosela add_line_node(line_t *lp)
1437e81b07cSAndy Kosela {
1447e81b07cSAndy Kosela 	line_t *cp;
1457e81b07cSAndy Kosela 
1467e81b07cSAndy Kosela 	cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */
1477e81b07cSAndy Kosela 	INSQUE(lp, cp);
1487e81b07cSAndy Kosela 	addr_last++;
1497e81b07cSAndy Kosela 	current_addr++;
1507e81b07cSAndy Kosela }
1517e81b07cSAndy Kosela 
1527e81b07cSAndy Kosela 
1537e81b07cSAndy Kosela /* get_line_node_addr: return line number of pointer */
1547e81b07cSAndy Kosela long
get_line_node_addr(line_t * lp)1557e81b07cSAndy Kosela get_line_node_addr(line_t *lp)
1567e81b07cSAndy Kosela {
1577e81b07cSAndy Kosela 	line_t *cp = &buffer_head;
1587e81b07cSAndy Kosela 	long n = 0;
1597e81b07cSAndy Kosela 
1607e81b07cSAndy Kosela 	while (cp != lp && (cp = cp->q_forw) != &buffer_head)
1617e81b07cSAndy Kosela 		n++;
1627e81b07cSAndy Kosela 	if (n && cp == &buffer_head) {
163*0a6a1f1dSLionel Sambuc 		seterrmsg("invalid address");
1647e81b07cSAndy Kosela 		return ERR;
1657e81b07cSAndy Kosela 	}
1667e81b07cSAndy Kosela 	return n;
1677e81b07cSAndy Kosela }
1687e81b07cSAndy Kosela 
1697e81b07cSAndy Kosela 
1707e81b07cSAndy Kosela /* get_addressed_line_node: return pointer to a line node in the editor buffer */
1717e81b07cSAndy Kosela line_t *
get_addressed_line_node(long n)1727e81b07cSAndy Kosela get_addressed_line_node(long n)
1737e81b07cSAndy Kosela {
1747e81b07cSAndy Kosela 	static line_t *lp = &buffer_head;
1757e81b07cSAndy Kosela 	static long on = 0;
1767e81b07cSAndy Kosela 
1777e81b07cSAndy Kosela 	SPL1();
1787e81b07cSAndy Kosela 	if (n > on) {
1797e81b07cSAndy Kosela 		if (n <= (on + addr_last) >> 1) {
1807e81b07cSAndy Kosela 			for (; on < n; on++)
1817e81b07cSAndy Kosela 				lp = lp->q_forw;
1827e81b07cSAndy Kosela 		} else {
1837e81b07cSAndy Kosela 			lp = buffer_head.q_back;
1847e81b07cSAndy Kosela 			for (on = addr_last; on > n; on--)
1857e81b07cSAndy Kosela 				lp = lp->q_back;
1867e81b07cSAndy Kosela 		}
1877e81b07cSAndy Kosela 	} else {
1887e81b07cSAndy Kosela 		if (n >= on >> 1) {
1897e81b07cSAndy Kosela 			for (; on > n; on--)
1907e81b07cSAndy Kosela 				lp = lp->q_back;
1917e81b07cSAndy Kosela 		} else {
1927e81b07cSAndy Kosela 			lp = &buffer_head;
1937e81b07cSAndy Kosela 			for (on = 0; on < n; on++)
1947e81b07cSAndy Kosela 				lp = lp->q_forw;
1957e81b07cSAndy Kosela 		}
1967e81b07cSAndy Kosela 	}
1977e81b07cSAndy Kosela 	SPL0();
1987e81b07cSAndy Kosela 	return lp;
1997e81b07cSAndy Kosela }
2007e81b07cSAndy Kosela 
2017e81b07cSAndy Kosela 
2027e81b07cSAndy Kosela char *sfn = NULL;				/* scratch file name */
2037e81b07cSAndy Kosela 
2047e81b07cSAndy Kosela /* open_sbuf: open scratch file */
2057e81b07cSAndy Kosela int
open_sbuf(void)2067e81b07cSAndy Kosela open_sbuf(void)
2077e81b07cSAndy Kosela {
2087e81b07cSAndy Kosela 	int u, fd;
2097e81b07cSAndy Kosela 	const char *tmp;
2107e81b07cSAndy Kosela 	size_t s;
2117e81b07cSAndy Kosela 
2127e81b07cSAndy Kosela 	isbinary = newline_added = 0;
2137e81b07cSAndy Kosela 	fd = -1;
2147e81b07cSAndy Kosela 	u = umask(077);
2157e81b07cSAndy Kosela 
2167e81b07cSAndy Kosela 	if ((tmp = getenv("TMPDIR")) == NULL)
2177e81b07cSAndy Kosela 		tmp = _PATH_TMP;
2187e81b07cSAndy Kosela 
2197e81b07cSAndy Kosela 	if ((s = strlen(tmp)) == 0 || tmp[s - 1] == '/')
2207e81b07cSAndy Kosela 		(void)asprintf(&sfn, "%sed.XXXXXX", tmp);
2217e81b07cSAndy Kosela 	else
2227e81b07cSAndy Kosela 		(void)asprintf(&sfn, "%s/ed.XXXXXX", tmp);
2237e81b07cSAndy Kosela 	if (sfn == NULL) {
2247e81b07cSAndy Kosela 		warn(NULL);
225*0a6a1f1dSLionel Sambuc 		seterrmsg("could not allocate memory");
2267e81b07cSAndy Kosela 		umask(u);
2277e81b07cSAndy Kosela 		return ERR;
2287e81b07cSAndy Kosela 	}
2297e81b07cSAndy Kosela 
2307e81b07cSAndy Kosela 
2317e81b07cSAndy Kosela 	if ((fd = mkstemp(sfn)) == -1 || (sfp = fdopen(fd, "w+")) == NULL) {
2327e81b07cSAndy Kosela 		if (fd != -1)
2337e81b07cSAndy Kosela 			close(fd);
2347e81b07cSAndy Kosela 		warn("%s", sfn);
235*0a6a1f1dSLionel Sambuc 		seterrmsg("cannot open temp file");
2367e81b07cSAndy Kosela 		umask(u);
2377e81b07cSAndy Kosela 		return ERR;
2387e81b07cSAndy Kosela 	}
2397e81b07cSAndy Kosela 	umask(u);
2407e81b07cSAndy Kosela 	return 0;
2417e81b07cSAndy Kosela }
2427e81b07cSAndy Kosela 
2437e81b07cSAndy Kosela 
2447e81b07cSAndy Kosela /* close_sbuf: close scratch file */
2457e81b07cSAndy Kosela int
close_sbuf(void)2467e81b07cSAndy Kosela close_sbuf(void)
2477e81b07cSAndy Kosela {
2487e81b07cSAndy Kosela 	if (sfp) {
2497e81b07cSAndy Kosela 		if (fclose(sfp) < 0) {
2507e81b07cSAndy Kosela 			fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
251*0a6a1f1dSLionel Sambuc 			seterrmsg("cannot close temp file");
2527e81b07cSAndy Kosela 			return ERR;
2537e81b07cSAndy Kosela 		}
2547e81b07cSAndy Kosela 		sfp = NULL;
2557e81b07cSAndy Kosela 		if (sfn) {
2567e81b07cSAndy Kosela 			unlink(sfn);
2577e81b07cSAndy Kosela 			free(sfn);
2587e81b07cSAndy Kosela 			sfn = NULL;
2597e81b07cSAndy Kosela 		}
2607e81b07cSAndy Kosela 	}
2617e81b07cSAndy Kosela 	sfseek = seek_write = 0;
2627e81b07cSAndy Kosela 	return 0;
2637e81b07cSAndy Kosela }
2647e81b07cSAndy Kosela 
2657e81b07cSAndy Kosela 
2667e81b07cSAndy Kosela /* quit: remove_lines scratch file and exit */
2677e81b07cSAndy Kosela void
quit(int n)2687e81b07cSAndy Kosela quit(int n)
2697e81b07cSAndy Kosela {
2707e81b07cSAndy Kosela 	if (sfp) {
2717e81b07cSAndy Kosela 		fclose(sfp);
2727e81b07cSAndy Kosela 		if (sfn) {
2737e81b07cSAndy Kosela 			unlink(sfn);
2747e81b07cSAndy Kosela 			free(sfn);
2757e81b07cSAndy Kosela 			sfn = NULL;
2767e81b07cSAndy Kosela 		}
2777e81b07cSAndy Kosela 	}
2787e81b07cSAndy Kosela 	exit(n);
2797e81b07cSAndy Kosela 	/* NOTREACHED */
2807e81b07cSAndy Kosela }
2817e81b07cSAndy Kosela 
2827e81b07cSAndy Kosela 
2837e81b07cSAndy Kosela unsigned char ctab[256];		/* character translation table */
2847e81b07cSAndy Kosela 
2857e81b07cSAndy Kosela /* init_buffers: open scratch buffer; initialize line queue */
2867e81b07cSAndy Kosela void
init_buffers(void)2877e81b07cSAndy Kosela init_buffers(void)
2887e81b07cSAndy Kosela {
2897e81b07cSAndy Kosela 	int i = 0;
2907e81b07cSAndy Kosela 
2917e81b07cSAndy Kosela 	/* Read stdin one character at a time to avoid i/o contention
2927e81b07cSAndy Kosela 	   with shell escapes invoked by nonterminal input, e.g.,
2937e81b07cSAndy Kosela 	   ed - <<EOF
2947e81b07cSAndy Kosela 	   !cat
2957e81b07cSAndy Kosela 	   hello, world
2967e81b07cSAndy Kosela 	   EOF */
2977e81b07cSAndy Kosela 	setbuffer(stdin, stdinbuf, 1);
2987e81b07cSAndy Kosela 	if (open_sbuf() < 0)
2997e81b07cSAndy Kosela 		quit(2);
3007e81b07cSAndy Kosela 	REQUE(&buffer_head, &buffer_head);
3017e81b07cSAndy Kosela 	for (i = 0; i < 256; i++)
3027e81b07cSAndy Kosela 		ctab[i] = i;
3037e81b07cSAndy Kosela }
3047e81b07cSAndy Kosela 
3057e81b07cSAndy Kosela 
3067e81b07cSAndy Kosela /* translit_text: translate characters in a string */
3077e81b07cSAndy Kosela char *
translit_text(char * s,int len,int from,int to)3087e81b07cSAndy Kosela translit_text(char *s, int len, int from, int to)
3097e81b07cSAndy Kosela {
3107e81b07cSAndy Kosela 	static int i = 0;
3117e81b07cSAndy Kosela 
3127e81b07cSAndy Kosela 	unsigned char *us;
3137e81b07cSAndy Kosela 
3147e81b07cSAndy Kosela 	ctab[i] = i;			/* restore table to initial state */
3157e81b07cSAndy Kosela 	ctab[i = from] = to;
3167e81b07cSAndy Kosela 	for (us = (unsigned char *) s; len-- > 0; us++)
3177e81b07cSAndy Kosela 		*us = ctab[*us];
3187e81b07cSAndy Kosela 	return s;
3197e81b07cSAndy Kosela }
320