]> git.saurik.com Git - redis.git/blame - src/rio.c
BSD license added to every C source and header file.
[redis.git] / src / rio.c
CommitLineData
5a181d43 1/* rio.c is a simple stream-oriented I/O abstraction that provides an interface
2 * to write code that can consume/produce data using different concrete input
4365e5b2 3 * and output devices. For instance the same rdb.c code using the rio
4 * abstraction can be used to read and write the RDB format using in-memory
5 * buffers or files.
5a181d43 6 *
7 * A rio object provides the following methods:
8 * read: read from stream.
9 * write: write to stream.
10 * tell: get the current offset.
11 *
12 * It is also possible to set a 'checksum' method that is used by rio.c in order
13 * to compute a checksum of the data written or read, or to query the rio object
4365e5b2 14 * for the current checksum.
15 *
16 * ----------------------------------------------------------------------------
17 *
18 * Copyright (c) 2009-2012, Pieter Noordhuis <pcnoordhuis at gmail dot com>
19 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are met:
24 *
25 * * Redistributions of source code must retain the above copyright notice,
26 * this list of conditions and the following disclaimer.
27 * * Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * * Neither the name of Redis nor the names of its contributors may be used
31 * to endorse or promote products derived from this software without
32 * specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
35 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
38 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44 * POSSIBILITY OF SUCH DAMAGE.
45 */
46
5a181d43 47
f013f400 48#include "fmacros.h"
2e4b0e77 49#include <string.h>
f013f400 50#include <stdio.h>
2e4b0e77
PN
51#include "rio.h"
52#include "util.h"
53
8491f1d9 54uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l);
55
2e4b0e77
PN
56/* Returns 1 or 0 for success/failure. */
57static size_t rioBufferWrite(rio *r, const void *buf, size_t len) {
58 r->io.buffer.ptr = sdscatlen(r->io.buffer.ptr,(char*)buf,len);
59 r->io.buffer.pos += len;
69cecb51 60 return 1;
2e4b0e77
PN
61}
62
63/* Returns 1 or 0 for success/failure. */
64static size_t rioBufferRead(rio *r, void *buf, size_t len) {
65 if (sdslen(r->io.buffer.ptr)-r->io.buffer.pos < len)
69cecb51 66 return 0; /* not enough buffer to return len bytes. */
2e4b0e77
PN
67 memcpy(buf,r->io.buffer.ptr+r->io.buffer.pos,len);
68 r->io.buffer.pos += len;
69 return 1;
70}
71
72/* Returns read/write position in buffer. */
73static off_t rioBufferTell(rio *r) {
74 return r->io.buffer.pos;
75}
76
77/* Returns 1 or 0 for success/failure. */
78static size_t rioFileWrite(rio *r, const void *buf, size_t len) {
79 return fwrite(buf,len,1,r->io.file.fp);
80}
81
82/* Returns 1 or 0 for success/failure. */
83static size_t rioFileRead(rio *r, void *buf, size_t len) {
84 return fread(buf,len,1,r->io.file.fp);
85}
86
87/* Returns read/write position in file. */
88static off_t rioFileTell(rio *r) {
89 return ftello(r->io.file.fp);
90}
91
92static const rio rioBufferIO = {
93 rioBufferRead,
94 rioBufferWrite,
95 rioBufferTell,
736b7c3f 96 NULL, /* update_checksum */
97 0, /* current checksum */
2e4b0e77
PN
98 { { NULL, 0 } } /* union for io-specific vars */
99};
100
101static const rio rioFileIO = {
102 rioFileRead,
103 rioFileWrite,
104 rioFileTell,
736b7c3f 105 NULL, /* update_checksum */
106 0, /* current checksum */
2e4b0e77
PN
107 { { NULL, 0 } } /* union for io-specific vars */
108};
109
f96a8a80 110void rioInitWithFile(rio *r, FILE *fp) {
111 *r = rioFileIO;
112 r->io.file.fp = fp;
2e4b0e77 113}
f96a8a80 114
115void rioInitWithBuffer(rio *r, sds s) {
116 *r = rioBufferIO;
117 r->io.buffer.ptr = s;
118 r->io.buffer.pos = 0;
2e4b0e77
PN
119}
120
736b7c3f 121/* This function can be installed both in memory and file streams when checksum
122 * computation is needed. */
123void rioGenericUpdateChecksum(rio *r, const void *buf, size_t len) {
8491f1d9 124 r->cksum = crc64(r->cksum,buf,len);
736b7c3f 125}
126
5a181d43 127/* ------------------------------ Higher level interface ---------------------------
128 * The following higher level functions use lower level rio.c functions to help
129 * generating the Redis protocol for the Append Only File. */
130
2e4b0e77
PN
131/* Write multi bulk count in the format: "*<count>\r\n". */
132size_t rioWriteBulkCount(rio *r, char prefix, int count) {
133 char cbuf[128];
134 int clen;
135
136 cbuf[0] = prefix;
137 clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,count);
138 cbuf[clen++] = '\r';
139 cbuf[clen++] = '\n';
140 if (rioWrite(r,cbuf,clen) == 0) return 0;
141 return clen;
142}
143
144/* Write binary-safe string in the format: "$<count>\r\n<payload>\r\n". */
145size_t rioWriteBulkString(rio *r, const char *buf, size_t len) {
146 size_t nwritten;
147
148 if ((nwritten = rioWriteBulkCount(r,'$',len)) == 0) return 0;
149 if (len > 0 && rioWrite(r,buf,len) == 0) return 0;
150 if (rioWrite(r,"\r\n",2) == 0) return 0;
151 return nwritten+len+2;
152}
153
154/* Write a long long value in format: "$<count>\r\n<payload>\r\n". */
155size_t rioWriteBulkLongLong(rio *r, long long l) {
156 char lbuf[32];
157 unsigned int llen;
158
159 llen = ll2string(lbuf,sizeof(lbuf),l);
160 return rioWriteBulkString(r,lbuf,llen);
161}
162
163/* Write a double value in the format: "$<count>\r\n<payload>\r\n" */
164size_t rioWriteBulkDouble(rio *r, double d) {
165 char dbuf[128];
166 unsigned int dlen;
167
168 dlen = snprintf(dbuf,sizeof(dbuf),"%.17g",d);
169 return rioWriteBulkString(r,dbuf,dlen);
170}