oblok.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * Copyright (c) 2003 Gunnar Ritter
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute
  10. * it freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. *
  17. * 2. Altered source versions must be plainly marked as such, and must not be
  18. * misrepresented as being the original software.
  19. *
  20. * 3. This notice may not be removed or altered from any source distribution.
  21. */
  22. /* Sccsid @(#)oblok.c 1.7 (gritter) 7/16/04 */
  23. #include <sys/types.h>
  24. #include <unistd.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <malloc.h>
  30. #include "memalign.h"
  31. #include "oblok.h"
  32. struct list {
  33. struct list *l_nxt;
  34. struct oblok *l_op;
  35. };
  36. static struct list *bloks;
  37. static int exitset;
  38. int
  39. ob_clear(void)
  40. {
  41. struct list *lp;
  42. int val = 0;
  43. for (lp = bloks; lp; lp = lp->l_nxt) {
  44. if (ob_flush(lp->l_op) < 0)
  45. val = -1;
  46. else if (val >= 0)
  47. val++;
  48. }
  49. return val;
  50. }
  51. static void
  52. add(struct oblok *op)
  53. {
  54. struct list *lp, *lq;
  55. if ((lp = calloc(1, sizeof *lp)) != NULL) {
  56. lp->l_nxt = NULL;
  57. lp->l_op = op;
  58. if (bloks) {
  59. for (lq = bloks; lq->l_nxt; lq = lq->l_nxt);
  60. lq->l_nxt = lp;
  61. } else
  62. bloks = lp;
  63. if (exitset == 0) {
  64. exitset = 1;
  65. atexit((void (*)(void))ob_clear);
  66. }
  67. }
  68. }
  69. static void
  70. del(struct oblok *op)
  71. {
  72. struct list *lp, *lq = NULL;
  73. if (bloks) {
  74. for (lp = bloks; lp && lp->l_op != op; lp = lp->l_nxt)
  75. lq = lp;
  76. if (lp) {
  77. if (lq)
  78. lq->l_nxt = lp->l_nxt;
  79. if (lp == bloks)
  80. bloks = bloks->l_nxt;
  81. free(lp);
  82. }
  83. }
  84. }
  85. struct oblok *
  86. ob_alloc(int fd, enum ob_mode bf)
  87. {
  88. static long pagesize;
  89. struct oblok *op;
  90. if (pagesize == 0)
  91. if ((pagesize = sysconf(_SC_PAGESIZE)) < 0)
  92. pagesize = 4096;
  93. if ((op = memalign(pagesize, sizeof *op)) == NULL)
  94. return NULL;
  95. memset(op, 0, sizeof *op);
  96. op->ob_fd = fd;
  97. switch (bf) {
  98. case OB_EBF:
  99. op->ob_bf = isatty(fd) ? OB_LBF : OB_FBF;
  100. break;
  101. default:
  102. op->ob_bf = bf;
  103. }
  104. add(op);
  105. return op;
  106. }
  107. ssize_t
  108. ob_free(struct oblok *op)
  109. {
  110. ssize_t wrt;
  111. wrt = ob_flush(op);
  112. del(op);
  113. free(op);
  114. return wrt;
  115. }
  116. static ssize_t
  117. swrite(int fd, const char *data, size_t sz)
  118. {
  119. ssize_t wo, wt = 0;
  120. do {
  121. if ((wo = write(fd, data + wt, sz - wt)) < 0) {
  122. if (errno == EINTR)
  123. continue;
  124. else
  125. return wt;
  126. }
  127. wt += wo;
  128. } while (wt < sz);
  129. return sz;
  130. }
  131. ssize_t
  132. ob_write(struct oblok *op, const char *data, size_t sz)
  133. {
  134. ssize_t wrt;
  135. size_t di, isz;
  136. switch (op->ob_bf) {
  137. case OB_NBF:
  138. wrt = swrite(op->ob_fd, data, sz);
  139. op->ob_wrt += wrt;
  140. if (wrt != sz) {
  141. op->ob_bf = OB_EBF;
  142. writerr(op, sz, wrt>0?wrt:0);
  143. return -1;
  144. }
  145. return wrt;
  146. case OB_LBF:
  147. case OB_FBF:
  148. isz = sz;
  149. while (op->ob_pos + sz > (OBLOK)) {
  150. di = (OBLOK) - op->ob_pos;
  151. sz -= di;
  152. if (op->ob_pos > 0) {
  153. memcpy(&op->ob_blk[op->ob_pos], data, di);
  154. wrt = swrite(op->ob_fd, op->ob_blk, (OBLOK));
  155. } else
  156. wrt = swrite(op->ob_fd, data, (OBLOK));
  157. op->ob_wrt += wrt;
  158. if (wrt != (OBLOK)) {
  159. op->ob_bf = OB_EBF;
  160. writerr(op, (OBLOK), wrt>0?wrt:0);
  161. return -1;
  162. }
  163. data += di;
  164. op->ob_pos = 0;
  165. }
  166. if (op->ob_bf == OB_LBF) {
  167. const char *cp;
  168. cp = data;
  169. while (cp < &data[sz]) {
  170. if (*cp == '\n') {
  171. di = cp - data + 1;
  172. sz -= di;
  173. if (op->ob_pos > 0) {
  174. memcpy(&op->ob_blk[op->ob_pos],
  175. data, di);
  176. wrt = swrite(op->ob_fd,
  177. op->ob_blk,
  178. op->ob_pos + di);
  179. } else
  180. wrt = swrite(op->ob_fd,
  181. data, di);
  182. op->ob_wrt += wrt;
  183. if (wrt != op->ob_pos + di) {
  184. op->ob_bf = OB_EBF;
  185. writerr(op, di, wrt>0?wrt:0);
  186. return -1;
  187. }
  188. op->ob_pos = 0;
  189. data += di;
  190. cp = data;
  191. }
  192. cp++;
  193. }
  194. }
  195. if (sz == (OBLOK)) {
  196. wrt = swrite(op->ob_fd, data, sz);
  197. op->ob_wrt += wrt;
  198. if (wrt != sz) {
  199. op->ob_bf = OB_EBF;
  200. writerr(op, sz, wrt>0?wrt:0);
  201. return -1;
  202. }
  203. } else if (sz) {
  204. memcpy(&op->ob_blk[op->ob_pos], data, sz);
  205. op->ob_pos += sz;
  206. }
  207. return isz;
  208. case OB_EBF:
  209. ;
  210. }
  211. return -1;
  212. }
  213. ssize_t
  214. ob_flush(struct oblok *op)
  215. {
  216. ssize_t wrt = 0;
  217. if (op->ob_pos) {
  218. wrt = swrite(op->ob_fd, op->ob_blk, op->ob_pos);
  219. op->ob_wrt += wrt;
  220. if (wrt != op->ob_pos) {
  221. op->ob_bf = OB_EBF;
  222. writerr(op, op->ob_pos, wrt>0?wrt:0);
  223. wrt = -1;
  224. }
  225. op->ob_pos = 0;
  226. }
  227. return wrt;
  228. }
  229. int
  230. ob_chr(int c, struct oblok *op)
  231. {
  232. char b;
  233. ssize_t wrt;
  234. b = (char)c;
  235. wrt = ob_write(op, &b, 1);
  236. return wrt < 0 ? EOF : c;
  237. }