/* This file is in the public domain. */ #include #include #include #include #include extern const char *__progname; #include "dequal.h" #include "strings.h" #include "oq.h" struct oqe { OQE *link; const char *data; int left; char *datafree; } ; static void queue_common(OQ *q, OQE *e) { e->link = 0; *q->tail = e; q->tail = &e->link; } static void queue_norm(OQ *q, OQE *e, int len) { e->left = len; q->len += len; queue_common(q,e); } void oq_init(OQ *q) { q->len = 0; q->head = 0; q->tail = &q->head; } unsigned int oq_qlen(OQ *q) { return(q->len); } int oq_empty(OQ *q) { return(q->head == 0); } int oq_nonempty(OQ *q) { return(q->head != 0); } void oq_queue_point(OQ *q, const void *data, int len) { OQE *e; if (len == OQ_STRLEN) len = strlen(data); if (len == 0) return; if (len < 1) abort(); e = malloc(sizeof(OQE)); e->data = data; e->datafree = 0; queue_norm(q,e,len); } void oq_queue_copy(OQ *q, const void *data, int len) { OQE *e; if (len == OQ_STRLEN) len = strlen(data); if (len == 0) return; if (len < 1) abort(); e = malloc(sizeof(OQE)+len); e->data = (void *) (e+1); e->datafree = 0; bcopy(data,e+1,len); queue_norm(q,e,len); } void oq_queue_free(OQ *q, void *data, int len) { OQE *e; if (len == OQ_STRLEN) len = strlen(data); if (len == 0) { free(data); return; } if (len < 1) abort(); e = malloc(sizeof(OQE)); e->data = data; e->datafree = data; queue_norm(q,e,len); } int oq_writev(OQ *q, int fd) { static int maxiov = -1; static struct iovec *iov; static int iovn; int iovl; OQE *e; if (maxiov < 0) { #ifdef __Linux__ /* Not clear to me how to get the max iovec size on Linux. This comes from the manpages on one particular version. */ maxiov = 1024; #else int mib[2]; size_t oldlen; mib[0] = CTL_KERN; mib[1] = KERN_IOV_MAX; oldlen = sizeof(maxiov); if (sysctl(&mib[0],2,&maxiov,&oldlen,0,0) < 0) { fprintf(stderr,"%s: can't get kern.iov_max: %s\n",__progname,strerror(errno)); exit(1); } if (maxiov > 1024) maxiov = 1024; if (maxiov < 1) maxiov = 1; #endif iov = 0; iovn = 0; } iovl = 0; for (e=q->head;e;e=e->link) { if (iovl >= maxiov) break; if (iovl >= iovn) iov = realloc(iov,(iovn=iovl+4)*sizeof(*iov)); iov[iovl++] = (struct iovec){ .iov_base=dequal(e->data), .iov_len=e->left }; } return(writev(fd,iov,iovl)); } int oq_dropdata(OQ *q, int n) { OQE *e; while ((e=q->head) && n && (n >= e->left)) { q->head = e->link; q->len -= e->left; n -= e->left; free(e->datafree); free(e); } if (e) { if (n) { e->data += n; e->left -= n; q->len -= n; } return(0); } else { q->tail = &q->head; if (q->len) abort(); return(1); } } void oq_flush(OQ *q) { OQE *e; while (q->head) { e = q->head; q->head = e->link; free(e->datafree); free(e); } q->len = 0; q->tail = &q->head; } void oq_cbwalk(OQ *q, void (*cb)(const char *, int), int max) { OQE *e; int n; for (e=q->head;e;e=e->link) { if ((max < 0) || (max >= e->left)) n = e->left; else n = max; if (n < 1) return; (*cb)(e->data,n); if (max >= 0) max -= n; } }