summaryrefslogtreecommitdiff
path: root/corebinutils/ed/buf.c
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:25:19 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:25:19 +0300
commitf0f174696b38adfd6063bb74e5b48d2b864cb650 (patch)
tree445ec6db16bfd8ecd36dfcb8907c852c8c104b10 /corebinutils/ed/buf.c
parent0e49ba0e7b8b9bc8bdc61f8c80228252392e758e (diff)
parent93528dc40c12704e0f9ca16475e97e68b4317fb9 (diff)
downloadProject-Tick-f0f174696b38adfd6063bb74e5b48d2b864cb650.tar.gz
Project-Tick-f0f174696b38adfd6063bb74e5b48d2b864cb650.zip
Add 'corebinutils/ed/' from commit '93528dc40c12704e0f9ca16475e97e68b4317fb9'
git-subtree-dir: corebinutils/ed git-subtree-mainline: 0e49ba0e7b8b9bc8bdc61f8c80228252392e758e git-subtree-split: 93528dc40c12704e0f9ca16475e97e68b4317fb9
Diffstat (limited to 'corebinutils/ed/buf.c')
-rw-r--r--corebinutils/ed/buf.c331
1 files changed, 331 insertions, 0 deletions
diff --git a/corebinutils/ed/buf.c b/corebinutils/ed/buf.c
new file mode 100644
index 0000000000..9b41c066ff
--- /dev/null
+++ b/corebinutils/ed/buf.c
@@ -0,0 +1,331 @@
+/* buf.c: This file contains the scratch-file buffer routines for the
+ ed line editor. */
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * Copyright (c) 2026 Project Tick.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+
+#include "ed.h"
+
+
+static FILE *sfp; /* scratch file pointer */
+static off_t sfseek; /* scratch file position */
+static int seek_write; /* seek before writing */
+static line_t buffer_head; /* incore buffer */
+
+/* get_sbuf_line: get a line of text from the scratch file; return pointer
+ to the text */
+char *
+get_sbuf_line(line_t *lp)
+{
+ static char *sfbuf = NULL; /* buffer */
+ static size_t sfbufsz; /* buffer size */
+
+ size_t len;
+
+ if (lp == &buffer_head)
+ return NULL;
+ seek_write = 1; /* force seek on write */
+ /* out of position */
+ if (sfseek != lp->seek) {
+ sfseek = lp->seek;
+ if (fseeko(sfp, sfseek, SEEK_SET) < 0) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot seek temp file";
+ return NULL;
+ }
+ }
+ len = lp->len;
+ REALLOC(sfbuf, sfbufsz, len + 1, NULL);
+ if (fread(sfbuf, sizeof(char), len, sfp) != len) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot read temp file";
+ return NULL;
+ }
+ sfseek += len; /* update file position */
+ sfbuf[len] = '\0';
+ return sfbuf;
+}
+
+
+/* put_sbuf_line: write a line of text to the scratch file and add a line node
+ to the editor buffer; return a pointer to the end of the text */
+const char *
+put_sbuf_line(const char *cs)
+{
+ line_t *lp;
+ size_t len;
+ const char *s;
+
+ if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "out of memory";
+ return NULL;
+ }
+ /* assert: cs is '\n' terminated */
+ for (s = cs; *s != '\n'; s++)
+ ;
+ if (s - cs >= LINECHARS) {
+ errmsg = "line too long";
+ free(lp);
+ return NULL;
+ }
+ len = s - cs;
+ /* out of position */
+ if (seek_write) {
+ if (fseeko(sfp, (off_t)0, SEEK_END) < 0) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot seek temp file";
+ free(lp);
+ return NULL;
+ }
+ sfseek = ftello(sfp);
+ seek_write = 0;
+ }
+ /* assert: SPL1() */
+ if (fwrite(cs, sizeof(char), len, sfp) != len) {
+ sfseek = -1;
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot write temp file";
+ free(lp);
+ return NULL;
+ }
+ lp->len = len;
+ lp->seek = sfseek;
+ add_line_node(lp);
+ sfseek += len; /* update file position */
+ return ++s;
+}
+
+
+/* add_line_node: add a line node in the editor buffer after the current line */
+void
+add_line_node(line_t *lp)
+{
+ line_t *cp;
+
+ cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */
+ INSQUE(lp, cp);
+ addr_last++;
+ current_addr++;
+}
+
+
+/* get_line_node_addr: return line number of pointer */
+long
+get_line_node_addr(line_t *lp)
+{
+ line_t *cp = &buffer_head;
+ long n = 0;
+
+ while (cp != lp && (cp = cp->q_forw) != &buffer_head)
+ n++;
+ if (n && cp == &buffer_head) {
+ errmsg = "invalid address";
+ return ERR;
+ }
+ return n;
+}
+
+
+/* get_addressed_line_node: return pointer to a line node in the editor buffer */
+line_t *
+get_addressed_line_node(long n)
+{
+ static line_t *lp = &buffer_head;
+ static long on = 0;
+
+ SPL1();
+ if (n > on)
+ if (n <= (on + addr_last) >> 1)
+ for (; on < n; on++)
+ lp = lp->q_forw;
+ else {
+ lp = buffer_head.q_back;
+ for (on = addr_last; on > n; on--)
+ lp = lp->q_back;
+ }
+ else
+ if (n >= on >> 1)
+ for (; on > n; on--)
+ lp = lp->q_back;
+ else {
+ lp = &buffer_head;
+ for (on = 0; on < n; on++)
+ lp = lp->q_forw;
+ }
+ SPL0();
+ return lp;
+}
+
+static char *sfn; /* scratch file name */
+
+static int
+prepare_scratch_name(void)
+{
+ static const char suffix[] = "ed.XXXXXX";
+ const char *tmpdir;
+ size_t dirlen;
+ size_t suffixlen;
+ size_t need;
+ int needslash;
+ char *path;
+
+ tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL || tmpdir[0] == '\0')
+ tmpdir = "/tmp";
+ dirlen = strlen(tmpdir);
+ suffixlen = sizeof(suffix);
+ needslash = dirlen > 0 && tmpdir[dirlen - 1] != '/';
+ need = dirlen + (size_t)needslash + suffixlen;
+ if (need > PATH_MAX) {
+ fprintf(stderr, "%s\n", "temporary directory path too long");
+ errmsg = "temporary directory path too long";
+ return ERR;
+ }
+ path = malloc(need);
+ if (path == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "out of memory";
+ return ERR;
+ }
+ memcpy(path, tmpdir, dirlen);
+ if (needslash)
+ path[dirlen++] = '/';
+ memcpy(path + dirlen, suffix, suffixlen);
+ free(sfn);
+ sfn = path;
+ return 0;
+}
+
+/* open_sbuf: open scratch file */
+int
+open_sbuf(void)
+{
+ int fd = -1;
+ int u;
+
+ isbinary = newline_added = 0;
+ if (prepare_scratch_name() < 0)
+ return ERR;
+ u = umask(077);
+ if ((fd = mkstemp(sfn)) == -1 ||
+ (sfp = fdopen(fd, "w+")) == NULL) {
+ if (fd != -1) {
+ close(fd);
+ unlink(sfn);
+ }
+ perror(sfn != NULL ? sfn : "mkstemp");
+ errmsg = "cannot open temp file";
+ umask(u);
+ return ERR;
+ }
+ umask(u);
+ return 0;
+}
+
+
+/* close_sbuf: close scratch file */
+int
+close_sbuf(void)
+{
+ if (sfp) {
+ if (fclose(sfp) < 0) {
+ fprintf(stderr, "%s: %s\n", sfn != NULL ? sfn : "ed",
+ strerror(errno));
+ errmsg = "cannot close temp file";
+ return ERR;
+ }
+ sfp = NULL;
+ if (sfn != NULL)
+ unlink(sfn);
+ }
+ free(sfn);
+ sfn = NULL;
+ sfseek = seek_write = 0;
+ return 0;
+}
+
+
+/* quit: remove_lines scratch file and exit */
+void
+quit(int n)
+{
+ if (sfp) {
+ fclose(sfp);
+ if (sfn != NULL)
+ unlink(sfn);
+ }
+ free(sfn);
+ sfn = NULL;
+ exit(n);
+}
+
+
+static unsigned char ctab[256]; /* character translation table */
+
+/* init_buffers: open scratch buffer; initialize line queue */
+void
+init_buffers(void)
+{
+ int i = 0;
+
+ /* Keep stdin unbuffered to avoid i/o contention with shell escapes
+ invoked by nonterminal input, e.g.,
+ ed - <<EOF
+ !cat
+ hello, world
+ EOF */
+ setvbuf(stdin, NULL, _IONBF, 0);
+
+ /* Ensure stdout is line buffered. This avoids bogus delays
+ of output if stdout is piped through utilities to a terminal. */
+ setvbuf(stdout, NULL, _IOLBF, 0);
+ if (open_sbuf() < 0)
+ quit(2);
+ REQUE(&buffer_head, &buffer_head);
+ for (i = 0; i < 256; i++)
+ ctab[i] = i;
+}
+
+
+/* translit_text: translate characters in a string */
+char *
+translit_text(char *s, int len, int from, int to)
+{
+ static int i = 0;
+
+ unsigned char *us;
+
+ ctab[i] = i; /* restore table to initial state */
+ ctab[i = from] = to;
+ for (us = (unsigned char *) s; len-- > 0; us++)
+ *us = ctab[*us];
+ return s;
+}