oblok.c (4937B)
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 24 #include <sys/types.h> 25 #include <unistd.h> 26 #include <string.h> 27 #include <errno.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <malloc.h> 31 32 #include "memalign.h" 33 #include "oblok.h" 34 35 struct list { 36 struct list *l_nxt; 37 struct oblok *l_op; 38 }; 39 40 static struct list *bloks; 41 static int exitset; 42 43 int 44 ob_clear(void) 45 { 46 struct list *lp; 47 int val = 0; 48 49 for (lp = bloks; lp; lp = lp->l_nxt) { 50 if (ob_flush(lp->l_op) < 0) 51 val = -1; 52 else if (val >= 0) 53 val++; 54 } 55 return val; 56 } 57 58 static void 59 add(struct oblok *op) 60 { 61 struct list *lp, *lq; 62 63 if ((lp = calloc(1, sizeof *lp)) != NULL) { 64 lp->l_nxt = NULL; 65 lp->l_op = op; 66 if (bloks) { 67 for (lq = bloks; lq->l_nxt; lq = lq->l_nxt); 68 lq->l_nxt = lp; 69 } else 70 bloks = lp; 71 if (exitset == 0) { 72 exitset = 1; 73 atexit((void (*)(void))ob_clear); 74 } 75 } 76 } 77 78 static void 79 del(struct oblok *op) 80 { 81 struct list *lp, *lq = NULL; 82 83 if (bloks) { 84 for (lp = bloks; lp && lp->l_op != op; lp = lp->l_nxt) 85 lq = lp; 86 if (lp) { 87 if (lq) 88 lq->l_nxt = lp->l_nxt; 89 if (lp == bloks) 90 bloks = bloks->l_nxt; 91 free(lp); 92 } 93 } 94 } 95 96 struct oblok * 97 ob_alloc(int fd, enum ob_mode bf) 98 { 99 static long pagesize; 100 struct oblok *op; 101 102 if (pagesize == 0) 103 if ((pagesize = sysconf(_SC_PAGESIZE)) < 0) 104 pagesize = 4096; 105 if ((op = memalign(pagesize, sizeof *op)) == NULL) 106 return NULL; 107 memset(op, 0, sizeof *op); 108 op->ob_fd = fd; 109 switch (bf) { 110 case OB_EBF: 111 op->ob_bf = isatty(fd) ? OB_LBF : OB_FBF; 112 break; 113 default: 114 op->ob_bf = bf; 115 } 116 add(op); 117 return op; 118 } 119 120 ssize_t 121 ob_free(struct oblok *op) 122 { 123 ssize_t wrt; 124 125 wrt = ob_flush(op); 126 del(op); 127 free(op); 128 return wrt; 129 } 130 131 static ssize_t 132 swrite(int fd, const char *data, size_t sz) 133 { 134 ssize_t wo, wt = 0; 135 136 do { 137 if ((wo = write(fd, data + wt, sz - wt)) < 0) { 138 if (errno == EINTR) 139 continue; 140 else 141 return wt; 142 } 143 wt += wo; 144 } while (wt < sz); 145 return sz; 146 } 147 148 ssize_t 149 ob_write(struct oblok *op, const char *data, size_t sz) 150 { 151 ssize_t wrt; 152 size_t di, isz; 153 154 switch (op->ob_bf) { 155 case OB_NBF: 156 wrt = swrite(op->ob_fd, data, sz); 157 op->ob_wrt += wrt; 158 if (wrt != sz) { 159 op->ob_bf = OB_EBF; 160 writerr(op, sz, wrt>0?wrt:0); 161 return -1; 162 } 163 return wrt; 164 case OB_LBF: 165 case OB_FBF: 166 isz = sz; 167 while (op->ob_pos + sz > (OBLOK)) { 168 di = (OBLOK) - op->ob_pos; 169 sz -= di; 170 if (op->ob_pos > 0) { 171 memcpy(&op->ob_blk[op->ob_pos], data, di); 172 wrt = swrite(op->ob_fd, op->ob_blk, (OBLOK)); 173 } else 174 wrt = swrite(op->ob_fd, data, (OBLOK)); 175 op->ob_wrt += wrt; 176 if (wrt != (OBLOK)) { 177 op->ob_bf = OB_EBF; 178 writerr(op, (OBLOK), wrt>0?wrt:0); 179 return -1; 180 } 181 data += di; 182 op->ob_pos = 0; 183 } 184 if (op->ob_bf == OB_LBF) { 185 const char *cp; 186 187 cp = data; 188 while (cp < &data[sz]) { 189 if (*cp == '\n') { 190 di = cp - data + 1; 191 sz -= di; 192 if (op->ob_pos > 0) { 193 memcpy(&op->ob_blk[op->ob_pos], 194 data, di); 195 wrt = swrite(op->ob_fd, 196 op->ob_blk, 197 op->ob_pos + di); 198 } else 199 wrt = swrite(op->ob_fd, 200 data, di); 201 op->ob_wrt += wrt; 202 if (wrt != op->ob_pos + di) { 203 op->ob_bf = OB_EBF; 204 writerr(op, di, wrt>0?wrt:0); 205 return -1; 206 } 207 op->ob_pos = 0; 208 data += di; 209 cp = data; 210 } 211 cp++; 212 } 213 } 214 if (sz == (OBLOK)) { 215 wrt = swrite(op->ob_fd, data, sz); 216 op->ob_wrt += wrt; 217 if (wrt != sz) { 218 op->ob_bf = OB_EBF; 219 writerr(op, sz, wrt>0?wrt:0); 220 return -1; 221 } 222 } else if (sz) { 223 memcpy(&op->ob_blk[op->ob_pos], data, sz); 224 op->ob_pos += sz; 225 } 226 return isz; 227 case OB_EBF: 228 ; 229 } 230 return -1; 231 } 232 233 ssize_t 234 ob_flush(struct oblok *op) 235 { 236 ssize_t wrt = 0; 237 238 if (op->ob_pos) { 239 wrt = swrite(op->ob_fd, op->ob_blk, op->ob_pos); 240 op->ob_wrt += wrt; 241 if (wrt != op->ob_pos) { 242 op->ob_bf = OB_EBF; 243 writerr(op, op->ob_pos, wrt>0?wrt:0); 244 wrt = -1; 245 } 246 op->ob_pos = 0; 247 } 248 return wrt; 249 } 250 251 int 252 ob_chr(int c, struct oblok *op) 253 { 254 char b; 255 ssize_t wrt; 256 257 b = (char)c; 258 wrt = ob_write(op, &b, 1); 259 return wrt < 0 ? EOF : c; 260 }