/* This file is in the public domain. */ #include #include #include #include #include #include "util.h" /* * Implementations of the utility interfaces in util.h. */ typedef struct wrap_w_priv WRAP_W_PRIV; typedef struct accum_priv ACCUM_PRIV; /* * Private data block for stdio_wrap_w's streams. All we need is * copies of the arguments. */ struct wrap_w_priv { FILE *wrapped; void *cookie; void (*proc)(FILE *, void *, const char *, int); unsigned int flags; } ; /* * Private data block for open_accum's streams. sp and lp are the * arguments to open_accum; s and l are the string and length of the * string accumulated so far. * * We don't keep separate length and allocated-space figures. We * depend on stdio buffering to call our write function seldom. * * If sp is nil, we don't actually bother saving the data anywhere; in * this case, s is not used. (We need the length in order to build s, * so we always maintain it, even if lp is nil. We perhaps could skip * it if both sp and lp are nil, but that's a use case I feel no need * to optimize for, especially since the win would be tiny.) */ struct accum_priv { char *s; int l; char **sp; int *lp; } ; /* * Write function for stdio_wrap_w streams. All we do is call the * callback procedure. */ static int wrap_w_w(void *pv, const char *buf, int len) { WRAP_W_PRIV *p; p = pv; (*p->proc)(p->wrapped,p->cookie,buf,len); return(len); } /* * Close function for stdio_wrap_w streams. Not much to do here: * implement SWW_CLOSE_WRAPPED, then just free the private data. */ static int wrap_w_c(void *pv) { WRAP_W_PRIV *p; p = pv; if (p->flags & SWW_CLOSE_WRAPPED) fclose(p->wrapped); free(pv); return(0); } /* * Open a wrapped stream. All we do here is save the arguments and set * up the outer FILE * with funopen(3). */ FILE *stdio_wrap_w(FILE *wrapped, void *cookie, void (*proc)(FILE *, void *, const char *, int), unsigned int flags) { WRAP_W_PRIV *p; FILE *f; int e; p = malloc(sizeof(WRAP_W_PRIV)); if (! p) return(0); p->wrapped = wrapped; p->cookie = cookie; p->proc = proc; p->flags = flags; f = funopen(p,0,&wrap_w_w,0,&wrap_w_c); if (! f) { e = errno; free(p); errno = e; } return(f); } /* * Write function for open_accum's streams. Nothing noteworthy here. */ static int accum_w(void *pv, const char *buf, int len) { ACCUM_PRIV *p; p = pv; if (p->sp) { p->s = realloc(p->s,p->l+len); bcopy(buf,p->s+p->l,len); } p->l += len; return(len); } /* * Close function for open-accum's streams. We get the trailing \0 * there by calling accum_w to write it, then backing up l by one. * (This entails another realloc. We count on the malloc * implementation to optimize this away in most cases. There isn't * much alternative, anyway, short of always adding one to the realloc * argument and then allocating one byte to start with; by this point * the stream may be too shut-down to write anything to - certainly * the documentation doesn't promise otherwise.) */ static int accum_c(void *pv) { ACCUM_PRIV *p; p = pv; if (p->sp) { accum_w(pv,"",1); *p->sp = p->s; p->l --; } if (p->lp) *p->lp = p->l; free(pv); return(0); } /* * Open an accumulator. Set up the ACCUM_PRIV, then create the FILE * * with funopen - nothing noteworthy. */ FILE *open_accum(char **sp, int *lp) { ACCUM_PRIV *p; FILE *f; int e; p = malloc(sizeof(ACCUM_PRIV)); if (! p) return(0); p->s = 0; p->l = 0; p->sp = sp; p->lp = lp; f = funopen(p,0,&accum_w,0,&accum_c); if (! f) { e = errno; free(p); errno = e; } return(f); } /* * Make a \0-terminated mallocked copy of a pointer-and-length string. * Nothing to add, really, beyond what util.h says. */ char *blk_to_nulterm(const void *buf, int len) { char *s; s = malloc(len+1); if (s) { if (len > 0) bcopy(buf,s,len); s[len] = '\0'; } return(s); } /* * Turn on O_NONBLOCK on a file descriptor. */ void set_nonblock(int fd) { fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0)|O_NONBLOCK); }