buf.c

     1	/* buf.c: This file contains the scratch-file buffer routines for the
     2	   ed line editor. */
     3	/*-
     4	 * Copyright (c) 1993 Andrew Moore, Talke Studio.
     5	 * All rights reserved.
     6	 *
     7	 * Redistribution and use in source and binary forms, with or without
     8	 * modification, are permitted provided that the following conditions
     9	 * are met:
    10	 * 1. Redistributions of source code must retain the above copyright
    11	 *    notice, this list of conditions and the following disclaimer.
    12	 * 2. Redistributions in binary form must reproduce the above copyright
    13	 *    notice, this list of conditions and the following disclaimer in the
    14	 *    documentation and/or other materials provided with the distribution.
    15	 *
    16	 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    17	 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18	 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19	 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    20	 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    21	 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    22	 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    23	 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    24	 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    25	 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    26	 * SUCH DAMAGE.
    27	 */
    28	
    29	#include <sys/cdefs.h>
    30	__FBSDID("$FreeBSD: src/bin/ed/buf.c,v 1.22 2002/06/30 05:13:53 obrien Exp $");
    31	
    32	#include <sys/file.h>
    33	#include <sys/stat.h>
    34	
    35	#include "ed.h"
    36	
    37	
    38	FILE *sfp;				/* scratch file pointer */
    39	off_t sfseek;				/* scratch file position */
    40	int seek_write;				/* seek before writing */
    41	line_t buffer_head;			/* incore buffer */
    42	
    43	/* get_sbuf_line: get a line of text from the scratch file; return pointer
    44	   to the text */
    45	char *
    46	get_sbuf_line(line_t *lp)
    47	{
    48		static char *sfbuf = NULL;	/* buffer */
    49		static int sfbufsz = 0;		/* buffer size */
    50	
    51		int len, ct;
    52	
    53		if (lp == &buffer_head)
    54			return NULL;
    55		seek_write = 1;				/* force seek on write */
    56		/* out of position */
    57		if (sfseek != lp->seek) {
    58			sfseek = lp->seek;
    59			if (fseeko(sfp, sfseek, SEEK_SET) < 0) {
    60				fprintf(stderr, "%s\n", strerror(errno));
    61				errmsg = "cannot seek temp file";
    62				return NULL;
    63			}
    64		}
    65		len = lp->len;
    66		REALLOC(sfbuf, sfbufsz, len + 1, NULL);
    67		if ((ct = fread(sfbuf, sizeof(char), len, sfp)) <  0 || ct != len) {
    68			fprintf(stderr, "%s\n", strerror(errno));
    69			errmsg = "cannot read temp file";
    70			return NULL;
    71		}
    72		sfseek += len;				/* update file position */
    73		sfbuf[len] = '\0';
    74		return sfbuf;
    75	}
    76	
    77	
    78	/* put_sbuf_line: write a line of text to the scratch file and add a line node
    79	   to the editor buffer;  return a pointer to the end of the text */
    80	const char *
    81	put_sbuf_line(const char *cs)
    82	{
    83		line_t *lp;
    84		int len, ct;
    85		const char *s;
    86	
    87		if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
    88			fprintf(stderr, "%s\n", strerror(errno));
    89			errmsg = "out of memory";
    90			return NULL;
    91		}
    92		/* assert: cs is '\n' terminated */
    93		for (s = cs; *s != '\n'; s++)
    94			;
    95		if (s - cs >= LINECHARS) {
    96			errmsg = "line too long";
    97			return NULL;
    98		}
    99		len = s - cs;
   100		/* out of position */
   101		if (seek_write) {
   102			if (fseeko(sfp, (off_t)0, SEEK_END) < 0) {
   103				fprintf(stderr, "%s\n", strerror(errno));
   104				errmsg = "cannot seek temp file";
   105				return NULL;
   106			}
   107			sfseek = ftello(sfp);
   108			seek_write = 0;
   109		}
   110		/* assert: SPL1() */
   111		if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
   112			sfseek = -1;
   113			fprintf(stderr, "%s\n", strerror(errno));
   114			errmsg = "cannot write temp file";
   115			return NULL;
   116		}
   117		lp->len = len;
   118		lp->seek  = sfseek;
   119		add_line_node(lp);
   120		sfseek += len;			/* update file position */
   121		return ++s;
   122	}
   123	
   124	
   125	/* add_line_node: add a line node in the editor buffer after the current line */
   126	void
   127	add_line_node(line_t *lp)
   128	{
   129		line_t *cp;
   130	
   131		cp = get_addressed_line_node(current_addr);				/* this get_addressed_line_node last! */
   132		INSQUE(lp, cp);
   133		addr_last++;
   134		current_addr++;
   135	}
   136	
   137	
   138	/* get_line_node_addr: return line number of pointer */
   139	long
   140	get_line_node_addr(line_t *lp)
   141	{
   142		line_t *cp = &buffer_head;
   143		long n = 0;
   144	
   145		while (cp != lp && (cp = cp->q_forw) != &buffer_head)
   146			n++;
   147		if (n && cp == &buffer_head) {
   148			errmsg = "invalid address";
   149			return ERR;
   150		 }
   151		 return n;
   152	}
   153	
   154	
   155	/* get_addressed_line_node: return pointer to a line node in the editor buffer */
   156	line_t *
   157	get_addressed_line_node(long n)
   158	{
   159		static line_t *lp = &buffer_head;
   160		static long on = 0;
   161	
   162		SPL1();
   163		if (n > on)
   164			if (n <= (on + addr_last) >> 1)
   165				for (; on < n; on++)
   166					lp = lp->q_forw;
   167			else {
   168				lp = buffer_head.q_back;
   169				for (on = addr_last; on > n; on--)
   170					lp = lp->q_back;
   171			}
   172		else
   173			if (n >= on >> 1)
   174				for (; on > n; on--)
   175					lp = lp->q_back;
   176			else {
   177				lp = &buffer_head;
   178				for (on = 0; on < n; on++)
   179					lp = lp->q_forw;
   180			}
   181		SPL0();
   182		return lp;
   183	}
   184	
   185	
   186	extern int newline_added;
   187	
   188	char sfn[15] = "";				/* scratch file name */
   189	
   190	/* open_sbuf: open scratch file */
   191	int
   192	open_sbuf(void)
   193	{
   194		int fd;
   195		int u;
   196	
   197		isbinary = newline_added = 0;
   198		u = umask(077);
   199		strcpy(sfn, "/tmp/ed.XXXXXX");
   200		if ((fd = mkstemp(sfn)) == -1 ||
   201		    (sfp = fdopen(fd, "w+")) == NULL) {
   202			if (fd != -1)
   203				close(fd);
   204			perror(sfn);
   205			errmsg = "cannot open temp file";
   206			umask(u);
   207			return ERR;
   208		}
   209		umask(u);
   210		return 0;
   211	}
   212	
   213	
   214	/* close_sbuf: close scratch file */
   215	int
   216	close_sbuf(void)
   217	{
   218		if (sfp) {
   219			if (fclose(sfp) < 0) {
   220				fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
   221				errmsg = "cannot close temp file";
   222				return ERR;
   223			}
   224			sfp = NULL;
   225			unlink(sfn);
   226		}
   227		sfseek = seek_write = 0;
   228		return 0;
   229	}
   230	
   231	
   232	/* quit: remove_lines scratch file and exit */
   233	void
   234	quit(int n)
   235	{
   236		if (sfp) {
   237			fclose(sfp);
   238			unlink(sfn);
   239		}
   240		exit(n);
   241	}
   242	
   243	
   244	unsigned char ctab[256];		/* character translation table */
   245	
   246	/* init_buffers: open scratch buffer; initialize line queue */
   247	void
   248	init_buffers(void)
   249	{
   250		int i = 0;
   251	
   252		/* Read stdin one character at a time to avoid i/o contention
   253		   with shell escapes invoked by nonterminal input, e.g.,
   254		   ed - <<EOF
   255		   !cat
   256		   hello, world
   257		   EOF */
   258		setbuffer(stdin, stdinbuf, 1);
   259	
   260		/* Ensure stdout is line buffered. This avoids bogus delays
   261		   of output if stdout is piped through utilities to a terminal. */
   262		setvbuf(stdout, NULL, _IOLBF, 0);
   263		if (open_sbuf() < 0)
   264			quit(2);
   265		REQUE(&buffer_head, &buffer_head);
   266		for (i = 0; i < 256; i++)
   267			ctab[i] = i;
   268	}
   269	
   270	
   271	/* translit_text: translate characters in a string */
   272	char *
   273	translit_text(char *s, int len, int from, int to)
   274	{
   275		static int i = 0;
   276	
   277		unsigned char *us;
   278	
   279		ctab[i] = i;			/* restore table to initial state */
   280		ctab[i = from] = to;
   281		for (us = (unsigned char *) s; len-- > 0; us++)
   282			*us = ctab[*us];
   283		return s;
   284	}

Generated by GNU Enscript 1.6.6.