/bin/sh/output.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 335 lines · 236 code · 53 blank · 46 comment · 39 complexity · 73b7d777ef276d5d7f5e604b81abda94 MD5 · raw file

  1. /*-
  2. * Copyright (c) 1991, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * This code is derived from software contributed to Berkeley by
  6. * Kenneth Almquist.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 4. Neither the name of the University nor the names of its contributors
  17. * may be used to endorse or promote products derived from this software
  18. * without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  21. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  24. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. */
  32. #ifndef lint
  33. #if 0
  34. static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
  35. #endif
  36. #endif /* not lint */
  37. #include <sys/cdefs.h>
  38. __FBSDID("$FreeBSD$");
  39. /*
  40. * Shell output routines. We use our own output routines because:
  41. * When a builtin command is interrupted we have to discard
  42. * any pending output.
  43. * When a builtin command appears in back quotes, we want to
  44. * save the output of the command in a region obtained
  45. * via malloc, rather than doing a fork and reading the
  46. * output of the command via a pipe.
  47. */
  48. #include <stdio.h> /* defines BUFSIZ */
  49. #include <string.h>
  50. #include <stdarg.h>
  51. #include <errno.h>
  52. #include <unistd.h>
  53. #include <stdlib.h>
  54. #include "shell.h"
  55. #include "syntax.h"
  56. #include "output.h"
  57. #include "memalloc.h"
  58. #include "error.h"
  59. #include "var.h"
  60. #define OUTBUFSIZ BUFSIZ
  61. #define MEM_OUT -2 /* output to dynamically allocated memory */
  62. #define OUTPUT_ERR 01 /* error occurred on output */
  63. static int doformat_wr(void *, const char *, int);
  64. struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
  65. struct output errout = {NULL, 0, NULL, 256, 2, 0};
  66. struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
  67. struct output *out1 = &output;
  68. struct output *out2 = &errout;
  69. #ifdef mkinit
  70. INCLUDE "output.h"
  71. INCLUDE "memalloc.h"
  72. RESET {
  73. out1 = &output;
  74. out2 = &errout;
  75. if (memout.buf != NULL) {
  76. ckfree(memout.buf);
  77. memout.buf = NULL;
  78. }
  79. }
  80. #endif
  81. void
  82. outcslow(int c, struct output *file)
  83. {
  84. outc(c, file);
  85. }
  86. void
  87. out1str(const char *p)
  88. {
  89. outstr(p, out1);
  90. }
  91. void
  92. out1qstr(const char *p)
  93. {
  94. outqstr(p, out1);
  95. }
  96. void
  97. out2str(const char *p)
  98. {
  99. outstr(p, out2);
  100. }
  101. void
  102. out2qstr(const char *p)
  103. {
  104. outqstr(p, out2);
  105. }
  106. void
  107. outstr(const char *p, struct output *file)
  108. {
  109. outbin(p, strlen(p), file);
  110. }
  111. /* Like outstr(), but quote for re-input into the shell. */
  112. void
  113. outqstr(const char *p, struct output *file)
  114. {
  115. char ch;
  116. int inquotes;
  117. if (p[0] == '\0') {
  118. outstr("''", file);
  119. return;
  120. }
  121. /* Caller will handle '=' if necessary */
  122. if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' ||
  123. strcmp(p, "[") == 0) {
  124. outstr(p, file);
  125. return;
  126. }
  127. inquotes = 0;
  128. while ((ch = *p++) != '\0') {
  129. switch (ch) {
  130. case '\'':
  131. /* Can't quote single quotes inside single quotes. */
  132. if (inquotes)
  133. outcslow('\'', file);
  134. inquotes = 0;
  135. outstr("\\'", file);
  136. break;
  137. default:
  138. if (!inquotes)
  139. outcslow('\'', file);
  140. inquotes = 1;
  141. outc(ch, file);
  142. }
  143. }
  144. if (inquotes)
  145. outcslow('\'', file);
  146. }
  147. void
  148. outbin(const void *data, size_t len, struct output *file)
  149. {
  150. const char *p;
  151. p = data;
  152. while (len-- > 0)
  153. outc(*p++, file);
  154. }
  155. void
  156. emptyoutbuf(struct output *dest)
  157. {
  158. int offset;
  159. if (dest->buf == NULL) {
  160. INTOFF;
  161. dest->buf = ckmalloc(dest->bufsize);
  162. dest->nextc = dest->buf;
  163. dest->nleft = dest->bufsize;
  164. INTON;
  165. } else if (dest->fd == MEM_OUT) {
  166. offset = dest->bufsize;
  167. INTOFF;
  168. dest->bufsize <<= 1;
  169. dest->buf = ckrealloc(dest->buf, dest->bufsize);
  170. dest->nleft = dest->bufsize - offset;
  171. dest->nextc = dest->buf + offset;
  172. INTON;
  173. } else {
  174. flushout(dest);
  175. }
  176. dest->nleft--;
  177. }
  178. void
  179. flushall(void)
  180. {
  181. flushout(&output);
  182. flushout(&errout);
  183. }
  184. void
  185. flushout(struct output *dest)
  186. {
  187. if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
  188. return;
  189. if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
  190. dest->flags |= OUTPUT_ERR;
  191. dest->nextc = dest->buf;
  192. dest->nleft = dest->bufsize;
  193. }
  194. void
  195. freestdout(void)
  196. {
  197. INTOFF;
  198. if (output.buf) {
  199. ckfree(output.buf);
  200. output.buf = NULL;
  201. output.nleft = 0;
  202. }
  203. INTON;
  204. }
  205. void
  206. outfmt(struct output *file, const char *fmt, ...)
  207. {
  208. va_list ap;
  209. va_start(ap, fmt);
  210. doformat(file, fmt, ap);
  211. va_end(ap);
  212. }
  213. void
  214. out1fmt(const char *fmt, ...)
  215. {
  216. va_list ap;
  217. va_start(ap, fmt);
  218. doformat(out1, fmt, ap);
  219. va_end(ap);
  220. }
  221. void
  222. out2fmt_flush(const char *fmt, ...)
  223. {
  224. va_list ap;
  225. va_start(ap, fmt);
  226. doformat(out2, fmt, ap);
  227. va_end(ap);
  228. flushout(out2);
  229. }
  230. void
  231. fmtstr(char *outbuf, int length, const char *fmt, ...)
  232. {
  233. va_list ap;
  234. INTOFF;
  235. va_start(ap, fmt);
  236. vsnprintf(outbuf, length, fmt, ap);
  237. va_end(ap);
  238. INTON;
  239. }
  240. static int
  241. doformat_wr(void *cookie, const char *buf, int len)
  242. {
  243. struct output *o;
  244. o = (struct output *)cookie;
  245. outbin(buf, len, o);
  246. return (len);
  247. }
  248. void
  249. doformat(struct output *dest, const char *f, va_list ap)
  250. {
  251. FILE *fp;
  252. if ((fp = fwopen(dest, doformat_wr)) != NULL) {
  253. vfprintf(fp, f, ap);
  254. fclose(fp);
  255. }
  256. }
  257. /*
  258. * Version of write which resumes after a signal is caught.
  259. */
  260. int
  261. xwrite(int fd, const char *buf, int nbytes)
  262. {
  263. int ntry;
  264. int i;
  265. int n;
  266. n = nbytes;
  267. ntry = 0;
  268. for (;;) {
  269. i = write(fd, buf, n);
  270. if (i > 0) {
  271. if ((n -= i) <= 0)
  272. return nbytes;
  273. buf += i;
  274. ntry = 0;
  275. } else if (i == 0) {
  276. if (++ntry > 10)
  277. return nbytes - n;
  278. } else if (errno != EINTR) {
  279. return -1;
  280. }
  281. }
  282. }