buf.c revision 1057
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 */
2816Salm#ifndef lint
291057Salmstatic char *rcsid = "@(#)$Id: buf.c,v 1.3 1993/12/14 16:19:56 alm Exp $";
3016Salm#endif /* not lint */
3116Salm
3216Salm#include <sys/file.h>
3316Salm
3416Salm#include "ed.h"
3516Salm
3616Salm
3716SalmFILE *sfp;				/* scratch file pointer */
3816Salmoff_t sfseek;				/* scratch file position */
3916Salmint seek_write;				/* seek before writing */
401057Salmline_t buffer_head;			/* incore buffer */
4116Salm
421057Salm/* get_sbuf_line: get a line of text from the scratch file; return pointer
4316Salm   to the text */
4416Salmchar *
451057Salmget_sbuf_line(lp)
4616Salm	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;
5916Salm		if (fseek(sfp, sfseek, SEEK_SET) < 0) {
6016Salm			fprintf(stderr, "%s\n", strerror(errno));
6116Salm			sprintf(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));
6916Salm		sprintf(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 */
8016Salmchar *
811057Salmput_sbuf_line(cs)
8216Salm	char *cs;
8316Salm{
8416Salm	line_t *lp;
8516Salm	int len, ct;
8616Salm	char *s;
8716Salm
8816Salm	if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
8916Salm		fprintf(stderr, "%s\n", strerror(errno));
9016Salm		sprintf(errmsg, "out of memory");
9116Salm		return NULL;
9216Salm	}
9316Salm	/* assert: cs is '\n' terminated */
9416Salm	for (s = cs; *s != '\n'; s++)
9516Salm		;
9616Salm	if (s - cs >= LINECHARS) {
9716Salm		sprintf(errmsg, "line too long");
9816Salm		return NULL;
9916Salm	}
1001057Salm	len = s - cs;
10116Salm	/* out of position */
10216Salm	if (seek_write) {
10316Salm		if (fseek(sfp, 0L, SEEK_END) < 0) {
10416Salm			fprintf(stderr, "%s\n", strerror(errno));
10516Salm			sprintf(errmsg, "cannot seek temp file");
10616Salm			return NULL;
10716Salm		}
10816Salm		sfseek = ftell(sfp);
10916Salm		seek_write = 0;
11016Salm	}
1111057Salm	/* assert: SPL1() */
11216Salm	if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
11316Salm		sfseek = -1;
11416Salm		fprintf(stderr, "%s\n", strerror(errno));
11516Salm		sprintf(errmsg, "cannot write temp file");
11616Salm		return NULL;
11716Salm	}
11816Salm	lp->len = len;
11916Salm	lp->seek  = sfseek;
1201057Salm	add_line_node(lp);
12116Salm	sfseek += len;			/* update file position */
12216Salm	return ++s;
12316Salm}
12416Salm
12516Salm
1261057Salm/* add_line_node: add a line node in the editor buffer after the current line */
12716Salmvoid
1281057Salmadd_line_node(lp)
12916Salm	line_t *lp;
13016Salm{
13116Salm	line_t *cp;
13216Salm
1331057Salm	cp = get_addressed_line_node(current_addr);				/* this get_addressed_line_node last! */
1341057Salm	insque(lp, cp);
1351057Salm	addr_last++;
1361057Salm	current_addr++;
13716Salm}
13816Salm
13916Salm
1401057Salm/* get_line_node_addr: return line number of pointer */
14116Salmlong
1421057Salmget_line_node_addr(lp)
14316Salm	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) {
15149Salm		sprintf(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 *
1601057Salmget_addressed_line_node(n)
16116Salm	long n;
16216Salm{
1631057Salm	static line_t *lp = &buffer_head;
16416Salm	static long on = 0;
16516Salm
1661057Salm	SPL1();
16716Salm	if (n > on)
1681057Salm		if (n <= (on + addr_last) >> 1)
16916Salm			for (; on < n; on++)
1701057Salm				lp = lp->q_forw;
17116Salm		else {
1721057Salm			lp = buffer_head.q_back;
1731057Salm			for (on = addr_last; on > n; on--)
1741057Salm				lp = lp->q_back;
17516Salm		}
17616Salm	else
17716Salm		if (n >= on >> 1)
17816Salm			for (; on > n; on--)
1791057Salm				lp = lp->q_back;
18016Salm		else {
1811057Salm			lp = &buffer_head;
18216Salm			for (on = 0; on < n; on++)
1831057Salm				lp = lp->q_forw;
18416Salm		}
1851057Salm	SPL0();
18616Salm	return lp;
18716Salm}
18816Salm
18916Salm
1901057Salmextern int newline_added;
1911057Salm
19216Salmchar sfn[15] = "";				/* scratch file name */
19316Salm
1941057Salm/* open_sbuf: open scratch file */
1951057Salmint
1961057Salmopen_sbuf()
19716Salm{
1981057Salm	isbinary = newline_added = 0;
19916Salm	strcpy(sfn, "/tmp/ed.XXXXXX");
20016Salm	if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) {
20116Salm		fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
20216Salm		sprintf(errmsg, "cannot open temp file");
20316Salm		return ERR;
20416Salm	}
20516Salm	return 0;
20616Salm}
20716Salm
20816Salm
2091057Salm/* close_sbuf: close scratch file */
2101057Salmint
2111057Salmclose_sbuf()
21216Salm{
21316Salm	if (sfp) {
21416Salm		if (fclose(sfp) < 0) {
21516Salm			fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
21616Salm			sprintf(errmsg, "cannot close temp file");
21716Salm			return ERR;
21816Salm		}
21916Salm		sfp = NULL;
22016Salm		unlink(sfn);
22116Salm	}
22216Salm	sfseek = seek_write = 0;
22316Salm	return 0;
22416Salm}
22516Salm
22616Salm
2271057Salm/* quit: remove_lines scratch file and exit */
22816Salmvoid
22916Salmquit(n)
23016Salm	int n;
23116Salm{
23216Salm	if (sfp) {
23316Salm		fclose(sfp);
23416Salm		unlink(sfn);
23516Salm	}
23616Salm	exit(n);
23716Salm}
23887Salm
23987Salm
24087Salmunsigned char ctab[256];		/* character translation table */
24187Salm
2421057Salm/* init_buffers: open scratch buffer; initialize line queue */
24387Salmvoid
2441057Salminit_buffers()
24587Salm{
24687Salm	int i = 0;
24787Salm
2481057Salm	/* Read stdin one character at a time to avoid i/o contention
2491057Salm	   with shell escapes invoked by nonterminal input, e.g.,
2501057Salm	   ed - <<EOF
2511057Salm	   !cat
2521057Salm	   hello, world
2531057Salm	   EOF */
2541057Salm	setbuffer(stdin, stdinbuf, 1);
2551057Salm	if (open_sbuf() < 0)
25687Salm		quit(2);
2571057Salm	REQUE(&buffer_head, &buffer_head);
25887Salm	for (i = 0; i < 256; i++)
25987Salm		ctab[i] = i;
26087Salm}
26187Salm
26287Salm
2631057Salm/* translit_text: translate characters in a string */
26487Salmchar *
2651057Salmtranslit_text(s, len, from, to)
26687Salm	char *s;
26787Salm	int len;
26887Salm	int from;
26987Salm	int to;
27087Salm{
27187Salm	static int i = 0;
27287Salm
27387Salm	unsigned char *us;
27487Salm
27587Salm	ctab[i] = i;			/* restore table to initial state */
27687Salm	ctab[i = from] = to;
27787Salm	for (us = (unsigned char *) s; len-- > 0; us++)
27887Salm		*us = ctab[*us];
27987Salm	return s;
28087Salm}
281