146684Skris/* buf.c: This file contains the scratch-file buffer routines 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 */ 2827963Ssteve 2999109Sobrien#include <sys/cdefs.h> 3099109Sobrien__FBSDID("$FreeBSD$"); 3116Salm 3216Salm#include <sys/file.h> 331297Salm#include <sys/stat.h> 3416Salm 3516Salm#include "ed.h" 3616Salm 3716Salm 38241720Sedstatic FILE *sfp; /* scratch file pointer */ 39241720Sedstatic off_t sfseek; /* scratch file position */ 40241720Sedstatic int seek_write; /* seek before writing */ 41241720Sedstatic line_t buffer_head; /* incore buffer */ 4216Salm 431057Salm/* get_sbuf_line: get a line of text from the scratch file; return pointer 4416Salm to the text */ 4516Salmchar * 4690109Simpget_sbuf_line(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; 5982771Sache if (fseeko(sfp, sfseek, SEEK_SET) < 0) { 6016Salm fprintf(stderr, "%s\n", strerror(errno)); 6181220Smike 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)); 6981220Smike 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 */ 8081220Smikeconst char * 8190109Simpput_sbuf_line(const char *cs) 8216Salm{ 8316Salm line_t *lp; 8416Salm int len, ct; 8581220Smike const char *s; 8616Salm 8716Salm if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) { 8816Salm fprintf(stderr, "%s\n", strerror(errno)); 8981220Smike errmsg = "out of memory"; 9016Salm return NULL; 9116Salm } 9216Salm /* assert: cs is '\n' terminated */ 9316Salm for (s = cs; *s != '\n'; s++) 9416Salm ; 9516Salm if (s - cs >= LINECHARS) { 9681220Smike errmsg = "line too long"; 97225215Sbrueffer free(lp); 9816Salm return NULL; 9916Salm } 1001057Salm len = s - cs; 10116Salm /* out of position */ 10216Salm if (seek_write) { 10382771Sache if (fseeko(sfp, (off_t)0, SEEK_END) < 0) { 10416Salm fprintf(stderr, "%s\n", strerror(errno)); 10581220Smike errmsg = "cannot seek temp file"; 106225215Sbrueffer free(lp); 10716Salm return NULL; 10816Salm } 10982771Sache sfseek = ftello(sfp); 11016Salm seek_write = 0; 11116Salm } 1121057Salm /* assert: SPL1() */ 11316Salm if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) { 11416Salm sfseek = -1; 11516Salm fprintf(stderr, "%s\n", strerror(errno)); 11681220Smike errmsg = "cannot write temp file"; 117225215Sbrueffer free(lp); 11816Salm return NULL; 11916Salm } 12016Salm lp->len = len; 12116Salm lp->seek = sfseek; 1221057Salm add_line_node(lp); 12316Salm sfseek += len; /* update file position */ 12416Salm return ++s; 12516Salm} 12616Salm 12716Salm 1281057Salm/* add_line_node: add a line node in the editor buffer after the current line */ 12916Salmvoid 13090109Simpadd_line_node(line_t *lp) 13116Salm{ 13216Salm line_t *cp; 13316Salm 1341057Salm cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */ 1351297Salm INSQUE(lp, cp); 1361057Salm addr_last++; 1371057Salm current_addr++; 13816Salm} 13916Salm 14016Salm 1411057Salm/* get_line_node_addr: return line number of pointer */ 14216Salmlong 14390109Simpget_line_node_addr(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) { 15181220Smike 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 * 16090109Simpget_addressed_line_node(long n) 16116Salm{ 1621057Salm static line_t *lp = &buffer_head; 16316Salm static long on = 0; 16416Salm 1651057Salm SPL1(); 16616Salm if (n > on) 1671057Salm if (n <= (on + addr_last) >> 1) 16816Salm for (; on < n; on++) 1691057Salm lp = lp->q_forw; 17016Salm else { 1711057Salm lp = buffer_head.q_back; 1721057Salm for (on = addr_last; on > n; on--) 1731057Salm lp = lp->q_back; 17416Salm } 17516Salm else 17616Salm if (n >= on >> 1) 17716Salm for (; on > n; on--) 1781057Salm lp = lp->q_back; 17916Salm else { 1801057Salm lp = &buffer_head; 18116Salm for (on = 0; on < n; on++) 1821057Salm lp = lp->q_forw; 18316Salm } 1841057Salm SPL0(); 18516Salm return lp; 18616Salm} 18716Salm 188241720Sedstatic char sfn[15] = ""; /* scratch file name */ 18916Salm 1901057Salm/* open_sbuf: open scratch file */ 1911057Salmint 19290109Simpopen_sbuf(void) 19316Salm{ 19498481Sjmallett int fd; 1951297Salm int u; 1961297Salm 1971057Salm isbinary = newline_added = 0; 1981297Salm u = umask(077); 19916Salm strcpy(sfn, "/tmp/ed.XXXXXX"); 20030247Seivind if ((fd = mkstemp(sfn)) == -1 || 20124181Simp (sfp = fdopen(fd, "w+")) == NULL) { 20224181Simp if (fd != -1) 20324181Simp close(fd); 20424181Simp perror(sfn); 20581220Smike errmsg = "cannot open temp file"; 2061297Salm umask(u); 20716Salm return ERR; 20816Salm } 2091297Salm umask(u); 21016Salm return 0; 21116Salm} 21216Salm 21316Salm 2141057Salm/* close_sbuf: close scratch file */ 2151057Salmint 21690109Simpclose_sbuf(void) 21716Salm{ 21816Salm if (sfp) { 21916Salm if (fclose(sfp) < 0) { 22016Salm fprintf(stderr, "%s: %s\n", sfn, strerror(errno)); 22181220Smike errmsg = "cannot close temp file"; 22216Salm return ERR; 22316Salm } 22416Salm sfp = NULL; 22516Salm unlink(sfn); 22616Salm } 22716Salm sfseek = seek_write = 0; 22816Salm return 0; 22916Salm} 23016Salm 23116Salm 2321057Salm/* quit: remove_lines scratch file and exit */ 23316Salmvoid 23490109Simpquit(int n) 23516Salm{ 23616Salm if (sfp) { 23716Salm fclose(sfp); 23816Salm unlink(sfn); 23916Salm } 24016Salm exit(n); 24116Salm} 24287Salm 24387Salm 244241720Sedstatic unsigned char ctab[256]; /* character translation table */ 24587Salm 2461057Salm/* init_buffers: open scratch buffer; initialize line queue */ 24787Salmvoid 24890109Simpinit_buffers(void) 24987Salm{ 25087Salm int i = 0; 25187Salm 2528855Srgrimes /* Read stdin one character at a time to avoid i/o contention 2531057Salm with shell escapes invoked by nonterminal input, e.g., 2541057Salm ed - <<EOF 2551057Salm !cat 2561057Salm hello, world 2571057Salm EOF */ 2581057Salm setbuffer(stdin, stdinbuf, 1); 25932138Shelbig 26032138Shelbig /* Ensure stdout is line buffered. This avoids bogus delays 26132138Shelbig of output if stdout is piped through utilities to a terminal. */ 26232138Shelbig setvbuf(stdout, NULL, _IOLBF, 0); 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 * 27390109Simptranslit_text(char *s, int len, int from, int to) 27487Salm{ 27587Salm static int i = 0; 27687Salm 27787Salm unsigned char *us; 27887Salm 27987Salm ctab[i] = i; /* restore table to initial state */ 28087Salm ctab[i = from] = to; 28187Salm for (us = (unsigned char *) s; len-- > 0; us++) 28287Salm *us = ctab[*us]; 28387Salm return s; 28487Salm} 285