]>
git.saurik.com Git - redis.git/blob - src/rio.c
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
3 * and output devices. For instance the same rdb.c code using the rio abstraction
4 * can be used to read and write the RDB format using in-memory buffers or files.
6 * A rio object provides the following methods:
7 * read: read from stream.
8 * write: write to stream.
9 * tell: get the current offset.
11 * It is also possible to set a 'checksum' method that is used by rio.c in order
12 * to compute a checksum of the data written or read, or to query the rio object
13 * for the current checksum. */
21 /* Returns 1 or 0 for success/failure. */
22 static size_t rioBufferWrite(rio
*r
, const void *buf
, size_t len
) {
23 r
->io
.buffer
.ptr
= sdscatlen(r
->io
.buffer
.ptr
,(char*)buf
,len
);
24 r
->io
.buffer
.pos
+= len
;
28 /* Returns 1 or 0 for success/failure. */
29 static size_t rioBufferRead(rio
*r
, void *buf
, size_t len
) {
30 if (sdslen(r
->io
.buffer
.ptr
)-r
->io
.buffer
.pos
< len
)
31 return 0; /* not enough buffer to return len bytes. */
32 memcpy(buf
,r
->io
.buffer
.ptr
+r
->io
.buffer
.pos
,len
);
33 r
->io
.buffer
.pos
+= len
;
37 /* Returns read/write position in buffer. */
38 static off_t
rioBufferTell(rio
*r
) {
39 return r
->io
.buffer
.pos
;
42 /* Returns 1 or 0 for success/failure. */
43 static size_t rioFileWrite(rio
*r
, const void *buf
, size_t len
) {
44 return fwrite(buf
,len
,1,r
->io
.file
.fp
);
47 /* Returns 1 or 0 for success/failure. */
48 static size_t rioFileRead(rio
*r
, void *buf
, size_t len
) {
49 return fread(buf
,len
,1,r
->io
.file
.fp
);
52 /* Returns read/write position in file. */
53 static off_t
rioFileTell(rio
*r
) {
54 return ftello(r
->io
.file
.fp
);
57 static const rio rioBufferIO
= {
61 NULL
, /* update_checksum */
62 0, /* current checksum */
63 { { NULL
, 0 } } /* union for io-specific vars */
66 static const rio rioFileIO
= {
70 NULL
, /* update_checksum */
71 0, /* current checksum */
72 { { NULL
, 0 } } /* union for io-specific vars */
75 void rioInitWithFile(rio
*r
, FILE *fp
) {
80 void rioInitWithBuffer(rio
*r
, sds s
) {
86 /* This function can be installed both in memory and file streams when checksum
87 * computation is needed. */
88 void rioGenericUpdateChecksum(rio
*r
, const void *buf
, size_t len
) {
89 r
->checksum
= crc64(r
->checksum
,buf
,len
);
92 /* ------------------------------ Higher level interface ---------------------------
93 * The following higher level functions use lower level rio.c functions to help
94 * generating the Redis protocol for the Append Only File. */
96 /* Write multi bulk count in the format: "*<count>\r\n". */
97 size_t rioWriteBulkCount(rio
*r
, char prefix
, int count
) {
102 clen
= 1+ll2string(cbuf
+1,sizeof(cbuf
)-1,count
);
105 if (rioWrite(r
,cbuf
,clen
) == 0) return 0;
109 /* Write binary-safe string in the format: "$<count>\r\n<payload>\r\n". */
110 size_t rioWriteBulkString(rio
*r
, const char *buf
, size_t len
) {
113 if ((nwritten
= rioWriteBulkCount(r
,'$',len
)) == 0) return 0;
114 if (len
> 0 && rioWrite(r
,buf
,len
) == 0) return 0;
115 if (rioWrite(r
,"\r\n",2) == 0) return 0;
116 return nwritten
+len
+2;
119 /* Write a long long value in format: "$<count>\r\n<payload>\r\n". */
120 size_t rioWriteBulkLongLong(rio
*r
, long long l
) {
124 llen
= ll2string(lbuf
,sizeof(lbuf
),l
);
125 return rioWriteBulkString(r
,lbuf
,llen
);
128 /* Write a double value in the format: "$<count>\r\n<payload>\r\n" */
129 size_t rioWriteBulkDouble(rio
*r
, double d
) {
133 dlen
= snprintf(dbuf
,sizeof(dbuf
),"%.17g",d
);
134 return rioWriteBulkString(r
,dbuf
,dlen
);