buf.c revision 241720
146684Skris/* buf.c: This file contains the scratch-file buffer routines for the
216Salm   ed line editor. */
316Salm/*-
41057Salm * Copyright (c) 1993 Andrew Moore, Talke Studio.
516Salm * All rights reserved.
616Salm *
716Salm * Redistribution and use in source and binary forms, with or without
816Salm * modification, are permitted provided that the following conditions
916Salm * are met:
1016Salm * 1. Redistributions of source code must retain the above copyright
1116Salm *    notice, this list of conditions and the following disclaimer.
1216Salm * 2. Redistributions in binary form must reproduce the above copyright
1316Salm *    notice, this list of conditions and the following disclaimer in the
1416Salm *    documentation and/or other materials provided with the distribution.
1516Salm *
161057Salm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1716Salm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1816Salm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191057Salm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2016Salm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2116Salm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2216Salm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2316Salm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2416Salm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2516Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2616Salm * SUCH DAMAGE.
2716Salm */
2827963Ssteve
2999109Sobrien#include <sys/cdefs.h>
3099109Sobrien__FBSDID("$FreeBSD: head/bin/ed/buf.c 241720 2012-10-19 05:43:38Z ed $");
3116Salm
3216Salm#include <sys/file.h>
331297Salm#include <sys/stat.h>
3416Salm
3516Salm#include "ed.h"
3616Salm
3716Salm
38241720Sedstatic FILE *sfp;			/* scratch file pointer */
39241720Sedstatic off_t sfseek;			/* scratch file position */
40241720Sedstatic int seek_write;			/* seek before writing */
41241720Sedstatic line_t buffer_head;		/* incore buffer */
4216Salm
431057Salm/* get_sbuf_line: get a line of text from the scratch file; return pointer
4416Salm   to the text */
4516Salmchar *
4690109Simpget_sbuf_line(line_t *lp)
4716Salm{
481057Salm	static char *sfbuf = NULL;	/* buffer */
491057Salm	static int sfbufsz = 0;		/* buffer size */
501057Salm
5116Salm	int len, ct;
5216Salm
531057Salm	if (lp == &buffer_head)
5416Salm		return NULL;
5516Salm	seek_write = 1;				/* force seek on write */
5616Salm	/* out of position */
5716Salm	if (sfseek != lp->seek) {
5816Salm		sfseek = lp->seek;
5982771Sache		if (fseeko(sfp, sfseek, SEEK_SET) < 0) {
6016Salm			fprintf(stderr, "%s\n", strerror(errno));
6181220Smike			errmsg = "cannot seek temp file";
6216Salm			return NULL;
6316Salm		}
6416Salm	}
651057Salm	len = lp->len;
661057Salm	REALLOC(sfbuf, sfbufsz, len + 1, NULL);
6716Salm	if ((ct = fread(sfbuf, sizeof(char), len, sfp)) <  0 || ct != len) {
6816Salm		fprintf(stderr, "%s\n", strerror(errno));
6981220Smike		errmsg = "cannot read temp file";
7016Salm		return NULL;
7116Salm	}
7216Salm	sfseek += len;				/* update file position */
7316Salm	sfbuf[len] = '\0';
7416Salm	return sfbuf;
7516Salm}
7616Salm
7716Salm
781057Salm/* put_sbuf_line: write a line of text to the scratch file and add a line node
7916Salm   to the editor buffer;  return a pointer to the end of the text */
8081220Smikeconst char *
8190109Simpput_sbuf_line(const char *cs)
8216Salm{
8316Salm	line_t *lp;
8416Salm	int len, ct;
8581220Smike	const char *s;
8616Salm
8716Salm	if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
8816Salm		fprintf(stderr, "%s\n", strerror(errno));
8981220Smike		errmsg = "out of memory";
9016Salm		return NULL;
9116Salm	}
9216Salm	/* assert: cs is '\n' terminated */
9316Salm	for (s = cs; *s != '\n'; s++)
9416Salm		;
9516Salm	if (s - cs >= LINECHARS) {
9681220Smike		errmsg = "line too long";
97225215Sbrueffer		free(lp);
9816Salm		return NULL;
9916Salm	}
1001057Salm	len = s - cs;
10116Salm	/* out of position */
10216Salm	if (seek_write) {
10382771Sache		if (fseeko(sfp, (off_t)0, SEEK_END) < 0) {
10416Salm			fprintf(stderr, "%s\n", strerror(errno));
10581220Smike			errmsg = "cannot seek temp file";
106225215Sbrueffer			free(lp);
10716Salm			return NULL;
10816Salm		}
10982771Sache		sfseek = ftello(sfp);
11016Salm		seek_write = 0;
11116Salm	}
1121057Salm	/* assert: SPL1() */
11316Salm	if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
11416Salm		sfseek = -1;
11516Salm		fprintf(stderr, "%s\n", strerror(errno));
11681220Smike		errmsg = "cannot write temp file";
117225215Sbrueffer		free(lp);
11816Salm		return NULL;
11916Salm	}
12016Salm	lp->len = len;
12116Salm	lp->seek  = sfseek;
1221057Salm	add_line_node(lp);
12316Salm	sfseek += len;			/* update file position */
12416Salm	return ++s;
12516Salm}
12616Salm
12716Salm
1281057Salm/* add_line_node: add a line node in the editor buffer after the current line */
12916Salmvoid
13090109Simpadd_line_node(line_t *lp)
13116Salm{
13216Salm	line_t *cp;
13316Salm
1341057Salm	cp = get_addressed_line_node(current_addr);				/* this get_addressed_line_node last! */
1351297Salm	INSQUE(lp, cp);
1361057Salm	addr_last++;
1371057Salm	current_addr++;
13816Salm}
13916Salm
14016Salm
1411057Salm/* get_line_node_addr: return line number of pointer */
14216Salmlong
14390109Simpget_line_node_addr(line_t *lp)
14416Salm{
1451057Salm	line_t *cp = &buffer_head;
14616Salm	long n = 0;
14716Salm
1481057Salm	while (cp != lp && (cp = cp->q_forw) != &buffer_head)
14916Salm		n++;
1501057Salm	if (n && cp == &buffer_head) {
15181220Smike		errmsg = "invalid address";
15249Salm		return ERR;
15349Salm	 }
15449Salm	 return n;
15516Salm}
15616Salm
15716Salm
1581057Salm/* get_addressed_line_node: return pointer to a line node in the editor buffer */
15916Salmline_t *
16090109Simpget_addressed_line_node(long n)
16116Salm{
1621057Salm	static line_t *lp = &buffer_head;
16316Salm	static long on = 0;
16416Salm
1651057Salm	SPL1();
16616Salm	if (n > on)
1671057Salm		if (n <= (on + addr_last) >> 1)
16816Salm			for (; on < n; on++)
1691057Salm				lp = lp->q_forw;
17016Salm		else {
1711057Salm			lp = buffer_head.q_back;
1721057Salm			for (on = addr_last; on > n; on--)
1731057Salm				lp = lp->q_back;
17416Salm		}
17516Salm	else
17616Salm		if (n >= on >> 1)
17716Salm			for (; on > n; on--)
1781057Salm				lp = lp->q_back;
17916Salm		else {
1801057Salm			lp = &buffer_head;
18116Salm			for (on = 0; on < n; on++)
1821057Salm				lp = lp->q_forw;
18316Salm		}
1841057Salm	SPL0();
18516Salm	return lp;
18616Salm}
18716Salm
18816Salm
1891057Salmextern int newline_added;
1901057Salm
191241720Sedstatic char sfn[15] = "";			/* scratch file name */
19216Salm
1931057Salm/* open_sbuf: open scratch file */
1941057Salmint
19590109Simpopen_sbuf(void)
19616Salm{
19798481Sjmallett	int fd;
1981297Salm	int u;
1991297Salm
2001057Salm	isbinary = newline_added = 0;
2011297Salm	u = umask(077);
20216Salm	strcpy(sfn, "/tmp/ed.XXXXXX");
20330247Seivind	if ((fd = mkstemp(sfn)) == -1 ||
20424181Simp	    (sfp = fdopen(fd, "w+")) == NULL) {
20524181Simp		if (fd != -1)
20624181Simp			close(fd);
20724181Simp		perror(sfn);
20881220Smike		errmsg = "cannot open temp file";
2091297Salm		umask(u);
21016Salm		return ERR;
21116Salm	}
2121297Salm	umask(u);
21316Salm	return 0;
21416Salm}
21516Salm
21616Salm
2171057Salm/* close_sbuf: close scratch file */
2181057Salmint
21990109Simpclose_sbuf(void)
22016Salm{
22116Salm	if (sfp) {
22216Salm		if (fclose(sfp) < 0) {
22316Salm			fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
22481220Smike			errmsg = "cannot close temp file";
22516Salm			return ERR;
22616Salm		}
22716Salm		sfp = NULL;
22816Salm		unlink(sfn);
22916Salm	}
23016Salm	sfseek = seek_write = 0;
23116Salm	return 0;
23216Salm}
23316Salm
23416Salm
2351057Salm/* quit: remove_lines scratch file and exit */
23616Salmvoid
23790109Simpquit(int n)
23816Salm{
23916Salm	if (sfp) {
24016Salm		fclose(sfp);
24116Salm		unlink(sfn);
24216Salm	}
24316Salm	exit(n);
24416Salm}
24587Salm
24687Salm
247241720Sedstatic unsigned char ctab[256];		/* character translation table */
24887Salm
2491057Salm/* init_buffers: open scratch buffer; initialize line queue */
25087Salmvoid
25190109Simpinit_buffers(void)
25287Salm{
25387Salm	int i = 0;
25487Salm
2558855Srgrimes	/* Read stdin one character at a time to avoid i/o contention
2561057Salm	   with shell escapes invoked by nonterminal input, e.g.,
2571057Salm	   ed - <<EOF
2581057Salm	   !cat
2591057Salm	   hello, world
2601057Salm	   EOF */
2611057Salm	setbuffer(stdin, stdinbuf, 1);
26232138Shelbig
26332138Shelbig	/* Ensure stdout is line buffered. This avoids bogus delays
26432138Shelbig	   of output if stdout is piped through utilities to a terminal. */
26532138Shelbig	setvbuf(stdout, NULL, _IOLBF, 0);
2661057Salm	if (open_sbuf() < 0)
26787Salm		quit(2);
2681057Salm	REQUE(&buffer_head, &buffer_head);
26987Salm	for (i = 0; i < 256; i++)
27087Salm		ctab[i] = i;
27187Salm}
27287Salm
27387Salm
2741057Salm/* translit_text: translate characters in a string */
27587Salmchar *
27690109Simptranslit_text(char *s, int len, int from, int to)
27787Salm{
27887Salm	static int i = 0;
27987Salm
28087Salm	unsigned char *us;
28187Salm
28287Salm	ctab[i] = i;			/* restore table to initial state */
28387Salm	ctab[i = from] = to;
28487Salm	for (us = (unsigned char *) s; len-- > 0; us++)
28587Salm		*us = ctab[*us];
28687Salm	return s;
28787Salm}
288