Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
886a04c2
Commit
886a04c2
authored
Feb 14, 2022
by
Yossi Gottlieb
Browse files
Merge commit '
418de21d
' into refresh-hiredis
parents
e6478cfd
418de21d
Changes
31
Show whitespace changes
Inline
Side-by-side
deps/hiredis/hiredis.c
View file @
886a04c2
...
@@ -96,6 +96,8 @@ void freeReplyObject(void *reply) {
...
@@ -96,6 +96,8 @@ void freeReplyObject(void *reply) {
switch
(
r
->
type
)
{
switch
(
r
->
type
)
{
case
REDIS_REPLY_INTEGER
:
case
REDIS_REPLY_INTEGER
:
case
REDIS_REPLY_NIL
:
case
REDIS_REPLY_BOOL
:
break
;
/* Nothing to free */
break
;
/* Nothing to free */
case
REDIS_REPLY_ARRAY
:
case
REDIS_REPLY_ARRAY
:
case
REDIS_REPLY_MAP
:
case
REDIS_REPLY_MAP
:
...
@@ -112,6 +114,7 @@ void freeReplyObject(void *reply) {
...
@@ -112,6 +114,7 @@ void freeReplyObject(void *reply) {
case
REDIS_REPLY_STRING
:
case
REDIS_REPLY_STRING
:
case
REDIS_REPLY_DOUBLE
:
case
REDIS_REPLY_DOUBLE
:
case
REDIS_REPLY_VERB
:
case
REDIS_REPLY_VERB
:
case
REDIS_REPLY_BIGNUM
:
hi_free
(
r
->
str
);
hi_free
(
r
->
str
);
break
;
break
;
}
}
...
@@ -129,7 +132,8 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
...
@@ -129,7 +132,8 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
assert
(
task
->
type
==
REDIS_REPLY_ERROR
||
assert
(
task
->
type
==
REDIS_REPLY_ERROR
||
task
->
type
==
REDIS_REPLY_STATUS
||
task
->
type
==
REDIS_REPLY_STATUS
||
task
->
type
==
REDIS_REPLY_STRING
||
task
->
type
==
REDIS_REPLY_STRING
||
task
->
type
==
REDIS_REPLY_VERB
);
task
->
type
==
REDIS_REPLY_VERB
||
task
->
type
==
REDIS_REPLY_BIGNUM
);
/* Copy string value */
/* Copy string value */
if
(
task
->
type
==
REDIS_REPLY_VERB
)
{
if
(
task
->
type
==
REDIS_REPLY_VERB
)
{
...
@@ -235,12 +239,14 @@ static void *createDoubleObject(const redisReadTask *task, double value, char *s
...
@@ -235,12 +239,14 @@ static void *createDoubleObject(const redisReadTask *task, double value, char *s
* decimal string conversion artifacts. */
* decimal string conversion artifacts. */
memcpy
(
r
->
str
,
str
,
len
);
memcpy
(
r
->
str
,
str
,
len
);
r
->
str
[
len
]
=
'\0'
;
r
->
str
[
len
]
=
'\0'
;
r
->
len
=
len
;
if
(
task
->
parent
)
{
if
(
task
->
parent
)
{
parent
=
task
->
parent
->
obj
;
parent
=
task
->
parent
->
obj
;
assert
(
parent
->
type
==
REDIS_REPLY_ARRAY
||
assert
(
parent
->
type
==
REDIS_REPLY_ARRAY
||
parent
->
type
==
REDIS_REPLY_MAP
||
parent
->
type
==
REDIS_REPLY_MAP
||
parent
->
type
==
REDIS_REPLY_SET
);
parent
->
type
==
REDIS_REPLY_SET
||
parent
->
type
==
REDIS_REPLY_PUSH
);
parent
->
element
[
task
->
idx
]
=
r
;
parent
->
element
[
task
->
idx
]
=
r
;
}
}
return
r
;
return
r
;
...
@@ -277,7 +283,8 @@ static void *createBoolObject(const redisReadTask *task, int bval) {
...
@@ -277,7 +283,8 @@ static void *createBoolObject(const redisReadTask *task, int bval) {
parent
=
task
->
parent
->
obj
;
parent
=
task
->
parent
->
obj
;
assert
(
parent
->
type
==
REDIS_REPLY_ARRAY
||
assert
(
parent
->
type
==
REDIS_REPLY_ARRAY
||
parent
->
type
==
REDIS_REPLY_MAP
||
parent
->
type
==
REDIS_REPLY_MAP
||
parent
->
type
==
REDIS_REPLY_SET
);
parent
->
type
==
REDIS_REPLY_SET
||
parent
->
type
==
REDIS_REPLY_PUSH
);
parent
->
element
[
task
->
idx
]
=
r
;
parent
->
element
[
task
->
idx
]
=
r
;
}
}
return
r
;
return
r
;
...
@@ -306,7 +313,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
...
@@ -306,7 +313,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
const
char
*
c
=
format
;
const
char
*
c
=
format
;
char
*
cmd
=
NULL
;
/* final command */
char
*
cmd
=
NULL
;
/* final command */
int
pos
;
/* position in final command */
int
pos
;
/* position in final command */
hi
sds
curarg
,
newarg
;
/* current argument */
sds
curarg
,
newarg
;
/* current argument */
int
touched
=
0
;
/* was the current argument touched? */
int
touched
=
0
;
/* was the current argument touched? */
char
**
curargv
=
NULL
,
**
newargv
=
NULL
;
char
**
curargv
=
NULL
,
**
newargv
=
NULL
;
int
argc
=
0
;
int
argc
=
0
;
...
@@ -319,7 +326,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
...
@@ -319,7 +326,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
return
-
1
;
return
-
1
;
/* Build the command string accordingly to protocol */
/* Build the command string accordingly to protocol */
curarg
=
hi_
sdsempty
();
curarg
=
sdsempty
();
if
(
curarg
==
NULL
)
if
(
curarg
==
NULL
)
return
-
1
;
return
-
1
;
...
@@ -331,15 +338,15 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
...
@@ -331,15 +338,15 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
if
(
newargv
==
NULL
)
goto
memory_err
;
if
(
newargv
==
NULL
)
goto
memory_err
;
curargv
=
newargv
;
curargv
=
newargv
;
curargv
[
argc
++
]
=
curarg
;
curargv
[
argc
++
]
=
curarg
;
totlen
+=
bulklen
(
hi_
sdslen
(
curarg
));
totlen
+=
bulklen
(
sdslen
(
curarg
));
/* curarg is put in argv so it can be overwritten. */
/* curarg is put in argv so it can be overwritten. */
curarg
=
hi_
sdsempty
();
curarg
=
sdsempty
();
if
(
curarg
==
NULL
)
goto
memory_err
;
if
(
curarg
==
NULL
)
goto
memory_err
;
touched
=
0
;
touched
=
0
;
}
}
}
else
{
}
else
{
newarg
=
hi_
sdscatlen
(
curarg
,
c
,
1
);
newarg
=
sdscatlen
(
curarg
,
c
,
1
);
if
(
newarg
==
NULL
)
goto
memory_err
;
if
(
newarg
==
NULL
)
goto
memory_err
;
curarg
=
newarg
;
curarg
=
newarg
;
touched
=
1
;
touched
=
1
;
...
@@ -356,16 +363,16 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
...
@@ -356,16 +363,16 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
arg
=
va_arg
(
ap
,
char
*
);
arg
=
va_arg
(
ap
,
char
*
);
size
=
strlen
(
arg
);
size
=
strlen
(
arg
);
if
(
size
>
0
)
if
(
size
>
0
)
newarg
=
hi_
sdscatlen
(
curarg
,
arg
,
size
);
newarg
=
sdscatlen
(
curarg
,
arg
,
size
);
break
;
break
;
case
'b'
:
case
'b'
:
arg
=
va_arg
(
ap
,
char
*
);
arg
=
va_arg
(
ap
,
char
*
);
size
=
va_arg
(
ap
,
size_t
);
size
=
va_arg
(
ap
,
size_t
);
if
(
size
>
0
)
if
(
size
>
0
)
newarg
=
hi_
sdscatlen
(
curarg
,
arg
,
size
);
newarg
=
sdscatlen
(
curarg
,
arg
,
size
);
break
;
break
;
case
'%'
:
case
'%'
:
newarg
=
hi_
sdscat
(
curarg
,
"%"
);
newarg
=
sdscat
(
curarg
,
"%"
);
break
;
break
;
default:
default:
/* Try to detect printf format */
/* Try to detect printf format */
...
@@ -453,7 +460,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
...
@@ -453,7 +460,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
if
(
_l
<
sizeof
(
_format
)
-
2
)
{
if
(
_l
<
sizeof
(
_format
)
-
2
)
{
memcpy
(
_format
,
c
,
_l
);
memcpy
(
_format
,
c
,
_l
);
_format
[
_l
]
=
'\0'
;
_format
[
_l
]
=
'\0'
;
newarg
=
hi_
sdscatvprintf
(
curarg
,
_format
,
_cpy
);
newarg
=
sdscatvprintf
(
curarg
,
_format
,
_cpy
);
/* Update current position (note: outer blocks
/* Update current position (note: outer blocks
* increment c twice so compensate here) */
* increment c twice so compensate here) */
...
@@ -480,9 +487,9 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
...
@@ -480,9 +487,9 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
if
(
newargv
==
NULL
)
goto
memory_err
;
if
(
newargv
==
NULL
)
goto
memory_err
;
curargv
=
newargv
;
curargv
=
newargv
;
curargv
[
argc
++
]
=
curarg
;
curargv
[
argc
++
]
=
curarg
;
totlen
+=
bulklen
(
hi_
sdslen
(
curarg
));
totlen
+=
bulklen
(
sdslen
(
curarg
));
}
else
{
}
else
{
hi_
sdsfree
(
curarg
);
sdsfree
(
curarg
);
}
}
/* Clear curarg because it was put in curargv or was free'd. */
/* Clear curarg because it was put in curargv or was free'd. */
...
@@ -497,10 +504,10 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
...
@@ -497,10 +504,10 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
pos
=
sprintf
(
cmd
,
"*%d
\r\n
"
,
argc
);
pos
=
sprintf
(
cmd
,
"*%d
\r\n
"
,
argc
);
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
pos
+=
sprintf
(
cmd
+
pos
,
"$%zu
\r\n
"
,
hi_
sdslen
(
curargv
[
j
]));
pos
+=
sprintf
(
cmd
+
pos
,
"$%zu
\r\n
"
,
sdslen
(
curargv
[
j
]));
memcpy
(
cmd
+
pos
,
curargv
[
j
],
hi_
sdslen
(
curargv
[
j
]));
memcpy
(
cmd
+
pos
,
curargv
[
j
],
sdslen
(
curargv
[
j
]));
pos
+=
hi_
sdslen
(
curargv
[
j
]);
pos
+=
sdslen
(
curargv
[
j
]);
hi_
sdsfree
(
curargv
[
j
]);
sdsfree
(
curargv
[
j
]);
cmd
[
pos
++
]
=
'\r'
;
cmd
[
pos
++
]
=
'\r'
;
cmd
[
pos
++
]
=
'\n'
;
cmd
[
pos
++
]
=
'\n'
;
}
}
...
@@ -522,11 +529,11 @@ memory_err:
...
@@ -522,11 +529,11 @@ memory_err:
cleanup:
cleanup:
if
(
curargv
)
{
if
(
curargv
)
{
while
(
argc
--
)
while
(
argc
--
)
hi_
sdsfree
(
curargv
[
argc
]);
sdsfree
(
curargv
[
argc
]);
hi_free
(
curargv
);
hi_free
(
curargv
);
}
}
hi_
sdsfree
(
curarg
);
sdsfree
(
curarg
);
hi_free
(
cmd
);
hi_free
(
cmd
);
return
error_type
;
return
error_type
;
...
@@ -559,19 +566,18 @@ int redisFormatCommand(char **target, const char *format, ...) {
...
@@ -559,19 +566,18 @@ int redisFormatCommand(char **target, const char *format, ...) {
return
len
;
return
len
;
}
}
/* Format a command according to the Redis protocol using an
hi
sds string and
/* Format a command according to the Redis protocol using an sds string and
*
hi_
sdscatfmt for the processing of arguments. This function takes the
* sdscatfmt for the processing of arguments. This function takes the
* number of arguments, an array with arguments and an array with their
* number of arguments, an array with arguments and an array with their
* lengths. If the latter is set to NULL, strlen will be used to compute the
* lengths. If the latter is set to NULL, strlen will be used to compute the
* argument lengths.
* argument lengths.
*/
*/
int
redisFormatSdsCommandArgv
(
hi
sds
*
target
,
int
argc
,
const
char
**
argv
,
long
long
redisFormatSdsCommandArgv
(
sds
*
target
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
)
const
size_t
*
argvlen
)
{
{
hi
sds
cmd
,
aux
;
sds
cmd
,
aux
;
unsigned
long
long
totlen
;
unsigned
long
long
totlen
,
len
;
int
j
;
int
j
;
size_t
len
;
/* Abort on a NULL target */
/* Abort on a NULL target */
if
(
target
==
NULL
)
if
(
target
==
NULL
)
...
@@ -585,36 +591,36 @@ int redisFormatSdsCommandArgv(hisds *target, int argc, const char **argv,
...
@@ -585,36 +591,36 @@ int redisFormatSdsCommandArgv(hisds *target, int argc, const char **argv,
}
}
/* Use an SDS string for command construction */
/* Use an SDS string for command construction */
cmd
=
hi_
sdsempty
();
cmd
=
sdsempty
();
if
(
cmd
==
NULL
)
if
(
cmd
==
NULL
)
return
-
1
;
return
-
1
;
/* We already know how much storage we need */
/* We already know how much storage we need */
aux
=
hi_
sdsMakeRoomFor
(
cmd
,
totlen
);
aux
=
sdsMakeRoomFor
(
cmd
,
totlen
);
if
(
aux
==
NULL
)
{
if
(
aux
==
NULL
)
{
hi_
sdsfree
(
cmd
);
sdsfree
(
cmd
);
return
-
1
;
return
-
1
;
}
}
cmd
=
aux
;
cmd
=
aux
;
/* Construct command */
/* Construct command */
cmd
=
hi_
sdscatfmt
(
cmd
,
"*%i
\r\n
"
,
argc
);
cmd
=
sdscatfmt
(
cmd
,
"*%i
\r\n
"
,
argc
);
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
len
=
argvlen
?
argvlen
[
j
]
:
strlen
(
argv
[
j
]);
len
=
argvlen
?
argvlen
[
j
]
:
strlen
(
argv
[
j
]);
cmd
=
hi_
sdscatfmt
(
cmd
,
"$%
u
\r\n
"
,
len
);
cmd
=
sdscatfmt
(
cmd
,
"$%
U
\r\n
"
,
len
);
cmd
=
hi_
sdscatlen
(
cmd
,
argv
[
j
],
len
);
cmd
=
sdscatlen
(
cmd
,
argv
[
j
],
len
);
cmd
=
hi_
sdscatlen
(
cmd
,
"
\r\n
"
,
sizeof
(
"
\r\n
"
)
-
1
);
cmd
=
sdscatlen
(
cmd
,
"
\r\n
"
,
sizeof
(
"
\r\n
"
)
-
1
);
}
}
assert
(
hi_
sdslen
(
cmd
)
==
totlen
);
assert
(
sdslen
(
cmd
)
==
totlen
);
*
target
=
cmd
;
*
target
=
cmd
;
return
totlen
;
return
totlen
;
}
}
void
redisFreeSdsCommand
(
hi
sds
cmd
)
{
void
redisFreeSdsCommand
(
sds
cmd
)
{
hi_
sdsfree
(
cmd
);
sdsfree
(
cmd
);
}
}
/* Format a command according to the Redis protocol. This function takes the
/* Format a command according to the Redis protocol. This function takes the
...
@@ -622,11 +628,11 @@ void redisFreeSdsCommand(hisds cmd) {
...
@@ -622,11 +628,11 @@ void redisFreeSdsCommand(hisds cmd) {
* lengths. If the latter is set to NULL, strlen will be used to compute the
* lengths. If the latter is set to NULL, strlen will be used to compute the
* argument lengths.
* argument lengths.
*/
*/
int
redisFormatCommandArgv
(
char
**
target
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
)
{
long
long
redisFormatCommandArgv
(
char
**
target
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
)
{
char
*
cmd
=
NULL
;
/* final command */
char
*
cmd
=
NULL
;
/* final command */
in
t
pos
;
/* position in final command */
size_
t
pos
;
/* position in final command */
size_t
len
;
size_t
len
,
totlen
;
int
totlen
,
j
;
int
j
;
/* Abort on a NULL target */
/* Abort on a NULL target */
if
(
target
==
NULL
)
if
(
target
==
NULL
)
...
@@ -698,7 +704,7 @@ static redisContext *redisContextInit(void) {
...
@@ -698,7 +704,7 @@ static redisContext *redisContextInit(void) {
c
->
funcs
=
&
redisContextDefaultFuncs
;
c
->
funcs
=
&
redisContextDefaultFuncs
;
c
->
obuf
=
hi_
sdsempty
();
c
->
obuf
=
sdsempty
();
c
->
reader
=
redisReaderCreate
();
c
->
reader
=
redisReaderCreate
();
c
->
fd
=
REDIS_INVALID_FD
;
c
->
fd
=
REDIS_INVALID_FD
;
...
@@ -715,7 +721,7 @@ void redisFree(redisContext *c) {
...
@@ -715,7 +721,7 @@ void redisFree(redisContext *c) {
return
;
return
;
redisNetClose
(
c
);
redisNetClose
(
c
);
hi_
sdsfree
(
c
->
obuf
);
sdsfree
(
c
->
obuf
);
redisReaderFree
(
c
->
reader
);
redisReaderFree
(
c
->
reader
);
hi_free
(
c
->
tcp
.
host
);
hi_free
(
c
->
tcp
.
host
);
hi_free
(
c
->
tcp
.
source_addr
);
hi_free
(
c
->
tcp
.
source_addr
);
...
@@ -752,10 +758,10 @@ int redisReconnect(redisContext *c) {
...
@@ -752,10 +758,10 @@ int redisReconnect(redisContext *c) {
redisNetClose
(
c
);
redisNetClose
(
c
);
hi_
sdsfree
(
c
->
obuf
);
sdsfree
(
c
->
obuf
);
redisReaderFree
(
c
->
reader
);
redisReaderFree
(
c
->
reader
);
c
->
obuf
=
hi_
sdsempty
();
c
->
obuf
=
sdsempty
();
c
->
reader
=
redisReaderCreate
();
c
->
reader
=
redisReaderCreate
();
if
(
c
->
obuf
==
NULL
||
c
->
reader
==
NULL
)
{
if
(
c
->
obuf
==
NULL
||
c
->
reader
==
NULL
)
{
...
@@ -797,6 +803,9 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
...
@@ -797,6 +803,9 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
if
(
options
->
options
&
REDIS_OPT_NOAUTOFREE
)
{
if
(
options
->
options
&
REDIS_OPT_NOAUTOFREE
)
{
c
->
flags
|=
REDIS_NO_AUTO_FREE
;
c
->
flags
|=
REDIS_NO_AUTO_FREE
;
}
}
if
(
options
->
options
&
REDIS_OPT_NOAUTOFREEREPLIES
)
{
c
->
flags
|=
REDIS_NO_AUTO_FREE_REPLIES
;
}
/* Set any user supplied RESP3 PUSH handler or use freeReplyObject
/* Set any user supplied RESP3 PUSH handler or use freeReplyObject
* as a default unless specifically flagged that we don't want one. */
* as a default unless specifically flagged that we don't want one. */
...
@@ -825,7 +834,7 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
...
@@ -825,7 +834,7 @@ redisContext *redisConnectWithOptions(const redisOptions *options) {
c
->
fd
=
options
->
endpoint
.
fd
;
c
->
fd
=
options
->
endpoint
.
fd
;
c
->
flags
|=
REDIS_CONNECTED
;
c
->
flags
|=
REDIS_CONNECTED
;
}
else
{
}
else
{
// Unknown type - FIXME - FREE
redisFree
(
c
);
return
NULL
;
return
NULL
;
}
}
...
@@ -939,13 +948,11 @@ int redisBufferRead(redisContext *c) {
...
@@ -939,13 +948,11 @@ int redisBufferRead(redisContext *c) {
return
REDIS_ERR
;
return
REDIS_ERR
;
nread
=
c
->
funcs
->
read
(
c
,
buf
,
sizeof
(
buf
));
nread
=
c
->
funcs
->
read
(
c
,
buf
,
sizeof
(
buf
));
if
(
nread
>
0
)
{
if
(
nread
<
0
)
{
if
(
redisReaderFeed
(
c
->
reader
,
buf
,
nread
)
!=
REDIS_OK
)
{
__redisSetError
(
c
,
c
->
reader
->
err
,
c
->
reader
->
errstr
);
return
REDIS_ERR
;
return
REDIS_ERR
;
}
else
{
}
}
}
else
if
(
nread
<
0
)
{
if
(
nread
>
0
&&
redisReaderFeed
(
c
->
reader
,
buf
,
nread
)
!=
REDIS_OK
)
{
__redisSetError
(
c
,
c
->
reader
->
err
,
c
->
reader
->
errstr
);
return
REDIS_ERR
;
return
REDIS_ERR
;
}
}
return
REDIS_OK
;
return
REDIS_OK
;
...
@@ -966,22 +973,22 @@ int redisBufferWrite(redisContext *c, int *done) {
...
@@ -966,22 +973,22 @@ int redisBufferWrite(redisContext *c, int *done) {
if
(
c
->
err
)
if
(
c
->
err
)
return
REDIS_ERR
;
return
REDIS_ERR
;
if
(
hi_
sdslen
(
c
->
obuf
)
>
0
)
{
if
(
sdslen
(
c
->
obuf
)
>
0
)
{
ssize_t
nwritten
=
c
->
funcs
->
write
(
c
);
ssize_t
nwritten
=
c
->
funcs
->
write
(
c
);
if
(
nwritten
<
0
)
{
if
(
nwritten
<
0
)
{
return
REDIS_ERR
;
return
REDIS_ERR
;
}
else
if
(
nwritten
>
0
)
{
}
else
if
(
nwritten
>
0
)
{
if
(
nwritten
==
(
ssize_t
)
hi_
sdslen
(
c
->
obuf
))
{
if
(
nwritten
==
(
ssize_t
)
sdslen
(
c
->
obuf
))
{
hi_
sdsfree
(
c
->
obuf
);
sdsfree
(
c
->
obuf
);
c
->
obuf
=
hi_
sdsempty
();
c
->
obuf
=
sdsempty
();
if
(
c
->
obuf
==
NULL
)
if
(
c
->
obuf
==
NULL
)
goto
oom
;
goto
oom
;
}
else
{
}
else
{
if
(
hi_
sdsrange
(
c
->
obuf
,
nwritten
,
-
1
)
<
0
)
goto
oom
;
if
(
sdsrange
(
c
->
obuf
,
nwritten
,
-
1
)
<
0
)
goto
oom
;
}
}
}
}
}
}
if
(
done
!=
NULL
)
*
done
=
(
hi_
sdslen
(
c
->
obuf
)
==
0
);
if
(
done
!=
NULL
)
*
done
=
(
sdslen
(
c
->
obuf
)
==
0
);
return
REDIS_OK
;
return
REDIS_OK
;
oom:
oom:
...
@@ -989,17 +996,6 @@ oom:
...
@@ -989,17 +996,6 @@ oom:
return
REDIS_ERR
;
return
REDIS_ERR
;
}
}
/* Internal helper function to try and get a reply from the reader,
* or set an error in the context otherwise. */
int
redisGetReplyFromReader
(
redisContext
*
c
,
void
**
reply
)
{
if
(
redisReaderGetReply
(
c
->
reader
,
reply
)
==
REDIS_ERR
)
{
__redisSetError
(
c
,
c
->
reader
->
err
,
c
->
reader
->
errstr
);
return
REDIS_ERR
;
}
return
REDIS_OK
;
}
/* Internal helper that returns 1 if the reply was a RESP3 PUSH
/* Internal helper that returns 1 if the reply was a RESP3 PUSH
* message and we handled it with a user-provided callback. */
* message and we handled it with a user-provided callback. */
static
int
redisHandledPushReply
(
redisContext
*
c
,
void
*
reply
)
{
static
int
redisHandledPushReply
(
redisContext
*
c
,
void
*
reply
)
{
...
@@ -1011,12 +1007,34 @@ static int redisHandledPushReply(redisContext *c, void *reply) {
...
@@ -1011,12 +1007,34 @@ static int redisHandledPushReply(redisContext *c, void *reply) {
return
0
;
return
0
;
}
}
/* Get a reply from our reader or set an error in the context. */
int
redisGetReplyFromReader
(
redisContext
*
c
,
void
**
reply
)
{
if
(
redisReaderGetReply
(
c
->
reader
,
reply
)
==
REDIS_ERR
)
{
__redisSetError
(
c
,
c
->
reader
->
err
,
c
->
reader
->
errstr
);
return
REDIS_ERR
;
}
return
REDIS_OK
;
}
/* Internal helper to get the next reply from our reader while handling
* any PUSH messages we encounter along the way. This is separate from
* redisGetReplyFromReader so as to not change its behavior. */
static
int
redisNextInBandReplyFromReader
(
redisContext
*
c
,
void
**
reply
)
{
do
{
if
(
redisGetReplyFromReader
(
c
,
reply
)
==
REDIS_ERR
)
return
REDIS_ERR
;
}
while
(
redisHandledPushReply
(
c
,
*
reply
));
return
REDIS_OK
;
}
int
redisGetReply
(
redisContext
*
c
,
void
**
reply
)
{
int
redisGetReply
(
redisContext
*
c
,
void
**
reply
)
{
int
wdone
=
0
;
int
wdone
=
0
;
void
*
aux
=
NULL
;
void
*
aux
=
NULL
;
/* Try to read pending replies */
/* Try to read pending replies */
if
(
redis
Get
ReplyFromReader
(
c
,
&
aux
)
==
REDIS_ERR
)
if
(
redis
NextInBand
ReplyFromReader
(
c
,
&
aux
)
==
REDIS_ERR
)
return
REDIS_ERR
;
return
REDIS_ERR
;
/* For the blocking context, flush output buffer and read reply */
/* For the blocking context, flush output buffer and read reply */
...
@@ -1032,12 +1050,8 @@ int redisGetReply(redisContext *c, void **reply) {
...
@@ -1032,12 +1050,8 @@ int redisGetReply(redisContext *c, void **reply) {
if
(
redisBufferRead
(
c
)
==
REDIS_ERR
)
if
(
redisBufferRead
(
c
)
==
REDIS_ERR
)
return
REDIS_ERR
;
return
REDIS_ERR
;
/* We loop here in case the user has specified a RESP3
if
(
redisNextInBandReplyFromReader
(
c
,
&
aux
)
==
REDIS_ERR
)
* PUSH handler (e.g. for client tracking). */
do
{
if
(
redisGetReplyFromReader
(
c
,
&
aux
)
==
REDIS_ERR
)
return
REDIS_ERR
;
return
REDIS_ERR
;
}
while
(
redisHandledPushReply
(
c
,
aux
));
}
while
(
aux
==
NULL
);
}
while
(
aux
==
NULL
);
}
}
...
@@ -1059,9 +1073,9 @@ int redisGetReply(redisContext *c, void **reply) {
...
@@ -1059,9 +1073,9 @@ int redisGetReply(redisContext *c, void **reply) {
* the reply (or replies in pub/sub).
* the reply (or replies in pub/sub).
*/
*/
int
__redisAppendCommand
(
redisContext
*
c
,
const
char
*
cmd
,
size_t
len
)
{
int
__redisAppendCommand
(
redisContext
*
c
,
const
char
*
cmd
,
size_t
len
)
{
hi
sds
newbuf
;
sds
newbuf
;
newbuf
=
hi_
sdscatlen
(
c
->
obuf
,
cmd
,
len
);
newbuf
=
sdscatlen
(
c
->
obuf
,
cmd
,
len
);
if
(
newbuf
==
NULL
)
{
if
(
newbuf
==
NULL
)
{
__redisSetError
(
c
,
REDIS_ERR_OOM
,
"Out of memory"
);
__redisSetError
(
c
,
REDIS_ERR_OOM
,
"Out of memory"
);
return
REDIS_ERR
;
return
REDIS_ERR
;
...
@@ -1113,8 +1127,8 @@ int redisAppendCommand(redisContext *c, const char *format, ...) {
...
@@ -1113,8 +1127,8 @@ int redisAppendCommand(redisContext *c, const char *format, ...) {
}
}
int
redisAppendCommandArgv
(
redisContext
*
c
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
)
{
int
redisAppendCommandArgv
(
redisContext
*
c
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
)
{
hi
sds
cmd
;
sds
cmd
;
int
len
;
long
long
len
;
len
=
redisFormatSdsCommandArgv
(
&
cmd
,
argc
,
argv
,
argvlen
);
len
=
redisFormatSdsCommandArgv
(
&
cmd
,
argc
,
argv
,
argvlen
);
if
(
len
==
-
1
)
{
if
(
len
==
-
1
)
{
...
@@ -1123,11 +1137,11 @@ int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const s
...
@@ -1123,11 +1137,11 @@ int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const s
}
}
if
(
__redisAppendCommand
(
c
,
cmd
,
len
)
!=
REDIS_OK
)
{
if
(
__redisAppendCommand
(
c
,
cmd
,
len
)
!=
REDIS_OK
)
{
hi_
sdsfree
(
cmd
);
sdsfree
(
cmd
);
return
REDIS_ERR
;
return
REDIS_ERR
;
}
}
hi_
sdsfree
(
cmd
);
sdsfree
(
cmd
);
return
REDIS_OK
;
return
REDIS_OK
;
}
}
...
...
deps/hiredis/hiredis.h
View file @
886a04c2
...
@@ -42,13 +42,13 @@ struct timeval; /* forward declaration */
...
@@ -42,13 +42,13 @@ struct timeval; /* forward declaration */
typedef
long
long
ssize_t
;
typedef
long
long
ssize_t
;
#endif
#endif
#include <stdint.h>
/* uintXX_t, etc */
#include <stdint.h>
/* uintXX_t, etc */
#include "sds.h"
/* for
hi
sds */
#include "sds.h"
/* for sds */
#include "alloc.h"
/* for allocation wrappers */
#include "alloc.h"
/* for allocation wrappers */
#define HIREDIS_MAJOR 1
#define HIREDIS_MAJOR 1
#define HIREDIS_MINOR 0
#define HIREDIS_MINOR 0
#define HIREDIS_PATCH
0
#define HIREDIS_PATCH
3
#define HIREDIS_SONAME 1.0.
0
#define HIREDIS_SONAME 1.0.
3-dev
/* Connection type can be blocking or non-blocking and is set in the
/* Connection type can be blocking or non-blocking and is set in the
* least significant bit of the flags field in redisContext. */
* least significant bit of the flags field in redisContext. */
...
@@ -80,12 +80,18 @@ typedef long long ssize_t;
...
@@ -80,12 +80,18 @@ typedef long long ssize_t;
/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
/* Flag that is set when we should set SO_REUSEADDR before calling bind() */
#define REDIS_REUSEADDR 0x80
#define REDIS_REUSEADDR 0x80
/* Flag that is set when the async connection supports push replies. */
#define REDIS_SUPPORTS_PUSH 0x100
/**
/**
* Flag that indicates the user does not want the context to
* Flag that indicates the user does not want the context to
* be automatically freed upon error
* be automatically freed upon error
*/
*/
#define REDIS_NO_AUTO_FREE 0x200
#define REDIS_NO_AUTO_FREE 0x200
/* Flag that indicates the user does not want replies to be automatically freed */
#define REDIS_NO_AUTO_FREE_REPLIES 0x400
#define REDIS_KEEPALIVE_INTERVAL 15
/* seconds */
#define REDIS_KEEPALIVE_INTERVAL 15
/* seconds */
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
/* number of times we retry to connect in the case of EADDRNOTAVAIL and
...
@@ -112,7 +118,8 @@ typedef struct redisReply {
...
@@ -112,7 +118,8 @@ typedef struct redisReply {
double
dval
;
/* The double when type is REDIS_REPLY_DOUBLE */
double
dval
;
/* The double when type is REDIS_REPLY_DOUBLE */
size_t
len
;
/* Length of string */
size_t
len
;
/* Length of string */
char
*
str
;
/* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
char
*
str
;
/* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
REDIS_REPLY_VERB, and REDIS_REPLY_DOUBLE (in additional to dval). */
REDIS_REPLY_VERB, REDIS_REPLY_DOUBLE (in additional to dval),
and REDIS_REPLY_BIGNUM. */
char
vtype
[
4
];
/* Used for REDIS_REPLY_VERB, contains the null
char
vtype
[
4
];
/* Used for REDIS_REPLY_VERB, contains the null
terminated 3 character content type, such as "txt". */
terminated 3 character content type, such as "txt". */
size_t
elements
;
/* number of elements, for REDIS_REPLY_ARRAY */
size_t
elements
;
/* number of elements, for REDIS_REPLY_ARRAY */
...
@@ -127,10 +134,10 @@ void freeReplyObject(void *reply);
...
@@ -127,10 +134,10 @@ void freeReplyObject(void *reply);
/* Functions to format a command according to the protocol. */
/* Functions to format a command according to the protocol. */
int
redisvFormatCommand
(
char
**
target
,
const
char
*
format
,
va_list
ap
);
int
redisvFormatCommand
(
char
**
target
,
const
char
*
format
,
va_list
ap
);
int
redisFormatCommand
(
char
**
target
,
const
char
*
format
,
...);
int
redisFormatCommand
(
char
**
target
,
const
char
*
format
,
...);
int
redisFormatCommandArgv
(
char
**
target
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
);
long
long
redisFormatCommandArgv
(
char
**
target
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
);
int
redisFormatSdsCommandArgv
(
hi
sds
*
target
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
);
long
long
redisFormatSdsCommandArgv
(
sds
*
target
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
);
void
redisFreeCommand
(
char
*
cmd
);
void
redisFreeCommand
(
char
*
cmd
);
void
redisFreeSdsCommand
(
hi
sds
cmd
);
void
redisFreeSdsCommand
(
sds
cmd
);
enum
redisConnectionType
{
enum
redisConnectionType
{
REDIS_CONN_TCP
,
REDIS_CONN_TCP
,
...
@@ -152,6 +159,11 @@ struct redisSsl;
...
@@ -152,6 +159,11 @@ struct redisSsl;
/* Don't automatically intercept and free RESP3 PUSH replies. */
/* Don't automatically intercept and free RESP3 PUSH replies. */
#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08
#define REDIS_OPT_NO_PUSH_AUTOFREE 0x08
/**
* Don't automatically free replies
*/
#define REDIS_OPT_NOAUTOFREEREPLIES 0x10
/* In Unix systems a file descriptor is a regular signed int, with -1
/* In Unix systems a file descriptor is a regular signed int, with -1
* representing an invalid descriptor. In Windows it is a SOCKET
* representing an invalid descriptor. In Windows it is a SOCKET
* (32- or 64-bit unsigned integer depending on the architecture), where
* (32- or 64-bit unsigned integer depending on the architecture), where
...
@@ -255,7 +267,7 @@ typedef struct redisContext {
...
@@ -255,7 +267,7 @@ typedef struct redisContext {
}
unix_sock
;
}
unix_sock
;
/* For non-blocking connect */
/* For non-blocking connect */
struct
sockadr
*
saddr
;
struct
sockad
d
r
*
saddr
;
size_t
addrlen
;
size_t
addrlen
;
/* Optional data and corresponding destructor users can use to provide
/* Optional data and corresponding destructor users can use to provide
...
...
deps/hiredis/hiredis.targets
0 → 100644
View file @
886a04c2
<?xml version="1.0" encoding="utf-8"?>
<Project
ToolsVersion=
"4.0"
xmlns=
"http://schemas.microsoft.com/developer/msbuild/2003"
>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>
$(MSBuildThisFileDirectory)\..\..\include;%(AdditionalIncludeDirectories)
</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>
$(MSBuildThisFileDirectory)\..\..\lib;%(AdditionalLibraryDirectories)
</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
</Project>
\ No newline at end of file
deps/hiredis/hiredis_ssl.h
View file @
886a04c2
...
@@ -56,7 +56,9 @@ typedef enum {
...
@@ -56,7 +56,9 @@ typedef enum {
REDIS_SSL_CTX_CERT_KEY_REQUIRED
,
/* Client cert and key must both be specified or skipped */
REDIS_SSL_CTX_CERT_KEY_REQUIRED
,
/* Client cert and key must both be specified or skipped */
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
,
/* Failed to load CA Certificate or CA Path */
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
,
/* Failed to load CA Certificate or CA Path */
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED
,
/* Failed to load client certificate */
REDIS_SSL_CTX_CLIENT_CERT_LOAD_FAILED
,
/* Failed to load client certificate */
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
/* Failed to load private key */
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
,
/* Failed to load private key */
REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED
,
/* Failed to open system certifcate store */
REDIS_SSL_CTX_OS_CERT_ADD_FAILED
/* Failed to add CA certificates obtained from system to the SSL context */
}
redisSSLContextError
;
}
redisSSLContextError
;
/**
/**
...
...
deps/hiredis/net.c
View file @
886a04c2
...
@@ -80,7 +80,7 @@ ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
...
@@ -80,7 +80,7 @@ ssize_t redisNetRead(redisContext *c, char *buf, size_t bufcap) {
}
}
ssize_t
redisNetWrite
(
redisContext
*
c
)
{
ssize_t
redisNetWrite
(
redisContext
*
c
)
{
ssize_t
nwritten
=
send
(
c
->
fd
,
c
->
obuf
,
hi_
sdslen
(
c
->
obuf
),
0
);
ssize_t
nwritten
=
send
(
c
->
fd
,
c
->
obuf
,
sdslen
(
c
->
obuf
),
0
);
if
(
nwritten
<
0
)
{
if
(
nwritten
<
0
)
{
if
((
errno
==
EWOULDBLOCK
&&
!
(
c
->
flags
&
REDIS_BLOCK
))
||
(
errno
==
EINTR
))
{
if
((
errno
==
EWOULDBLOCK
&&
!
(
c
->
flags
&
REDIS_BLOCK
))
||
(
errno
==
EINTR
))
{
/* Try again later */
/* Try again later */
...
...
deps/hiredis/read.c
View file @
886a04c2
...
@@ -59,7 +59,7 @@ static void __redisReaderSetError(redisReader *r, int type, const char *str) {
...
@@ -59,7 +59,7 @@ static void __redisReaderSetError(redisReader *r, int type, const char *str) {
}
}
/* Clear input buffer on errors. */
/* Clear input buffer on errors. */
hi_
sdsfree
(
r
->
buf
);
sdsfree
(
r
->
buf
);
r
->
buf
=
NULL
;
r
->
buf
=
NULL
;
r
->
pos
=
r
->
len
=
0
;
r
->
pos
=
r
->
len
=
0
;
...
@@ -123,29 +123,28 @@ static char *readBytes(redisReader *r, unsigned int bytes) {
...
@@ -123,29 +123,28 @@ static char *readBytes(redisReader *r, unsigned int bytes) {
/* Find pointer to \r\n. */
/* Find pointer to \r\n. */
static
char
*
seekNewline
(
char
*
s
,
size_t
len
)
{
static
char
*
seekNewline
(
char
*
s
,
size_t
len
)
{
int
pos
=
0
;
char
*
ret
;
int
_len
=
len
-
1
;
/* We cannot match with fewer than 2 bytes */
/* Position should be < len-1 because the character at "pos" should be
if
(
len
<
2
)
* followed by a \n. Note that strchr cannot be used because it doesn't
* allow to search a limited length and the buffer that is being searched
* might not have a trailing NULL character. */
while
(
pos
<
_len
)
{
while
(
pos
<
_len
&&
s
[
pos
]
!=
'\r'
)
pos
++
;
if
(
pos
==
_len
)
{
/* Not found. */
return
NULL
;
return
NULL
;
}
else
{
if
(
s
[
pos
+
1
]
==
'\n'
)
{
/* Search up to len - 1 characters */
len
--
;
/* Look for the \r */
while
((
ret
=
memchr
(
s
,
'\r'
,
len
))
!=
NULL
)
{
if
(
ret
[
1
]
==
'\n'
)
{
/* Found. */
/* Found. */
return
s
+
pos
;
break
;
}
else
{
/* Continue searching. */
pos
++
;
}
}
}
/* Continue searching. */
ret
++
;
len
-=
ret
-
s
;
s
=
ret
;
}
}
return
NULL
;
return
ret
;
}
}
/* Convert a string into a long long. Returns REDIS_OK if the string could be
/* Convert a string into a long long. Returns REDIS_OK if the string could be
...
@@ -274,19 +273,20 @@ static int processLineItem(redisReader *r) {
...
@@ -274,19 +273,20 @@ static int processLineItem(redisReader *r) {
if
((
p
=
readLine
(
r
,
&
len
))
!=
NULL
)
{
if
((
p
=
readLine
(
r
,
&
len
))
!=
NULL
)
{
if
(
cur
->
type
==
REDIS_REPLY_INTEGER
)
{
if
(
cur
->
type
==
REDIS_REPLY_INTEGER
)
{
if
(
r
->
fn
&&
r
->
fn
->
createInteger
)
{
long
long
v
;
long
long
v
;
if
(
string2ll
(
p
,
len
,
&
v
)
==
REDIS_ERR
)
{
if
(
string2ll
(
p
,
len
,
&
v
)
==
REDIS_ERR
)
{
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
"Bad integer value"
);
"Bad integer value"
);
return
REDIS_ERR
;
return
REDIS_ERR
;
}
}
if
(
r
->
fn
&&
r
->
fn
->
createInteger
)
{
obj
=
r
->
fn
->
createInteger
(
cur
,
v
);
obj
=
r
->
fn
->
createInteger
(
cur
,
v
);
}
else
{
}
else
{
obj
=
(
void
*
)
REDIS_REPLY_INTEGER
;
obj
=
(
void
*
)
REDIS_REPLY_INTEGER
;
}
}
}
else
if
(
cur
->
type
==
REDIS_REPLY_DOUBLE
)
{
}
else
if
(
cur
->
type
==
REDIS_REPLY_DOUBLE
)
{
if
(
r
->
fn
&&
r
->
fn
->
createDouble
)
{
char
buf
[
326
],
*
eptr
;
char
buf
[
326
],
*
eptr
;
double
d
;
double
d
;
...
@@ -299,35 +299,78 @@ static int processLineItem(redisReader *r) {
...
@@ -299,35 +299,78 @@ static int processLineItem(redisReader *r) {
memcpy
(
buf
,
p
,
len
);
memcpy
(
buf
,
p
,
len
);
buf
[
len
]
=
'\0'
;
buf
[
len
]
=
'\0'
;
if
(
strcasecmp
(
buf
,
"
,
inf"
)
==
0
)
{
if
(
len
==
3
&&
strcasecmp
(
buf
,
"inf"
)
==
0
)
{
d
=
INFINITY
;
/* Positive infinite. */
d
=
INFINITY
;
/* Positive infinite. */
}
else
if
(
strcasecmp
(
buf
,
"
,
-inf"
)
==
0
)
{
}
else
if
(
len
==
4
&&
strcasecmp
(
buf
,
"-inf"
)
==
0
)
{
d
=
-
INFINITY
;
/* Negative infinite. */
d
=
-
INFINITY
;
/* Negative infinite. */
}
else
{
}
else
{
d
=
strtod
((
char
*
)
buf
,
&
eptr
);
d
=
strtod
((
char
*
)
buf
,
&
eptr
);
if
(
buf
[
0
]
==
'\0'
||
eptr
[
0
]
!=
'\0'
||
isnan
(
d
))
{
/* RESP3 only allows "inf", "-inf", and finite values, while
* strtod() allows other variations on infinity, NaN,
* etc. We explicity handle our two allowed infinite cases
* above, so strtod() should only result in finite values. */
if
(
buf
[
0
]
==
'\0'
||
eptr
!=
&
buf
[
len
]
||
!
isfinite
(
d
))
{
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
"Bad double value"
);
"Bad double value"
);
return
REDIS_ERR
;
return
REDIS_ERR
;
}
}
}
}
if
(
r
->
fn
&&
r
->
fn
->
createDouble
)
{
obj
=
r
->
fn
->
createDouble
(
cur
,
d
,
buf
,
len
);
obj
=
r
->
fn
->
createDouble
(
cur
,
d
,
buf
,
len
);
}
else
{
}
else
{
obj
=
(
void
*
)
REDIS_REPLY_DOUBLE
;
obj
=
(
void
*
)
REDIS_REPLY_DOUBLE
;
}
}
}
else
if
(
cur
->
type
==
REDIS_REPLY_NIL
)
{
}
else
if
(
cur
->
type
==
REDIS_REPLY_NIL
)
{
if
(
len
!=
0
)
{
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
"Bad nil value"
);
return
REDIS_ERR
;
}
if
(
r
->
fn
&&
r
->
fn
->
createNil
)
if
(
r
->
fn
&&
r
->
fn
->
createNil
)
obj
=
r
->
fn
->
createNil
(
cur
);
obj
=
r
->
fn
->
createNil
(
cur
);
else
else
obj
=
(
void
*
)
REDIS_REPLY_NIL
;
obj
=
(
void
*
)
REDIS_REPLY_NIL
;
}
else
if
(
cur
->
type
==
REDIS_REPLY_BOOL
)
{
}
else
if
(
cur
->
type
==
REDIS_REPLY_BOOL
)
{
int
bval
=
p
[
0
]
==
't'
||
p
[
0
]
==
'T'
;
int
bval
;
if
(
len
!=
1
||
!
strchr
(
"tTfF"
,
p
[
0
]))
{
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
"Bad bool value"
);
return
REDIS_ERR
;
}
bval
=
p
[
0
]
==
't'
||
p
[
0
]
==
'T'
;
if
(
r
->
fn
&&
r
->
fn
->
createBool
)
if
(
r
->
fn
&&
r
->
fn
->
createBool
)
obj
=
r
->
fn
->
createBool
(
cur
,
bval
);
obj
=
r
->
fn
->
createBool
(
cur
,
bval
);
else
else
obj
=
(
void
*
)
REDIS_REPLY_BOOL
;
obj
=
(
void
*
)
REDIS_REPLY_BOOL
;
}
else
if
(
cur
->
type
==
REDIS_REPLY_BIGNUM
)
{
/* Ensure all characters are decimal digits (with possible leading
* minus sign). */
for
(
int
i
=
0
;
i
<
len
;
i
++
)
{
/* XXX Consider: Allow leading '+'? Error on leading '0's? */
if
(
i
==
0
&&
p
[
0
]
==
'-'
)
continue
;
if
(
p
[
i
]
<
'0'
||
p
[
i
]
>
'9'
)
{
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
"Bad bignum value"
);
return
REDIS_ERR
;
}
}
if
(
r
->
fn
&&
r
->
fn
->
createString
)
obj
=
r
->
fn
->
createString
(
cur
,
p
,
len
);
else
obj
=
(
void
*
)
REDIS_REPLY_BIGNUM
;
}
else
{
}
else
{
/* Type will be error or status. */
/* Type will be error or status. */
for
(
int
i
=
0
;
i
<
len
;
i
++
)
{
if
(
p
[
i
]
==
'\r'
||
p
[
i
]
==
'\n'
)
{
__redisReaderSetError
(
r
,
REDIS_ERR_PROTOCOL
,
"Bad simple string value"
);
return
REDIS_ERR
;
}
}
if
(
r
->
fn
&&
r
->
fn
->
createString
)
if
(
r
->
fn
&&
r
->
fn
->
createString
)
obj
=
r
->
fn
->
createString
(
cur
,
p
,
len
);
obj
=
r
->
fn
->
createString
(
cur
,
p
,
len
);
else
else
...
@@ -453,7 +496,6 @@ static int processAggregateItem(redisReader *r) {
...
@@ -453,7 +496,6 @@ static int processAggregateItem(redisReader *r) {
long
long
elements
;
long
long
elements
;
int
root
=
0
,
len
;
int
root
=
0
,
len
;
/* Set error for nested multi bulks with depth > 7 */
if
(
r
->
ridx
==
r
->
tasks
-
1
)
{
if
(
r
->
ridx
==
r
->
tasks
-
1
)
{
if
(
redisReaderGrow
(
r
)
==
REDIS_ERR
)
if
(
redisReaderGrow
(
r
)
==
REDIS_ERR
)
return
REDIS_ERR
;
return
REDIS_ERR
;
...
@@ -569,6 +611,9 @@ static int processItem(redisReader *r) {
...
@@ -569,6 +611,9 @@ static int processItem(redisReader *r) {
case
'>'
:
case
'>'
:
cur
->
type
=
REDIS_REPLY_PUSH
;
cur
->
type
=
REDIS_REPLY_PUSH
;
break
;
break
;
case
'('
:
cur
->
type
=
REDIS_REPLY_BIGNUM
;
break
;
default:
default:
__redisReaderSetErrorProtocolByte
(
r
,
*
p
);
__redisReaderSetErrorProtocolByte
(
r
,
*
p
);
return
REDIS_ERR
;
return
REDIS_ERR
;
...
@@ -587,6 +632,7 @@ static int processItem(redisReader *r) {
...
@@ -587,6 +632,7 @@ static int processItem(redisReader *r) {
case
REDIS_REPLY_DOUBLE
:
case
REDIS_REPLY_DOUBLE
:
case
REDIS_REPLY_NIL
:
case
REDIS_REPLY_NIL
:
case
REDIS_REPLY_BOOL
:
case
REDIS_REPLY_BOOL
:
case
REDIS_REPLY_BIGNUM
:
return
processLineItem
(
r
);
return
processLineItem
(
r
);
case
REDIS_REPLY_STRING
:
case
REDIS_REPLY_STRING
:
case
REDIS_REPLY_VERB
:
case
REDIS_REPLY_VERB
:
...
@@ -609,7 +655,7 @@ redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
...
@@ -609,7 +655,7 @@ redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) {
if
(
r
==
NULL
)
if
(
r
==
NULL
)
return
NULL
;
return
NULL
;
r
->
buf
=
hi_
sdsempty
();
r
->
buf
=
sdsempty
();
if
(
r
->
buf
==
NULL
)
if
(
r
->
buf
==
NULL
)
goto
oom
;
goto
oom
;
...
@@ -650,12 +696,12 @@ void redisReaderFree(redisReader *r) {
...
@@ -650,12 +696,12 @@ void redisReaderFree(redisReader *r) {
hi_free
(
r
->
task
);
hi_free
(
r
->
task
);
}
}
hi_
sdsfree
(
r
->
buf
);
sdsfree
(
r
->
buf
);
hi_free
(
r
);
hi_free
(
r
);
}
}
int
redisReaderFeed
(
redisReader
*
r
,
const
char
*
buf
,
size_t
len
)
{
int
redisReaderFeed
(
redisReader
*
r
,
const
char
*
buf
,
size_t
len
)
{
hi
sds
newbuf
;
sds
newbuf
;
/* Return early when this reader is in an erroneous state. */
/* Return early when this reader is in an erroneous state. */
if
(
r
->
err
)
if
(
r
->
err
)
...
@@ -664,19 +710,19 @@ int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
...
@@ -664,19 +710,19 @@ int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
/* Copy the provided buffer. */
/* Copy the provided buffer. */
if
(
buf
!=
NULL
&&
len
>=
1
)
{
if
(
buf
!=
NULL
&&
len
>=
1
)
{
/* Destroy internal buffer when it is empty and is quite large. */
/* Destroy internal buffer when it is empty and is quite large. */
if
(
r
->
len
==
0
&&
r
->
maxbuf
!=
0
&&
hi_
sdsavail
(
r
->
buf
)
>
r
->
maxbuf
)
{
if
(
r
->
len
==
0
&&
r
->
maxbuf
!=
0
&&
sdsavail
(
r
->
buf
)
>
r
->
maxbuf
)
{
hi_
sdsfree
(
r
->
buf
);
sdsfree
(
r
->
buf
);
r
->
buf
=
hi_
sdsempty
();
r
->
buf
=
sdsempty
();
if
(
r
->
buf
==
0
)
goto
oom
;
if
(
r
->
buf
==
0
)
goto
oom
;
r
->
pos
=
0
;
r
->
pos
=
0
;
}
}
newbuf
=
hi_
sdscatlen
(
r
->
buf
,
buf
,
len
);
newbuf
=
sdscatlen
(
r
->
buf
,
buf
,
len
);
if
(
newbuf
==
NULL
)
goto
oom
;
if
(
newbuf
==
NULL
)
goto
oom
;
r
->
buf
=
newbuf
;
r
->
buf
=
newbuf
;
r
->
len
=
hi_
sdslen
(
r
->
buf
);
r
->
len
=
sdslen
(
r
->
buf
);
}
}
return
REDIS_OK
;
return
REDIS_OK
;
...
@@ -721,9 +767,9 @@ int redisReaderGetReply(redisReader *r, void **reply) {
...
@@ -721,9 +767,9 @@ int redisReaderGetReply(redisReader *r, void **reply) {
/* Discard part of the buffer when we've consumed at least 1k, to avoid
/* Discard part of the buffer when we've consumed at least 1k, to avoid
* doing unnecessary calls to memmove() in sds.c. */
* doing unnecessary calls to memmove() in sds.c. */
if
(
r
->
pos
>=
1024
)
{
if
(
r
->
pos
>=
1024
)
{
if
(
hi_
sdsrange
(
r
->
buf
,
r
->
pos
,
-
1
)
<
0
)
return
REDIS_ERR
;
if
(
sdsrange
(
r
->
buf
,
r
->
pos
,
-
1
)
<
0
)
return
REDIS_ERR
;
r
->
pos
=
0
;
r
->
pos
=
0
;
r
->
len
=
hi_
sdslen
(
r
->
buf
);
r
->
len
=
sdslen
(
r
->
buf
);
}
}
/* Emit a reply when there is one. */
/* Emit a reply when there is one. */
...
...
deps/hiredis/sds.c
View file @
886a04c2
...
@@ -40,90 +40,90 @@
...
@@ -40,90 +40,90 @@
#include "sds.h"
#include "sds.h"
#include "sdsalloc.h"
#include "sdsalloc.h"
static
inline
int
hi_
sdsHdrSize
(
char
type
)
{
static
inline
int
sdsHdrSize
(
char
type
)
{
switch
(
type
&
HI_
SDS_TYPE_MASK
)
{
switch
(
type
&
SDS_TYPE_MASK
)
{
case
HI_
SDS_TYPE_5
:
case
SDS_TYPE_5
:
return
sizeof
(
struct
hi
sdshdr5
);
return
sizeof
(
struct
sdshdr5
);
case
HI_
SDS_TYPE_8
:
case
SDS_TYPE_8
:
return
sizeof
(
struct
hi
sdshdr8
);
return
sizeof
(
struct
sdshdr8
);
case
HI_
SDS_TYPE_16
:
case
SDS_TYPE_16
:
return
sizeof
(
struct
hi
sdshdr16
);
return
sizeof
(
struct
sdshdr16
);
case
HI_
SDS_TYPE_32
:
case
SDS_TYPE_32
:
return
sizeof
(
struct
hi
sdshdr32
);
return
sizeof
(
struct
sdshdr32
);
case
HI_
SDS_TYPE_64
:
case
SDS_TYPE_64
:
return
sizeof
(
struct
hi
sdshdr64
);
return
sizeof
(
struct
sdshdr64
);
}
}
return
0
;
return
0
;
}
}
static
inline
char
hi_
sdsReqType
(
size_t
string_size
)
{
static
inline
char
sdsReqType
(
size_t
string_size
)
{
if
(
string_size
<
32
)
if
(
string_size
<
32
)
return
HI_
SDS_TYPE_5
;
return
SDS_TYPE_5
;
if
(
string_size
<
0xff
)
if
(
string_size
<
0xff
)
return
HI_
SDS_TYPE_8
;
return
SDS_TYPE_8
;
if
(
string_size
<
0xffff
)
if
(
string_size
<
0xffff
)
return
HI_
SDS_TYPE_16
;
return
SDS_TYPE_16
;
if
(
string_size
<
0xffffffff
)
if
(
string_size
<
0xffffffff
)
return
HI_
SDS_TYPE_32
;
return
SDS_TYPE_32
;
return
HI_
SDS_TYPE_64
;
return
SDS_TYPE_64
;
}
}
/* Create a new
hi
sds string with the content specified by the 'init' pointer
/* Create a new sds string with the content specified by the 'init' pointer
* and 'initlen'.
* and 'initlen'.
* If NULL is used for 'init' the string is initialized with zero bytes.
* If NULL is used for 'init' the string is initialized with zero bytes.
*
*
* The string is always null-termined (all the
hi
sds strings are, always) so
* The string is always null-termin
at
ed (all the sds strings are, always) so
* even if you create an
hi
sds string with:
* even if you create an sds string with:
*
*
* mystring =
hi_
sdsnewlen("abc",3);
* mystring = sdsnewlen("abc",3);
*
*
* You can print the string with printf() as there is an implicit \0 at the
* You can print the string with printf() as there is an implicit \0 at the
* end of the string. However the string is binary safe and can contain
* end of the string. However the string is binary safe and can contain
* \0 characters in the middle, as the length is stored in the
hi
sds header. */
* \0 characters in the middle, as the length is stored in the sds header. */
hi
sds
hi_
sdsnewlen
(
const
void
*
init
,
size_t
initlen
)
{
sds
sdsnewlen
(
const
void
*
init
,
size_t
initlen
)
{
void
*
sh
;
void
*
sh
;
hi
sds
s
;
sds
s
;
char
type
=
hi_
sdsReqType
(
initlen
);
char
type
=
sdsReqType
(
initlen
);
/* Empty strings are usually created in order to append. Use type 8
/* Empty strings are usually created in order to append. Use type 8
* since type 5 is not good at this. */
* since type 5 is not good at this. */
if
(
type
==
HI_
SDS_TYPE_5
&&
initlen
==
0
)
type
=
HI_
SDS_TYPE_8
;
if
(
type
==
SDS_TYPE_5
&&
initlen
==
0
)
type
=
SDS_TYPE_8
;
int
hdrlen
=
hi_
sdsHdrSize
(
type
);
int
hdrlen
=
sdsHdrSize
(
type
);
unsigned
char
*
fp
;
/* flags pointer. */
unsigned
char
*
fp
;
/* flags pointer. */
sh
=
hi_
s_malloc
(
hdrlen
+
initlen
+
1
);
sh
=
s_malloc
(
hdrlen
+
initlen
+
1
);
if
(
sh
==
NULL
)
return
NULL
;
if
(
sh
==
NULL
)
return
NULL
;
if
(
!
init
)
if
(
!
init
)
memset
(
sh
,
0
,
hdrlen
+
initlen
+
1
);
memset
(
sh
,
0
,
hdrlen
+
initlen
+
1
);
s
=
(
char
*
)
sh
+
hdrlen
;
s
=
(
char
*
)
sh
+
hdrlen
;
fp
=
((
unsigned
char
*
)
s
)
-
1
;
fp
=
((
unsigned
char
*
)
s
)
-
1
;
switch
(
type
)
{
switch
(
type
)
{
case
HI_
SDS_TYPE_5
:
{
case
SDS_TYPE_5
:
{
*
fp
=
type
|
(
initlen
<<
HI_
SDS_TYPE_BITS
);
*
fp
=
type
|
(
initlen
<<
SDS_TYPE_BITS
);
break
;
break
;
}
}
case
HI_
SDS_TYPE_8
:
{
case
SDS_TYPE_8
:
{
HI_
SDS_HDR_VAR
(
8
,
s
);
SDS_HDR_VAR
(
8
,
s
);
sh
->
len
=
initlen
;
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
sh
->
alloc
=
initlen
;
*
fp
=
type
;
*
fp
=
type
;
break
;
break
;
}
}
case
HI_
SDS_TYPE_16
:
{
case
SDS_TYPE_16
:
{
HI_
SDS_HDR_VAR
(
16
,
s
);
SDS_HDR_VAR
(
16
,
s
);
sh
->
len
=
initlen
;
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
sh
->
alloc
=
initlen
;
*
fp
=
type
;
*
fp
=
type
;
break
;
break
;
}
}
case
HI_
SDS_TYPE_32
:
{
case
SDS_TYPE_32
:
{
HI_
SDS_HDR_VAR
(
32
,
s
);
SDS_HDR_VAR
(
32
,
s
);
sh
->
len
=
initlen
;
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
sh
->
alloc
=
initlen
;
*
fp
=
type
;
*
fp
=
type
;
break
;
break
;
}
}
case
HI_
SDS_TYPE_64
:
{
case
SDS_TYPE_64
:
{
HI_
SDS_HDR_VAR
(
64
,
s
);
SDS_HDR_VAR
(
64
,
s
);
sh
->
len
=
initlen
;
sh
->
len
=
initlen
;
sh
->
alloc
=
initlen
;
sh
->
alloc
=
initlen
;
*
fp
=
type
;
*
fp
=
type
;
...
@@ -136,164 +136,164 @@ hisds hi_sdsnewlen(const void *init, size_t initlen) {
...
@@ -136,164 +136,164 @@ hisds hi_sdsnewlen(const void *init, size_t initlen) {
return
s
;
return
s
;
}
}
/* Create an empty (zero length)
hi
sds string. Even in this case the string
/* Create an empty (zero length) sds string. Even in this case the string
* always has an implicit null term. */
* always has an implicit null term. */
hi
sds
hi_
sdsempty
(
void
)
{
sds
sdsempty
(
void
)
{
return
hi_
sdsnewlen
(
""
,
0
);
return
sdsnewlen
(
""
,
0
);
}
}
/* Create a new
hi
sds string starting from a null terminated C string. */
/* Create a new sds string starting from a null terminated C string. */
hi
sds
hi_
sdsnew
(
const
char
*
init
)
{
sds
sdsnew
(
const
char
*
init
)
{
size_t
initlen
=
(
init
==
NULL
)
?
0
:
strlen
(
init
);
size_t
initlen
=
(
init
==
NULL
)
?
0
:
strlen
(
init
);
return
hi_
sdsnewlen
(
init
,
initlen
);
return
sdsnewlen
(
init
,
initlen
);
}
}
/* Duplicate an
hi
sds string. */
/* Duplicate an sds string. */
hi
sds
hi_
sdsdup
(
const
hi
sds
s
)
{
sds
sdsdup
(
const
sds
s
)
{
return
hi_
sdsnewlen
(
s
,
hi_
sdslen
(
s
));
return
sdsnewlen
(
s
,
sdslen
(
s
));
}
}
/* Free an
hi
sds string. No operation is performed if 's' is NULL. */
/* Free an sds string. No operation is performed if 's' is NULL. */
void
hi_
sdsfree
(
hi
sds
s
)
{
void
sdsfree
(
sds
s
)
{
if
(
s
==
NULL
)
return
;
if
(
s
==
NULL
)
return
;
hi_
s_free
((
char
*
)
s
-
hi_
sdsHdrSize
(
s
[
-
1
]));
s_free
((
char
*
)
s
-
sdsHdrSize
(
s
[
-
1
]));
}
}
/* Set the
hi
sds string length to the length as obtained with strlen(), so
/* Set the sds string length to the length as obtained with strlen(), so
* considering as content only up to the first null term character.
* considering as content only up to the first null term character.
*
*
* This function is useful when the
hi
sds string is hacked manually in some
* This function is useful when the sds string is hacked manually in some
* way, like in the following example:
* way, like in the following example:
*
*
* s =
hi_
sdsnew("foobar");
* s = sdsnew("foobar");
* s[2] = '\0';
* s[2] = '\0';
*
hi_
sdsupdatelen(s);
* sdsupdatelen(s);
* printf("%d\n",
hi_
sdslen(s));
* printf("%d\n", sdslen(s));
*
*
* The output will be "2", but if we comment out the call to
hi_
sdsupdatelen()
* The output will be "2", but if we comment out the call to sdsupdatelen()
* the output will be "6" as the string was modified but the logical length
* the output will be "6" as the string was modified but the logical length
* remains 6 bytes. */
* remains 6 bytes. */
void
hi_
sdsupdatelen
(
hi
sds
s
)
{
void
sdsupdatelen
(
sds
s
)
{
int
reallen
=
strlen
(
s
);
int
reallen
=
strlen
(
s
);
hi_
sdssetlen
(
s
,
reallen
);
sdssetlen
(
s
,
reallen
);
}
}
/* Modify an
hi
sds string in-place to make it empty (zero length).
/* Modify an sds string in-place to make it empty (zero length).
* However all the existing buffer is not discarded but set as free space
* However all the existing buffer is not discarded but set as free space
* so that next append operations will not require allocations up to the
* so that next append operations will not require allocations up to the
* number of bytes previously available. */
* number of bytes previously available. */
void
hi_
sdsclear
(
hi
sds
s
)
{
void
sdsclear
(
sds
s
)
{
hi_
sdssetlen
(
s
,
0
);
sdssetlen
(
s
,
0
);
s
[
0
]
=
'\0'
;
s
[
0
]
=
'\0'
;
}
}
/* Enlarge the free space at the end of the
hi
sds string so that the caller
/* Enlarge the free space at the end of the sds string so that the caller
* is sure that after calling this function can overwrite up to addlen
* is sure that after calling this function can overwrite up to addlen
* bytes after the end of the string, plus one more byte for nul term.
* bytes after the end of the string, plus one more byte for nul term.
*
*
* Note: this does not change the *length* of the
hi
sds string as returned
* Note: this does not change the *length* of the sds string as returned
* by
hi_
sdslen(), but only the free buffer space we have. */
* by sdslen(), but only the free buffer space we have. */
hi
sds
hi_
sdsMakeRoomFor
(
hi
sds
s
,
size_t
addlen
)
{
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
)
{
void
*
sh
,
*
newsh
;
void
*
sh
,
*
newsh
;
size_t
avail
=
hi_
sdsavail
(
s
);
size_t
avail
=
sdsavail
(
s
);
size_t
len
,
newlen
;
size_t
len
,
newlen
;
char
type
,
oldtype
=
s
[
-
1
]
&
HI_
SDS_TYPE_MASK
;
char
type
,
oldtype
=
s
[
-
1
]
&
SDS_TYPE_MASK
;
int
hdrlen
;
int
hdrlen
;
/* Return ASAP if there is enough space left. */
/* Return ASAP if there is enough space left. */
if
(
avail
>=
addlen
)
return
s
;
if
(
avail
>=
addlen
)
return
s
;
len
=
hi_
sdslen
(
s
);
len
=
sdslen
(
s
);
sh
=
(
char
*
)
s
-
hi_
sdsHdrSize
(
oldtype
);
sh
=
(
char
*
)
s
-
sdsHdrSize
(
oldtype
);
newlen
=
(
len
+
addlen
);
newlen
=
(
len
+
addlen
);
if
(
newlen
<
HI_
SDS_MAX_PREALLOC
)
if
(
newlen
<
SDS_MAX_PREALLOC
)
newlen
*=
2
;
newlen
*=
2
;
else
else
newlen
+=
HI_
SDS_MAX_PREALLOC
;
newlen
+=
SDS_MAX_PREALLOC
;
type
=
hi_
sdsReqType
(
newlen
);
type
=
sdsReqType
(
newlen
);
/* Don't use type 5: the user is appending to the string and type 5 is
/* Don't use type 5: the user is appending to the string and type 5 is
* not able to remember empty space, so
hi_
sdsMakeRoomFor() must be called
* not able to remember empty space, so sdsMakeRoomFor() must be called
* at every appending operation. */
* at every appending operation. */
if
(
type
==
HI_
SDS_TYPE_5
)
type
=
HI_
SDS_TYPE_8
;
if
(
type
==
SDS_TYPE_5
)
type
=
SDS_TYPE_8
;
hdrlen
=
hi_
sdsHdrSize
(
type
);
hdrlen
=
sdsHdrSize
(
type
);
if
(
oldtype
==
type
)
{
if
(
oldtype
==
type
)
{
newsh
=
hi_
s_realloc
(
sh
,
hdrlen
+
newlen
+
1
);
newsh
=
s_realloc
(
sh
,
hdrlen
+
newlen
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
if
(
newsh
==
NULL
)
return
NULL
;
s
=
(
char
*
)
newsh
+
hdrlen
;
s
=
(
char
*
)
newsh
+
hdrlen
;
}
else
{
}
else
{
/* Since the header size changes, need to move the string forward,
/* Since the header size changes, need to move the string forward,
* and can't use realloc */
* and can't use realloc */
newsh
=
hi_
s_malloc
(
hdrlen
+
newlen
+
1
);
newsh
=
s_malloc
(
hdrlen
+
newlen
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
if
(
newsh
==
NULL
)
return
NULL
;
memcpy
((
char
*
)
newsh
+
hdrlen
,
s
,
len
+
1
);
memcpy
((
char
*
)
newsh
+
hdrlen
,
s
,
len
+
1
);
hi_
s_free
(
sh
);
s_free
(
sh
);
s
=
(
char
*
)
newsh
+
hdrlen
;
s
=
(
char
*
)
newsh
+
hdrlen
;
s
[
-
1
]
=
type
;
s
[
-
1
]
=
type
;
hi_
sdssetlen
(
s
,
len
);
sdssetlen
(
s
,
len
);
}
}
hi_
sdssetalloc
(
s
,
newlen
);
sdssetalloc
(
s
,
newlen
);
return
s
;
return
s
;
}
}
/* Reallocate the
hi
sds string so that it has no free space at the end. The
/* Reallocate the sds string so that it has no free space at the end. The
* contained string remains not altered, but next concatenation operations
* contained string remains not altered, but next concatenation operations
* will require a reallocation.
* will require a reallocation.
*
*
* After the call, the passed
hi
sds string is no longer valid and all the
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
* references must be substituted with the new pointer returned by the call. */
hi
sds
hi_
sdsRemoveFreeSpace
(
hi
sds
s
)
{
sds
sdsRemoveFreeSpace
(
sds
s
)
{
void
*
sh
,
*
newsh
;
void
*
sh
,
*
newsh
;
char
type
,
oldtype
=
s
[
-
1
]
&
HI_
SDS_TYPE_MASK
;
char
type
,
oldtype
=
s
[
-
1
]
&
SDS_TYPE_MASK
;
int
hdrlen
;
int
hdrlen
;
size_t
len
=
hi_
sdslen
(
s
);
size_t
len
=
sdslen
(
s
);
sh
=
(
char
*
)
s
-
hi_
sdsHdrSize
(
oldtype
);
sh
=
(
char
*
)
s
-
sdsHdrSize
(
oldtype
);
type
=
hi_
sdsReqType
(
len
);
type
=
sdsReqType
(
len
);
hdrlen
=
hi_
sdsHdrSize
(
type
);
hdrlen
=
sdsHdrSize
(
type
);
if
(
oldtype
==
type
)
{
if
(
oldtype
==
type
)
{
newsh
=
hi_
s_realloc
(
sh
,
hdrlen
+
len
+
1
);
newsh
=
s_realloc
(
sh
,
hdrlen
+
len
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
if
(
newsh
==
NULL
)
return
NULL
;
s
=
(
char
*
)
newsh
+
hdrlen
;
s
=
(
char
*
)
newsh
+
hdrlen
;
}
else
{
}
else
{
newsh
=
hi_
s_malloc
(
hdrlen
+
len
+
1
);
newsh
=
s_malloc
(
hdrlen
+
len
+
1
);
if
(
newsh
==
NULL
)
return
NULL
;
if
(
newsh
==
NULL
)
return
NULL
;
memcpy
((
char
*
)
newsh
+
hdrlen
,
s
,
len
+
1
);
memcpy
((
char
*
)
newsh
+
hdrlen
,
s
,
len
+
1
);
hi_
s_free
(
sh
);
s_free
(
sh
);
s
=
(
char
*
)
newsh
+
hdrlen
;
s
=
(
char
*
)
newsh
+
hdrlen
;
s
[
-
1
]
=
type
;
s
[
-
1
]
=
type
;
hi_
sdssetlen
(
s
,
len
);
sdssetlen
(
s
,
len
);
}
}
hi_
sdssetalloc
(
s
,
len
);
sdssetalloc
(
s
,
len
);
return
s
;
return
s
;
}
}
/* Return the total size of the allocation of the specifed
hi
sds string,
/* Return the total size of the allocation of the specifed sds string,
* including:
* including:
* 1) The
hi
sds header before the pointer.
* 1) The sds header before the pointer.
* 2) The string.
* 2) The string.
* 3) The free buffer at the end if any.
* 3) The free buffer at the end if any.
* 4) The implicit null term.
* 4) The implicit null term.
*/
*/
size_t
hi_
sdsAllocSize
(
hi
sds
s
)
{
size_t
sdsAllocSize
(
sds
s
)
{
size_t
alloc
=
hi_
sdsalloc
(
s
);
size_t
alloc
=
sdsalloc
(
s
);
return
hi_
sdsHdrSize
(
s
[
-
1
])
+
alloc
+
1
;
return
sdsHdrSize
(
s
[
-
1
])
+
alloc
+
1
;
}
}
/* Return the pointer of the actual SDS allocation (normally SDS strings
/* Return the pointer of the actual SDS allocation (normally SDS strings
* are referenced by the start of the string buffer). */
* are referenced by the start of the string buffer). */
void
*
hi_
sdsAllocPtr
(
hi
sds
s
)
{
void
*
sdsAllocPtr
(
sds
s
)
{
return
(
void
*
)
(
s
-
hi_
sdsHdrSize
(
s
[
-
1
]));
return
(
void
*
)
(
s
-
sdsHdrSize
(
s
[
-
1
]));
}
}
/* Increment the
hi
sds length and decrements the left free space at the
/* Increment the sds length and decrements the left free space at the
* end of the string according to 'incr'. Also set the null term
* end of the string according to 'incr'. Also set the null term
* in the new end of the string.
* in the new end of the string.
*
*
* This function is used in order to fix the string length after the
* This function is used in order to fix the string length after the
* user calls
hi_
sdsMakeRoomFor(), writes something after the end of
* user calls sdsMakeRoomFor(), writes something after the end of
* the current string, and finally needs to set the new length.
* the current string, and finally needs to set the new length.
*
*
* Note: it is possible to use a negative increment in order to
* Note: it is possible to use a negative increment in order to
...
@@ -301,48 +301,48 @@ void *hi_sdsAllocPtr(hisds s) {
...
@@ -301,48 +301,48 @@ void *hi_sdsAllocPtr(hisds s) {
*
*
* Usage example:
* Usage example:
*
*
* Using
hi_
sdsIncrLen() and
hi_
sdsMakeRoomFor() it is possible to mount the
* Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
* following schema, to cat bytes coming from the kernel to the end of an
* following schema, to cat bytes coming from the kernel to the end of an
*
hi
sds string without copying into an intermediate buffer:
* sds string without copying into an intermediate buffer:
*
*
* oldlen =
hi_hi_
sdslen(s);
* oldlen = sdslen(s);
* s =
hi_
sdsMakeRoomFor(s, BUFFER_SIZE);
* s = sdsMakeRoomFor(s, BUFFER_SIZE);
* nread = read(fd, s+oldlen, BUFFER_SIZE);
* nread = read(fd, s+oldlen, BUFFER_SIZE);
* ... check for nread <= 0 and handle it ...
* ... check for nread <= 0 and handle it ...
*
hi_
sdsIncrLen(s, nread);
* sdsIncrLen(s, nread);
*/
*/
void
hi_
sdsIncrLen
(
hi
sds
s
,
int
incr
)
{
void
sdsIncrLen
(
sds
s
,
int
incr
)
{
unsigned
char
flags
=
s
[
-
1
];
unsigned
char
flags
=
s
[
-
1
];
size_t
len
;
size_t
len
;
switch
(
flags
&
HI_
SDS_TYPE_MASK
)
{
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
HI_
SDS_TYPE_5
:
{
case
SDS_TYPE_5
:
{
unsigned
char
*
fp
=
((
unsigned
char
*
)
s
)
-
1
;
unsigned
char
*
fp
=
((
unsigned
char
*
)
s
)
-
1
;
unsigned
char
oldlen
=
HI_
SDS_TYPE_5_LEN
(
flags
);
unsigned
char
oldlen
=
SDS_TYPE_5_LEN
(
flags
);
assert
((
incr
>
0
&&
oldlen
+
incr
<
32
)
||
(
incr
<
0
&&
oldlen
>=
(
unsigned
int
)(
-
incr
)));
assert
((
incr
>
0
&&
oldlen
+
incr
<
32
)
||
(
incr
<
0
&&
oldlen
>=
(
unsigned
int
)(
-
incr
)));
*
fp
=
HI_
SDS_TYPE_5
|
((
oldlen
+
incr
)
<<
HI_
SDS_TYPE_BITS
);
*
fp
=
SDS_TYPE_5
|
((
oldlen
+
incr
)
<<
SDS_TYPE_BITS
);
len
=
oldlen
+
incr
;
len
=
oldlen
+
incr
;
break
;
break
;
}
}
case
HI_
SDS_TYPE_8
:
{
case
SDS_TYPE_8
:
{
HI_
SDS_HDR_VAR
(
8
,
s
);
SDS_HDR_VAR
(
8
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
len
=
(
sh
->
len
+=
incr
);
break
;
break
;
}
}
case
HI_
SDS_TYPE_16
:
{
case
SDS_TYPE_16
:
{
HI_
SDS_HDR_VAR
(
16
,
s
);
SDS_HDR_VAR
(
16
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
len
=
(
sh
->
len
+=
incr
);
break
;
break
;
}
}
case
HI_
SDS_TYPE_32
:
{
case
SDS_TYPE_32
:
{
HI_
SDS_HDR_VAR
(
32
,
s
);
SDS_HDR_VAR
(
32
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
(
unsigned
int
)
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
(
unsigned
int
)
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
unsigned
int
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
len
=
(
sh
->
len
+=
incr
);
break
;
break
;
}
}
case
HI_
SDS_TYPE_64
:
{
case
SDS_TYPE_64
:
{
HI_
SDS_HDR_VAR
(
64
,
s
);
SDS_HDR_VAR
(
64
,
s
);
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
(
uint64_t
)
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
uint64_t
)(
-
incr
)));
assert
((
incr
>=
0
&&
sh
->
alloc
-
sh
->
len
>=
(
uint64_t
)
incr
)
||
(
incr
<
0
&&
sh
->
len
>=
(
uint64_t
)(
-
incr
)));
len
=
(
sh
->
len
+=
incr
);
len
=
(
sh
->
len
+=
incr
);
break
;
break
;
...
@@ -352,83 +352,83 @@ void hi_sdsIncrLen(hisds s, int incr) {
...
@@ -352,83 +352,83 @@ void hi_sdsIncrLen(hisds s, int incr) {
s
[
len
]
=
'\0'
;
s
[
len
]
=
'\0'
;
}
}
/* Grow the
hi
sds to have the specified length. Bytes that were not part of
/* Grow the sds to have the specified length. Bytes that were not part of
* the original length of the
hi
sds will be set to zero.
* the original length of the sds will be set to zero.
*
*
* if the specified length is smaller than the current length, no operation
* if the specified length is smaller than the current length, no operation
* is performed. */
* is performed. */
hi
sds
hi_
sdsgrowzero
(
hi
sds
s
,
size_t
len
)
{
sds
sdsgrowzero
(
sds
s
,
size_t
len
)
{
size_t
curlen
=
hi_
sdslen
(
s
);
size_t
curlen
=
sdslen
(
s
);
if
(
len
<=
curlen
)
return
s
;
if
(
len
<=
curlen
)
return
s
;
s
=
hi_
sdsMakeRoomFor
(
s
,
len
-
curlen
);
s
=
sdsMakeRoomFor
(
s
,
len
-
curlen
);
if
(
s
==
NULL
)
return
NULL
;
if
(
s
==
NULL
)
return
NULL
;
/* Make sure added region doesn't contain garbage */
/* Make sure added region doesn't contain garbage */
memset
(
s
+
curlen
,
0
,(
len
-
curlen
+
1
));
/* also set trailing \0 byte */
memset
(
s
+
curlen
,
0
,(
len
-
curlen
+
1
));
/* also set trailing \0 byte */
hi_
sdssetlen
(
s
,
len
);
sdssetlen
(
s
,
len
);
return
s
;
return
s
;
}
}
/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
* end of the specified
hi
sds string 's'.
* end of the specified sds string 's'.
*
*
* After the call, the passed
hi
sds string is no longer valid and all the
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
* references must be substituted with the new pointer returned by the call. */
hi
sds
hi_
sdscatlen
(
hi
sds
s
,
const
void
*
t
,
size_t
len
)
{
sds
sdscatlen
(
sds
s
,
const
void
*
t
,
size_t
len
)
{
size_t
curlen
=
hi_
sdslen
(
s
);
size_t
curlen
=
sdslen
(
s
);
s
=
hi_
sdsMakeRoomFor
(
s
,
len
);
s
=
sdsMakeRoomFor
(
s
,
len
);
if
(
s
==
NULL
)
return
NULL
;
if
(
s
==
NULL
)
return
NULL
;
memcpy
(
s
+
curlen
,
t
,
len
);
memcpy
(
s
+
curlen
,
t
,
len
);
hi_
sdssetlen
(
s
,
curlen
+
len
);
sdssetlen
(
s
,
curlen
+
len
);
s
[
curlen
+
len
]
=
'\0'
;
s
[
curlen
+
len
]
=
'\0'
;
return
s
;
return
s
;
}
}
/* Append the specified null termianted C string to the
hi
sds string 's'.
/* Append the specified null termianted C string to the sds string 's'.
*
*
* After the call, the passed
hi
sds string is no longer valid and all the
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
* references must be substituted with the new pointer returned by the call. */
hi
sds
hi_
sdscat
(
hi
sds
s
,
const
char
*
t
)
{
sds
sdscat
(
sds
s
,
const
char
*
t
)
{
return
hi_
sdscatlen
(
s
,
t
,
strlen
(
t
));
return
sdscatlen
(
s
,
t
,
strlen
(
t
));
}
}
/* Append the specified
hi
sds 't' to the existing
hi
sds 's'.
/* Append the specified sds 't' to the existing sds 's'.
*
*
* After the call, the modified
hi
sds string is no longer valid and all the
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
* references must be substituted with the new pointer returned by the call. */
hi
sds
hi_
sdscatsds
(
hi
sds
s
,
const
hi
sds
t
)
{
sds
sdscatsds
(
sds
s
,
const
sds
t
)
{
return
hi_
sdscatlen
(
s
,
t
,
hi_
sdslen
(
t
));
return
sdscatlen
(
s
,
t
,
sdslen
(
t
));
}
}
/* Destructively modify the
hi
sds string 's' to hold the specified binary
/* Destructively modify the sds string 's' to hold the specified binary
* safe string pointed by 't' of length 'len' bytes. */
* safe string pointed by 't' of length 'len' bytes. */
hi
sds
hi_
sdscpylen
(
hi
sds
s
,
const
char
*
t
,
size_t
len
)
{
sds
sdscpylen
(
sds
s
,
const
char
*
t
,
size_t
len
)
{
if
(
hi_
sdsalloc
(
s
)
<
len
)
{
if
(
sdsalloc
(
s
)
<
len
)
{
s
=
hi_
sdsMakeRoomFor
(
s
,
len
-
hi_
sdslen
(
s
));
s
=
sdsMakeRoomFor
(
s
,
len
-
sdslen
(
s
));
if
(
s
==
NULL
)
return
NULL
;
if
(
s
==
NULL
)
return
NULL
;
}
}
memcpy
(
s
,
t
,
len
);
memcpy
(
s
,
t
,
len
);
s
[
len
]
=
'\0'
;
s
[
len
]
=
'\0'
;
hi_
sdssetlen
(
s
,
len
);
sdssetlen
(
s
,
len
);
return
s
;
return
s
;
}
}
/* Like
hi_
sdscpylen() but 't' must be a null-termined string so that the length
/* Like sdscpylen() but 't' must be a null-termin
at
ed string so that the length
* of the string is obtained with strlen(). */
* of the string is obtained with strlen(). */
hi
sds
hi_
sdscpy
(
hi
sds
s
,
const
char
*
t
)
{
sds
sdscpy
(
sds
s
,
const
char
*
t
)
{
return
hi_
sdscpylen
(
s
,
t
,
strlen
(
t
));
return
sdscpylen
(
s
,
t
,
strlen
(
t
));
}
}
/* Helper for
hi_
sdscatlonglong() doing the actual number -> string
/* Helper for sdscatlonglong() doing the actual number -> string
* conversion. 's' must point to a string with room for at least
* conversion. 's' must point to a string with room for at least
*
HI_
SDS_LLSTR_SIZE bytes.
* SDS_LLSTR_SIZE bytes.
*
*
* The function returns the length of the null-terminated string
* The function returns the length of the null-terminated string
* representation stored at 's'. */
* representation stored at 's'. */
#define
HI_
SDS_LLSTR_SIZE 21
#define SDS_LLSTR_SIZE 21
int
hi_
sdsll2str
(
char
*
s
,
long
long
value
)
{
int
sdsll2str
(
char
*
s
,
long
long
value
)
{
char
*
p
,
aux
;
char
*
p
,
aux
;
unsigned
long
long
v
;
unsigned
long
long
v
;
size_t
l
;
size_t
l
;
...
@@ -459,8 +459,8 @@ int hi_sdsll2str(char *s, long long value) {
...
@@ -459,8 +459,8 @@ int hi_sdsll2str(char *s, long long value) {
return
l
;
return
l
;
}
}
/* Identical
hi_
sdsll2str(), but for unsigned long long type. */
/* Identical sdsll2str(), but for unsigned long long type. */
int
hi_
sdsull2str
(
char
*
s
,
unsigned
long
long
v
)
{
int
sdsull2str
(
char
*
s
,
unsigned
long
long
v
)
{
char
*
p
,
aux
;
char
*
p
,
aux
;
size_t
l
;
size_t
l
;
...
@@ -488,19 +488,19 @@ int hi_sdsull2str(char *s, unsigned long long v) {
...
@@ -488,19 +488,19 @@ int hi_sdsull2str(char *s, unsigned long long v) {
return
l
;
return
l
;
}
}
/* Create an
hi
sds string from a long long value. It is much faster than:
/* Create an sds string from a long long value. It is much faster than:
*
*
*
hi_
sdscatprintf(
hi_
sdsempty(),"%lld\n", value);
* sdscatprintf(sdsempty(),"%lld\n", value);
*/
*/
hi
sds
hi_
sdsfromlonglong
(
long
long
value
)
{
sds
sdsfromlonglong
(
long
long
value
)
{
char
buf
[
HI_
SDS_LLSTR_SIZE
];
char
buf
[
SDS_LLSTR_SIZE
];
int
len
=
hi_
sdsll2str
(
buf
,
value
);
int
len
=
sdsll2str
(
buf
,
value
);
return
hi_
sdsnewlen
(
buf
,
len
);
return
sdsnewlen
(
buf
,
len
);
}
}
/* Like
hi_
sdscatprintf() but gets va_list instead of being variadic. */
/* Like sdscatprintf() but gets va_list instead of being variadic. */
hi
sds
hi_
sdscatvprintf
(
hi
sds
s
,
const
char
*
fmt
,
va_list
ap
)
{
sds
sdscatvprintf
(
sds
s
,
const
char
*
fmt
,
va_list
ap
)
{
va_list
cpy
;
va_list
cpy
;
char
staticbuf
[
1024
],
*
buf
=
staticbuf
,
*
t
;
char
staticbuf
[
1024
],
*
buf
=
staticbuf
,
*
t
;
size_t
buflen
=
strlen
(
fmt
)
*
2
;
size_t
buflen
=
strlen
(
fmt
)
*
2
;
...
@@ -508,7 +508,7 @@ hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
...
@@ -508,7 +508,7 @@ hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
/* We try to start using a static buffer for speed.
/* We try to start using a static buffer for speed.
* If not possible we revert to heap allocation. */
* If not possible we revert to heap allocation. */
if
(
buflen
>
sizeof
(
staticbuf
))
{
if
(
buflen
>
sizeof
(
staticbuf
))
{
buf
=
hi_
s_malloc
(
buflen
);
buf
=
s_malloc
(
buflen
);
if
(
buf
==
NULL
)
return
NULL
;
if
(
buf
==
NULL
)
return
NULL
;
}
else
{
}
else
{
buflen
=
sizeof
(
staticbuf
);
buflen
=
sizeof
(
staticbuf
);
...
@@ -522,9 +522,9 @@ hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
...
@@ -522,9 +522,9 @@ hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
vsnprintf
(
buf
,
buflen
,
fmt
,
cpy
);
vsnprintf
(
buf
,
buflen
,
fmt
,
cpy
);
va_end
(
cpy
);
va_end
(
cpy
);
if
(
buf
[
buflen
-
2
]
!=
'\0'
)
{
if
(
buf
[
buflen
-
2
]
!=
'\0'
)
{
if
(
buf
!=
staticbuf
)
hi_
s_free
(
buf
);
if
(
buf
!=
staticbuf
)
s_free
(
buf
);
buflen
*=
2
;
buflen
*=
2
;
buf
=
hi_
s_malloc
(
buflen
);
buf
=
s_malloc
(
buflen
);
if
(
buf
==
NULL
)
return
NULL
;
if
(
buf
==
NULL
)
return
NULL
;
continue
;
continue
;
}
}
...
@@ -532,39 +532,39 @@ hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
...
@@ -532,39 +532,39 @@ hisds hi_sdscatvprintf(hisds s, const char *fmt, va_list ap) {
}
}
/* Finally concat the obtained string to the SDS string and return it. */
/* Finally concat the obtained string to the SDS string and return it. */
t
=
hi_
sdscat
(
s
,
buf
);
t
=
sdscat
(
s
,
buf
);
if
(
buf
!=
staticbuf
)
hi_
s_free
(
buf
);
if
(
buf
!=
staticbuf
)
s_free
(
buf
);
return
t
;
return
t
;
}
}
/* Append to the
hi
sds string 's' a string obtained using printf-alike format
/* Append to the sds string 's' a string obtained using printf-alike format
* specifier.
* specifier.
*
*
* After the call, the modified
hi
sds string is no longer valid and all the
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call.
* references must be substituted with the new pointer returned by the call.
*
*
* Example:
* Example:
*
*
* s =
hi_
sdsnew("Sum is: ");
* s = sdsnew("Sum is: ");
* s =
hi_
sdscatprintf(s,"%d+%d = %d",a,b,a+b).
* s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
*
*
* Often you need to create a string from scratch with the printf-alike
* Often you need to create a string from scratch with the printf-alike
* format. When this is the need, just use
hi_
sdsempty() as the target string:
* format. When this is the need, just use sdsempty() as the target string:
*
*
* s =
hi_
sdscatprintf(
hi_
sdsempty(), "... your format ...", args);
* s = sdscatprintf(sdsempty(), "... your format ...", args);
*/
*/
hi
sds
hi_
sdscatprintf
(
hi
sds
s
,
const
char
*
fmt
,
...)
{
sds
sdscatprintf
(
sds
s
,
const
char
*
fmt
,
...)
{
va_list
ap
;
va_list
ap
;
char
*
t
;
char
*
t
;
va_start
(
ap
,
fmt
);
va_start
(
ap
,
fmt
);
t
=
hi_
sdscatvprintf
(
s
,
fmt
,
ap
);
t
=
sdscatvprintf
(
s
,
fmt
,
ap
);
va_end
(
ap
);
va_end
(
ap
);
return
t
;
return
t
;
}
}
/* This function is similar to
hi_
sdscatprintf, but much faster as it does
/* This function is similar to sdscatprintf, but much faster as it does
* not rely on sprintf() family functions implemented by the libc that
* not rely on sprintf() family functions implemented by the libc that
* are often very slow. Moreover directly handling the
hi
sds string as
* are often very slow. Moreover directly handling the sds string as
* new data is concatenated provides a performance improvement.
* new data is concatenated provides a performance improvement.
*
*
* However this function only handles an incompatible subset of printf-alike
* However this function only handles an incompatible subset of printf-alike
...
@@ -578,13 +578,13 @@ hisds hi_sdscatprintf(hisds s, const char *fmt, ...) {
...
@@ -578,13 +578,13 @@ hisds hi_sdscatprintf(hisds s, const char *fmt, ...) {
* %U - 64 bit unsigned integer (unsigned long long, uint64_t)
* %U - 64 bit unsigned integer (unsigned long long, uint64_t)
* %% - Verbatim "%" character.
* %% - Verbatim "%" character.
*/
*/
hi
sds
hi_
sdscatfmt
(
hi
sds
s
,
char
const
*
fmt
,
...)
{
sds
sdscatfmt
(
sds
s
,
char
const
*
fmt
,
...)
{
const
char
*
f
=
fmt
;
const
char
*
f
=
fmt
;
int
i
;
int
i
;
va_list
ap
;
va_list
ap
;
va_start
(
ap
,
fmt
);
va_start
(
ap
,
fmt
);
i
=
hi_
sdslen
(
s
);
/* Position of the next byte to write to dest str. */
i
=
sdslen
(
s
);
/* Position of the next byte to write to dest str. */
while
(
*
f
)
{
while
(
*
f
)
{
char
next
,
*
str
;
char
next
,
*
str
;
size_t
l
;
size_t
l
;
...
@@ -592,8 +592,8 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
...
@@ -592,8 +592,8 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
unsigned
long
long
unum
;
unsigned
long
long
unum
;
/* Make sure there is always space for at least 1 char. */
/* Make sure there is always space for at least 1 char. */
if
(
hi_
sdsavail
(
s
)
==
0
)
{
if
(
sdsavail
(
s
)
==
0
)
{
s
=
hi_
sdsMakeRoomFor
(
s
,
1
);
s
=
sdsMakeRoomFor
(
s
,
1
);
if
(
s
==
NULL
)
goto
fmt_error
;
if
(
s
==
NULL
)
goto
fmt_error
;
}
}
...
@@ -605,13 +605,13 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
...
@@ -605,13 +605,13 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
case
's'
:
case
's'
:
case
'S'
:
case
'S'
:
str
=
va_arg
(
ap
,
char
*
);
str
=
va_arg
(
ap
,
char
*
);
l
=
(
next
==
's'
)
?
strlen
(
str
)
:
hi_
sdslen
(
str
);
l
=
(
next
==
's'
)
?
strlen
(
str
)
:
sdslen
(
str
);
if
(
hi_
sdsavail
(
s
)
<
l
)
{
if
(
sdsavail
(
s
)
<
l
)
{
s
=
hi_
sdsMakeRoomFor
(
s
,
l
);
s
=
sdsMakeRoomFor
(
s
,
l
);
if
(
s
==
NULL
)
goto
fmt_error
;
if
(
s
==
NULL
)
goto
fmt_error
;
}
}
memcpy
(
s
+
i
,
str
,
l
);
memcpy
(
s
+
i
,
str
,
l
);
hi_
sdsinclen
(
s
,
l
);
sdsinclen
(
s
,
l
);
i
+=
l
;
i
+=
l
;
break
;
break
;
case
'i'
:
case
'i'
:
...
@@ -621,14 +621,14 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
...
@@ -621,14 +621,14 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
else
else
num
=
va_arg
(
ap
,
long
long
);
num
=
va_arg
(
ap
,
long
long
);
{
{
char
buf
[
HI_
SDS_LLSTR_SIZE
];
char
buf
[
SDS_LLSTR_SIZE
];
l
=
hi_
sdsll2str
(
buf
,
num
);
l
=
sdsll2str
(
buf
,
num
);
if
(
hi_
sdsavail
(
s
)
<
l
)
{
if
(
sdsavail
(
s
)
<
l
)
{
s
=
hi_
sdsMakeRoomFor
(
s
,
l
);
s
=
sdsMakeRoomFor
(
s
,
l
);
if
(
s
==
NULL
)
goto
fmt_error
;
if
(
s
==
NULL
)
goto
fmt_error
;
}
}
memcpy
(
s
+
i
,
buf
,
l
);
memcpy
(
s
+
i
,
buf
,
l
);
hi_
sdsinclen
(
s
,
l
);
sdsinclen
(
s
,
l
);
i
+=
l
;
i
+=
l
;
}
}
break
;
break
;
...
@@ -639,26 +639,26 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
...
@@ -639,26 +639,26 @@ hisds hi_sdscatfmt(hisds s, char const *fmt, ...) {
else
else
unum
=
va_arg
(
ap
,
unsigned
long
long
);
unum
=
va_arg
(
ap
,
unsigned
long
long
);
{
{
char
buf
[
HI_
SDS_LLSTR_SIZE
];
char
buf
[
SDS_LLSTR_SIZE
];
l
=
hi_
sdsull2str
(
buf
,
unum
);
l
=
sdsull2str
(
buf
,
unum
);
if
(
hi_
sdsavail
(
s
)
<
l
)
{
if
(
sdsavail
(
s
)
<
l
)
{
s
=
hi_
sdsMakeRoomFor
(
s
,
l
);
s
=
sdsMakeRoomFor
(
s
,
l
);
if
(
s
==
NULL
)
goto
fmt_error
;
if
(
s
==
NULL
)
goto
fmt_error
;
}
}
memcpy
(
s
+
i
,
buf
,
l
);
memcpy
(
s
+
i
,
buf
,
l
);
hi_
sdsinclen
(
s
,
l
);
sdsinclen
(
s
,
l
);
i
+=
l
;
i
+=
l
;
}
}
break
;
break
;
default:
/* Handle %% and generally %<unknown>. */
default:
/* Handle %% and generally %<unknown>. */
s
[
i
++
]
=
next
;
s
[
i
++
]
=
next
;
hi_
sdsinclen
(
s
,
1
);
sdsinclen
(
s
,
1
);
break
;
break
;
}
}
break
;
break
;
default:
default:
s
[
i
++
]
=
*
f
;
s
[
i
++
]
=
*
f
;
hi_
sdsinclen
(
s
,
1
);
sdsinclen
(
s
,
1
);
break
;
break
;
}
}
f
++
;
f
++
;
...
@@ -677,29 +677,29 @@ fmt_error:
...
@@ -677,29 +677,29 @@ fmt_error:
/* Remove the part of the string from left and from right composed just of
/* Remove the part of the string from left and from right composed just of
* contiguous characters found in 'cset', that is a null terminted C string.
* contiguous characters found in 'cset', that is a null terminted C string.
*
*
* After the call, the modified
hi
sds string is no longer valid and all the
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call.
* references must be substituted with the new pointer returned by the call.
*
*
* Example:
* Example:
*
*
* s =
hi_
sdsnew("AA...AA.a.aa.aHelloWorld :::");
* s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
* s =
hi_
sdstrim(s,"Aa. :");
* s = sdstrim(s,"Aa. :");
* printf("%s\n", s);
* printf("%s\n", s);
*
*
* Output will be just "Hello World".
* Output will be just "Hello World".
*/
*/
hi
sds
hi_
sdstrim
(
hi
sds
s
,
const
char
*
cset
)
{
sds
sdstrim
(
sds
s
,
const
char
*
cset
)
{
char
*
start
,
*
end
,
*
sp
,
*
ep
;
char
*
start
,
*
end
,
*
sp
,
*
ep
;
size_t
len
;
size_t
len
;
sp
=
start
=
s
;
sp
=
start
=
s
;
ep
=
end
=
s
+
hi_
sdslen
(
s
)
-
1
;
ep
=
end
=
s
+
sdslen
(
s
)
-
1
;
while
(
sp
<=
end
&&
strchr
(
cset
,
*
sp
))
sp
++
;
while
(
sp
<=
end
&&
strchr
(
cset
,
*
sp
))
sp
++
;
while
(
ep
>
sp
&&
strchr
(
cset
,
*
ep
))
ep
--
;
while
(
ep
>
sp
&&
strchr
(
cset
,
*
ep
))
ep
--
;
len
=
(
sp
>
ep
)
?
0
:
((
ep
-
sp
)
+
1
);
len
=
(
sp
>
ep
)
?
0
:
((
ep
-
sp
)
+
1
);
if
(
s
!=
sp
)
memmove
(
s
,
sp
,
len
);
if
(
s
!=
sp
)
memmove
(
s
,
sp
,
len
);
s
[
len
]
=
'\0'
;
s
[
len
]
=
'\0'
;
hi_
sdssetlen
(
s
,
len
);
sdssetlen
(
s
,
len
);
return
s
;
return
s
;
}
}
...
@@ -715,16 +715,16 @@ hisds hi_sdstrim(hisds s, const char *cset) {
...
@@ -715,16 +715,16 @@ hisds hi_sdstrim(hisds s, const char *cset) {
* The string is modified in-place.
* The string is modified in-place.
*
*
* Return value:
* Return value:
* -1 (error) if
hi_
sdslen(s) is larger than maximum positive ssize_t value.
* -1 (error) if sdslen(s) is larger than maximum positive ssize_t value.
* 0 on success.
* 0 on success.
*
*
* Example:
* Example:
*
*
* s =
hi_
sdsnew("Hello World");
* s = sdsnew("Hello World");
*
hi_
sdsrange(s,1,-1); => "ello World"
* sdsrange(s,1,-1); => "ello World"
*/
*/
int
hi_
sdsrange
(
hi
sds
s
,
ssize_t
start
,
ssize_t
end
)
{
int
sdsrange
(
sds
s
,
ssize_t
start
,
ssize_t
end
)
{
size_t
newlen
,
len
=
hi_
sdslen
(
s
);
size_t
newlen
,
len
=
sdslen
(
s
);
if
(
len
>
SSIZE_MAX
)
return
-
1
;
if
(
len
>
SSIZE_MAX
)
return
-
1
;
if
(
len
==
0
)
return
0
;
if
(
len
==
0
)
return
0
;
...
@@ -749,25 +749,25 @@ int hi_sdsrange(hisds s, ssize_t start, ssize_t end) {
...
@@ -749,25 +749,25 @@ int hi_sdsrange(hisds s, ssize_t start, ssize_t end) {
}
}
if
(
start
&&
newlen
)
memmove
(
s
,
s
+
start
,
newlen
);
if
(
start
&&
newlen
)
memmove
(
s
,
s
+
start
,
newlen
);
s
[
newlen
]
=
0
;
s
[
newlen
]
=
0
;
hi_
sdssetlen
(
s
,
newlen
);
sdssetlen
(
s
,
newlen
);
return
0
;
return
0
;
}
}
/* Apply tolower() to every character of the
hi
sds string 's'. */
/* Apply tolower() to every character of the sds string 's'. */
void
hi_
sdstolower
(
hi
sds
s
)
{
void
sdstolower
(
sds
s
)
{
int
len
=
hi_
sdslen
(
s
),
j
;
int
len
=
sdslen
(
s
),
j
;
for
(
j
=
0
;
j
<
len
;
j
++
)
s
[
j
]
=
tolower
(
s
[
j
]);
for
(
j
=
0
;
j
<
len
;
j
++
)
s
[
j
]
=
tolower
(
s
[
j
]);
}
}
/* Apply toupper() to every character of the
hi
sds string 's'. */
/* Apply toupper() to every character of the sds string 's'. */
void
hi_
sdstoupper
(
hi
sds
s
)
{
void
sdstoupper
(
sds
s
)
{
int
len
=
hi_
sdslen
(
s
),
j
;
int
len
=
sdslen
(
s
),
j
;
for
(
j
=
0
;
j
<
len
;
j
++
)
s
[
j
]
=
toupper
(
s
[
j
]);
for
(
j
=
0
;
j
<
len
;
j
++
)
s
[
j
]
=
toupper
(
s
[
j
]);
}
}
/* Compare two
hi
sds strings s1 and s2 with memcmp().
/* Compare two sds strings s1 and s2 with memcmp().
*
*
* Return value:
* Return value:
*
*
...
@@ -778,12 +778,12 @@ void hi_sdstoupper(hisds s) {
...
@@ -778,12 +778,12 @@ void hi_sdstoupper(hisds s) {
* If two strings share exactly the same prefix, but one of the two has
* If two strings share exactly the same prefix, but one of the two has
* additional characters, the longer string is considered to be greater than
* additional characters, the longer string is considered to be greater than
* the smaller one. */
* the smaller one. */
int
hi_
sdscmp
(
const
hi
sds
s1
,
const
hi
sds
s2
)
{
int
sdscmp
(
const
sds
s1
,
const
sds
s2
)
{
size_t
l1
,
l2
,
minlen
;
size_t
l1
,
l2
,
minlen
;
int
cmp
;
int
cmp
;
l1
=
hi_
sdslen
(
s1
);
l1
=
sdslen
(
s1
);
l2
=
hi_
sdslen
(
s2
);
l2
=
sdslen
(
s2
);
minlen
=
(
l1
<
l2
)
?
l1
:
l2
;
minlen
=
(
l1
<
l2
)
?
l1
:
l2
;
cmp
=
memcmp
(
s1
,
s2
,
minlen
);
cmp
=
memcmp
(
s1
,
s2
,
minlen
);
if
(
cmp
==
0
)
return
l1
-
l2
;
if
(
cmp
==
0
)
return
l1
-
l2
;
...
@@ -791,7 +791,7 @@ int hi_sdscmp(const hisds s1, const hisds s2) {
...
@@ -791,7 +791,7 @@ int hi_sdscmp(const hisds s1, const hisds s2) {
}
}
/* Split 's' with separator in 'sep'. An array
/* Split 's' with separator in 'sep'. An array
* of
hi
sds strings is returned. *count will be set
* of sds strings is returned. *count will be set
* by reference to the number of tokens returned.
* by reference to the number of tokens returned.
*
*
* On out of memory, zero length string, zero length
* On out of memory, zero length string, zero length
...
@@ -799,20 +799,20 @@ int hi_sdscmp(const hisds s1, const hisds s2) {
...
@@ -799,20 +799,20 @@ int hi_sdscmp(const hisds s1, const hisds s2) {
*
*
* Note that 'sep' is able to split a string using
* Note that 'sep' is able to split a string using
* a multi-character separator. For example
* a multi-character separator. For example
*
hi_
sdssplit("foo_-_bar","_-_"); will return two
* sdssplit("foo_-_bar","_-_"); will return two
* elements "foo" and "bar".
* elements "foo" and "bar".
*
*
* This version of the function is binary-safe but
* This version of the function is binary-safe but
* requires length arguments.
hi_
sdssplit() is just the
* requires length arguments. sdssplit() is just the
* same function but for zero-terminated strings.
* same function but for zero-terminated strings.
*/
*/
hi
sds
*
hi_
sdssplitlen
(
const
char
*
s
,
int
len
,
const
char
*
sep
,
int
seplen
,
int
*
count
)
{
sds
*
sdssplitlen
(
const
char
*
s
,
int
len
,
const
char
*
sep
,
int
seplen
,
int
*
count
)
{
int
elements
=
0
,
slots
=
5
,
start
=
0
,
j
;
int
elements
=
0
,
slots
=
5
,
start
=
0
,
j
;
hi
sds
*
tokens
;
sds
*
tokens
;
if
(
seplen
<
1
||
len
<
0
)
return
NULL
;
if
(
seplen
<
1
||
len
<
0
)
return
NULL
;
tokens
=
hi_
s_malloc
(
sizeof
(
hi
sds
)
*
slots
);
tokens
=
s_malloc
(
sizeof
(
sds
)
*
slots
);
if
(
tokens
==
NULL
)
return
NULL
;
if
(
tokens
==
NULL
)
return
NULL
;
if
(
len
==
0
)
{
if
(
len
==
0
)
{
...
@@ -822,16 +822,16 @@ hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *
...
@@ -822,16 +822,16 @@ hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *
for
(
j
=
0
;
j
<
(
len
-
(
seplen
-
1
));
j
++
)
{
for
(
j
=
0
;
j
<
(
len
-
(
seplen
-
1
));
j
++
)
{
/* make sure there is room for the next element and the final one */
/* make sure there is room for the next element and the final one */
if
(
slots
<
elements
+
2
)
{
if
(
slots
<
elements
+
2
)
{
hi
sds
*
newtokens
;
sds
*
newtokens
;
slots
*=
2
;
slots
*=
2
;
newtokens
=
hi_
s_realloc
(
tokens
,
sizeof
(
hi
sds
)
*
slots
);
newtokens
=
s_realloc
(
tokens
,
sizeof
(
sds
)
*
slots
);
if
(
newtokens
==
NULL
)
goto
cleanup
;
if
(
newtokens
==
NULL
)
goto
cleanup
;
tokens
=
newtokens
;
tokens
=
newtokens
;
}
}
/* search the separator */
/* search the separator */
if
((
seplen
==
1
&&
*
(
s
+
j
)
==
sep
[
0
])
||
(
memcmp
(
s
+
j
,
sep
,
seplen
)
==
0
))
{
if
((
seplen
==
1
&&
*
(
s
+
j
)
==
sep
[
0
])
||
(
memcmp
(
s
+
j
,
sep
,
seplen
)
==
0
))
{
tokens
[
elements
]
=
hi_
sdsnewlen
(
s
+
start
,
j
-
start
);
tokens
[
elements
]
=
sdsnewlen
(
s
+
start
,
j
-
start
);
if
(
tokens
[
elements
]
==
NULL
)
goto
cleanup
;
if
(
tokens
[
elements
]
==
NULL
)
goto
cleanup
;
elements
++
;
elements
++
;
start
=
j
+
seplen
;
start
=
j
+
seplen
;
...
@@ -839,7 +839,7 @@ hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *
...
@@ -839,7 +839,7 @@ hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *
}
}
}
}
/* Add the final element. We are sure there is room in the tokens array. */
/* Add the final element. We are sure there is room in the tokens array. */
tokens
[
elements
]
=
hi_
sdsnewlen
(
s
+
start
,
len
-
start
);
tokens
[
elements
]
=
sdsnewlen
(
s
+
start
,
len
-
start
);
if
(
tokens
[
elements
]
==
NULL
)
goto
cleanup
;
if
(
tokens
[
elements
]
==
NULL
)
goto
cleanup
;
elements
++
;
elements
++
;
*
count
=
elements
;
*
count
=
elements
;
...
@@ -848,55 +848,55 @@ hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *
...
@@ -848,55 +848,55 @@ hisds *hi_sdssplitlen(const char *s, int len, const char *sep, int seplen, int *
cleanup:
cleanup:
{
{
int
i
;
int
i
;
for
(
i
=
0
;
i
<
elements
;
i
++
)
hi_
sdsfree
(
tokens
[
i
]);
for
(
i
=
0
;
i
<
elements
;
i
++
)
sdsfree
(
tokens
[
i
]);
hi_
s_free
(
tokens
);
s_free
(
tokens
);
*
count
=
0
;
*
count
=
0
;
return
NULL
;
return
NULL
;
}
}
}
}
/* Free the result returned by
hi_
sdssplitlen(), or do nothing if 'tokens' is NULL. */
/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */
void
hi_
sdsfreesplitres
(
hi
sds
*
tokens
,
int
count
)
{
void
sdsfreesplitres
(
sds
*
tokens
,
int
count
)
{
if
(
!
tokens
)
return
;
if
(
!
tokens
)
return
;
while
(
count
--
)
while
(
count
--
)
hi_
sdsfree
(
tokens
[
count
]);
sdsfree
(
tokens
[
count
]);
hi_
s_free
(
tokens
);
s_free
(
tokens
);
}
}
/* Append to the
hi
sds string "s" an escaped string representation where
/* Append to the sds string "s" an escaped string representation where
* all the non-printable characters (tested with isprint()) are turned into
* all the non-printable characters (tested with isprint()) are turned into
* escapes in the form "\n\r\a...." or "\x<hex-number>".
* escapes in the form "\n\r\a...." or "\x<hex-number>".
*
*
* After the call, the modified
hi
sds string is no longer valid and all the
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
* references must be substituted with the new pointer returned by the call. */
hi
sds
hi_
sdscatrepr
(
hi
sds
s
,
const
char
*
p
,
size_t
len
)
{
sds
sdscatrepr
(
sds
s
,
const
char
*
p
,
size_t
len
)
{
s
=
hi_
sdscatlen
(
s
,
"
\"
"
,
1
);
s
=
sdscatlen
(
s
,
"
\"
"
,
1
);
while
(
len
--
)
{
while
(
len
--
)
{
switch
(
*
p
)
{
switch
(
*
p
)
{
case
'\\'
:
case
'\\'
:
case
'"'
:
case
'"'
:
s
=
hi_
sdscatprintf
(
s
,
"
\\
%c"
,
*
p
);
s
=
sdscatprintf
(
s
,
"
\\
%c"
,
*
p
);
break
;
break
;
case
'\n'
:
s
=
hi_
sdscatlen
(
s
,
"
\\
n"
,
2
);
break
;
case
'\n'
:
s
=
sdscatlen
(
s
,
"
\\
n"
,
2
);
break
;
case
'\r'
:
s
=
hi_
sdscatlen
(
s
,
"
\\
r"
,
2
);
break
;
case
'\r'
:
s
=
sdscatlen
(
s
,
"
\\
r"
,
2
);
break
;
case
'\t'
:
s
=
hi_
sdscatlen
(
s
,
"
\\
t"
,
2
);
break
;
case
'\t'
:
s
=
sdscatlen
(
s
,
"
\\
t"
,
2
);
break
;
case
'\a'
:
s
=
hi_
sdscatlen
(
s
,
"
\\
a"
,
2
);
break
;
case
'\a'
:
s
=
sdscatlen
(
s
,
"
\\
a"
,
2
);
break
;
case
'\b'
:
s
=
hi_
sdscatlen
(
s
,
"
\\
b"
,
2
);
break
;
case
'\b'
:
s
=
sdscatlen
(
s
,
"
\\
b"
,
2
);
break
;
default:
default:
if
(
isprint
(
*
p
))
if
(
isprint
(
*
p
))
s
=
hi_
sdscatprintf
(
s
,
"%c"
,
*
p
);
s
=
sdscatprintf
(
s
,
"%c"
,
*
p
);
else
else
s
=
hi_
sdscatprintf
(
s
,
"
\\
x%02x"
,(
unsigned
char
)
*
p
);
s
=
sdscatprintf
(
s
,
"
\\
x%02x"
,(
unsigned
char
)
*
p
);
break
;
break
;
}
}
p
++
;
p
++
;
}
}
return
hi_
sdscatlen
(
s
,
"
\"
"
,
1
);
return
sdscatlen
(
s
,
"
\"
"
,
1
);
}
}
/* Helper function for
hi_
sdssplitargs() that converts a hex digit into an
/* Helper function for sdssplitargs() that converts a hex digit into an
* integer from 0 to 15 */
* integer from 0 to 15 */
static
int
hi_
hex_digit_to_int
(
char
c
)
{
int
hex_digit_to_int
(
char
c
)
{
switch
(
c
)
{
switch
(
c
)
{
case
'0'
:
return
0
;
case
'0'
:
return
0
;
case
'1'
:
return
1
;
case
'1'
:
return
1
;
...
@@ -924,20 +924,20 @@ static int hi_hex_digit_to_int(char c) {
...
@@ -924,20 +924,20 @@ static int hi_hex_digit_to_int(char c) {
* foo bar "newline are supported\n" and "\xff\x00otherstuff"
* foo bar "newline are supported\n" and "\xff\x00otherstuff"
*
*
* The number of arguments is stored into *argc, and an array
* The number of arguments is stored into *argc, and an array
* of
hi
sds is returned.
* of sds is returned.
*
*
* The caller should free the resulting array of
hi
sds strings with
* The caller should free the resulting array of sds strings with
*
hi_
sdsfreesplitres().
* sdsfreesplitres().
*
*
* Note that
hi_
sdscatrepr() is able to convert back a string into
* Note that sdscatrepr() is able to convert back a string into
* a quoted string in the same format
hi_
sdssplitargs() is able to parse.
* a quoted string in the same format sdssplitargs() is able to parse.
*
*
* The function returns the allocated tokens on success, even when the
* The function returns the allocated tokens on success, even when the
* input string is empty, or NULL if the input contains unbalanced
* input string is empty, or NULL if the input contains unbalanced
* quotes or closed quotes followed by non space characters
* quotes or closed quotes followed by non space characters
* as in: "foo"bar or "foo'
* as in: "foo"bar or "foo'
*/
*/
hi
sds
*
hi_
sdssplitargs
(
const
char
*
line
,
int
*
argc
)
{
sds
*
sdssplitargs
(
const
char
*
line
,
int
*
argc
)
{
const
char
*
p
=
line
;
const
char
*
p
=
line
;
char
*
current
=
NULL
;
char
*
current
=
NULL
;
char
**
vector
=
NULL
;
char
**
vector
=
NULL
;
...
@@ -952,7 +952,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
...
@@ -952,7 +952,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
int
insq
=
0
;
/* set to 1 if we are in 'single quotes' */
int
insq
=
0
;
/* set to 1 if we are in 'single quotes' */
int
done
=
0
;
int
done
=
0
;
if
(
current
==
NULL
)
current
=
hi_
sdsempty
();
if
(
current
==
NULL
)
current
=
sdsempty
();
while
(
!
done
)
{
while
(
!
done
)
{
if
(
inq
)
{
if
(
inq
)
{
if
(
*
p
==
'\\'
&&
*
(
p
+
1
)
==
'x'
&&
if
(
*
p
==
'\\'
&&
*
(
p
+
1
)
==
'x'
&&
...
@@ -961,9 +961,9 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
...
@@ -961,9 +961,9 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
{
{
unsigned
char
byte
;
unsigned
char
byte
;
byte
=
(
hi_
hex_digit_to_int
(
*
(
p
+
2
))
*
16
)
+
byte
=
(
hex_digit_to_int
(
*
(
p
+
2
))
*
16
)
+
hi_
hex_digit_to_int
(
*
(
p
+
3
));
hex_digit_to_int
(
*
(
p
+
3
));
current
=
hi_
sdscatlen
(
current
,(
char
*
)
&
byte
,
1
);
current
=
sdscatlen
(
current
,(
char
*
)
&
byte
,
1
);
p
+=
3
;
p
+=
3
;
}
else
if
(
*
p
==
'\\'
&&
*
(
p
+
1
))
{
}
else
if
(
*
p
==
'\\'
&&
*
(
p
+
1
))
{
char
c
;
char
c
;
...
@@ -977,7 +977,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
...
@@ -977,7 +977,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
case
'a'
:
c
=
'\a'
;
break
;
case
'a'
:
c
=
'\a'
;
break
;
default:
c
=
*
p
;
break
;
default:
c
=
*
p
;
break
;
}
}
current
=
hi_
sdscatlen
(
current
,
&
c
,
1
);
current
=
sdscatlen
(
current
,
&
c
,
1
);
}
else
if
(
*
p
==
'"'
)
{
}
else
if
(
*
p
==
'"'
)
{
/* closing quote must be followed by a space or
/* closing quote must be followed by a space or
* nothing at all. */
* nothing at all. */
...
@@ -987,12 +987,12 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
...
@@ -987,12 +987,12 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
/* unterminated quotes */
/* unterminated quotes */
goto
err
;
goto
err
;
}
else
{
}
else
{
current
=
hi_
sdscatlen
(
current
,
p
,
1
);
current
=
sdscatlen
(
current
,
p
,
1
);
}
}
}
else
if
(
insq
)
{
}
else
if
(
insq
)
{
if
(
*
p
==
'\\'
&&
*
(
p
+
1
)
==
'\''
)
{
if
(
*
p
==
'\\'
&&
*
(
p
+
1
)
==
'\''
)
{
p
++
;
p
++
;
current
=
hi_
sdscatlen
(
current
,
"'"
,
1
);
current
=
sdscatlen
(
current
,
"'"
,
1
);
}
else
if
(
*
p
==
'\''
)
{
}
else
if
(
*
p
==
'\''
)
{
/* closing quote must be followed by a space or
/* closing quote must be followed by a space or
* nothing at all. */
* nothing at all. */
...
@@ -1002,7 +1002,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
...
@@ -1002,7 +1002,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
/* unterminated quotes */
/* unterminated quotes */
goto
err
;
goto
err
;
}
else
{
}
else
{
current
=
hi_
sdscatlen
(
current
,
p
,
1
);
current
=
sdscatlen
(
current
,
p
,
1
);
}
}
}
else
{
}
else
{
switch
(
*
p
)
{
switch
(
*
p
)
{
...
@@ -1020,7 +1020,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
...
@@ -1020,7 +1020,7 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
insq
=
1
;
insq
=
1
;
break
;
break
;
default:
default:
current
=
hi_
sdscatlen
(
current
,
p
,
1
);
current
=
sdscatlen
(
current
,
p
,
1
);
break
;
break
;
}
}
}
}
...
@@ -1028,9 +1028,9 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
...
@@ -1028,9 +1028,9 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
}
}
/* add the token to the vector */
/* add the token to the vector */
{
{
char
**
new_vector
=
hi_
s_realloc
(
vector
,((
*
argc
)
+
1
)
*
sizeof
(
char
*
));
char
**
new_vector
=
s_realloc
(
vector
,((
*
argc
)
+
1
)
*
sizeof
(
char
*
));
if
(
new_vector
==
NULL
)
{
if
(
new_vector
==
NULL
)
{
hi_
s_free
(
vector
);
s_free
(
vector
);
return
NULL
;
return
NULL
;
}
}
...
@@ -1041,16 +1041,16 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
...
@@ -1041,16 +1041,16 @@ hisds *hi_sdssplitargs(const char *line, int *argc) {
}
}
}
else
{
}
else
{
/* Even on empty input string return something not NULL. */
/* Even on empty input string return something not NULL. */
if
(
vector
==
NULL
)
vector
=
hi_
s_malloc
(
sizeof
(
void
*
));
if
(
vector
==
NULL
)
vector
=
s_malloc
(
sizeof
(
void
*
));
return
vector
;
return
vector
;
}
}
}
}
err:
err:
while
((
*
argc
)
--
)
while
((
*
argc
)
--
)
hi_
sdsfree
(
vector
[
*
argc
]);
sdsfree
(
vector
[
*
argc
]);
hi_
s_free
(
vector
);
s_free
(
vector
);
if
(
current
)
hi_
sdsfree
(
current
);
if
(
current
)
sdsfree
(
current
);
*
argc
=
0
;
*
argc
=
0
;
return
NULL
;
return
NULL
;
}
}
...
@@ -1059,13 +1059,13 @@ err:
...
@@ -1059,13 +1059,13 @@ err:
* characters specified in the 'from' string to the corresponding character
* characters specified in the 'from' string to the corresponding character
* in the 'to' array.
* in the 'to' array.
*
*
* For instance:
hi_
sdsmapchars(mystring, "ho", "01", 2)
* For instance: sdsmapchars(mystring, "ho", "01", 2)
* will have the effect of turning the string "hello" into "0ell1".
* will have the effect of turning the string "hello" into "0ell1".
*
*
* The function returns the
hi
sds string pointer, that is always the same
* The function returns the sds string pointer, that is always the same
* as the input pointer since no resize is needed. */
* as the input pointer since no resize is needed. */
hi
sds
hi_
sdsmapchars
(
hi
sds
s
,
const
char
*
from
,
const
char
*
to
,
size_t
setlen
)
{
sds
sdsmapchars
(
sds
s
,
const
char
*
from
,
const
char
*
to
,
size_t
setlen
)
{
size_t
j
,
i
,
l
=
hi_
sdslen
(
s
);
size_t
j
,
i
,
l
=
sdslen
(
s
);
for
(
j
=
0
;
j
<
l
;
j
++
)
{
for
(
j
=
0
;
j
<
l
;
j
++
)
{
for
(
i
=
0
;
i
<
setlen
;
i
++
)
{
for
(
i
=
0
;
i
<
setlen
;
i
++
)
{
...
@@ -1079,26 +1079,26 @@ hisds hi_sdsmapchars(hisds s, const char *from, const char *to, size_t setlen) {
...
@@ -1079,26 +1079,26 @@ hisds hi_sdsmapchars(hisds s, const char *from, const char *to, size_t setlen) {
}
}
/* Join an array of C strings using the specified separator (also a C string).
/* Join an array of C strings using the specified separator (also a C string).
* Returns the result as an
hi
sds string. */
* Returns the result as an sds string. */
hi
sds
hi_
sdsjoin
(
char
**
argv
,
int
argc
,
char
*
sep
)
{
sds
sdsjoin
(
char
**
argv
,
int
argc
,
char
*
sep
)
{
hi
sds
join
=
hi_
sdsempty
();
sds
join
=
sdsempty
();
int
j
;
int
j
;
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
join
=
hi_
sdscat
(
join
,
argv
[
j
]);
join
=
sdscat
(
join
,
argv
[
j
]);
if
(
j
!=
argc
-
1
)
join
=
hi_
sdscat
(
join
,
sep
);
if
(
j
!=
argc
-
1
)
join
=
sdscat
(
join
,
sep
);
}
}
return
join
;
return
join
;
}
}
/* Like
hi_
sdsjoin, but joins an array of SDS strings. */
/* Like sdsjoin, but joins an array of SDS strings. */
hi
sds
hi_
sdsjoinsds
(
hi
sds
*
argv
,
int
argc
,
const
char
*
sep
,
size_t
seplen
)
{
sds
sdsjoinsds
(
sds
*
argv
,
int
argc
,
const
char
*
sep
,
size_t
seplen
)
{
hi
sds
join
=
hi_
sdsempty
();
sds
join
=
sdsempty
();
int
j
;
int
j
;
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
join
=
hi_
sdscatsds
(
join
,
argv
[
j
]);
join
=
sdscatsds
(
join
,
argv
[
j
]);
if
(
j
!=
argc
-
1
)
join
=
hi_
sdscatlen
(
join
,
sep
,
seplen
);
if
(
j
!=
argc
-
1
)
join
=
sdscatlen
(
join
,
sep
,
seplen
);
}
}
return
join
;
return
join
;
}
}
...
@@ -1108,138 +1108,138 @@ hisds hi_sdsjoinsds(hisds *argv, int argc, const char *sep, size_t seplen) {
...
@@ -1108,138 +1108,138 @@ hisds hi_sdsjoinsds(hisds *argv, int argc, const char *sep, size_t seplen) {
* the overhead of function calls. Here we define these wrappers only for
* the overhead of function calls. Here we define these wrappers only for
* the programs SDS is linked to, if they want to touch the SDS internals
* the programs SDS is linked to, if they want to touch the SDS internals
* even if they use a different allocator. */
* even if they use a different allocator. */
void
*
hi_
sds_malloc
(
size_t
size
)
{
return
hi_
s_malloc
(
size
);
}
void
*
sds_malloc
(
size_t
size
)
{
return
s_malloc
(
size
);
}
void
*
hi_
sds_realloc
(
void
*
ptr
,
size_t
size
)
{
return
hi_
s_realloc
(
ptr
,
size
);
}
void
*
sds_realloc
(
void
*
ptr
,
size_t
size
)
{
return
s_realloc
(
ptr
,
size
);
}
void
hi_
sds_free
(
void
*
ptr
)
{
hi_
s_free
(
ptr
);
}
void
sds_free
(
void
*
ptr
)
{
s_free
(
ptr
);
}
#if defined(
HI_
SDS_TEST_MAIN)
#if defined(SDS_TEST_MAIN)
#include <stdio.h>
#include <stdio.h>
#include "testhelp.h"
#include "testhelp.h"
#include "limits.h"
#include "limits.h"
#define UNUSED(x) (void)(x)
#define UNUSED(x) (void)(x)
int
hi_
sdsTest
(
void
)
{
int
sdsTest
(
void
)
{
{
{
hi
sds
x
=
hi_
sdsnew
(
"foo"
),
y
;
sds
x
=
sdsnew
(
"foo"
),
y
;
test_cond
(
"Create a string and obtain the length"
,
test_cond
(
"Create a string and obtain the length"
,
hi_
sdslen
(
x
)
==
3
&&
memcmp
(
x
,
"foo
\0
"
,
4
)
==
0
)
sdslen
(
x
)
==
3
&&
memcmp
(
x
,
"foo
\0
"
,
4
)
==
0
)
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnewlen
(
"foo"
,
2
);
x
=
sdsnewlen
(
"foo"
,
2
);
test_cond
(
"Create a string with specified length"
,
test_cond
(
"Create a string with specified length"
,
hi_
sdslen
(
x
)
==
2
&&
memcmp
(
x
,
"fo
\0
"
,
3
)
==
0
)
sdslen
(
x
)
==
2
&&
memcmp
(
x
,
"fo
\0
"
,
3
)
==
0
)
x
=
hi_
sdscat
(
x
,
"bar"
);
x
=
sdscat
(
x
,
"bar"
);
test_cond
(
"Strings concatenation"
,
test_cond
(
"Strings concatenation"
,
hi_
sdslen
(
x
)
==
5
&&
memcmp
(
x
,
"fobar
\0
"
,
6
)
==
0
);
sdslen
(
x
)
==
5
&&
memcmp
(
x
,
"fobar
\0
"
,
6
)
==
0
);
x
=
hi_
sdscpy
(
x
,
"a"
);
x
=
sdscpy
(
x
,
"a"
);
test_cond
(
"
hi_
sdscpy() against an originally longer string"
,
test_cond
(
"sdscpy() against an originally longer string"
,
hi_
sdslen
(
x
)
==
1
&&
memcmp
(
x
,
"a
\0
"
,
2
)
==
0
)
sdslen
(
x
)
==
1
&&
memcmp
(
x
,
"a
\0
"
,
2
)
==
0
)
x
=
hi_
sdscpy
(
x
,
"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"
);
x
=
sdscpy
(
x
,
"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"
);
test_cond
(
"
hi_
sdscpy() against an originally shorter string"
,
test_cond
(
"sdscpy() against an originally shorter string"
,
hi_
sdslen
(
x
)
==
33
&&
sdslen
(
x
)
==
33
&&
memcmp
(
x
,
"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk
\0
"
,
33
)
==
0
)
memcmp
(
x
,
"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk
\0
"
,
33
)
==
0
)
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdscatprintf
(
hi_
sdsempty
(),
"%d"
,
123
);
x
=
sdscatprintf
(
sdsempty
(),
"%d"
,
123
);
test_cond
(
"
hi_
sdscatprintf() seems working in the base case"
,
test_cond
(
"sdscatprintf() seems working in the base case"
,
hi_
sdslen
(
x
)
==
3
&&
memcmp
(
x
,
"123
\0
"
,
4
)
==
0
)
sdslen
(
x
)
==
3
&&
memcmp
(
x
,
"123
\0
"
,
4
)
==
0
)
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnew
(
"--"
);
x
=
sdsnew
(
"--"
);
x
=
hi_
sdscatfmt
(
x
,
"Hello %s World %I,%I--"
,
"Hi!"
,
LLONG_MIN
,
LLONG_MAX
);
x
=
sdscatfmt
(
x
,
"Hello %s World %I,%I--"
,
"Hi!"
,
LLONG_MIN
,
LLONG_MAX
);
test_cond
(
"
hi_
sdscatfmt() seems working in the base case"
,
test_cond
(
"sdscatfmt() seems working in the base case"
,
hi_
sdslen
(
x
)
==
60
&&
sdslen
(
x
)
==
60
&&
memcmp
(
x
,
"--Hello Hi! World -9223372036854775808,"
memcmp
(
x
,
"--Hello Hi! World -9223372036854775808,"
"9223372036854775807--"
,
60
)
==
0
)
"9223372036854775807--"
,
60
)
==
0
)
printf
(
"[%s]
\n
"
,
x
);
printf
(
"[%s]
\n
"
,
x
);
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnew
(
"--"
);
x
=
sdsnew
(
"--"
);
x
=
hi_
sdscatfmt
(
x
,
"%u,%U--"
,
UINT_MAX
,
ULLONG_MAX
);
x
=
sdscatfmt
(
x
,
"%u,%U--"
,
UINT_MAX
,
ULLONG_MAX
);
test_cond
(
"
hi_
sdscatfmt() seems working with unsigned numbers"
,
test_cond
(
"sdscatfmt() seems working with unsigned numbers"
,
hi_
sdslen
(
x
)
==
35
&&
sdslen
(
x
)
==
35
&&
memcmp
(
x
,
"--4294967295,18446744073709551615--"
,
35
)
==
0
)
memcmp
(
x
,
"--4294967295,18446744073709551615--"
,
35
)
==
0
)
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnew
(
" x "
);
x
=
sdsnew
(
" x "
);
hi_
sdstrim
(
x
,
" x"
);
sdstrim
(
x
,
" x"
);
test_cond
(
"
hi_
sdstrim() works when all chars match"
,
test_cond
(
"sdstrim() works when all chars match"
,
hi_
sdslen
(
x
)
==
0
)
sdslen
(
x
)
==
0
)
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnew
(
" x "
);
x
=
sdsnew
(
" x "
);
hi_
sdstrim
(
x
,
" "
);
sdstrim
(
x
,
" "
);
test_cond
(
"
hi_
sdstrim() works when a single char remains"
,
test_cond
(
"sdstrim() works when a single char remains"
,
hi_
sdslen
(
x
)
==
1
&&
x
[
0
]
==
'x'
)
sdslen
(
x
)
==
1
&&
x
[
0
]
==
'x'
)
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnew
(
"xxciaoyyy"
);
x
=
sdsnew
(
"xxciaoyyy"
);
hi_
sdstrim
(
x
,
"xy"
);
sdstrim
(
x
,
"xy"
);
test_cond
(
"
hi_
sdstrim() correctly trims characters"
,
test_cond
(
"sdstrim() correctly trims characters"
,
hi_
sdslen
(
x
)
==
4
&&
memcmp
(
x
,
"ciao
\0
"
,
5
)
==
0
)
sdslen
(
x
)
==
4
&&
memcmp
(
x
,
"ciao
\0
"
,
5
)
==
0
)
y
=
hi_
sdsdup
(
x
);
y
=
sdsdup
(
x
);
hi_
sdsrange
(
y
,
1
,
1
);
sdsrange
(
y
,
1
,
1
);
test_cond
(
"
hi_
sdsrange(...,1,1)"
,
test_cond
(
"sdsrange(...,1,1)"
,
hi_
sdslen
(
y
)
==
1
&&
memcmp
(
y
,
"i
\0
"
,
2
)
==
0
)
sdslen
(
y
)
==
1
&&
memcmp
(
y
,
"i
\0
"
,
2
)
==
0
)
hi_
sdsfree
(
y
);
sdsfree
(
y
);
y
=
hi_
sdsdup
(
x
);
y
=
sdsdup
(
x
);
hi_
sdsrange
(
y
,
1
,
-
1
);
sdsrange
(
y
,
1
,
-
1
);
test_cond
(
"
hi_
sdsrange(...,1,-1)"
,
test_cond
(
"sdsrange(...,1,-1)"
,
hi_
sdslen
(
y
)
==
3
&&
memcmp
(
y
,
"iao
\0
"
,
4
)
==
0
)
sdslen
(
y
)
==
3
&&
memcmp
(
y
,
"iao
\0
"
,
4
)
==
0
)
hi_
sdsfree
(
y
);
sdsfree
(
y
);
y
=
hi_
sdsdup
(
x
);
y
=
sdsdup
(
x
);
hi_
sdsrange
(
y
,
-
2
,
-
1
);
sdsrange
(
y
,
-
2
,
-
1
);
test_cond
(
"
hi_
sdsrange(...,-2,-1)"
,
test_cond
(
"sdsrange(...,-2,-1)"
,
hi_
sdslen
(
y
)
==
2
&&
memcmp
(
y
,
"ao
\0
"
,
3
)
==
0
)
sdslen
(
y
)
==
2
&&
memcmp
(
y
,
"ao
\0
"
,
3
)
==
0
)
hi_
sdsfree
(
y
);
sdsfree
(
y
);
y
=
hi_
sdsdup
(
x
);
y
=
sdsdup
(
x
);
hi_
sdsrange
(
y
,
2
,
1
);
sdsrange
(
y
,
2
,
1
);
test_cond
(
"
hi_
sdsrange(...,2,1)"
,
test_cond
(
"sdsrange(...,2,1)"
,
hi_
sdslen
(
y
)
==
0
&&
memcmp
(
y
,
"
\0
"
,
1
)
==
0
)
sdslen
(
y
)
==
0
&&
memcmp
(
y
,
"
\0
"
,
1
)
==
0
)
hi_
sdsfree
(
y
);
sdsfree
(
y
);
y
=
hi_
sdsdup
(
x
);
y
=
sdsdup
(
x
);
hi_
sdsrange
(
y
,
1
,
100
);
sdsrange
(
y
,
1
,
100
);
test_cond
(
"
hi_
sdsrange(...,1,100)"
,
test_cond
(
"sdsrange(...,1,100)"
,
hi_
sdslen
(
y
)
==
3
&&
memcmp
(
y
,
"iao
\0
"
,
4
)
==
0
)
sdslen
(
y
)
==
3
&&
memcmp
(
y
,
"iao
\0
"
,
4
)
==
0
)
hi_
sdsfree
(
y
);
sdsfree
(
y
);
y
=
hi_
sdsdup
(
x
);
y
=
sdsdup
(
x
);
hi_
sdsrange
(
y
,
100
,
100
);
sdsrange
(
y
,
100
,
100
);
test_cond
(
"
hi_
sdsrange(...,100,100)"
,
test_cond
(
"sdsrange(...,100,100)"
,
hi_
sdslen
(
y
)
==
0
&&
memcmp
(
y
,
"
\0
"
,
1
)
==
0
)
sdslen
(
y
)
==
0
&&
memcmp
(
y
,
"
\0
"
,
1
)
==
0
)
hi_
sdsfree
(
y
);
sdsfree
(
y
);
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnew
(
"foo"
);
x
=
sdsnew
(
"foo"
);
y
=
hi_
sdsnew
(
"foa"
);
y
=
sdsnew
(
"foa"
);
test_cond
(
"
hi_
sdscmp(foo,foa)"
,
hi_
sdscmp
(
x
,
y
)
>
0
)
test_cond
(
"sdscmp(foo,foa)"
,
sdscmp
(
x
,
y
)
>
0
)
hi_
sdsfree
(
y
);
sdsfree
(
y
);
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnew
(
"bar"
);
x
=
sdsnew
(
"bar"
);
y
=
hi_
sdsnew
(
"bar"
);
y
=
sdsnew
(
"bar"
);
test_cond
(
"
hi_
sdscmp(bar,bar)"
,
hi_
sdscmp
(
x
,
y
)
==
0
)
test_cond
(
"sdscmp(bar,bar)"
,
sdscmp
(
x
,
y
)
==
0
)
hi_
sdsfree
(
y
);
sdsfree
(
y
);
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnew
(
"aar"
);
x
=
sdsnew
(
"aar"
);
y
=
hi_
sdsnew
(
"bar"
);
y
=
sdsnew
(
"bar"
);
test_cond
(
"
hi_
sdscmp(bar,bar)"
,
hi_
sdscmp
(
x
,
y
)
<
0
)
test_cond
(
"sdscmp(bar,bar)"
,
sdscmp
(
x
,
y
)
<
0
)
hi_
sdsfree
(
y
);
sdsfree
(
y
);
hi_
sdsfree
(
x
);
sdsfree
(
x
);
x
=
hi_
sdsnewlen
(
"
\a\n\0
foo
\r
"
,
7
);
x
=
sdsnewlen
(
"
\a\n\0
foo
\r
"
,
7
);
y
=
hi_
sdscatrepr
(
hi_
sdsempty
(),
x
,
hi_
sdslen
(
x
));
y
=
sdscatrepr
(
sdsempty
(),
x
,
sdslen
(
x
));
test_cond
(
"
hi_
sdscatrepr(...data...)"
,
test_cond
(
"sdscatrepr(...data...)"
,
memcmp
(
y
,
"
\"\\
a
\\
n
\\
x00foo
\\
r
\"
"
,
15
)
==
0
)
memcmp
(
y
,
"
\"\\
a
\\
n
\\
x00foo
\\
r
\"
"
,
15
)
==
0
)
{
{
...
@@ -1247,43 +1247,43 @@ int hi_sdsTest(void) {
...
@@ -1247,43 +1247,43 @@ int hi_sdsTest(void) {
char
*
p
;
char
*
p
;
int
step
=
10
,
j
,
i
;
int
step
=
10
,
j
,
i
;
hi_
sdsfree
(
x
);
sdsfree
(
x
);
hi_
sdsfree
(
y
);
sdsfree
(
y
);
x
=
hi_
sdsnew
(
"0"
);
x
=
sdsnew
(
"0"
);
test_cond
(
"
hi_
sdsnew() free/len buffers"
,
hi_
sdslen
(
x
)
==
1
&&
hi_
sdsavail
(
x
)
==
0
);
test_cond
(
"sdsnew() free/len buffers"
,
sdslen
(
x
)
==
1
&&
sdsavail
(
x
)
==
0
);
/* Run the test a few times in order to hit the first two
/* Run the test a few times in order to hit the first two
* SDS header types. */
* SDS header types. */
for
(
i
=
0
;
i
<
10
;
i
++
)
{
for
(
i
=
0
;
i
<
10
;
i
++
)
{
int
oldlen
=
hi_
sdslen
(
x
);
int
oldlen
=
sdslen
(
x
);
x
=
hi_
sdsMakeRoomFor
(
x
,
step
);
x
=
sdsMakeRoomFor
(
x
,
step
);
int
type
=
x
[
-
1
]
&
HI_
SDS_TYPE_MASK
;
int
type
=
x
[
-
1
]
&
SDS_TYPE_MASK
;
test_cond
(
"sdsMakeRoomFor() len"
,
hi_
sdslen
(
x
)
==
oldlen
);
test_cond
(
"sdsMakeRoomFor() len"
,
sdslen
(
x
)
==
oldlen
);
if
(
type
!=
HI_
SDS_TYPE_5
)
{
if
(
type
!=
SDS_TYPE_5
)
{
test_cond
(
"
hi_
sdsMakeRoomFor() free"
,
hi_
sdsavail
(
x
)
>=
step
);
test_cond
(
"sdsMakeRoomFor() free"
,
sdsavail
(
x
)
>=
step
);
oldfree
=
hi_
sdsavail
(
x
);
oldfree
=
sdsavail
(
x
);
}
}
p
=
x
+
oldlen
;
p
=
x
+
oldlen
;
for
(
j
=
0
;
j
<
step
;
j
++
)
{
for
(
j
=
0
;
j
<
step
;
j
++
)
{
p
[
j
]
=
'A'
+
j
;
p
[
j
]
=
'A'
+
j
;
}
}
hi_
sdsIncrLen
(
x
,
step
);
sdsIncrLen
(
x
,
step
);
}
}
test_cond
(
"
hi_
sdsMakeRoomFor() content"
,
test_cond
(
"sdsMakeRoomFor() content"
,
memcmp
(
"0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ"
,
x
,
101
)
==
0
);
memcmp
(
"0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ"
,
x
,
101
)
==
0
);
test_cond
(
"sdsMakeRoomFor() final length"
,
hi_
sdslen
(
x
)
==
101
);
test_cond
(
"sdsMakeRoomFor() final length"
,
sdslen
(
x
)
==
101
);
hi_
sdsfree
(
x
);
sdsfree
(
x
);
}
}
}
}
test_report
()
;
test_report
()
return
0
;
return
0
;
}
}
#endif
#endif
#ifdef
HI_
SDS_TEST_MAIN
#ifdef SDS_TEST_MAIN
int
main
(
void
)
{
int
main
(
void
)
{
return
hi_
sdsTest
();
return
sdsTest
();
}
}
#endif
#endif
deps/hiredis/sds.h
View file @
886a04c2
...
@@ -30,10 +30,10 @@
...
@@ -30,10 +30,10 @@
* POSSIBILITY OF SUCH DAMAGE.
* POSSIBILITY OF SUCH DAMAGE.
*/
*/
#ifndef
HIREDIS
_SDS_H
#ifndef
_
_SDS_H
#define
HIREDIS
_SDS_H
#define
_
_SDS_H
#define
HI_
SDS_MAX_PREALLOC (1024*1024)
#define SDS_MAX_PREALLOC (1024*1024)
#ifdef _MSC_VER
#ifdef _MSC_VER
#define __attribute__(x)
#define __attribute__(x)
typedef
long
long
ssize_t
;
typedef
long
long
ssize_t
;
...
@@ -44,235 +44,235 @@ typedef long long ssize_t;
...
@@ -44,235 +44,235 @@ typedef long long ssize_t;
#include <stdarg.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdint.h>
typedef
char
*
hi
sds
;
typedef
char
*
sds
;
/* Note: sdshdr5 is never used, we just access the flags byte directly.
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
* However is here to document the layout of type 5 SDS strings. */
struct
__attribute__
((
__packed__
))
hi
sdshdr5
{
struct
__attribute__
((
__packed__
))
sdshdr5
{
unsigned
char
flags
;
/* 3 lsb of type, and 5 msb of string length */
unsigned
char
flags
;
/* 3 lsb of type, and 5 msb of string length */
char
buf
[];
char
buf
[];
};
};
struct
__attribute__
((
__packed__
))
hi
sdshdr8
{
struct
__attribute__
((
__packed__
))
sdshdr8
{
uint8_t
len
;
/* used */
uint8_t
len
;
/* used */
uint8_t
alloc
;
/* excluding the header and null terminator */
uint8_t
alloc
;
/* excluding the header and null terminator */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
char
buf
[];
char
buf
[];
};
};
struct
__attribute__
((
__packed__
))
hi
sdshdr16
{
struct
__attribute__
((
__packed__
))
sdshdr16
{
uint16_t
len
;
/* used */
uint16_t
len
;
/* used */
uint16_t
alloc
;
/* excluding the header and null terminator */
uint16_t
alloc
;
/* excluding the header and null terminator */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
char
buf
[];
char
buf
[];
};
};
struct
__attribute__
((
__packed__
))
hi
sdshdr32
{
struct
__attribute__
((
__packed__
))
sdshdr32
{
uint32_t
len
;
/* used */
uint32_t
len
;
/* used */
uint32_t
alloc
;
/* excluding the header and null terminator */
uint32_t
alloc
;
/* excluding the header and null terminator */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
char
buf
[];
char
buf
[];
};
};
struct
__attribute__
((
__packed__
))
hi
sdshdr64
{
struct
__attribute__
((
__packed__
))
sdshdr64
{
uint64_t
len
;
/* used */
uint64_t
len
;
/* used */
uint64_t
alloc
;
/* excluding the header and null terminator */
uint64_t
alloc
;
/* excluding the header and null terminator */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
unsigned
char
flags
;
/* 3 lsb of type, 5 unused bits */
char
buf
[];
char
buf
[];
};
};
#define
HI_
SDS_TYPE_5 0
#define SDS_TYPE_5 0
#define
HI_
SDS_TYPE_8 1
#define SDS_TYPE_8 1
#define
HI_
SDS_TYPE_16 2
#define SDS_TYPE_16 2
#define
HI_
SDS_TYPE_32 3
#define SDS_TYPE_32 3
#define
HI_
SDS_TYPE_64 4
#define SDS_TYPE_64 4
#define
HI_
SDS_TYPE_MASK 7
#define SDS_TYPE_MASK 7
#define
HI_
SDS_TYPE_BITS 3
#define SDS_TYPE_BITS 3
#define
HI_
SDS_HDR_VAR(T,s) struct
hi
sdshdr##T *sh = (struct
hi
sdshdr##T *)((s)-(sizeof(struct
hi
sdshdr##T)));
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)));
#define
HI_
SDS_HDR(T,s) ((struct
hi
sdshdr##T *)((s)-(sizeof(struct
hi
sdshdr##T))))
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
#define
HI_
SDS_TYPE_5_LEN(f) ((f)>>
HI_
SDS_TYPE_BITS)
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
static
inline
size_t
hi_
sdslen
(
const
hi
sds
s
)
{
static
inline
size_t
sdslen
(
const
sds
s
)
{
unsigned
char
flags
=
s
[
-
1
];
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
HI_
SDS_TYPE_MASK
)
{
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
HI_
SDS_TYPE_5
:
case
SDS_TYPE_5
:
return
HI_
SDS_TYPE_5_LEN
(
flags
);
return
SDS_TYPE_5_LEN
(
flags
);
case
HI_
SDS_TYPE_8
:
case
SDS_TYPE_8
:
return
HI_
SDS_HDR
(
8
,
s
)
->
len
;
return
SDS_HDR
(
8
,
s
)
->
len
;
case
HI_
SDS_TYPE_16
:
case
SDS_TYPE_16
:
return
HI_
SDS_HDR
(
16
,
s
)
->
len
;
return
SDS_HDR
(
16
,
s
)
->
len
;
case
HI_
SDS_TYPE_32
:
case
SDS_TYPE_32
:
return
HI_
SDS_HDR
(
32
,
s
)
->
len
;
return
SDS_HDR
(
32
,
s
)
->
len
;
case
HI_
SDS_TYPE_64
:
case
SDS_TYPE_64
:
return
HI_
SDS_HDR
(
64
,
s
)
->
len
;
return
SDS_HDR
(
64
,
s
)
->
len
;
}
}
return
0
;
return
0
;
}
}
static
inline
size_t
hi_
sdsavail
(
const
hi
sds
s
)
{
static
inline
size_t
sdsavail
(
const
sds
s
)
{
unsigned
char
flags
=
s
[
-
1
];
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
HI_
SDS_TYPE_MASK
)
{
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
HI_
SDS_TYPE_5
:
{
case
SDS_TYPE_5
:
{
return
0
;
return
0
;
}
}
case
HI_
SDS_TYPE_8
:
{
case
SDS_TYPE_8
:
{
HI_
SDS_HDR_VAR
(
8
,
s
);
SDS_HDR_VAR
(
8
,
s
);
return
sh
->
alloc
-
sh
->
len
;
return
sh
->
alloc
-
sh
->
len
;
}
}
case
HI_
SDS_TYPE_16
:
{
case
SDS_TYPE_16
:
{
HI_
SDS_HDR_VAR
(
16
,
s
);
SDS_HDR_VAR
(
16
,
s
);
return
sh
->
alloc
-
sh
->
len
;
return
sh
->
alloc
-
sh
->
len
;
}
}
case
HI_
SDS_TYPE_32
:
{
case
SDS_TYPE_32
:
{
HI_
SDS_HDR_VAR
(
32
,
s
);
SDS_HDR_VAR
(
32
,
s
);
return
sh
->
alloc
-
sh
->
len
;
return
sh
->
alloc
-
sh
->
len
;
}
}
case
HI_
SDS_TYPE_64
:
{
case
SDS_TYPE_64
:
{
HI_
SDS_HDR_VAR
(
64
,
s
);
SDS_HDR_VAR
(
64
,
s
);
return
sh
->
alloc
-
sh
->
len
;
return
sh
->
alloc
-
sh
->
len
;
}
}
}
}
return
0
;
return
0
;
}
}
static
inline
void
hi_
sdssetlen
(
hi
sds
s
,
size_t
newlen
)
{
static
inline
void
sdssetlen
(
sds
s
,
size_t
newlen
)
{
unsigned
char
flags
=
s
[
-
1
];
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
HI_
SDS_TYPE_MASK
)
{
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
HI_
SDS_TYPE_5
:
case
SDS_TYPE_5
:
{
{
unsigned
char
*
fp
=
((
unsigned
char
*
)
s
)
-
1
;
unsigned
char
*
fp
=
((
unsigned
char
*
)
s
)
-
1
;
*
fp
=
(
unsigned
char
)(
HI_
SDS_TYPE_5
|
(
newlen
<<
HI_
SDS_TYPE_BITS
));
*
fp
=
(
unsigned
char
)(
SDS_TYPE_5
|
(
newlen
<<
SDS_TYPE_BITS
));
}
}
break
;
break
;
case
HI_
SDS_TYPE_8
:
case
SDS_TYPE_8
:
HI_
SDS_HDR
(
8
,
s
)
->
len
=
(
uint8_t
)
newlen
;
SDS_HDR
(
8
,
s
)
->
len
=
(
uint8_t
)
newlen
;
break
;
break
;
case
HI_
SDS_TYPE_16
:
case
SDS_TYPE_16
:
HI_
SDS_HDR
(
16
,
s
)
->
len
=
(
uint16_t
)
newlen
;
SDS_HDR
(
16
,
s
)
->
len
=
(
uint16_t
)
newlen
;
break
;
break
;
case
HI_
SDS_TYPE_32
:
case
SDS_TYPE_32
:
HI_
SDS_HDR
(
32
,
s
)
->
len
=
(
uint32_t
)
newlen
;
SDS_HDR
(
32
,
s
)
->
len
=
(
uint32_t
)
newlen
;
break
;
break
;
case
HI_
SDS_TYPE_64
:
case
SDS_TYPE_64
:
HI_
SDS_HDR
(
64
,
s
)
->
len
=
(
uint64_t
)
newlen
;
SDS_HDR
(
64
,
s
)
->
len
=
(
uint64_t
)
newlen
;
break
;
break
;
}
}
}
}
static
inline
void
hi_
sdsinclen
(
hi
sds
s
,
size_t
inc
)
{
static
inline
void
sdsinclen
(
sds
s
,
size_t
inc
)
{
unsigned
char
flags
=
s
[
-
1
];
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
HI_
SDS_TYPE_MASK
)
{
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
HI_
SDS_TYPE_5
:
case
SDS_TYPE_5
:
{
{
unsigned
char
*
fp
=
((
unsigned
char
*
)
s
)
-
1
;
unsigned
char
*
fp
=
((
unsigned
char
*
)
s
)
-
1
;
unsigned
char
newlen
=
HI_
SDS_TYPE_5_LEN
(
flags
)
+
(
unsigned
char
)
inc
;
unsigned
char
newlen
=
SDS_TYPE_5_LEN
(
flags
)
+
(
unsigned
char
)
inc
;
*
fp
=
HI_
SDS_TYPE_5
|
(
newlen
<<
HI_
SDS_TYPE_BITS
);
*
fp
=
SDS_TYPE_5
|
(
newlen
<<
SDS_TYPE_BITS
);
}
}
break
;
break
;
case
HI_
SDS_TYPE_8
:
case
SDS_TYPE_8
:
HI_
SDS_HDR
(
8
,
s
)
->
len
+=
(
uint8_t
)
inc
;
SDS_HDR
(
8
,
s
)
->
len
+=
(
uint8_t
)
inc
;
break
;
break
;
case
HI_
SDS_TYPE_16
:
case
SDS_TYPE_16
:
HI_
SDS_HDR
(
16
,
s
)
->
len
+=
(
uint16_t
)
inc
;
SDS_HDR
(
16
,
s
)
->
len
+=
(
uint16_t
)
inc
;
break
;
break
;
case
HI_
SDS_TYPE_32
:
case
SDS_TYPE_32
:
HI_
SDS_HDR
(
32
,
s
)
->
len
+=
(
uint32_t
)
inc
;
SDS_HDR
(
32
,
s
)
->
len
+=
(
uint32_t
)
inc
;
break
;
break
;
case
HI_
SDS_TYPE_64
:
case
SDS_TYPE_64
:
HI_
SDS_HDR
(
64
,
s
)
->
len
+=
(
uint64_t
)
inc
;
SDS_HDR
(
64
,
s
)
->
len
+=
(
uint64_t
)
inc
;
break
;
break
;
}
}
}
}
/*
hi_
sdsalloc() =
hi_
sdsavail() +
hi_
sdslen() */
/* sdsalloc() = sdsavail() + sdslen() */
static
inline
size_t
hi_
sdsalloc
(
const
hi
sds
s
)
{
static
inline
size_t
sdsalloc
(
const
sds
s
)
{
unsigned
char
flags
=
s
[
-
1
];
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
HI_
SDS_TYPE_MASK
)
{
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
HI_
SDS_TYPE_5
:
case
SDS_TYPE_5
:
return
HI_
SDS_TYPE_5_LEN
(
flags
);
return
SDS_TYPE_5_LEN
(
flags
);
case
HI_
SDS_TYPE_8
:
case
SDS_TYPE_8
:
return
HI_
SDS_HDR
(
8
,
s
)
->
alloc
;
return
SDS_HDR
(
8
,
s
)
->
alloc
;
case
HI_
SDS_TYPE_16
:
case
SDS_TYPE_16
:
return
HI_
SDS_HDR
(
16
,
s
)
->
alloc
;
return
SDS_HDR
(
16
,
s
)
->
alloc
;
case
HI_
SDS_TYPE_32
:
case
SDS_TYPE_32
:
return
HI_
SDS_HDR
(
32
,
s
)
->
alloc
;
return
SDS_HDR
(
32
,
s
)
->
alloc
;
case
HI_
SDS_TYPE_64
:
case
SDS_TYPE_64
:
return
HI_
SDS_HDR
(
64
,
s
)
->
alloc
;
return
SDS_HDR
(
64
,
s
)
->
alloc
;
}
}
return
0
;
return
0
;
}
}
static
inline
void
hi_
sdssetalloc
(
hi
sds
s
,
size_t
newlen
)
{
static
inline
void
sdssetalloc
(
sds
s
,
size_t
newlen
)
{
unsigned
char
flags
=
s
[
-
1
];
unsigned
char
flags
=
s
[
-
1
];
switch
(
flags
&
HI_
SDS_TYPE_MASK
)
{
switch
(
flags
&
SDS_TYPE_MASK
)
{
case
HI_
SDS_TYPE_5
:
case
SDS_TYPE_5
:
/* Nothing to do, this type has no total allocation info. */
/* Nothing to do, this type has no total allocation info. */
break
;
break
;
case
HI_
SDS_TYPE_8
:
case
SDS_TYPE_8
:
HI_
SDS_HDR
(
8
,
s
)
->
alloc
=
(
uint8_t
)
newlen
;
SDS_HDR
(
8
,
s
)
->
alloc
=
(
uint8_t
)
newlen
;
break
;
break
;
case
HI_
SDS_TYPE_16
:
case
SDS_TYPE_16
:
HI_
SDS_HDR
(
16
,
s
)
->
alloc
=
(
uint16_t
)
newlen
;
SDS_HDR
(
16
,
s
)
->
alloc
=
(
uint16_t
)
newlen
;
break
;
break
;
case
HI_
SDS_TYPE_32
:
case
SDS_TYPE_32
:
HI_
SDS_HDR
(
32
,
s
)
->
alloc
=
(
uint32_t
)
newlen
;
SDS_HDR
(
32
,
s
)
->
alloc
=
(
uint32_t
)
newlen
;
break
;
break
;
case
HI_
SDS_TYPE_64
:
case
SDS_TYPE_64
:
HI_
SDS_HDR
(
64
,
s
)
->
alloc
=
(
uint64_t
)
newlen
;
SDS_HDR
(
64
,
s
)
->
alloc
=
(
uint64_t
)
newlen
;
break
;
break
;
}
}
}
}
hi
sds
hi_
sdsnewlen
(
const
void
*
init
,
size_t
initlen
);
sds
sdsnewlen
(
const
void
*
init
,
size_t
initlen
);
hi
sds
hi_
sdsnew
(
const
char
*
init
);
sds
sdsnew
(
const
char
*
init
);
hi
sds
hi_
sdsempty
(
void
);
sds
sdsempty
(
void
);
hi
sds
hi_
sdsdup
(
const
hi
sds
s
);
sds
sdsdup
(
const
sds
s
);
void
hi_
sdsfree
(
hi
sds
s
);
void
sdsfree
(
sds
s
);
hi
sds
hi_
sdsgrowzero
(
hi
sds
s
,
size_t
len
);
sds
sdsgrowzero
(
sds
s
,
size_t
len
);
hi
sds
hi_
sdscatlen
(
hi
sds
s
,
const
void
*
t
,
size_t
len
);
sds
sdscatlen
(
sds
s
,
const
void
*
t
,
size_t
len
);
hi
sds
hi_
sdscat
(
hi
sds
s
,
const
char
*
t
);
sds
sdscat
(
sds
s
,
const
char
*
t
);
hi
sds
hi_
sdscatsds
(
hi
sds
s
,
const
hi
sds
t
);
sds
sdscatsds
(
sds
s
,
const
sds
t
);
hi
sds
hi_
sdscpylen
(
hi
sds
s
,
const
char
*
t
,
size_t
len
);
sds
sdscpylen
(
sds
s
,
const
char
*
t
,
size_t
len
);
hi
sds
hi_
sdscpy
(
hi
sds
s
,
const
char
*
t
);
sds
sdscpy
(
sds
s
,
const
char
*
t
);
hi
sds
hi_
sdscatvprintf
(
hi
sds
s
,
const
char
*
fmt
,
va_list
ap
);
sds
sdscatvprintf
(
sds
s
,
const
char
*
fmt
,
va_list
ap
);
#ifdef __GNUC__
#ifdef __GNUC__
hi
sds
hi_
sdscatprintf
(
hi
sds
s
,
const
char
*
fmt
,
...)
sds
sdscatprintf
(
sds
s
,
const
char
*
fmt
,
...)
__attribute__
((
format
(
printf
,
2
,
3
)));
__attribute__
((
format
(
printf
,
2
,
3
)));
#else
#else
hi
sds
hi_
sdscatprintf
(
hi
sds
s
,
const
char
*
fmt
,
...);
sds
sdscatprintf
(
sds
s
,
const
char
*
fmt
,
...);
#endif
#endif
hi
sds
hi_
sdscatfmt
(
hi
sds
s
,
char
const
*
fmt
,
...);
sds
sdscatfmt
(
sds
s
,
char
const
*
fmt
,
...);
hi
sds
hi_
sdstrim
(
hi
sds
s
,
const
char
*
cset
);
sds
sdstrim
(
sds
s
,
const
char
*
cset
);
int
hi_
sdsrange
(
hi
sds
s
,
ssize_t
start
,
ssize_t
end
);
int
sdsrange
(
sds
s
,
ssize_t
start
,
ssize_t
end
);
void
hi_
sdsupdatelen
(
hi
sds
s
);
void
sdsupdatelen
(
sds
s
);
void
hi_
sdsclear
(
hi
sds
s
);
void
sdsclear
(
sds
s
);
int
hi_
sdscmp
(
const
hi
sds
s1
,
const
hi
sds
s2
);
int
sdscmp
(
const
sds
s1
,
const
sds
s2
);
hi
sds
*
hi_
sdssplitlen
(
const
char
*
s
,
int
len
,
const
char
*
sep
,
int
seplen
,
int
*
count
);
sds
*
sdssplitlen
(
const
char
*
s
,
int
len
,
const
char
*
sep
,
int
seplen
,
int
*
count
);
void
hi_
sdsfreesplitres
(
hi
sds
*
tokens
,
int
count
);
void
sdsfreesplitres
(
sds
*
tokens
,
int
count
);
void
hi_
sdstolower
(
hi
sds
s
);
void
sdstolower
(
sds
s
);
void
hi_
sdstoupper
(
hi
sds
s
);
void
sdstoupper
(
sds
s
);
hi
sds
hi_
sdsfromlonglong
(
long
long
value
);
sds
sdsfromlonglong
(
long
long
value
);
hi
sds
hi_
sdscatrepr
(
hi
sds
s
,
const
char
*
p
,
size_t
len
);
sds
sdscatrepr
(
sds
s
,
const
char
*
p
,
size_t
len
);
hi
sds
*
hi_
sdssplitargs
(
const
char
*
line
,
int
*
argc
);
sds
*
sdssplitargs
(
const
char
*
line
,
int
*
argc
);
hi
sds
hi_
sdsmapchars
(
hi
sds
s
,
const
char
*
from
,
const
char
*
to
,
size_t
setlen
);
sds
sdsmapchars
(
sds
s
,
const
char
*
from
,
const
char
*
to
,
size_t
setlen
);
hi
sds
hi_
sdsjoin
(
char
**
argv
,
int
argc
,
char
*
sep
);
sds
sdsjoin
(
char
**
argv
,
int
argc
,
char
*
sep
);
hi
sds
hi_
sdsjoinsds
(
hi
sds
*
argv
,
int
argc
,
const
char
*
sep
,
size_t
seplen
);
sds
sdsjoinsds
(
sds
*
argv
,
int
argc
,
const
char
*
sep
,
size_t
seplen
);
/* Low level functions exposed to the user API */
/* Low level functions exposed to the user API */
hi
sds
hi_
sdsMakeRoomFor
(
hi
sds
s
,
size_t
addlen
);
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
);
void
hi_
sdsIncrLen
(
hi
sds
s
,
int
incr
);
void
sdsIncrLen
(
sds
s
,
int
incr
);
hi
sds
hi_
sdsRemoveFreeSpace
(
hi
sds
s
);
sds
sdsRemoveFreeSpace
(
sds
s
);
size_t
hi_
sdsAllocSize
(
hi
sds
s
);
size_t
sdsAllocSize
(
sds
s
);
void
*
hi_
sdsAllocPtr
(
hi
sds
s
);
void
*
sdsAllocPtr
(
sds
s
);
/* Export the allocator used by SDS to the program using SDS.
/* Export the allocator used by SDS to the program using SDS.
* Sometimes the program SDS is linked to, may use a different set of
* Sometimes the program SDS is linked to, may use a different set of
* allocators, but may want to allocate or free things that SDS will
* allocators, but may want to allocate or free things that SDS will
* respectively free or allocate. */
* respectively free or allocate. */
void
*
hi_
sds_malloc
(
size_t
size
);
void
*
sds_malloc
(
size_t
size
);
void
*
hi_
sds_realloc
(
void
*
ptr
,
size_t
size
);
void
*
sds_realloc
(
void
*
ptr
,
size_t
size
);
void
hi_
sds_free
(
void
*
ptr
);
void
sds_free
(
void
*
ptr
);
#ifdef REDIS_TEST
#ifdef REDIS_TEST
int
hi_
sdsTest
(
int
argc
,
char
*
argv
[]);
int
sdsTest
(
int
argc
,
char
*
argv
[]);
#endif
#endif
#endif
/* HIREDIS_SDS_H */
#endif
deps/hiredis/sdsalloc.h
View file @
886a04c2
...
@@ -39,6 +39,6 @@
...
@@ -39,6 +39,6 @@
#include "alloc.h"
#include "alloc.h"
#define
hi_
s_malloc hi_malloc
#define s_malloc hi_malloc
#define
hi_
s_realloc hi_realloc
#define s_realloc hi_realloc
#define
hi_
s_free hi_free
#define s_free hi_free
deps/hiredis/ssl.c
View file @
886a04c2
...
@@ -38,6 +38,7 @@
...
@@ -38,6 +38,7 @@
#include <string.h>
#include <string.h>
#ifdef _WIN32
#ifdef _WIN32
#include <windows.h>
#include <windows.h>
#include <wincrypt.h>
#else
#else
#include <pthread.h>
#include <pthread.h>
#endif
#endif
...
@@ -182,6 +183,10 @@ const char *redisSSLContextGetError(redisSSLContextError error)
...
@@ -182,6 +183,10 @@ const char *redisSSLContextGetError(redisSSLContextError error)
return
"Failed to load client certificate"
;
return
"Failed to load client certificate"
;
case
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
:
case
REDIS_SSL_CTX_PRIVATE_KEY_LOAD_FAILED
:
return
"Failed to load private key"
;
return
"Failed to load private key"
;
case
REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED
:
return
"Failed to open system certifcate store"
;
case
REDIS_SSL_CTX_OS_CERT_ADD_FAILED
:
return
"Failed to add CA certificates obtained from system to the SSL context"
;
default:
default:
return
"Unknown error code"
;
return
"Unknown error code"
;
}
}
...
@@ -214,6 +219,11 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
...
@@ -214,6 +219,11 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
const
char
*
cert_filename
,
const
char
*
private_key_filename
,
const
char
*
cert_filename
,
const
char
*
private_key_filename
,
const
char
*
server_name
,
redisSSLContextError
*
error
)
const
char
*
server_name
,
redisSSLContextError
*
error
)
{
{
#ifdef _WIN32
HCERTSTORE
win_store
=
NULL
;
PCCERT_CONTEXT
win_ctx
=
NULL
;
#endif
redisSSLContext
*
ctx
=
hi_calloc
(
1
,
sizeof
(
redisSSLContext
));
redisSSLContext
*
ctx
=
hi_calloc
(
1
,
sizeof
(
redisSSLContext
));
if
(
ctx
==
NULL
)
if
(
ctx
==
NULL
)
goto
error
;
goto
error
;
...
@@ -234,6 +244,31 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
...
@@ -234,6 +244,31 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
}
}
if
(
capath
||
cacert_filename
)
{
if
(
capath
||
cacert_filename
)
{
#ifdef _WIN32
if
(
0
==
strcmp
(
cacert_filename
,
"wincert"
))
{
win_store
=
CertOpenSystemStore
(
NULL
,
"Root"
);
if
(
!
win_store
)
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_OS_CERTSTORE_OPEN_FAILED
;
goto
error
;
}
X509_STORE
*
store
=
SSL_CTX_get_cert_store
(
ctx
->
ssl_ctx
);
while
(
win_ctx
=
CertEnumCertificatesInStore
(
win_store
,
win_ctx
))
{
X509
*
x509
=
NULL
;
x509
=
d2i_X509
(
NULL
,
(
const
unsigned
char
**
)
&
win_ctx
->
pbCertEncoded
,
win_ctx
->
cbCertEncoded
);
if
(
x509
)
{
if
((
1
!=
X509_STORE_add_cert
(
store
,
x509
))
||
(
1
!=
SSL_CTX_add_client_CA
(
ctx
->
ssl_ctx
,
x509
)))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_OS_CERT_ADD_FAILED
;
goto
error
;
}
X509_free
(
x509
);
}
}
CertFreeCertificateContext
(
win_ctx
);
CertCloseStore
(
win_store
,
0
);
}
else
#endif
if
(
!
SSL_CTX_load_verify_locations
(
ctx
->
ssl_ctx
,
cacert_filename
,
capath
))
{
if
(
!
SSL_CTX_load_verify_locations
(
ctx
->
ssl_ctx
,
cacert_filename
,
capath
))
{
if
(
error
)
*
error
=
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
;
if
(
error
)
*
error
=
REDIS_SSL_CTX_CA_CERT_LOAD_FAILED
;
goto
error
;
goto
error
;
...
@@ -257,6 +292,10 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
...
@@ -257,6 +292,10 @@ redisSSLContext *redisCreateSSLContext(const char *cacert_filename, const char *
return
ctx
;
return
ctx
;
error:
error:
#ifdef _WIN32
CertFreeCertificateContext
(
win_ctx
);
CertCloseStore
(
win_store
,
0
);
#endif
redisFreeSSLContext
(
ctx
);
redisFreeSSLContext
(
ctx
);
return
NULL
;
return
NULL
;
}
}
...
@@ -353,7 +392,11 @@ int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx)
...
@@ -353,7 +392,11 @@ int redisInitiateSSLWithContext(redisContext *c, redisSSLContext *redis_ssl_ctx)
}
}
}
}
return
redisSSLConnect
(
c
,
ssl
);
if
(
redisSSLConnect
(
c
,
ssl
)
!=
REDIS_OK
)
{
goto
error
;
}
return
REDIS_OK
;
error:
error:
if
(
ssl
)
if
(
ssl
)
...
@@ -437,7 +480,7 @@ static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
...
@@ -437,7 +480,7 @@ static ssize_t redisSSLRead(redisContext *c, char *buf, size_t bufcap) {
static
ssize_t
redisSSLWrite
(
redisContext
*
c
)
{
static
ssize_t
redisSSLWrite
(
redisContext
*
c
)
{
redisSSL
*
rssl
=
c
->
privctx
;
redisSSL
*
rssl
=
c
->
privctx
;
size_t
len
=
rssl
->
lastLen
?
rssl
->
lastLen
:
hi_
sdslen
(
c
->
obuf
);
size_t
len
=
rssl
->
lastLen
?
rssl
->
lastLen
:
sdslen
(
c
->
obuf
);
int
rv
=
SSL_write
(
rssl
->
ssl
,
c
->
obuf
,
len
);
int
rv
=
SSL_write
(
rssl
->
ssl
,
c
->
obuf
,
len
);
if
(
rv
>
0
)
{
if
(
rv
>
0
)
{
...
...
deps/hiredis/test.c
View file @
886a04c2
...
@@ -11,12 +11,17 @@
...
@@ -11,12 +11,17 @@
#include <signal.h>
#include <signal.h>
#include <errno.h>
#include <errno.h>
#include <limits.h>
#include <limits.h>
#include <math.h>
#include "hiredis.h"
#include "hiredis.h"
#include "async.h"
#include "async.h"
#ifdef HIREDIS_TEST_SSL
#ifdef HIREDIS_TEST_SSL
#include "hiredis_ssl.h"
#include "hiredis_ssl.h"
#endif
#endif
#ifdef HIREDIS_TEST_ASYNC
#include "adapters/libevent.h"
#include <event2/event.h>
#endif
#include "net.h"
#include "net.h"
#include "win32.h"
#include "win32.h"
...
@@ -58,6 +63,8 @@ struct pushCounters {
...
@@ -58,6 +63,8 @@ struct pushCounters {
int
str
;
int
str
;
};
};
static
int
insecure_calloc_calls
;
#ifdef HIREDIS_TEST_SSL
#ifdef HIREDIS_TEST_SSL
redisSSLContext
*
_ssl_ctx
=
NULL
;
redisSSLContext
*
_ssl_ctx
=
NULL
;
#endif
#endif
...
@@ -345,21 +352,21 @@ static void test_format_commands(void) {
...
@@ -345,21 +352,21 @@ static void test_format_commands(void) {
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
7
+
2
)
+
4
+
(
3
+
2
));
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
7
+
2
)
+
4
+
(
3
+
2
));
hi_free
(
cmd
);
hi_free
(
cmd
);
hi
sds
sds_cmd
;
sds
sds_cmd
;
sds_cmd
=
NULL
;
sds_cmd
=
NULL
;
test
(
"Format command into
hi
sds by passing argc/argv without lengths: "
);
test
(
"Format command into sds by passing argc/argv without lengths: "
);
len
=
redisFormatSdsCommandArgv
(
&
sds_cmd
,
argc
,
argv
,
NULL
);
len
=
redisFormatSdsCommandArgv
(
&
sds_cmd
,
argc
,
argv
,
NULL
);
test_cond
(
strncmp
(
sds_cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$3
\r\n
foo
\r\n
$3
\r\n
bar
\r\n
"
,
len
)
==
0
&&
test_cond
(
strncmp
(
sds_cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$3
\r\n
foo
\r\n
$3
\r\n
bar
\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
));
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
)
+
4
+
(
3
+
2
));
hi_
sdsfree
(
sds_cmd
);
sdsfree
(
sds_cmd
);
sds_cmd
=
NULL
;
sds_cmd
=
NULL
;
test
(
"Format command into
hi
sds by passing argc/argv with lengths: "
);
test
(
"Format command into sds by passing argc/argv with lengths: "
);
len
=
redisFormatSdsCommandArgv
(
&
sds_cmd
,
argc
,
argv
,
lens
);
len
=
redisFormatSdsCommandArgv
(
&
sds_cmd
,
argc
,
argv
,
lens
);
test_cond
(
strncmp
(
sds_cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$7
\r\n
foo
\0
xxx
\r\n
$3
\r\n
bar
\r\n
"
,
len
)
==
0
&&
test_cond
(
strncmp
(
sds_cmd
,
"*3
\r\n
$3
\r\n
SET
\r\n
$7
\r\n
foo
\0
xxx
\r\n
$3
\r\n
bar
\r\n
"
,
len
)
==
0
&&
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
7
+
2
)
+
4
+
(
3
+
2
));
len
==
4
+
4
+
(
3
+
2
)
+
4
+
(
7
+
2
)
+
4
+
(
3
+
2
));
hi_
sdsfree
(
sds_cmd
);
sdsfree
(
sds_cmd
);
}
}
static
void
test_append_formatted_commands
(
struct
config
config
)
{
static
void
test_append_formatted_commands
(
struct
config
config
)
{
...
@@ -597,6 +604,147 @@ static void test_reply_reader(void) {
...
@@ -597,6 +604,147 @@ static void test_reply_reader(void) {
((
redisReply
*
)
reply
)
->
element
[
1
]
->
integer
==
42
);
((
redisReply
*
)
reply
)
->
element
[
1
]
->
integer
==
42
);
freeReplyObject
(
reply
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
redisReaderFree
(
reader
);
test
(
"Can parse RESP3 doubles: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
",3.14159265358979323846
\r\n
"
,
25
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_DOUBLE
&&
fabs
(((
redisReply
*
)
reply
)
->
dval
-
3
.
14159265358979323846
)
<
0
.
00000001
&&
((
redisReply
*
)
reply
)
->
len
==
22
&&
strcmp
(((
redisReply
*
)
reply
)
->
str
,
"3.14159265358979323846"
)
==
0
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Set error on invalid RESP3 double: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
",3.14159
\000
265358979323846
\r\n
"
,
26
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_ERR
&&
strcasecmp
(
reader
->
errstr
,
"Bad double value"
)
==
0
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Correctly parses RESP3 double INFINITY: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
",inf
\r\n
"
,
6
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_DOUBLE
&&
isinf
(((
redisReply
*
)
reply
)
->
dval
)
&&
((
redisReply
*
)
reply
)
->
dval
>
0
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Set error when RESP3 double is NaN: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
",nan
\r\n
"
,
6
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_ERR
&&
strcasecmp
(
reader
->
errstr
,
"Bad double value"
)
==
0
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Can parse RESP3 nil: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
"_
\r\n
"
,
3
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_NIL
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Set error on invalid RESP3 nil: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
"_nil
\r\n
"
,
6
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_ERR
&&
strcasecmp
(
reader
->
errstr
,
"Bad nil value"
)
==
0
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Can parse RESP3 bool (true): "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
"#t
\r\n
"
,
4
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_BOOL
&&
((
redisReply
*
)
reply
)
->
integer
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Can parse RESP3 bool (false): "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
"#f
\r\n
"
,
4
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_BOOL
&&
!
((
redisReply
*
)
reply
)
->
integer
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Set error on invalid RESP3 bool: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
"#foobar
\r\n
"
,
9
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_ERR
&&
strcasecmp
(
reader
->
errstr
,
"Bad bool value"
)
==
0
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Can parse RESP3 map: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
"%2
\r\n
+first
\r\n
:123
\r\n
$6
\r\n
second
\r\n
#t
\r\n
"
,
34
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_MAP
&&
((
redisReply
*
)
reply
)
->
elements
==
4
&&
((
redisReply
*
)
reply
)
->
element
[
0
]
->
type
==
REDIS_REPLY_STATUS
&&
((
redisReply
*
)
reply
)
->
element
[
0
]
->
len
==
5
&&
!
strcmp
(((
redisReply
*
)
reply
)
->
element
[
0
]
->
str
,
"first"
)
&&
((
redisReply
*
)
reply
)
->
element
[
1
]
->
type
==
REDIS_REPLY_INTEGER
&&
((
redisReply
*
)
reply
)
->
element
[
1
]
->
integer
==
123
&&
((
redisReply
*
)
reply
)
->
element
[
2
]
->
type
==
REDIS_REPLY_STRING
&&
((
redisReply
*
)
reply
)
->
element
[
2
]
->
len
==
6
&&
!
strcmp
(((
redisReply
*
)
reply
)
->
element
[
2
]
->
str
,
"second"
)
&&
((
redisReply
*
)
reply
)
->
element
[
3
]
->
type
==
REDIS_REPLY_BOOL
&&
((
redisReply
*
)
reply
)
->
element
[
3
]
->
integer
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Can parse RESP3 set: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
"~5
\r\n
+orange
\r\n
$5
\r\n
apple
\r\n
#f
\r\n
:100
\r\n
:999
\r\n
"
,
40
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_SET
&&
((
redisReply
*
)
reply
)
->
elements
==
5
&&
((
redisReply
*
)
reply
)
->
element
[
0
]
->
type
==
REDIS_REPLY_STATUS
&&
((
redisReply
*
)
reply
)
->
element
[
0
]
->
len
==
6
&&
!
strcmp
(((
redisReply
*
)
reply
)
->
element
[
0
]
->
str
,
"orange"
)
&&
((
redisReply
*
)
reply
)
->
element
[
1
]
->
type
==
REDIS_REPLY_STRING
&&
((
redisReply
*
)
reply
)
->
element
[
1
]
->
len
==
5
&&
!
strcmp
(((
redisReply
*
)
reply
)
->
element
[
1
]
->
str
,
"apple"
)
&&
((
redisReply
*
)
reply
)
->
element
[
2
]
->
type
==
REDIS_REPLY_BOOL
&&
!
((
redisReply
*
)
reply
)
->
element
[
2
]
->
integer
&&
((
redisReply
*
)
reply
)
->
element
[
3
]
->
type
==
REDIS_REPLY_INTEGER
&&
((
redisReply
*
)
reply
)
->
element
[
3
]
->
integer
==
100
&&
((
redisReply
*
)
reply
)
->
element
[
4
]
->
type
==
REDIS_REPLY_INTEGER
&&
((
redisReply
*
)
reply
)
->
element
[
4
]
->
integer
==
999
);
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"Can parse RESP3 bignum: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
"(3492890328409238509324850943850943825024385
\r\n
"
,
46
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_OK
&&
((
redisReply
*
)
reply
)
->
type
==
REDIS_REPLY_BIGNUM
&&
((
redisReply
*
)
reply
)
->
len
==
43
&&
!
strcmp
(((
redisReply
*
)
reply
)
->
str
,
"3492890328409238509324850943850943825024385"
));
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
}
}
static
void
test_free_null
(
void
)
{
static
void
test_free_null
(
void
)
{
...
@@ -623,6 +771,13 @@ static void *hi_calloc_fail(size_t nmemb, size_t size) {
...
@@ -623,6 +771,13 @@ static void *hi_calloc_fail(size_t nmemb, size_t size) {
return
NULL
;
return
NULL
;
}
}
static
void
*
hi_calloc_insecure
(
size_t
nmemb
,
size_t
size
)
{
(
void
)
nmemb
;
(
void
)
size
;
insecure_calloc_calls
++
;
return
(
void
*
)
0xdeadc0de
;
}
static
void
*
hi_realloc_fail
(
void
*
ptr
,
size_t
size
)
{
static
void
*
hi_realloc_fail
(
void
*
ptr
,
size_t
size
)
{
(
void
)
ptr
;
(
void
)
ptr
;
(
void
)
size
;
(
void
)
size
;
...
@@ -630,6 +785,8 @@ static void *hi_realloc_fail(void *ptr, size_t size) {
...
@@ -630,6 +785,8 @@ static void *hi_realloc_fail(void *ptr, size_t size) {
}
}
static
void
test_allocator_injection
(
void
)
{
static
void
test_allocator_injection
(
void
)
{
void
*
ptr
;
hiredisAllocFuncs
ha
=
{
hiredisAllocFuncs
ha
=
{
.
mallocFn
=
hi_malloc_fail
,
.
mallocFn
=
hi_malloc_fail
,
.
callocFn
=
hi_calloc_fail
,
.
callocFn
=
hi_calloc_fail
,
...
@@ -649,6 +806,13 @@ static void test_allocator_injection(void) {
...
@@ -649,6 +806,13 @@ static void test_allocator_injection(void) {
redisReader
*
reader
=
redisReaderCreate
();
redisReader
*
reader
=
redisReaderCreate
();
test_cond
(
reader
==
NULL
);
test_cond
(
reader
==
NULL
);
/* Make sure hiredis itself protects against a non-overflow checking calloc */
test
(
"hiredis calloc wrapper protects against overflow: "
);
ha
.
callocFn
=
hi_calloc_insecure
;
hiredisSetAllocators
(
&
ha
);
ptr
=
hi_calloc
((
SIZE_MAX
/
sizeof
(
void
*
))
+
3
,
sizeof
(
void
*
));
test_cond
(
ptr
==
NULL
&&
insecure_calloc_calls
==
0
);
// Return allocators to default
// Return allocators to default
hiredisResetAllocators
();
hiredisResetAllocators
();
}
}
...
@@ -1283,6 +1447,440 @@ static void test_throughput(struct config config) {
...
@@ -1283,6 +1447,440 @@ static void test_throughput(struct config config) {
// redisFree(c);
// redisFree(c);
// }
// }
#ifdef HIREDIS_TEST_ASYNC
struct
event_base
*
base
;
typedef
struct
TestState
{
redisOptions
*
options
;
int
checkpoint
;
int
resp3
;
int
disconnect
;
}
TestState
;
/* Helper to disconnect and stop event loop */
void
async_disconnect
(
redisAsyncContext
*
ac
)
{
redisAsyncDisconnect
(
ac
);
event_base_loopbreak
(
base
);
}
/* Testcase timeout, will trigger a failure */
void
timeout_cb
(
int
fd
,
short
event
,
void
*
arg
)
{
(
void
)
fd
;
(
void
)
event
;
(
void
)
arg
;
printf
(
"Timeout in async testing!
\n
"
);
exit
(
1
);
}
/* Unexpected call, will trigger a failure */
void
unexpected_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
(
void
)
ac
;
(
void
)
r
;
printf
(
"Unexpected call: %s
\n
"
,(
char
*
)
privdata
);
exit
(
1
);
}
/* Helper function to publish a message via own client. */
void
publish_msg
(
redisOptions
*
options
,
const
char
*
channel
,
const
char
*
msg
)
{
redisContext
*
c
=
redisConnectWithOptions
(
options
);
assert
(
c
!=
NULL
);
redisReply
*
reply
=
redisCommand
(
c
,
"PUBLISH %s %s"
,
channel
,
msg
);
assert
(
reply
->
type
==
REDIS_REPLY_INTEGER
&&
reply
->
integer
==
1
);
freeReplyObject
(
reply
);
disconnect
(
c
,
0
);
}
/* Expect a reply of type INTEGER */
void
integer_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
TestState
*
state
=
privdata
;
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_INTEGER
);
state
->
checkpoint
++
;
if
(
state
->
disconnect
)
async_disconnect
(
ac
);
}
/* Subscribe callback for test_pubsub_handling and test_pubsub_handling_resp3:
* - a published message triggers an unsubscribe
* - a command is sent before the unsubscribe response is received. */
void
subscribe_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
TestState
*
state
=
privdata
;
assert
(
reply
!=
NULL
&&
reply
->
type
==
(
state
->
resp3
?
REDIS_REPLY_PUSH
:
REDIS_REPLY_ARRAY
)
&&
reply
->
elements
==
3
);
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"subscribe"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"mychannel"
)
==
0
&&
reply
->
element
[
2
]
->
str
==
NULL
);
publish_msg
(
state
->
options
,
"mychannel"
,
"Hello!"
);
}
else
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"message"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"mychannel"
)
==
0
&&
strcmp
(
reply
->
element
[
2
]
->
str
,
"Hello!"
)
==
0
);
state
->
checkpoint
++
;
/* Unsubscribe after receiving the published message. Send unsubscribe
* which should call the callback registered during subscribe */
redisAsyncCommand
(
ac
,
unexpected_cb
,
(
void
*
)
"unsubscribe should call subscribe_cb()"
,
"unsubscribe"
);
/* Send a regular command after unsubscribing, then disconnect */
state
->
disconnect
=
1
;
redisAsyncCommand
(
ac
,
integer_cb
,
state
,
"LPUSH mylist foo"
);
}
else
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"unsubscribe"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"mychannel"
)
==
0
&&
reply
->
element
[
2
]
->
str
==
NULL
);
}
else
{
printf
(
"Unexpected pubsub command: %s
\n
"
,
reply
->
element
[
0
]
->
str
);
exit
(
1
);
}
}
/* Expect a reply of type ARRAY */
void
array_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
TestState
*
state
=
privdata
;
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_ARRAY
);
state
->
checkpoint
++
;
if
(
state
->
disconnect
)
async_disconnect
(
ac
);
}
/* Expect a NULL reply */
void
null_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
(
void
)
ac
;
assert
(
r
==
NULL
);
TestState
*
state
=
privdata
;
state
->
checkpoint
++
;
}
static
void
test_pubsub_handling
(
struct
config
config
)
{
test
(
"Subscribe, handle published message and unsubscribe: "
);
/* Setup event dispatcher with a testcase timeout */
base
=
event_base_new
();
struct
event
*
timeout
=
evtimer_new
(
base
,
timeout_cb
,
NULL
);
assert
(
timeout
!=
NULL
);
evtimer_assign
(
timeout
,
base
,
timeout_cb
,
NULL
);
struct
timeval
timeout_tv
=
{.
tv_sec
=
10
};
evtimer_add
(
timeout
,
&
timeout_tv
);
/* Connect */
redisOptions
options
=
get_redis_tcp_options
(
config
);
redisAsyncContext
*
ac
=
redisAsyncConnectWithOptions
(
&
options
);
assert
(
ac
!=
NULL
&&
ac
->
err
==
0
);
redisLibeventAttach
(
ac
,
base
);
/* Start subscribe */
TestState
state
=
{.
options
=
&
options
};
redisAsyncCommand
(
ac
,
subscribe_cb
,
&
state
,
"subscribe mychannel"
);
/* Make sure non-subscribe commands are handled */
redisAsyncCommand
(
ac
,
array_cb
,
&
state
,
"PING"
);
/* Start event dispatching loop */
test_cond
(
event_base_dispatch
(
base
)
==
0
);
event_free
(
timeout
);
event_base_free
(
base
);
/* Verify test checkpoints */
assert
(
state
.
checkpoint
==
3
);
}
/* Unexpected push message, will trigger a failure */
void
unexpected_push_cb
(
redisAsyncContext
*
ac
,
void
*
r
)
{
(
void
)
ac
;
(
void
)
r
;
printf
(
"Unexpected call to the PUSH callback!
\n
"
);
exit
(
1
);
}
static
void
test_pubsub_handling_resp3
(
struct
config
config
)
{
test
(
"Subscribe, handle published message and unsubscribe using RESP3: "
);
/* Setup event dispatcher with a testcase timeout */
base
=
event_base_new
();
struct
event
*
timeout
=
evtimer_new
(
base
,
timeout_cb
,
NULL
);
assert
(
timeout
!=
NULL
);
evtimer_assign
(
timeout
,
base
,
timeout_cb
,
NULL
);
struct
timeval
timeout_tv
=
{.
tv_sec
=
10
};
evtimer_add
(
timeout
,
&
timeout_tv
);
/* Connect */
redisOptions
options
=
get_redis_tcp_options
(
config
);
redisAsyncContext
*
ac
=
redisAsyncConnectWithOptions
(
&
options
);
assert
(
ac
!=
NULL
&&
ac
->
err
==
0
);
redisLibeventAttach
(
ac
,
base
);
/* Not expecting any push messages in this test */
redisAsyncSetPushCallback
(
ac
,
unexpected_push_cb
);
/* Switch protocol */
redisAsyncCommand
(
ac
,
NULL
,
NULL
,
"HELLO 3"
);
/* Start subscribe */
TestState
state
=
{.
options
=
&
options
,
.
resp3
=
1
};
redisAsyncCommand
(
ac
,
subscribe_cb
,
&
state
,
"subscribe mychannel"
);
/* Make sure non-subscribe commands are handled in RESP3 */
redisAsyncCommand
(
ac
,
integer_cb
,
&
state
,
"LPUSH mylist foo"
);
redisAsyncCommand
(
ac
,
integer_cb
,
&
state
,
"LPUSH mylist foo"
);
redisAsyncCommand
(
ac
,
integer_cb
,
&
state
,
"LPUSH mylist foo"
);
/* Handle an array with 3 elements as a non-subscribe command */
redisAsyncCommand
(
ac
,
array_cb
,
&
state
,
"LRANGE mylist 0 2"
);
/* Start event dispatching loop */
test_cond
(
event_base_dispatch
(
base
)
==
0
);
event_free
(
timeout
);
event_base_free
(
base
);
/* Verify test checkpoints */
assert
(
state
.
checkpoint
==
6
);
}
/* Subscribe callback for test_command_timeout_during_pubsub:
* - a subscribe response triggers a published message
* - the published message triggers a command that times out
* - the command timeout triggers a disconnect */
void
subscribe_with_timeout_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
TestState
*
state
=
privdata
;
/* The non-clean disconnect should trigger the
* subscription callback with a NULL reply. */
if
(
reply
==
NULL
)
{
state
->
checkpoint
++
;
event_base_loopbreak
(
base
);
return
;
}
assert
(
reply
->
type
==
(
state
->
resp3
?
REDIS_REPLY_PUSH
:
REDIS_REPLY_ARRAY
)
&&
reply
->
elements
==
3
);
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"subscribe"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"mychannel"
)
==
0
&&
reply
->
element
[
2
]
->
str
==
NULL
);
publish_msg
(
state
->
options
,
"mychannel"
,
"Hello!"
);
state
->
checkpoint
++
;
}
else
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"message"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"mychannel"
)
==
0
&&
strcmp
(
reply
->
element
[
2
]
->
str
,
"Hello!"
)
==
0
);
state
->
checkpoint
++
;
/* Send a command that will trigger a timeout */
redisAsyncCommand
(
ac
,
null_cb
,
state
,
"DEBUG SLEEP 3"
);
redisAsyncCommand
(
ac
,
null_cb
,
state
,
"LPUSH mylist foo"
);
}
else
{
printf
(
"Unexpected pubsub command: %s
\n
"
,
reply
->
element
[
0
]
->
str
);
exit
(
1
);
}
}
static
void
test_command_timeout_during_pubsub
(
struct
config
config
)
{
test
(
"Command timeout during Pub/Sub: "
);
/* Setup event dispatcher with a testcase timeout */
base
=
event_base_new
();
struct
event
*
timeout
=
evtimer_new
(
base
,
timeout_cb
,
NULL
);
assert
(
timeout
!=
NULL
);
evtimer_assign
(
timeout
,
base
,
timeout_cb
,
NULL
);
struct
timeval
timeout_tv
=
{.
tv_sec
=
10
};
evtimer_add
(
timeout
,
&
timeout_tv
);
/* Connect */
redisOptions
options
=
get_redis_tcp_options
(
config
);
redisAsyncContext
*
ac
=
redisAsyncConnectWithOptions
(
&
options
);
assert
(
ac
!=
NULL
&&
ac
->
err
==
0
);
redisLibeventAttach
(
ac
,
base
);
/* Configure a command timout */
struct
timeval
command_timeout
=
{.
tv_sec
=
2
};
redisAsyncSetTimeout
(
ac
,
command_timeout
);
/* Not expecting any push messages in this test */
redisAsyncSetPushCallback
(
ac
,
unexpected_push_cb
);
/* Switch protocol */
redisAsyncCommand
(
ac
,
NULL
,
NULL
,
"HELLO 3"
);
/* Start subscribe */
TestState
state
=
{.
options
=
&
options
,
.
resp3
=
1
};
redisAsyncCommand
(
ac
,
subscribe_with_timeout_cb
,
&
state
,
"subscribe mychannel"
);
/* Start event dispatching loop */
assert
(
event_base_dispatch
(
base
)
==
0
);
event_free
(
timeout
);
event_base_free
(
base
);
/* Verify test checkpoints */
test_cond
(
state
.
checkpoint
==
5
);
}
/* Subscribe callback for test_pubsub_multiple_channels */
void
subscribe_channel_a_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
TestState
*
state
=
privdata
;
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_ARRAY
&&
reply
->
elements
==
3
);
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"subscribe"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"A"
)
==
0
);
publish_msg
(
state
->
options
,
"A"
,
"Hello!"
);
state
->
checkpoint
++
;
}
else
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"message"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"A"
)
==
0
&&
strcmp
(
reply
->
element
[
2
]
->
str
,
"Hello!"
)
==
0
);
state
->
checkpoint
++
;
/* Unsubscribe to channels, including a channel X which we don't subscribe to */
redisAsyncCommand
(
ac
,
unexpected_cb
,
(
void
*
)
"unsubscribe should not call unexpected_cb()"
,
"unsubscribe B X A"
);
/* Send a regular command after unsubscribing, then disconnect */
state
->
disconnect
=
1
;
redisAsyncCommand
(
ac
,
integer_cb
,
state
,
"LPUSH mylist foo"
);
}
else
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"unsubscribe"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"A"
)
==
0
);
state
->
checkpoint
++
;
}
else
{
printf
(
"Unexpected pubsub command: %s
\n
"
,
reply
->
element
[
0
]
->
str
);
exit
(
1
);
}
}
/* Subscribe callback for test_pubsub_multiple_channels */
void
subscribe_channel_b_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
TestState
*
state
=
privdata
;
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_ARRAY
&&
reply
->
elements
==
3
);
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"subscribe"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"B"
)
==
0
);
state
->
checkpoint
++
;
}
else
if
(
strcmp
(
reply
->
element
[
0
]
->
str
,
"unsubscribe"
)
==
0
)
{
assert
(
strcmp
(
reply
->
element
[
1
]
->
str
,
"B"
)
==
0
);
state
->
checkpoint
++
;
}
else
{
printf
(
"Unexpected pubsub command: %s
\n
"
,
reply
->
element
[
0
]
->
str
);
exit
(
1
);
}
}
/* Test handling of multiple channels
* - subscribe to channel A and B
* - a published message on A triggers an unsubscribe of channel B, X and A
* where channel X is not subscribed to.
* - a command sent after unsubscribe triggers a disconnect */
static
void
test_pubsub_multiple_channels
(
struct
config
config
)
{
test
(
"Subscribe to multiple channels: "
);
/* Setup event dispatcher with a testcase timeout */
base
=
event_base_new
();
struct
event
*
timeout
=
evtimer_new
(
base
,
timeout_cb
,
NULL
);
assert
(
timeout
!=
NULL
);
evtimer_assign
(
timeout
,
base
,
timeout_cb
,
NULL
);
struct
timeval
timeout_tv
=
{.
tv_sec
=
10
};
evtimer_add
(
timeout
,
&
timeout_tv
);
/* Connect */
redisOptions
options
=
get_redis_tcp_options
(
config
);
redisAsyncContext
*
ac
=
redisAsyncConnectWithOptions
(
&
options
);
assert
(
ac
!=
NULL
&&
ac
->
err
==
0
);
redisLibeventAttach
(
ac
,
base
);
/* Not expecting any push messages in this test */
redisAsyncSetPushCallback
(
ac
,
unexpected_push_cb
);
/* Start subscribing to two channels */
TestState
state
=
{.
options
=
&
options
};
redisAsyncCommand
(
ac
,
subscribe_channel_a_cb
,
&
state
,
"subscribe A"
);
redisAsyncCommand
(
ac
,
subscribe_channel_b_cb
,
&
state
,
"subscribe B"
);
/* Start event dispatching loop */
assert
(
event_base_dispatch
(
base
)
==
0
);
event_free
(
timeout
);
event_base_free
(
base
);
/* Verify test checkpoints */
test_cond
(
state
.
checkpoint
==
6
);
}
/* Command callback for test_monitor() */
void
monitor_cb
(
redisAsyncContext
*
ac
,
void
*
r
,
void
*
privdata
)
{
redisReply
*
reply
=
r
;
TestState
*
state
=
privdata
;
/* NULL reply is received when BYE triggers a disconnect. */
if
(
reply
==
NULL
)
{
event_base_loopbreak
(
base
);
return
;
}
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_STATUS
);
state
->
checkpoint
++
;
if
(
state
->
checkpoint
==
1
)
{
/* Response from MONITOR */
redisContext
*
c
=
redisConnectWithOptions
(
state
->
options
);
assert
(
c
!=
NULL
);
redisReply
*
reply
=
redisCommand
(
c
,
"SET first 1"
);
assert
(
reply
->
type
==
REDIS_REPLY_STATUS
);
freeReplyObject
(
reply
);
redisFree
(
c
);
}
else
if
(
state
->
checkpoint
==
2
)
{
/* Response for monitored command 'SET first 1' */
assert
(
strstr
(
reply
->
str
,
"first"
)
!=
NULL
);
redisContext
*
c
=
redisConnectWithOptions
(
state
->
options
);
assert
(
c
!=
NULL
);
redisReply
*
reply
=
redisCommand
(
c
,
"SET second 2"
);
assert
(
reply
->
type
==
REDIS_REPLY_STATUS
);
freeReplyObject
(
reply
);
redisFree
(
c
);
}
else
if
(
state
->
checkpoint
==
3
)
{
/* Response for monitored command 'SET second 2' */
assert
(
strstr
(
reply
->
str
,
"second"
)
!=
NULL
);
/* Send QUIT to disconnect */
redisAsyncCommand
(
ac
,
NULL
,
NULL
,
"QUIT"
);
}
}
/* Test handling of the monitor command
* - sends MONITOR to enable monitoring.
* - sends SET commands via separate clients to be monitored.
* - sends QUIT to stop monitoring and disconnect. */
static
void
test_monitor
(
struct
config
config
)
{
test
(
"Enable monitoring: "
);
/* Setup event dispatcher with a testcase timeout */
base
=
event_base_new
();
struct
event
*
timeout
=
evtimer_new
(
base
,
timeout_cb
,
NULL
);
assert
(
timeout
!=
NULL
);
evtimer_assign
(
timeout
,
base
,
timeout_cb
,
NULL
);
struct
timeval
timeout_tv
=
{.
tv_sec
=
10
};
evtimer_add
(
timeout
,
&
timeout_tv
);
/* Connect */
redisOptions
options
=
get_redis_tcp_options
(
config
);
redisAsyncContext
*
ac
=
redisAsyncConnectWithOptions
(
&
options
);
assert
(
ac
!=
NULL
&&
ac
->
err
==
0
);
redisLibeventAttach
(
ac
,
base
);
/* Not expecting any push messages in this test */
redisAsyncSetPushCallback
(
ac
,
unexpected_push_cb
);
/* Start monitor */
TestState
state
=
{.
options
=
&
options
};
redisAsyncCommand
(
ac
,
monitor_cb
,
&
state
,
"monitor"
);
/* Start event dispatching loop */
test_cond
(
event_base_dispatch
(
base
)
==
0
);
event_free
(
timeout
);
event_base_free
(
base
);
/* Verify test checkpoints */
assert
(
state
.
checkpoint
==
3
);
}
#endif
/* HIREDIS_TEST_ASYNC */
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
struct
config
cfg
=
{
struct
config
cfg
=
{
.
tcp
=
{
.
tcp
=
{
...
@@ -1401,6 +1999,24 @@ int main(int argc, char **argv) {
...
@@ -1401,6 +1999,24 @@ int main(int argc, char **argv) {
}
}
#endif
#endif
#ifdef HIREDIS_TEST_ASYNC
printf
(
"
\n
Testing asynchronous API against TCP connection (%s:%d):
\n
"
,
cfg
.
tcp
.
host
,
cfg
.
tcp
.
port
);
cfg
.
type
=
CONN_TCP
;
int
major
;
redisContext
*
c
=
do_connect
(
cfg
);
get_redis_version
(
c
,
&
major
,
NULL
);
disconnect
(
c
,
0
);
test_pubsub_handling
(
cfg
);
test_pubsub_multiple_channels
(
cfg
);
test_monitor
(
cfg
);
if
(
major
>=
6
)
{
test_pubsub_handling_resp3
(
cfg
);
test_command_timeout_during_pubsub
(
cfg
);
}
#endif
/* HIREDIS_TEST_ASYNC */
if
(
test_inherit_fd
)
{
if
(
test_inherit_fd
)
{
printf
(
"
\n
Testing against inherited fd (%s): "
,
cfg
.
unix_sock
.
path
);
printf
(
"
\n
Testing against inherited fd (%s): "
,
cfg
.
unix_sock
.
path
);
if
(
test_unix_socket
)
{
if
(
test_unix_socket
)
{
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment