buf.c revision 20420
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.
273044Sdg *
2820420Ssteve *	$Id: buf.c,v 1.7 1995/05/30 00:06:43 rgrimes Exp $
2916Salm */
3016Salm#ifndef lint
3120420Sstevestatic char * const rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp";
3216Salm#endif /* not lint */
3316Salm
3416Salm#include <sys/file.h>
351297Salm#include <sys/stat.h>
3616Salm
3716Salm#include "ed.h"
3816Salm
3916Salm
4016SalmFILE *sfp;				/* scratch file pointer */
4116Salmoff_t sfseek;				/* scratch file position */
4216Salmint seek_write;				/* seek before writing */
431057Salmline_t buffer_head;			/* incore buffer */
4416Salm
451057Salm/* get_sbuf_line: get a line of text from the scratch file; return pointer
4616Salm   to the text */
4716Salmchar *
481057Salmget_sbuf_line(lp)
4916Salm	line_t *lp;
5016Salm{
511057Salm	static char *sfbuf = NULL;	/* buffer */
521057Salm	static int sfbufsz = 0;		/* buffer size */
531057Salm
5416Salm	int len, ct;
5516Salm
561057Salm	if (lp == &buffer_head)
5716Salm		return NULL;
5816Salm	seek_write = 1;				/* force seek on write */
5916Salm	/* out of position */
6016Salm	if (sfseek != lp->seek) {
6116Salm		sfseek = lp->seek;
6216Salm		if (fseek(sfp, sfseek, SEEK_SET) < 0) {
6316Salm			fprintf(stderr, "%s\n", strerror(errno));
6416Salm			sprintf(errmsg, "cannot seek temp file");
6516Salm			return NULL;
6616Salm		}
6716Salm	}
681057Salm	len = lp->len;
691057Salm	REALLOC(sfbuf, sfbufsz, len + 1, NULL);
7016Salm	if ((ct = fread(sfbuf, sizeof(char), len, sfp)) <  0 || ct != len) {
7116Salm		fprintf(stderr, "%s\n", strerror(errno));
7216Salm		sprintf(errmsg, "cannot read temp file");
7316Salm		return NULL;
7416Salm	}
7516Salm	sfseek += len;				/* update file position */
7616Salm	sfbuf[len] = '\0';
7716Salm	return sfbuf;
7816Salm}
7916Salm
8016Salm
811057Salm/* put_sbuf_line: write a line of text to the scratch file and add a line node
8216Salm   to the editor buffer;  return a pointer to the end of the text */
8316Salmchar *
841057Salmput_sbuf_line(cs)
8516Salm	char *cs;
8616Salm{
8716Salm	line_t *lp;
8816Salm	int len, ct;
8916Salm	char *s;
9016Salm
9116Salm	if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
9216Salm		fprintf(stderr, "%s\n", strerror(errno));
9316Salm		sprintf(errmsg, "out of memory");
9416Salm		return NULL;
9516Salm	}
9616Salm	/* assert: cs is '\n' terminated */
9716Salm	for (s = cs; *s != '\n'; s++)
9816Salm		;
9916Salm	if (s - cs >= LINECHARS) {
10016Salm		sprintf(errmsg, "line too long");
10116Salm		return NULL;
10216Salm	}
1031057Salm	len = s - cs;
10416Salm	/* out of position */
10516Salm	if (seek_write) {
10616Salm		if (fseek(sfp, 0L, SEEK_END) < 0) {
10716Salm			fprintf(stderr, "%s\n", strerror(errno));
10816Salm			sprintf(errmsg, "cannot seek temp file");
10916Salm			return NULL;
11016Salm		}
11116Salm		sfseek = ftell(sfp);
11216Salm		seek_write = 0;
11316Salm	}
1141057Salm	/* assert: SPL1() */
11516Salm	if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
11616Salm		sfseek = -1;
11716Salm		fprintf(stderr, "%s\n", strerror(errno));
11816Salm		sprintf(errmsg, "cannot write temp file");
11916Salm		return NULL;
12016Salm	}
12116Salm	lp->len = len;
12216Salm	lp->seek  = sfseek;
1231057Salm	add_line_node(lp);
12416Salm	sfseek += len;			/* update file position */
12516Salm	return ++s;
12616Salm}
12716Salm
12816Salm
1291057Salm/* add_line_node: add a line node in the editor buffer after the current line */
13016Salmvoid
1311057Salmadd_line_node(lp)
13216Salm	line_t *lp;
13316Salm{
13416Salm	line_t *cp;
13516Salm
1361057Salm	cp = get_addressed_line_node(current_addr);				/* this get_addressed_line_node last! */
1371297Salm	INSQUE(lp, cp);
1381057Salm	addr_last++;
1391057Salm	current_addr++;
14016Salm}
14116Salm
14216Salm
1431057Salm/* get_line_node_addr: return line number of pointer */
14416Salmlong
1451057Salmget_line_node_addr(lp)
14616Salm	line_t *lp;
14716Salm{
1481057Salm	line_t *cp = &buffer_head;
14916Salm	long n = 0;
15016Salm
1511057Salm	while (cp != lp && (cp = cp->q_forw) != &buffer_head)
15216Salm		n++;
1531057Salm	if (n && cp == &buffer_head) {
15449Salm		sprintf(errmsg, "invalid address");
15549Salm		return ERR;
15649Salm	 }
15749Salm	 return n;
15816Salm}
15916Salm
16016Salm
1611057Salm/* get_addressed_line_node: return pointer to a line node in the editor buffer */
16216Salmline_t *
1631057Salmget_addressed_line_node(n)
16416Salm	long n;
16516Salm{
1661057Salm	static line_t *lp = &buffer_head;
16716Salm	static long on = 0;
16816Salm
1691057Salm	SPL1();
17016Salm	if (n > on)
1711057Salm		if (n <= (on + addr_last) >> 1)
17216Salm			for (; on < n; on++)
1731057Salm				lp = lp->q_forw;
17416Salm		else {
1751057Salm			lp = buffer_head.q_back;
1761057Salm			for (on = addr_last; on > n; on--)
1771057Salm				lp = lp->q_back;
17816Salm		}
17916Salm	else
18016Salm		if (n >= on >> 1)
18116Salm			for (; on > n; on--)
1821057Salm				lp = lp->q_back;
18316Salm		else {
1841057Salm			lp = &buffer_head;
18516Salm			for (on = 0; on < n; on++)
1861057Salm				lp = lp->q_forw;
18716Salm		}
1881057Salm	SPL0();
18916Salm	return lp;
19016Salm}
19116Salm
19216Salm
1931057Salmextern int newline_added;
1941057Salm
19516Salmchar sfn[15] = "";				/* scratch file name */
19616Salm
1971057Salm/* open_sbuf: open scratch file */
1981057Salmint
1991057Salmopen_sbuf()
20016Salm{
2011297Salm	int u;
2021297Salm
2031057Salm	isbinary = newline_added = 0;
2041297Salm	u = umask(077);
20516Salm	strcpy(sfn, "/tmp/ed.XXXXXX");
20616Salm	if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) {
20716Salm		fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
20816Salm		sprintf(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
2191057Salmclose_sbuf()
22016Salm{
22116Salm	if (sfp) {
22216Salm		if (fclose(sfp) < 0) {
22316Salm			fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
22416Salm			sprintf(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
23716Salmquit(n)
23816Salm	int n;
23916Salm{
24016Salm	if (sfp) {
24116Salm		fclose(sfp);
24216Salm		unlink(sfn);
24316Salm	}
24416Salm	exit(n);
24516Salm}
24687Salm
24787Salm
24887Salmunsigned char ctab[256];		/* character translation table */
24987Salm
2501057Salm/* init_buffers: open scratch buffer; initialize line queue */
25187Salmvoid
2521057Salminit_buffers()
25387Salm{
25487Salm	int i = 0;
25587Salm
2568855Srgrimes	/* Read stdin one character at a time to avoid i/o contention
2571057Salm	   with shell escapes invoked by nonterminal input, e.g.,
2581057Salm	   ed - <<EOF
2591057Salm	   !cat
2601057Salm	   hello, world
2611057Salm	   EOF */
2621057Salm	setbuffer(stdin, stdinbuf, 1);
2631057Salm	if (open_sbuf() < 0)
26487Salm		quit(2);
2651057Salm	REQUE(&buffer_head, &buffer_head);
26687Salm	for (i = 0; i < 256; i++)
26787Salm		ctab[i] = i;
26887Salm}
26987Salm
27087Salm
2711057Salm/* translit_text: translate characters in a string */
27287Salmchar *
2731057Salmtranslit_text(s, len, from, to)
27487Salm	char *s;
27587Salm	int len;
27687Salm	int from;
27787Salm	int to;
27887Salm{
27987Salm	static int i = 0;
28087Salm
28187Salm	unsigned char *us;
28287Salm
28387Salm	ctab[i] = i;			/* restore table to initial state */
28487Salm	ctab[i = from] = to;
28587Salm	for (us = (unsigned char *) s; len-- > 0; us++)
28687Salm		*us = ctab[*us];
28787Salm	return s;
28887Salm}
289