1*0a6a1f1dSLionel Sambuc /* $NetBSD: buf.c,v 1.27 2014/03/23 05:06:42 dholland Exp $ */
27e81b07cSAndy Kosela
37e81b07cSAndy Kosela /* buf.c: This file contains the scratch-file buffer routines for the
47e81b07cSAndy Kosela ed line editor. */
57e81b07cSAndy Kosela /*-
67e81b07cSAndy Kosela * Copyright (c) 1993 Andrew Moore, Talke Studio.
77e81b07cSAndy Kosela * All rights reserved.
87e81b07cSAndy Kosela *
97e81b07cSAndy Kosela * Redistribution and use in source and binary forms, with or without
107e81b07cSAndy Kosela * modification, are permitted provided that the following conditions
117e81b07cSAndy Kosela * are met:
127e81b07cSAndy Kosela * 1. Redistributions of source code must retain the above copyright
137e81b07cSAndy Kosela * notice, this list of conditions and the following disclaimer.
147e81b07cSAndy Kosela * 2. Redistributions in binary form must reproduce the above copyright
157e81b07cSAndy Kosela * notice, this list of conditions and the following disclaimer in the
167e81b07cSAndy Kosela * documentation and/or other materials provided with the distribution.
177e81b07cSAndy Kosela *
187e81b07cSAndy Kosela * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
197e81b07cSAndy Kosela * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
207e81b07cSAndy Kosela * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
217e81b07cSAndy Kosela * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
227e81b07cSAndy Kosela * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
237e81b07cSAndy Kosela * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
247e81b07cSAndy Kosela * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
257e81b07cSAndy Kosela * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
267e81b07cSAndy Kosela * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
277e81b07cSAndy Kosela * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
287e81b07cSAndy Kosela * SUCH DAMAGE.
297e81b07cSAndy Kosela */
307e81b07cSAndy Kosela
317e81b07cSAndy Kosela #include <sys/cdefs.h>
327e81b07cSAndy Kosela #ifndef lint
337e81b07cSAndy Kosela #if 0
347e81b07cSAndy Kosela static char *rcsid = "@(#)buf.c,v 1.4 1994/02/01 00:34:35 alm Exp";
357e81b07cSAndy Kosela #else
36*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: buf.c,v 1.27 2014/03/23 05:06:42 dholland Exp $");
377e81b07cSAndy Kosela #endif
387e81b07cSAndy Kosela #endif /* not lint */
397e81b07cSAndy Kosela
407e81b07cSAndy Kosela #include <sys/file.h>
417e81b07cSAndy Kosela #include <sys/stat.h>
427e81b07cSAndy Kosela
437e81b07cSAndy Kosela #include <paths.h>
447e81b07cSAndy Kosela #include <stdio.h>
457e81b07cSAndy Kosela #include <err.h>
467e81b07cSAndy Kosela
477e81b07cSAndy Kosela #include "ed.h"
487e81b07cSAndy Kosela
497e81b07cSAndy Kosela
507e81b07cSAndy Kosela FILE *sfp; /* scratch file pointer */
517e81b07cSAndy Kosela off_t sfseek; /* scratch file position */
527e81b07cSAndy Kosela int seek_write; /* seek before writing */
537e81b07cSAndy Kosela line_t buffer_head; /* incore buffer */
547e81b07cSAndy Kosela
557e81b07cSAndy Kosela /* get_sbuf_line: get a line of text from the scratch file; return pointer
567e81b07cSAndy Kosela to the text */
577e81b07cSAndy Kosela char *
get_sbuf_line(line_t * lp)587e81b07cSAndy Kosela get_sbuf_line(line_t *lp)
597e81b07cSAndy Kosela {
607e81b07cSAndy Kosela static char *sfbuf = NULL; /* buffer */
617e81b07cSAndy Kosela static int sfbufsz = 0; /* buffer size */
627e81b07cSAndy Kosela
637e81b07cSAndy Kosela int len, ct;
647e81b07cSAndy Kosela
657e81b07cSAndy Kosela if (lp == &buffer_head)
667e81b07cSAndy Kosela return NULL;
677e81b07cSAndy Kosela seek_write = 1; /* force seek on write */
687e81b07cSAndy Kosela /* out of position */
697e81b07cSAndy Kosela if (sfseek != lp->seek) {
707e81b07cSAndy Kosela sfseek = lp->seek;
717e81b07cSAndy Kosela if (fseek(sfp, sfseek, SEEK_SET) < 0) {
727e81b07cSAndy Kosela fprintf(stderr, "%s\n", strerror(errno));
73*0a6a1f1dSLionel Sambuc seterrmsg("cannot seek temp file");
747e81b07cSAndy Kosela return NULL;
757e81b07cSAndy Kosela }
767e81b07cSAndy Kosela }
777e81b07cSAndy Kosela len = lp->len;
787e81b07cSAndy Kosela REALLOC(sfbuf, sfbufsz, len + 1, NULL);
797e81b07cSAndy Kosela if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) {
807e81b07cSAndy Kosela fprintf(stderr, "%s\n", strerror(errno));
81*0a6a1f1dSLionel Sambuc seterrmsg("cannot read temp file");
827e81b07cSAndy Kosela return NULL;
837e81b07cSAndy Kosela }
847e81b07cSAndy Kosela sfseek += len; /* update file position */
857e81b07cSAndy Kosela sfbuf[len] = '\0';
867e81b07cSAndy Kosela return sfbuf;
877e81b07cSAndy Kosela }
887e81b07cSAndy Kosela
897e81b07cSAndy Kosela
907e81b07cSAndy Kosela /* put_sbuf_line: write a line of text to the scratch file and add a line node
917e81b07cSAndy Kosela to the editor buffer; return a pointer to the end of the text */
927e81b07cSAndy Kosela char *
put_sbuf_line(char * cs)937e81b07cSAndy Kosela put_sbuf_line(char *cs)
947e81b07cSAndy Kosela {
957e81b07cSAndy Kosela line_t *lp;
967e81b07cSAndy Kosela int len, ct;
977e81b07cSAndy Kosela char *s;
987e81b07cSAndy Kosela
997e81b07cSAndy Kosela if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
1007e81b07cSAndy Kosela fprintf(stderr, "%s\n", strerror(errno));
101*0a6a1f1dSLionel Sambuc seterrmsg("out of memory");
1027e81b07cSAndy Kosela return NULL;
1037e81b07cSAndy Kosela }
1047e81b07cSAndy Kosela /* assert: cs is '\n' terminated */
1057e81b07cSAndy Kosela for (s = cs; *s != '\n'; s++)
1067e81b07cSAndy Kosela ;
1077e81b07cSAndy Kosela if (s - cs >= LINECHARS) {
108*0a6a1f1dSLionel Sambuc seterrmsg("line too long");
1097e81b07cSAndy Kosela free(lp);
1107e81b07cSAndy Kosela return NULL;
1117e81b07cSAndy Kosela }
1127e81b07cSAndy Kosela len = s - cs;
1137e81b07cSAndy Kosela /* out of position */
1147e81b07cSAndy Kosela if (seek_write) {
1157e81b07cSAndy Kosela if (fseek(sfp, 0L, SEEK_END) < 0) {
1167e81b07cSAndy Kosela fprintf(stderr, "%s\n", strerror(errno));
117*0a6a1f1dSLionel Sambuc seterrmsg("cannot seek temp file");
1187e81b07cSAndy Kosela free(lp);
1197e81b07cSAndy Kosela return NULL;
1207e81b07cSAndy Kosela }
1217e81b07cSAndy Kosela sfseek = ftell(sfp);
1227e81b07cSAndy Kosela seek_write = 0;
1237e81b07cSAndy Kosela }
1247e81b07cSAndy Kosela /* assert: SPL1() */
1257e81b07cSAndy Kosela if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
1267e81b07cSAndy Kosela sfseek = -1;
1277e81b07cSAndy Kosela fprintf(stderr, "%s\n", strerror(errno));
128*0a6a1f1dSLionel Sambuc seterrmsg("cannot write temp file");
1297e81b07cSAndy Kosela free(lp);
1307e81b07cSAndy Kosela return NULL;
1317e81b07cSAndy Kosela }
1327e81b07cSAndy Kosela lp->len = len;
1337e81b07cSAndy Kosela lp->seek = sfseek;
1347e81b07cSAndy Kosela add_line_node(lp);
1357e81b07cSAndy Kosela sfseek += len; /* update file position */
1367e81b07cSAndy Kosela return ++s;
1377e81b07cSAndy Kosela }
1387e81b07cSAndy Kosela
1397e81b07cSAndy Kosela
1407e81b07cSAndy Kosela /* add_line_node: add a line node in the editor buffer after the current line */
1417e81b07cSAndy Kosela void
add_line_node(line_t * lp)1427e81b07cSAndy Kosela add_line_node(line_t *lp)
1437e81b07cSAndy Kosela {
1447e81b07cSAndy Kosela line_t *cp;
1457e81b07cSAndy Kosela
1467e81b07cSAndy Kosela cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */
1477e81b07cSAndy Kosela INSQUE(lp, cp);
1487e81b07cSAndy Kosela addr_last++;
1497e81b07cSAndy Kosela current_addr++;
1507e81b07cSAndy Kosela }
1517e81b07cSAndy Kosela
1527e81b07cSAndy Kosela
1537e81b07cSAndy Kosela /* get_line_node_addr: return line number of pointer */
1547e81b07cSAndy Kosela long
get_line_node_addr(line_t * lp)1557e81b07cSAndy Kosela get_line_node_addr(line_t *lp)
1567e81b07cSAndy Kosela {
1577e81b07cSAndy Kosela line_t *cp = &buffer_head;
1587e81b07cSAndy Kosela long n = 0;
1597e81b07cSAndy Kosela
1607e81b07cSAndy Kosela while (cp != lp && (cp = cp->q_forw) != &buffer_head)
1617e81b07cSAndy Kosela n++;
1627e81b07cSAndy Kosela if (n && cp == &buffer_head) {
163*0a6a1f1dSLionel Sambuc seterrmsg("invalid address");
1647e81b07cSAndy Kosela return ERR;
1657e81b07cSAndy Kosela }
1667e81b07cSAndy Kosela return n;
1677e81b07cSAndy Kosela }
1687e81b07cSAndy Kosela
1697e81b07cSAndy Kosela
1707e81b07cSAndy Kosela /* get_addressed_line_node: return pointer to a line node in the editor buffer */
1717e81b07cSAndy Kosela line_t *
get_addressed_line_node(long n)1727e81b07cSAndy Kosela get_addressed_line_node(long n)
1737e81b07cSAndy Kosela {
1747e81b07cSAndy Kosela static line_t *lp = &buffer_head;
1757e81b07cSAndy Kosela static long on = 0;
1767e81b07cSAndy Kosela
1777e81b07cSAndy Kosela SPL1();
1787e81b07cSAndy Kosela if (n > on) {
1797e81b07cSAndy Kosela if (n <= (on + addr_last) >> 1) {
1807e81b07cSAndy Kosela for (; on < n; on++)
1817e81b07cSAndy Kosela lp = lp->q_forw;
1827e81b07cSAndy Kosela } else {
1837e81b07cSAndy Kosela lp = buffer_head.q_back;
1847e81b07cSAndy Kosela for (on = addr_last; on > n; on--)
1857e81b07cSAndy Kosela lp = lp->q_back;
1867e81b07cSAndy Kosela }
1877e81b07cSAndy Kosela } else {
1887e81b07cSAndy Kosela if (n >= on >> 1) {
1897e81b07cSAndy Kosela for (; on > n; on--)
1907e81b07cSAndy Kosela lp = lp->q_back;
1917e81b07cSAndy Kosela } else {
1927e81b07cSAndy Kosela lp = &buffer_head;
1937e81b07cSAndy Kosela for (on = 0; on < n; on++)
1947e81b07cSAndy Kosela lp = lp->q_forw;
1957e81b07cSAndy Kosela }
1967e81b07cSAndy Kosela }
1977e81b07cSAndy Kosela SPL0();
1987e81b07cSAndy Kosela return lp;
1997e81b07cSAndy Kosela }
2007e81b07cSAndy Kosela
2017e81b07cSAndy Kosela
2027e81b07cSAndy Kosela char *sfn = NULL; /* scratch file name */
2037e81b07cSAndy Kosela
2047e81b07cSAndy Kosela /* open_sbuf: open scratch file */
2057e81b07cSAndy Kosela int
open_sbuf(void)2067e81b07cSAndy Kosela open_sbuf(void)
2077e81b07cSAndy Kosela {
2087e81b07cSAndy Kosela int u, fd;
2097e81b07cSAndy Kosela const char *tmp;
2107e81b07cSAndy Kosela size_t s;
2117e81b07cSAndy Kosela
2127e81b07cSAndy Kosela isbinary = newline_added = 0;
2137e81b07cSAndy Kosela fd = -1;
2147e81b07cSAndy Kosela u = umask(077);
2157e81b07cSAndy Kosela
2167e81b07cSAndy Kosela if ((tmp = getenv("TMPDIR")) == NULL)
2177e81b07cSAndy Kosela tmp = _PATH_TMP;
2187e81b07cSAndy Kosela
2197e81b07cSAndy Kosela if ((s = strlen(tmp)) == 0 || tmp[s - 1] == '/')
2207e81b07cSAndy Kosela (void)asprintf(&sfn, "%sed.XXXXXX", tmp);
2217e81b07cSAndy Kosela else
2227e81b07cSAndy Kosela (void)asprintf(&sfn, "%s/ed.XXXXXX", tmp);
2237e81b07cSAndy Kosela if (sfn == NULL) {
2247e81b07cSAndy Kosela warn(NULL);
225*0a6a1f1dSLionel Sambuc seterrmsg("could not allocate memory");
2267e81b07cSAndy Kosela umask(u);
2277e81b07cSAndy Kosela return ERR;
2287e81b07cSAndy Kosela }
2297e81b07cSAndy Kosela
2307e81b07cSAndy Kosela
2317e81b07cSAndy Kosela if ((fd = mkstemp(sfn)) == -1 || (sfp = fdopen(fd, "w+")) == NULL) {
2327e81b07cSAndy Kosela if (fd != -1)
2337e81b07cSAndy Kosela close(fd);
2347e81b07cSAndy Kosela warn("%s", sfn);
235*0a6a1f1dSLionel Sambuc seterrmsg("cannot open temp file");
2367e81b07cSAndy Kosela umask(u);
2377e81b07cSAndy Kosela return ERR;
2387e81b07cSAndy Kosela }
2397e81b07cSAndy Kosela umask(u);
2407e81b07cSAndy Kosela return 0;
2417e81b07cSAndy Kosela }
2427e81b07cSAndy Kosela
2437e81b07cSAndy Kosela
2447e81b07cSAndy Kosela /* close_sbuf: close scratch file */
2457e81b07cSAndy Kosela int
close_sbuf(void)2467e81b07cSAndy Kosela close_sbuf(void)
2477e81b07cSAndy Kosela {
2487e81b07cSAndy Kosela if (sfp) {
2497e81b07cSAndy Kosela if (fclose(sfp) < 0) {
2507e81b07cSAndy Kosela fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
251*0a6a1f1dSLionel Sambuc seterrmsg("cannot close temp file");
2527e81b07cSAndy Kosela return ERR;
2537e81b07cSAndy Kosela }
2547e81b07cSAndy Kosela sfp = NULL;
2557e81b07cSAndy Kosela if (sfn) {
2567e81b07cSAndy Kosela unlink(sfn);
2577e81b07cSAndy Kosela free(sfn);
2587e81b07cSAndy Kosela sfn = NULL;
2597e81b07cSAndy Kosela }
2607e81b07cSAndy Kosela }
2617e81b07cSAndy Kosela sfseek = seek_write = 0;
2627e81b07cSAndy Kosela return 0;
2637e81b07cSAndy Kosela }
2647e81b07cSAndy Kosela
2657e81b07cSAndy Kosela
2667e81b07cSAndy Kosela /* quit: remove_lines scratch file and exit */
2677e81b07cSAndy Kosela void
quit(int n)2687e81b07cSAndy Kosela quit(int n)
2697e81b07cSAndy Kosela {
2707e81b07cSAndy Kosela if (sfp) {
2717e81b07cSAndy Kosela fclose(sfp);
2727e81b07cSAndy Kosela if (sfn) {
2737e81b07cSAndy Kosela unlink(sfn);
2747e81b07cSAndy Kosela free(sfn);
2757e81b07cSAndy Kosela sfn = NULL;
2767e81b07cSAndy Kosela }
2777e81b07cSAndy Kosela }
2787e81b07cSAndy Kosela exit(n);
2797e81b07cSAndy Kosela /* NOTREACHED */
2807e81b07cSAndy Kosela }
2817e81b07cSAndy Kosela
2827e81b07cSAndy Kosela
2837e81b07cSAndy Kosela unsigned char ctab[256]; /* character translation table */
2847e81b07cSAndy Kosela
2857e81b07cSAndy Kosela /* init_buffers: open scratch buffer; initialize line queue */
2867e81b07cSAndy Kosela void
init_buffers(void)2877e81b07cSAndy Kosela init_buffers(void)
2887e81b07cSAndy Kosela {
2897e81b07cSAndy Kosela int i = 0;
2907e81b07cSAndy Kosela
2917e81b07cSAndy Kosela /* Read stdin one character at a time to avoid i/o contention
2927e81b07cSAndy Kosela with shell escapes invoked by nonterminal input, e.g.,
2937e81b07cSAndy Kosela ed - <<EOF
2947e81b07cSAndy Kosela !cat
2957e81b07cSAndy Kosela hello, world
2967e81b07cSAndy Kosela EOF */
2977e81b07cSAndy Kosela setbuffer(stdin, stdinbuf, 1);
2987e81b07cSAndy Kosela if (open_sbuf() < 0)
2997e81b07cSAndy Kosela quit(2);
3007e81b07cSAndy Kosela REQUE(&buffer_head, &buffer_head);
3017e81b07cSAndy Kosela for (i = 0; i < 256; i++)
3027e81b07cSAndy Kosela ctab[i] = i;
3037e81b07cSAndy Kosela }
3047e81b07cSAndy Kosela
3057e81b07cSAndy Kosela
3067e81b07cSAndy Kosela /* translit_text: translate characters in a string */
3077e81b07cSAndy Kosela char *
translit_text(char * s,int len,int from,int to)3087e81b07cSAndy Kosela translit_text(char *s, int len, int from, int to)
3097e81b07cSAndy Kosela {
3107e81b07cSAndy Kosela static int i = 0;
3117e81b07cSAndy Kosela
3127e81b07cSAndy Kosela unsigned char *us;
3137e81b07cSAndy Kosela
3147e81b07cSAndy Kosela ctab[i] = i; /* restore table to initial state */
3157e81b07cSAndy Kosela ctab[i = from] = to;
3167e81b07cSAndy Kosela for (us = (unsigned char *) s; len-- > 0; us++)
3177e81b07cSAndy Kosela *us = ctab[*us];
3187e81b07cSAndy Kosela return s;
3197e81b07cSAndy Kosela }
320