buf.c revision 30247
116Salm/* buf.c: This file contains the scratch-file buffer rountines 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
2916Salm#ifndef lint
3027963Ssteve#if 0
3120420Sstevestatic char * const rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp";
3227963Ssteve#else
3327963Sstevestatic char * const rcsid =
3430247Seivind	"$Id: buf.c,v 1.13 1997/10/08 13:46:39 eivind Exp $";
3527963Ssteve#endif
3616Salm#endif /* not lint */
3716Salm
3816Salm#include <sys/file.h>
391297Salm#include <sys/stat.h>
4016Salm
4116Salm#include "ed.h"
4216Salm
4316Salm
4416SalmFILE *sfp;				/* scratch file pointer */
4516Salmoff_t sfseek;				/* scratch file position */
4616Salmint seek_write;				/* seek before writing */
471057Salmline_t buffer_head;			/* incore buffer */
4816Salm
491057Salm/* get_sbuf_line: get a line of text from the scratch file; return pointer
5016Salm   to the text */
5116Salmchar *
521057Salmget_sbuf_line(lp)
5316Salm	line_t *lp;
5416Salm{
551057Salm	static char *sfbuf = NULL;	/* buffer */
561057Salm	static int sfbufsz = 0;		/* buffer size */
571057Salm
5816Salm	int len, ct;
5916Salm
601057Salm	if (lp == &buffer_head)
6116Salm		return NULL;
6216Salm	seek_write = 1;				/* force seek on write */
6316Salm	/* out of position */
6416Salm	if (sfseek != lp->seek) {
6516Salm		sfseek = lp->seek;
6616Salm		if (fseek(sfp, sfseek, SEEK_SET) < 0) {
6716Salm			fprintf(stderr, "%s\n", strerror(errno));
6816Salm			sprintf(errmsg, "cannot seek temp file");
6916Salm			return NULL;
7016Salm		}
7116Salm	}
721057Salm	len = lp->len;
731057Salm	REALLOC(sfbuf, sfbufsz, len + 1, NULL);
7416Salm	if ((ct = fread(sfbuf, sizeof(char), len, sfp)) <  0 || ct != len) {
7516Salm		fprintf(stderr, "%s\n", strerror(errno));
7616Salm		sprintf(errmsg, "cannot read temp file");
7716Salm		return NULL;
7816Salm	}
7916Salm	sfseek += len;				/* update file position */
8016Salm	sfbuf[len] = '\0';
8116Salm	return sfbuf;
8216Salm}
8316Salm
8416Salm
851057Salm/* put_sbuf_line: write a line of text to the scratch file and add a line node
8616Salm   to the editor buffer;  return a pointer to the end of the text */
8716Salmchar *
881057Salmput_sbuf_line(cs)
8916Salm	char *cs;
9016Salm{
9116Salm	line_t *lp;
9216Salm	int len, ct;
9316Salm	char *s;
9416Salm
9516Salm	if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
9616Salm		fprintf(stderr, "%s\n", strerror(errno));
9716Salm		sprintf(errmsg, "out of memory");
9816Salm		return NULL;
9916Salm	}
10016Salm	/* assert: cs is '\n' terminated */
10116Salm	for (s = cs; *s != '\n'; s++)
10216Salm		;
10316Salm	if (s - cs >= LINECHARS) {
10416Salm		sprintf(errmsg, "line too long");
10516Salm		return NULL;
10616Salm	}
1071057Salm	len = s - cs;
10816Salm	/* out of position */
10916Salm	if (seek_write) {
11016Salm		if (fseek(sfp, 0L, SEEK_END) < 0) {
11116Salm			fprintf(stderr, "%s\n", strerror(errno));
11216Salm			sprintf(errmsg, "cannot seek temp file");
11316Salm			return NULL;
11416Salm		}
11516Salm		sfseek = ftell(sfp);
11616Salm		seek_write = 0;
11716Salm	}
1181057Salm	/* assert: SPL1() */
11916Salm	if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
12016Salm		sfseek = -1;
12116Salm		fprintf(stderr, "%s\n", strerror(errno));
12216Salm		sprintf(errmsg, "cannot write temp file");
12316Salm		return NULL;
12416Salm	}
12516Salm	lp->len = len;
12616Salm	lp->seek  = sfseek;
1271057Salm	add_line_node(lp);
12816Salm	sfseek += len;			/* update file position */
12916Salm	return ++s;
13016Salm}
13116Salm
13216Salm
1331057Salm/* add_line_node: add a line node in the editor buffer after the current line */
13416Salmvoid
1351057Salmadd_line_node(lp)
13616Salm	line_t *lp;
13716Salm{
13816Salm	line_t *cp;
13916Salm
1401057Salm	cp = get_addressed_line_node(current_addr);				/* this get_addressed_line_node last! */
1411297Salm	INSQUE(lp, cp);
1421057Salm	addr_last++;
1431057Salm	current_addr++;
14416Salm}
14516Salm
14616Salm
1471057Salm/* get_line_node_addr: return line number of pointer */
14816Salmlong
1491057Salmget_line_node_addr(lp)
15016Salm	line_t *lp;
15116Salm{
1521057Salm	line_t *cp = &buffer_head;
15316Salm	long n = 0;
15416Salm
1551057Salm	while (cp != lp && (cp = cp->q_forw) != &buffer_head)
15616Salm		n++;
1571057Salm	if (n && cp == &buffer_head) {
15849Salm		sprintf(errmsg, "invalid address");
15949Salm		return ERR;
16049Salm	 }
16149Salm	 return n;
16216Salm}
16316Salm
16416Salm
1651057Salm/* get_addressed_line_node: return pointer to a line node in the editor buffer */
16616Salmline_t *
1671057Salmget_addressed_line_node(n)
16816Salm	long n;
16916Salm{
1701057Salm	static line_t *lp = &buffer_head;
17116Salm	static long on = 0;
17216Salm
1731057Salm	SPL1();
17416Salm	if (n > on)
1751057Salm		if (n <= (on + addr_last) >> 1)
17616Salm			for (; on < n; on++)
1771057Salm				lp = lp->q_forw;
17816Salm		else {
1791057Salm			lp = buffer_head.q_back;
1801057Salm			for (on = addr_last; on > n; on--)
1811057Salm				lp = lp->q_back;
18216Salm		}
18316Salm	else
18416Salm		if (n >= on >> 1)
18516Salm			for (; on > n; on--)
1861057Salm				lp = lp->q_back;
18716Salm		else {
1881057Salm			lp = &buffer_head;
18916Salm			for (on = 0; on < n; on++)
1901057Salm				lp = lp->q_forw;
19116Salm		}
1921057Salm	SPL0();
19316Salm	return lp;
19416Salm}
19516Salm
19616Salm
1971057Salmextern int newline_added;
1981057Salm
19916Salmchar sfn[15] = "";				/* scratch file name */
20016Salm
2011057Salm/* open_sbuf: open scratch file */
2021057Salmint
2031057Salmopen_sbuf()
20416Salm{
20524181Simp	int fd = -1;
2061297Salm	int u;
2071297Salm
2081057Salm	isbinary = newline_added = 0;
2091297Salm	u = umask(077);
21016Salm	strcpy(sfn, "/tmp/ed.XXXXXX");
21130247Seivind	if ((fd = mkstemp(sfn)) == -1 ||
21224181Simp	    (sfp = fdopen(fd, "w+")) == NULL) {
21324181Simp		if (fd != -1)
21424181Simp			close(fd);
21524181Simp		perror(sfn);
21624181Simp		strcpy(errmsg, "cannot open temp file");
2171297Salm		umask(u);
21816Salm		return ERR;
21916Salm	}
2201297Salm	umask(u);
22116Salm	return 0;
22216Salm}
22316Salm
22416Salm
2251057Salm/* close_sbuf: close scratch file */
2261057Salmint
2271057Salmclose_sbuf()
22816Salm{
22916Salm	if (sfp) {
23016Salm		if (fclose(sfp) < 0) {
23116Salm			fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
23216Salm			sprintf(errmsg, "cannot close temp file");
23316Salm			return ERR;
23416Salm		}
23516Salm		sfp = NULL;
23616Salm		unlink(sfn);
23716Salm	}
23816Salm	sfseek = seek_write = 0;
23916Salm	return 0;
24016Salm}
24116Salm
24216Salm
2431057Salm/* quit: remove_lines scratch file and exit */
24416Salmvoid
24516Salmquit(n)
24616Salm	int n;
24716Salm{
24816Salm	if (sfp) {
24916Salm		fclose(sfp);
25016Salm		unlink(sfn);
25116Salm	}
25216Salm	exit(n);
25316Salm}
25487Salm
25587Salm
25687Salmunsigned char ctab[256];		/* character translation table */
25787Salm
2581057Salm/* init_buffers: open scratch buffer; initialize line queue */
25987Salmvoid
2601057Salminit_buffers()
26187Salm{
26287Salm	int i = 0;
26387Salm
2648855Srgrimes	/* Read stdin one character at a time to avoid i/o contention
2651057Salm	   with shell escapes invoked by nonterminal input, e.g.,
2661057Salm	   ed - <<EOF
2671057Salm	   !cat
2681057Salm	   hello, world
2691057Salm	   EOF */
2701057Salm	setbuffer(stdin, stdinbuf, 1);
2711057Salm	if (open_sbuf() < 0)
27287Salm		quit(2);
2731057Salm	REQUE(&buffer_head, &buffer_head);
27487Salm	for (i = 0; i < 256; i++)
27587Salm		ctab[i] = i;
27687Salm}
27787Salm
27887Salm
2791057Salm/* translit_text: translate characters in a string */
28087Salmchar *
2811057Salmtranslit_text(s, len, from, to)
28287Salm	char *s;
28387Salm	int len;
28487Salm	int from;
28587Salm	int to;
28687Salm{
28787Salm	static int i = 0;
28887Salm
28987Salm	unsigned char *us;
29087Salm
29187Salm	ctab[i] = i;			/* restore table to initial state */
29287Salm	ctab[i = from] = to;
29387Salm	for (us = (unsigned char *) s; len-- > 0; us++)
29487Salm		*us = ctab[*us];
29587Salm	return s;
29687Salm}
297