2 * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/types.h>
47 * Simple stream API to make my life easier. If the fgetln() and
48 * funopen() functions were standard and if funopen() wasn't using
49 * wrong types for the function pointers, I could have just used
50 * stdio, but life sucks.
52 * For now, streams are always block-buffered.
56 * Try to quiet warnings as much as possible with GCC while staying
57 * compatible with other compilers.
60 #if defined(__GNUC__) && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7)
61 #define __unused __attribute__((__unused__))
68 * Flags passed to the flush methods.
70 * STREAM_FLUSH_CLOSING is passed during the last flush call before
71 * closing a stream. This allows the zlib filter to emit the EOF
72 * marker as appropriate. In all other cases, STREAM_FLUSH_NORMAL
75 * These flags are completely unused in the default flush method,
76 * but they are very important for the flush method of the zlib
85 * This is because buf_new() will always allocate size + 1 bytes,
86 * so our buffer sizes will still be power of 2 values.
88 #define STREAM_BUFSIZ 1023
103 stream_readfn_t *readfn;
104 stream_writefn_t *writefn;
105 stream_closefn_t *closefn;
107 struct stream_filter *filter;
111 typedef int stream_filter_initfn_t(struct stream *, void *);
112 typedef void stream_filter_finifn_t(struct stream *);
113 typedef int stream_filter_flushfn_t(struct stream *, struct buf *,
115 typedef ssize_t stream_filter_fillfn_t(struct stream *, struct buf *);
117 struct stream_filter {
119 stream_filter_initfn_t *initfn;
120 stream_filter_finifn_t *finifn;
121 stream_filter_fillfn_t *fillfn;
122 stream_filter_flushfn_t *flushfn;
125 /* Low-level buffer API. */
126 #define buf_avail(buf) ((buf)->size - (buf)->off - (buf)->in)
127 #define buf_count(buf) ((buf)->in)
128 #define buf_size(buf) ((buf)->size)
130 static void buf_more(struct buf *, size_t);
131 static void buf_less(struct buf *, size_t);
132 static void buf_grow(struct buf *, size_t);
134 /* Internal stream functions. */
135 static ssize_t stream_fill(struct stream *);
136 static ssize_t stream_fill_default(struct stream *, struct buf *);
137 static int stream_flush_int(struct stream *, stream_flush_t);
138 static int stream_flush_default(struct stream *, struct buf *,
141 /* Filters specific functions. */
142 static struct stream_filter *stream_filter_lookup(stream_filter_t);
143 static int stream_filter_init(struct stream *, void *);
144 static void stream_filter_fini(struct stream *);
146 /* The zlib stream filter declarations. */
147 #define ZFILTER_EOF 1 /* Got Z_STREAM_END. */
157 static int zfilter_init(struct stream *, void *);
158 static void zfilter_fini(struct stream *);
159 static ssize_t zfilter_fill(struct stream *, struct buf *);
160 static int zfilter_flush(struct stream *, struct buf *,
163 /* The MD5 stream filter. */
175 static int md5filter_init(struct stream *, void *);
176 static void md5filter_fini(struct stream *);
177 static ssize_t md5filter_fill(struct stream *, struct buf *);
178 static int md5filter_flush(struct stream *, struct buf *,
180 static int md5rcsfilter_flush(struct stream *, struct buf *,
183 /* The available stream filters. */
184 struct stream_filter stream_filters[] = {
207 STREAM_FILTER_MD5RCS,
217 /* Create a new buffer. */
223 buf = xmalloc(sizeof(struct buf));
225 * We keep one spare byte so that stream_getln() can put a '\0'
226 * there in case the stream doesn't have an ending newline.
228 buf->buf = xmalloc(size + 1);
229 memset(buf->buf, 0, size + 1);
237 * Grow the size of the buffer. If "need" is 0, bump its size to the
238 * next power of 2 value. Otherwise, bump it to the next power of 2
239 * value bigger than "need".
242 buf_grow(struct buf *buf, size_t need)
246 buf->size = buf->size * 2 + 1; /* Account for the spare byte. */
248 assert(need > buf->size);
249 while (buf->size < need)
250 buf->size = buf->size * 2 + 1;
252 buf->buf = xrealloc(buf->buf, buf->size + 1);
255 /* Make more room in the buffer if needed. */
257 buf_prewrite(struct buf *buf)
260 if (buf_count(buf) == buf_size(buf))
262 if (buf_count(buf) > 0 && buf_avail(buf) == 0) {
263 memmove(buf->buf, buf->buf + buf->off, buf_count(buf));
268 /* Account for "n" bytes being added in the buffer. */
270 buf_more(struct buf *buf, size_t n)
273 assert(n <= buf_avail(buf));
277 /* Account for "n" bytes having been read in the buffer. */
279 buf_less(struct buf *buf, size_t n)
282 assert(n <= buf_count(buf));
292 buf_free(struct buf *buf)
299 static struct stream *
300 stream_new(stream_readfn_t *readfn, stream_writefn_t *writefn,
301 stream_closefn_t *closefn)
303 struct stream *stream;
305 stream = xmalloc(sizeof(struct stream));
306 if (readfn == NULL && writefn == NULL) {
311 stream->rdbuf = buf_new(STREAM_BUFSIZ);
313 stream->rdbuf = NULL;
315 stream->wrbuf = buf_new(STREAM_BUFSIZ);
317 stream->wrbuf = NULL;
318 stream->cookie = NULL;
321 stream->readfn = readfn;
322 stream->writefn = writefn;
323 stream->closefn = closefn;
324 stream->filter = stream_filter_lookup(STREAM_FILTER_NULL);
325 stream->fdata = NULL;
330 /* Create a new stream associated with a void *. */
332 stream_open(void *cookie, stream_readfn_t *readfn, stream_writefn_t *writefn,
333 stream_closefn_t *closefn)
335 struct stream *stream;
337 stream = stream_new(readfn, writefn, closefn);
338 stream->cookie = cookie;
342 /* Associate a file descriptor with a stream. */
344 stream_open_fd(int fd, stream_readfn_t *readfn, stream_writefn_t *writefn,
345 stream_closefn_t *closefn)
347 struct stream *stream;
349 stream = stream_new(readfn, writefn, closefn);
350 stream->cookie = &stream->fd;
355 /* Associate a buf with a stream. */
357 stream_open_buf(struct buf *b)
359 struct stream *stream;
361 stream = stream_new(stream_read_buf, stream_append_buf, stream_close_buf);
369 * Truncate a buffer, just decrease offset pointer.
370 * XXX: this can be dangerous if not used correctly.
373 stream_truncate_buf(struct buf *b, off_t off)
378 /* Like open() but returns a stream. */
380 stream_open_file(const char *path, int flags, ...)
382 struct stream *stream;
383 stream_readfn_t *readfn;
384 stream_writefn_t *writefn;
390 if (flags & O_CREAT) {
392 * GCC says I should not be using mode_t here since it's
393 * promoted to an int when passed through `...'.
395 mode = va_arg(ap, int);
396 fd = open(path, flags, mode);
398 fd = open(path, flags);
404 if (flags == O_RDONLY) {
405 readfn = stream_read_fd;
407 } else if (flags == O_WRONLY) {
409 writefn = stream_write_fd;
410 } else if (flags == O_RDWR) {
411 assert(flags == O_RDWR);
412 readfn = stream_read_fd;
413 writefn = stream_write_fd;
420 stream = stream_open_fd(fd, readfn, writefn, stream_close_fd);
426 /* Return the file descriptor associated with this stream, or -1. */
428 stream_fileno(struct stream *stream)
434 /* Convenience read function for character buffers. */
436 stream_read_buf(void *cookie, void *buf, size_t size)
441 /* Use in to be read offset. */
442 b = (struct buf *)cookie;
443 /* Just return what we have if the request is to large. */
444 avail = b->off - b->in;
446 memcpy(buf, (b->buf + b->in), avail);
450 memcpy(buf, (b->buf + b->in), size);
455 /* Convenience write function for appending character buffers. */
457 stream_append_buf(void *cookie, const void *buf, size_t size)
462 /* Use off to be write offset. */
463 b = (struct buf *)cookie;
465 avail = b->size - b->off;
467 buf_grow(b, b->size + size);
468 memcpy((b->buf + b->off), buf, size);
470 b->buf[b->off] = '\0';
474 /* Convenience close function for freeing character buffers. */
476 stream_close_buf(void *cookie)
481 /* Basically a NOP. */
485 /* Convenience read function for file descriptors. */
487 stream_read_fd(void *cookie, void *buf, size_t size)
493 nbytes = read(fd, buf, size);
497 /* Convenience write function for file descriptors. */
499 stream_write_fd(void *cookie, const void *buf, size_t size)
505 nbytes = write(fd, buf, size);
509 /* Convenience close function for file descriptors. */
511 stream_close_fd(void *cookie)
520 /* Read some bytes from the stream. */
522 stream_read(struct stream *stream, void *buf, size_t size)
528 rdbuf = stream->rdbuf;
529 if (buf_count(rdbuf) == 0) {
530 ret = stream_fill(stream);
534 n = min(size, buf_count(rdbuf));
535 memcpy(buf, rdbuf->buf + rdbuf->off, n);
540 /* A blocking stream_read call. */
542 stream_read_blocking(struct stream *stream, void *buf, size_t size)
548 rdbuf = stream->rdbuf;
549 while (buf_count(rdbuf) <= size) {
550 ret = stream_fill(stream);
554 /* XXX: Should be at least size bytes in the buffer, right? */
555 /* Just do this to make sure. */
556 n = min(size, buf_count(rdbuf));
557 memcpy(buf, rdbuf->buf + rdbuf->off, n);
563 * Read a line from the stream and return a pointer to it.
565 * If "len" is non-NULL, the length of the string will be put into it.
566 * The pointer is only valid until the next stream API call. The line
567 * can be modified by the caller, provided he doesn't write before or
570 * This is somewhat similar to the BSD fgetln() function, except that
571 * "len" can be NULL here. In that case the string is terminated by
572 * overwriting the '\n' character with a NUL character. If it's the
573 * last line in the stream and it has no ending newline, we can still
574 * add '\0' after it, because we keep one spare byte in the buffers.
576 * However, be warned that one can't handle binary lines properly
577 * without knowing the size of the string since those can contain
581 stream_getln(struct stream *stream, size_t *len)
589 if (buf_count(buf) == 0) {
590 n = stream_fill(stream);
594 cp = memchr(buf->buf + buf->off, '\n', buf_count(buf));
595 for (done = buf_count(buf); cp == NULL; done += n) {
596 n = stream_fill(stream);
600 /* Last line of the stream. */
601 cp = buf->buf + buf->off + buf->in - 1;
603 cp = memchr(buf->buf + buf->off + done, '\n',
604 buf_count(buf) - done);
606 line = buf->buf + buf->off;
608 size = cp - line + 1;
613 /* Terminate the string when len == NULL. */
614 if (line[size - 1] == '\n')
615 line[size - 1] = '\0';
622 /* Write some bytes to a stream. */
624 stream_write(struct stream *stream, const void *src, size_t nbytes)
630 if (nbytes > buf_size(buf))
631 buf_grow(buf, nbytes);
632 if (nbytes > buf_avail(buf)) {
633 error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
637 memcpy(buf->buf + buf->off + buf->in, src, nbytes);
638 buf_more(buf, nbytes);
642 /* Formatted output to a stream. */
644 stream_printf(struct stream *stream, const char *fmt, ...)
653 ret = vsnprintf(buf->buf + buf->off + buf->in, buf_avail(buf), fmt, ap);
657 if ((unsigned)ret >= buf_avail(buf)) {
658 if ((unsigned)ret >= buf_size(buf))
659 buf_grow(buf, ret + 1);
660 if ((unsigned)ret >= buf_avail(buf)) {
661 error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
671 /* Flush the entire write buffer of the stream. */
673 stream_flush(struct stream *stream)
677 error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
681 /* Internal flush API. */
683 stream_flush_int(struct stream *stream, stream_flush_t how)
689 error = (*stream->filter->flushfn)(stream, buf, how);
690 assert(buf_count(buf) == 0);
694 /* The default flush method. */
696 stream_flush_default(struct stream *stream, struct buf *buf,
697 stream_flush_t __unused how)
701 while (buf_count(buf) > 0) {
703 n = (*stream->writefn)(stream->cookie,
704 buf->buf + buf->off, buf_count(buf));
705 } while (n == -1 && errno == EINTR);
713 /* Flush the write buffer and call fsync() on the file descriptor. */
715 stream_sync(struct stream *stream)
719 if (stream->fd == -1) {
723 error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
726 error = fsync(stream->fd);
730 /* Like truncate() but on a stream. */
732 stream_truncate(struct stream *stream, off_t size)
736 if (stream->fd == -1) {
740 error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
743 error = ftruncate(stream->fd, size);
747 /* Like stream_truncate() except the off_t parameter is an offset. */
749 stream_truncate_rel(struct stream *stream, off_t off)
755 stream_truncate_buf(stream->cookie, off);
758 if (stream->fd == -1) {
762 error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
765 error = fstat(stream->fd, &sb);
768 error = stream_truncate(stream, sb.st_size + off);
772 /* Rewind the stream. */
774 stream_rewind(struct stream *stream)
778 if (stream->fd == -1) {
782 if (stream->rdbuf != NULL)
783 buf_less(stream->rdbuf, buf_count(stream->rdbuf));
784 if (stream->wrbuf != NULL) {
785 error = stream_flush_int(stream, STREAM_FLUSH_NORMAL);
789 error = lseek(stream->fd, 0, SEEK_SET);
793 /* Return EOF status. */
795 stream_eof(struct stream *stream)
798 return (stream->eof);
801 /* Close a stream and free any resources held by it. */
803 stream_close(struct stream *stream)
811 if (stream->wrbuf != NULL)
812 error = stream_flush_int(stream, STREAM_FLUSH_CLOSING);
813 stream_filter_fini(stream);
814 if (stream->closefn != NULL)
816 * We might overwrite a previous error from stream_flush(),
817 * but we have no choice, because wether it had worked or
818 * not, we need to close the file descriptor.
820 error = (*stream->closefn)(stream->cookie);
821 if (stream->rdbuf != NULL)
822 buf_free(stream->rdbuf);
823 if (stream->wrbuf != NULL)
824 buf_free(stream->wrbuf);
829 /* The default fill method. */
831 stream_fill_default(struct stream *stream, struct buf *buf)
837 assert(buf_avail(buf) > 0);
838 n = (*stream->readfn)(stream->cookie, buf->buf + buf->off + buf->in,
851 * Refill the read buffer. This function is not permitted to return
852 * without having made more bytes available, unless there was an error.
853 * Moreover, stream_fill() returns the number of bytes added.
856 stream_fill(struct stream *stream)
858 struct stream_filter *filter;
865 filter = stream->filter;
869 oldcount = buf_count(buf);
871 n = (*filter->fillfn)(stream, buf);
872 assert((n > 0 && n == (signed)(buf_count(buf) - oldcount)) ||
873 (n <= 0 && buf_count(buf) == oldcount));
878 * Lookup a stream filter.
880 * We are not supposed to get passed an invalid filter id, since
881 * filter ids are an enum type and we don't have invalid filter
882 * ids in the enum :-). Thus, we are not checking for out of
883 * bounds access here. If it happens, it's the caller's fault
886 static struct stream_filter *
887 stream_filter_lookup(stream_filter_t id)
889 struct stream_filter *filter;
891 filter = stream_filters;
892 while (filter->id != id)
898 stream_filter_init(struct stream *stream, void *data)
900 struct stream_filter *filter;
903 filter = stream->filter;
904 if (filter->initfn == NULL)
906 error = (*filter->initfn)(stream, data);
911 stream_filter_fini(struct stream *stream)
913 struct stream_filter *filter;
915 filter = stream->filter;
916 if (filter->finifn != NULL)
917 (*filter->finifn)(stream);
921 * Start a filter on a stream.
924 stream_filter_start(struct stream *stream, stream_filter_t id, void *data)
926 struct stream_filter *filter;
929 filter = stream->filter;
930 if (id == filter->id)
932 stream_filter_fini(stream);
933 stream->filter = stream_filter_lookup(id);
934 stream->fdata = NULL;
935 error = stream_filter_init(stream, data);
940 /* Stop a filter, this is equivalent to setting the null filter. */
942 stream_filter_stop(struct stream *stream)
945 stream_filter_start(stream, STREAM_FILTER_NULL, NULL);
948 /* The zlib stream filter implementation. */
950 /* Take no chances with zlib... */
952 zfilter_alloc(void __unused *opaque, unsigned int items, unsigned int size)
955 return (xmalloc(items * size));
959 zfilter_free(void __unused *opaque, void *ptr)
966 zfilter_init(struct stream *stream, void __unused *data)
973 zf = xmalloc(sizeof(struct zfilter));
974 memset(zf, 0, sizeof(struct zfilter));
975 if (stream->rdbuf != NULL) {
976 state = xmalloc(sizeof(z_stream));
977 state->zalloc = zfilter_alloc;
978 state->zfree = zfilter_free;
979 state->opaque = Z_NULL;
980 rv = inflateInit(state);
982 errx(1, "inflateInit: %s", state->msg);
983 buf = buf_new(buf_size(stream->rdbuf));
984 zf->rdbuf = stream->rdbuf;
988 if (stream->wrbuf != NULL) {
989 state = xmalloc(sizeof(z_stream));
990 state->zalloc = zfilter_alloc;
991 state->zfree = zfilter_free;
992 state->opaque = Z_NULL;
993 rv = deflateInit(state, Z_DEFAULT_COMPRESSION);
995 errx(1, "deflateInit: %s", state->msg);
996 buf = buf_new(buf_size(stream->wrbuf));
997 zf->wrbuf = stream->wrbuf;
1006 zfilter_fini(struct stream *stream)
1014 if (zf->rdbuf != NULL) {
1015 state = zf->rdstate;
1018 * Even if it has produced all the bytes, zlib sometimes
1019 * hasn't seen the EOF marker, so we need to call inflate()
1020 * again to make sure we have eaten all the zlib'ed bytes.
1022 if ((zf->flags & ZFILTER_EOF) == 0) {
1023 n = zfilter_fill(stream, stream->rdbuf);
1024 assert(n == 0 && zf->flags & ZFILTER_EOF);
1028 buf_free(stream->rdbuf);
1029 stream->rdbuf = zbuf;
1031 if (zf->wrbuf != NULL) {
1032 state = zf->wrstate;
1035 * Compress the remaining bytes in the buffer, if any,
1036 * and emit an EOF marker as appropriate. We ignore
1037 * the error because we can't do anything about it at
1038 * this point, and it can happen if we're getting
1041 (void)zfilter_flush(stream, stream->wrbuf,
1042 STREAM_FLUSH_CLOSING);
1045 buf_free(stream->wrbuf);
1046 stream->wrbuf = zbuf;
1052 zfilter_flush(struct stream *stream, struct buf *buf, stream_flush_t how)
1057 size_t lastin, lastout, ate, prod;
1058 int done, error, flags, rv;
1061 state = zf->wrstate;
1064 if (how == STREAM_FLUSH_NORMAL)
1065 flags = Z_SYNC_FLUSH;
1074 * According to zlib.h, we should have at least 6 bytes
1075 * available when using deflate() with Z_SYNC_FLUSH.
1077 if ((buf_avail(zbuf) < 6 && flags == Z_SYNC_FLUSH) ||
1078 rv == Z_BUF_ERROR || buf_avail(buf) == 0) {
1079 error = stream_flush_default(stream, zbuf, how);
1084 state->next_in = (Bytef *)(buf->buf + buf->off);
1085 state->avail_in = buf_count(buf);
1086 state->next_out = (Bytef *)(zbuf->buf + zbuf->off + zbuf->in);
1087 state->avail_out = buf_avail(zbuf);
1088 lastin = state->avail_in;
1089 lastout = state->avail_out;
1090 rv = deflate(state, flags);
1091 if (rv != Z_BUF_ERROR && rv != Z_OK && rv != Z_STREAM_END)
1092 errx(1, "deflate: %s", state->msg);
1093 ate = lastin - state->avail_in;
1094 prod = lastout - state->avail_out;
1096 buf_more(zbuf, prod);
1097 if ((flags == Z_SYNC_FLUSH && buf_count(buf) > 0) ||
1098 (flags == Z_FINISH && rv != Z_STREAM_END) ||
1099 (rv == Z_BUF_ERROR))
1102 assert(rv == Z_OK || (rv == Z_STREAM_END && flags == Z_FINISH));
1103 error = stream_flush_default(stream, zbuf, how);
1108 zfilter_fill(struct stream *stream, struct buf *buf)
1113 size_t lastin, lastout, new;
1118 state = zf->rdstate;
1121 assert(buf_avail(buf) > 0);
1122 if (buf_count(zbuf) == 0) {
1123 n = stream_fill_default(stream, zbuf);
1128 assert(buf_count(zbuf) > 0);
1129 state->next_in = (Bytef *)(zbuf->buf + zbuf->off);
1130 state->avail_in = buf_count(zbuf);
1131 state->next_out = (Bytef *)(buf->buf + buf->off + buf->in);
1132 state->avail_out = buf_avail(buf);
1133 lastin = state->avail_in;
1134 lastout = state->avail_out;
1135 rv = inflate(state, Z_SYNC_FLUSH);
1136 buf_less(zbuf, lastin - state->avail_in);
1137 new = lastout - state->avail_out;
1138 if (new == 0 && rv != Z_STREAM_END) {
1139 n = stream_fill_default(stream, zbuf);
1146 if (rv != Z_STREAM_END && rv != Z_OK)
1147 errx(1, "inflate: %s", state->msg);
1148 if (rv == Z_STREAM_END)
1149 zf->flags |= ZFILTER_EOF;
1154 /* The MD5 stream filter implementation. */
1156 md5filter_init(struct stream *stream, void *data)
1158 struct md5filter *mf;
1160 mf = xmalloc(sizeof(struct md5filter));
1170 md5filter_fini(struct stream *stream)
1172 struct md5filter *mf;
1175 MD5_End(mf->md5, &mf->ctx);
1176 free(stream->fdata);
1180 md5filter_fill(struct stream *stream, struct buf *buf)
1184 assert(buf_avail(buf) > 0);
1185 n = stream_fill_default(stream, buf);
1190 md5filter_flush(struct stream *stream, struct buf *buf, stream_flush_t how)
1192 struct md5filter *mf;
1196 MD5_Update(&mf->ctx, buf->buf + buf->off, buf->in);
1197 error = stream_flush_default(stream, buf, how);
1201 /* MD5 flush for RCS, where whitespaces are omitted. */
1203 md5rcsfilter_flush(struct stream *stream, struct buf *buf, stream_flush_t how)
1205 struct md5filter *mf;
1214 ptr = buf->buf + buf->off;
1215 end = buf->buf + buf->off + buf->in;
1217 #define IS_WS(var) ((var) == ' ' || (var) == '\n' || (var) == '\t' || \
1218 (var) == '\010' || (var) == '\013' || (var) == '\f' || \
1221 #define IS_SPECIAL(var) ((var) == '$' || (var) == ',' || (var) == ':' || \
1222 (var) == ';' || (var) == '@')
1224 #define IS_PRINT(var) (!IS_WS(var) && (var) != '@')
1226 /* XXX: We can do better than this state machine. */
1228 switch (mf->state) {
1229 /* Outside RCS statements. */
1232 while (ptr < end && IS_PRINT(*ptr)) {
1236 MD5_Update(&mf->ctx, start, (ptr - start));
1239 MD5_Update(&mf->ctx, ptr, 1);
1248 while (ptr < end && IS_WS(*ptr)) {
1253 if (mf->lastc == '@') {
1254 MD5_Update(&mf->ctx,
1257 MD5_Update(&mf->ctx, ptr, 1);
1261 if (!IS_SPECIAL(*ptr) &&
1262 !IS_SPECIAL(mf->lastc)) {
1263 MD5_Update(&mf->ctx,
1272 while (ptr < end && *ptr != '@') {
1275 MD5_Update(&mf->ctx, start, (ptr - start));
1277 MD5_Update(&mf->ctx, ptr, 1);
1284 MD5_Update(&mf->ctx, ptr, 1);
1287 } else if(IS_WS(*ptr)) {
1295 err(1, "Invalid state");
1300 error = stream_flush_default(stream, buf, how);