buf.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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. #include <sys/cdefs.h>
  29. #include <sys/file.h>
  30. #include <sys/stat.h>
  31. #include "ed.h"
  32. static FILE *sfp; /* scratch file pointer */
  33. static off_t sfseek; /* scratch file position */
  34. static int seek_write; /* seek before writing */
  35. static line_t buffer_head; /* incore buffer */
  36. /* get_sbuf_line: get a line of text from the scratch file; return pointer
  37. to the text */
  38. char *
  39. get_sbuf_line(line_t *lp)
  40. {
  41. static char *sfbuf = NULL; /* buffer */
  42. static size_t sfbufsz; /* buffer size */
  43. size_t len;
  44. if (lp == &buffer_head)
  45. return NULL;
  46. seek_write = 1; /* force seek on write */
  47. /* out of position */
  48. if (sfseek != lp->seek) {
  49. sfseek = lp->seek;
  50. if (fseeko(sfp, sfseek, SEEK_SET) < 0) {
  51. fprintf(stderr, "%s\n", strerror(errno));
  52. errmsg = "cannot seek temp file";
  53. return NULL;
  54. }
  55. }
  56. len = lp->len;
  57. REALLOC(sfbuf, sfbufsz, len + 1, NULL);
  58. if (fread(sfbuf, sizeof(char), len, sfp) != len) {
  59. fprintf(stderr, "%s\n", strerror(errno));
  60. errmsg = "cannot read temp file";
  61. return NULL;
  62. }
  63. sfseek += len; /* update file position */
  64. sfbuf[len] = '\0';
  65. return sfbuf;
  66. }
  67. /* put_sbuf_line: write a line of text to the scratch file and add a line node
  68. to the editor buffer; return a pointer to the end of the text */
  69. const char *
  70. put_sbuf_line(const char *cs)
  71. {
  72. line_t *lp;
  73. size_t len;
  74. const char *s;
  75. if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
  76. fprintf(stderr, "%s\n", strerror(errno));
  77. errmsg = "out of memory";
  78. return NULL;
  79. }
  80. /* assert: cs is '\n' terminated */
  81. for (s = cs; *s != '\n'; s++)
  82. ;
  83. if (s - cs >= LINECHARS) {
  84. errmsg = "line too long";
  85. free(lp);
  86. return NULL;
  87. }
  88. len = s - cs;
  89. /* out of position */
  90. if (seek_write) {
  91. if (fseeko(sfp, (off_t)0, SEEK_END) < 0) {
  92. fprintf(stderr, "%s\n", strerror(errno));
  93. errmsg = "cannot seek temp file";
  94. free(lp);
  95. return NULL;
  96. }
  97. sfseek = ftello(sfp);
  98. seek_write = 0;
  99. }
  100. /* assert: SPL1() */
  101. if (fwrite(cs, sizeof(char), len, sfp) != len) {
  102. sfseek = -1;
  103. fprintf(stderr, "%s\n", strerror(errno));
  104. errmsg = "cannot write temp file";
  105. free(lp);
  106. return NULL;
  107. }
  108. lp->len = len;
  109. lp->seek = sfseek;
  110. add_line_node(lp);
  111. sfseek += len; /* update file position */
  112. return ++s;
  113. }
  114. /* add_line_node: add a line node in the editor buffer after the current line */
  115. void
  116. add_line_node(line_t *lp)
  117. {
  118. line_t *cp;
  119. cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */
  120. INSQUE(lp, cp);
  121. addr_last++;
  122. current_addr++;
  123. }
  124. /* get_line_node_addr: return line number of pointer */
  125. long
  126. get_line_node_addr(line_t *lp)
  127. {
  128. line_t *cp = &buffer_head;
  129. long n = 0;
  130. while (cp != lp && (cp = cp->q_forw) != &buffer_head)
  131. n++;
  132. if (n && cp == &buffer_head) {
  133. errmsg = "invalid address";
  134. return ERR;
  135. }
  136. return n;
  137. }
  138. /* get_addressed_line_node: return pointer to a line node in the editor buffer */
  139. line_t *
  140. get_addressed_line_node(long n)
  141. {
  142. static line_t *lp = &buffer_head;
  143. static long on = 0;
  144. SPL1();
  145. if (n > on)
  146. if (n <= (on + addr_last) >> 1)
  147. for (; on < n; on++)
  148. lp = lp->q_forw;
  149. else {
  150. lp = buffer_head.q_back;
  151. for (on = addr_last; on > n; on--)
  152. lp = lp->q_back;
  153. }
  154. else
  155. if (n >= on >> 1)
  156. for (; on > n; on--)
  157. lp = lp->q_back;
  158. else {
  159. lp = &buffer_head;
  160. for (on = 0; on < n; on++)
  161. lp = lp->q_forw;
  162. }
  163. SPL0();
  164. return lp;
  165. }
  166. static char sfn[15] = ""; /* scratch file name */
  167. /* open_sbuf: open scratch file */
  168. int
  169. open_sbuf(void)
  170. {
  171. int fd;
  172. int u;
  173. isbinary = newline_added = 0;
  174. u = umask(077);
  175. strcpy(sfn, "/tmp/ed.XXXXXX");
  176. if ((fd = mkstemp(sfn)) == -1 ||
  177. (sfp = fdopen(fd, "w+")) == NULL) {
  178. if (fd != -1)
  179. close(fd);
  180. perror(sfn);
  181. errmsg = "cannot open temp file";
  182. umask(u);
  183. return ERR;
  184. }
  185. umask(u);
  186. return 0;
  187. }
  188. /* close_sbuf: close scratch file */
  189. int
  190. close_sbuf(void)
  191. {
  192. if (sfp) {
  193. if (fclose(sfp) < 0) {
  194. fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
  195. errmsg = "cannot close temp file";
  196. return ERR;
  197. }
  198. sfp = NULL;
  199. unlink(sfn);
  200. }
  201. sfseek = seek_write = 0;
  202. return 0;
  203. }
  204. /* quit: remove_lines scratch file and exit */
  205. void
  206. quit(int n)
  207. {
  208. if (sfp) {
  209. fclose(sfp);
  210. unlink(sfn);
  211. }
  212. exit(n);
  213. }
  214. static unsigned char ctab[256]; /* character translation table */
  215. /* init_buffers: open scratch buffer; initialize line queue */
  216. void
  217. init_buffers(void)
  218. {
  219. int i = 0;
  220. /* Read stdin one character at a time to avoid i/o contention
  221. with shell escapes invoked by nonterminal input, e.g.,
  222. ed - <<EOF
  223. !cat
  224. hello, world
  225. EOF */
  226. setbuffer(stdin, stdinbuf, 1);
  227. /* Ensure stdout is line buffered. This avoids bogus delays
  228. of output if stdout is piped through utilities to a terminal. */
  229. setvbuf(stdout, NULL, _IOLBF, 0);
  230. if (open_sbuf() < 0)
  231. quit(2);
  232. REQUE(&buffer_head, &buffer_head);
  233. for (i = 0; i < 256; i++)
  234. ctab[i] = i;
  235. }
  236. /* translit_text: translate characters in a string */
  237. char *
  238. translit_text(char *s, int len, int from, int to)
  239. {
  240. static int i = 0;
  241. unsigned char *us;
  242. ctab[i] = i; /* restore table to initial state */
  243. ctab[i = from] = to;
  244. for (us = (unsigned char *) s; len-- > 0; us++)
  245. *us = ctab[*us];
  246. return s;
  247. }