/bin/ed/buf.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 287 lines · 198 code · 38 blank · 51 comment · 45 complexity · 4ccdd1ddc477763911c6831d14b8c167 MD5 · raw file

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