Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
bc8ffafe
Commit
bc8ffafe
authored
Dec 06, 2010
by
Pieter Noordhuis
Browse files
Merge branch 'master' into brpoplpush
parents
baa14ef9
bbac56c2
Changes
7
Hide whitespace changes
Inline
Side-by-side
Makefile
View file @
bc8ffafe
...
...
@@ -16,4 +16,7 @@ clean:
$(TARGETS)
:
cd
src
&&
$(MAKE)
$@
src/help.h
:
@
./utils/generate-command-help.rb
>
$@
dummy
:
deps/linenoise/example.c
View file @
bc8ffafe
...
...
@@ -2,9 +2,18 @@
#include <stdlib.h>
#include "linenoise.h"
void
completion
(
const
char
*
buf
,
linenoiseCompletions
*
lc
)
{
if
(
buf
[
0
]
==
'h'
)
{
linenoiseAddCompletion
(
lc
,
"hello"
);
linenoiseAddCompletion
(
lc
,
"hello there"
);
}
}
int
main
(
void
)
{
char
*
line
;
linenoiseSetCompletionCallback
(
completion
);
linenoiseHistoryLoad
(
"history.txt"
);
/* Load the history at startup */
while
((
line
=
linenoise
(
"hello> "
))
!=
NULL
)
{
if
(
line
[
0
]
!=
'\0'
)
{
...
...
deps/linenoise/linenoise.c
View file @
bc8ffafe
...
...
@@ -9,6 +9,8 @@
* the 2010 UNIX computers around.
*
* Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
...
...
@@ -66,6 +68,17 @@
* CUF (CUrsor Forward)
* Sequence: ESC [ n C
* Effect: moves cursor forward of n chars
*
* The following are used to clear the screen: ESC [ H ESC [ 2 J
* This is actually composed of two sequences:
*
* cursorhome
* Sequence: ESC [ H
* Effect: moves the cursor to upper left corner
*
* ED2 (Clear entire screen)
* Sequence: ESC [ 2 J
* Effect: clear the whole screen
*
*/
...
...
@@ -79,10 +92,12 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "linenoise.h"
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
#define LINENOISE_MAX_LINE 4096
static
char
*
unsupported_term
[]
=
{
"dumb"
,
"cons25"
,
NULL
};
static
linenoiseCompletionCallback
*
completionCallback
=
NULL
;
static
struct
termios
orig_termios
;
/* in order to restore at exit */
static
int
rawmode
=
0
;
/* for atexit() function to check if restore is needed*/
...
...
@@ -195,6 +210,78 @@ static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_
if
(
write
(
fd
,
seq
,
strlen
(
seq
))
==
-
1
)
return
;
}
static
void
beep
()
{
fprintf
(
stderr
,
"\x7"
);
fflush
(
stderr
);
}
static
void
freeCompletions
(
linenoiseCompletions
*
lc
)
{
size_t
i
;
for
(
i
=
0
;
i
<
lc
->
len
;
i
++
)
free
(
lc
->
cvec
[
i
]);
if
(
lc
->
cvec
!=
NULL
)
free
(
lc
->
cvec
);
}
static
int
completeLine
(
int
fd
,
const
char
*
prompt
,
char
*
buf
,
size_t
buflen
,
size_t
*
len
,
size_t
*
pos
,
size_t
cols
)
{
linenoiseCompletions
lc
=
{
0
,
NULL
};
int
nread
,
nwritten
;
char
c
=
0
;
completionCallback
(
buf
,
&
lc
);
if
(
lc
.
len
==
0
)
{
beep
();
}
else
{
size_t
stop
=
0
,
i
=
0
;
size_t
clen
;
while
(
!
stop
)
{
/* Show completion or original buffer */
if
(
i
<
lc
.
len
)
{
clen
=
strlen
(
lc
.
cvec
[
i
]);
refreshLine
(
fd
,
prompt
,
lc
.
cvec
[
i
],
clen
,
clen
,
cols
);
}
else
{
refreshLine
(
fd
,
prompt
,
buf
,
*
len
,
*
pos
,
cols
);
}
nread
=
read
(
fd
,
&
c
,
1
);
if
(
nread
<=
0
)
{
freeCompletions
(
&
lc
);
return
-
1
;
}
switch
(
c
)
{
case
9
:
/* tab */
i
=
(
i
+
1
)
%
(
lc
.
len
+
1
);
if
(
i
==
lc
.
len
)
beep
();
break
;
case
27
:
/* escape */
/* Re-show original buffer */
if
(
i
<
lc
.
len
)
{
refreshLine
(
fd
,
prompt
,
buf
,
*
len
,
*
pos
,
cols
);
}
stop
=
1
;
break
;
default:
/* Update buffer and return */
if
(
i
<
lc
.
len
)
{
nwritten
=
snprintf
(
buf
,
buflen
,
"%s"
,
lc
.
cvec
[
i
]);
*
len
=
*
pos
=
nwritten
;
}
stop
=
1
;
break
;
}
}
}
freeCompletions
(
&
lc
);
return
c
;
/* Return last read character */
}
void
linenoiseClearScreen
(
void
)
{
write
(
STDIN_FILENO
,
"
\x1b
[H
\x1b
[2J"
,
7
);
}
static
int
linenoisePrompt
(
int
fd
,
char
*
buf
,
size_t
buflen
,
const
char
*
prompt
)
{
size_t
plen
=
strlen
(
prompt
);
size_t
pos
=
0
;
...
...
@@ -217,6 +304,18 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
nread
=
read
(
fd
,
&
c
,
1
);
if
(
nread
<=
0
)
return
len
;
/* Only autocomplete when the callback is set. It returns < 0 when
* there was an error reading from fd. Otherwise it will return the
* character that should be handled next. */
if
(
c
==
9
&&
completionCallback
!=
NULL
)
{
c
=
completeLine
(
fd
,
prompt
,
buf
,
buflen
,
&
len
,
&
pos
,
cols
);
/* Return on errors */
if
(
c
<
0
)
return
len
;
/* Read next character when 0 */
if
(
c
==
0
)
continue
;
}
switch
(
c
)
{
case
13
:
/* enter */
case
4
:
/* ctrl-d */
...
...
@@ -350,6 +449,9 @@ up_down_arrow:
pos
=
len
;
refreshLine
(
fd
,
prompt
,
buf
,
len
,
pos
,
cols
);
break
;
case
12
:
/* ctrl+l, clear screen */
linenoiseClearScreen
();
refreshLine
(
fd
,
prompt
,
buf
,
len
,
pos
,
cols
);
}
}
return
len
;
...
...
@@ -402,6 +504,19 @@ char *linenoise(const char *prompt) {
}
}
/* Register a callback function to be called for tab-completion. */
void
linenoiseSetCompletionCallback
(
linenoiseCompletionCallback
*
fn
)
{
completionCallback
=
fn
;
}
void
linenoiseAddCompletion
(
linenoiseCompletions
*
lc
,
char
*
str
)
{
size_t
len
=
strlen
(
str
);
char
*
copy
=
malloc
(
len
+
1
);
memcpy
(
copy
,
str
,
len
+
1
);
lc
->
cvec
=
realloc
(
lc
->
cvec
,
sizeof
(
char
*
)
*
(
lc
->
len
+
1
));
lc
->
cvec
[
lc
->
len
++
]
=
copy
;
}
/* Using a circular buffer is smarter, but a bit more complex to handle. */
int
linenoiseHistoryAdd
(
const
char
*
line
)
{
char
*
linecopy
;
...
...
deps/linenoise/linenoise.h
View file @
bc8ffafe
...
...
@@ -4,6 +4,8 @@
* See linenoise.c for more information.
*
* Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
...
...
@@ -34,10 +36,20 @@
#ifndef __LINENOISE_H
#define __LINENOISE_H
typedef
struct
linenoiseCompletions
{
size_t
len
;
char
**
cvec
;
}
linenoiseCompletions
;
typedef
void
(
linenoiseCompletionCallback
)(
const
char
*
,
linenoiseCompletions
*
);
void
linenoiseSetCompletionCallback
(
linenoiseCompletionCallback
*
);
void
linenoiseAddCompletion
(
linenoiseCompletions
*
,
char
*
);
char
*
linenoise
(
const
char
*
prompt
);
int
linenoiseHistoryAdd
(
const
char
*
line
);
int
linenoiseHistorySetMaxLen
(
int
len
);
int
linenoiseHistorySave
(
char
*
filename
);
int
linenoiseHistoryLoad
(
char
*
filename
);
void
linenoiseClearScreen
(
void
);
#endif
/* __LINENOISE_H */
src/help.h
0 → 100644
View file @
bc8ffafe
/* Automatically generated by utils/generate-command-help.rb, do not edit. */
#ifndef __REDIS_HELP_H
#define __REDIS_HELP_H
static
char
*
commandGroups
[]
=
{
"generic"
,
"string"
,
"list"
,
"set"
,
"sorted_set"
,
"hash"
,
"pubsub"
,
"transactions"
,
"connection"
,
"server"
};
struct
commandHelp
{
char
*
name
;
char
*
params
;
char
*
summary
;
int
group
;
char
*
since
;
}
commandHelp
[]
=
{
{
"APPEND"
,
"key value"
,
"Append a value to a key"
,
1
,
"1.3.3"
},
{
"AUTH"
,
"password"
,
"Authenticate to the server"
,
8
,
"0.08"
},
{
"BGREWRITEAOF"
,
"-"
,
"Asynchronously rewrite the append-only file"
,
9
,
"1.07"
},
{
"BGSAVE"
,
"-"
,
"Asynchronously save the dataset to disk"
,
9
,
"0.07"
},
{
"BLPOP"
,
"key [key ...] timeout"
,
"Remove and get the first element in a list, or block until one is available"
,
2
,
"1.3.1"
},
{
"BRPOP"
,
"key [key ...] timeout"
,
"Remove and get the last element in a list, or block until one is available"
,
2
,
"1.3.1"
},
{
"CONFIG GET"
,
"parameter"
,
"Get the value of a configuration parameter"
,
9
,
"2.0"
},
{
"CONFIG SET"
,
"parameter value"
,
"Set a configuration parameter to the given value"
,
9
,
"2.0"
},
{
"DBSIZE"
,
"-"
,
"Return the number of keys in the selected database"
,
9
,
"0.07"
},
{
"DEBUG OBJECT"
,
"key"
,
"Get debugging information about a key"
,
9
,
"0.101"
},
{
"DEBUG SEGFAULT"
,
"-"
,
"Make the server crash"
,
9
,
"0.101"
},
{
"DECR"
,
"key decrement"
,
"Decrement the integer value of a key by one"
,
1
,
"0.07"
},
{
"DECRBY"
,
"key decrement"
,
"Decrement the integer value of a key by the given number"
,
1
,
"0.07"
},
{
"DEL"
,
"key [key ...]"
,
"Delete a key"
,
0
,
"0.07"
},
{
"DISCARD"
,
"-"
,
"Discard all commands issued after MULTI"
,
7
,
"1.3.3"
},
{
"ECHO"
,
"message"
,
"Echo the given string"
,
8
,
"0.07"
},
{
"EXEC"
,
"-"
,
"Execute all commands issued after MULTI"
,
7
,
"1.1.95"
},
{
"EXISTS"
,
"key"
,
"Determine if a key exists"
,
9
,
"0.07"
},
{
"EXPIRE"
,
"key seconds"
,
"Set a key's time to live in seconds"
,
0
,
"0.09"
},
{
"EXPIREAT"
,
"key timestamp"
,
"Set the expiration for a key as a UNIX timestamp"
,
0
,
"1.1"
},
{
"FLUSHALL"
,
"-"
,
"Remove all keys from all databases"
,
9
,
"0.07"
},
{
"FLUSHDB"
,
"-"
,
"Remove all keys from the current database"
,
9
,
"0.07"
},
{
"GET"
,
"key"
,
"Get the value of a key"
,
1
,
"0.07"
},
{
"GETSET"
,
"key value"
,
"Set the string value of a key and return its old value"
,
1
,
"0.091"
},
{
"HDEL"
,
"key field"
,
"Delete a hash field"
,
5
,
"1.3.10"
},
{
"HEXISTS"
,
"key field"
,
"Determine if a hash field exists"
,
5
,
"1.3.10"
},
{
"HGET"
,
"key field"
,
"Get the value of a hash field"
,
5
,
"1.3.10"
},
{
"HGETALL"
,
"key"
,
"Get all the fields and values in a hash"
,
5
,
"1.3.10"
},
{
"HINCRBY"
,
"key field increment"
,
"Increment the integer value of a hash field by the given number"
,
5
,
"1.3.10"
},
{
"HKEYS"
,
"key"
,
"Get all the fields in a hash"
,
5
,
"1.3.10"
},
{
"HLEN"
,
"key"
,
"Get the number of fields in a hash"
,
5
,
"1.3.10"
},
{
"HMGET"
,
"key field [field ...]"
,
"Get the values of all the given hash fields"
,
5
,
"1.3.10"
},
{
"HMSET"
,
"key field value [field value ...]"
,
"Set multiple hash fields to multiple values"
,
5
,
"1.3.8"
},
{
"HSET"
,
"key field value"
,
"Set the string value of a hash field"
,
5
,
"1.3.10"
},
{
"HSETNX"
,
"key field value"
,
"Set the value of a hash field, only if the field does not exist"
,
5
,
"1.3.8"
},
{
"HVALS"
,
"key"
,
"Get all the values in a hash"
,
5
,
"1.3.10"
},
{
"INCR"
,
"key"
,
"Increment the integer value of a key by one"
,
1
,
"0.07"
},
{
"INCRBY"
,
"key increment"
,
"Increment the integer value of a key by the given number"
,
1
,
"0.07"
},
{
"INFO"
,
"-"
,
"Get information and statistics about the server"
,
9
,
"0.07"
},
{
"KEYS"
,
"pattern"
,
"Find all keys matching the given pattern"
,
0
,
"0.07"
},
{
"LASTSAVE"
,
"-"
,
"Get the UNIX time stamp of the last successful save to disk"
,
9
,
"0.07"
},
{
"LINDEX"
,
"key index"
,
"Get an element from a list by its index"
,
2
,
"0.07"
},
{
"LINSERT"
,
"key BEFORE|AFTER pivot value"
,
"Insert an element before or after another element in a list"
,
2
,
"2.1.1"
},
{
"LLEN"
,
"key"
,
"Get the length of a list"
,
2
,
"0.07"
},
{
"LPOP"
,
"key"
,
"Remove and get the first element in a list"
,
2
,
"0.07"
},
{
"LPUSH"
,
"key value"
,
"Prepend a value to a list"
,
2
,
"0.07"
},
{
"LPUSHX"
,
"key value"
,
"Prepend a value to a list, only if the list exists"
,
2
,
"2.1.1"
},
{
"LRANGE"
,
"key start stop"
,
"Get a range of elements from a list"
,
2
,
"0.07"
},
{
"LREM"
,
"key count value"
,
"Remove elements from a list"
,
2
,
"0.07"
},
{
"LSET"
,
"key index value"
,
"Set the value of an element in a list by its index"
,
2
,
"0.07"
},
{
"LTRIM"
,
"key start stop"
,
"Trim a list to the specified range"
,
2
,
"0.07"
},
{
"MGET"
,
"key [key ...]"
,
"Get the values of all the given keys"
,
1
,
"0.07"
},
{
"MONITOR"
,
"-"
,
"Listen for all requests received by the server in real time"
,
9
,
"0.07"
},
{
"MOVE"
,
"key db"
,
"Move a key to another database"
,
0
,
"0.07"
},
{
"MSET"
,
"key value [key value ...]"
,
"Set multiple keys to multiple values"
,
1
,
"1.001"
},
{
"MSETNX"
,
"key value [key value ...]"
,
"Set multiple keys to multiple values, only if none of the keys exist"
,
1
,
"1.001"
},
{
"MULTI"
,
"-"
,
"Mark the start of a transaction block"
,
7
,
"1.1.95"
},
{
"PERSIST"
,
"key"
,
"Remove the expiration from a key"
,
0
,
"2.1.2"
},
{
"PING"
,
"-"
,
"Ping the server"
,
8
,
"0.07"
},
{
"PSUBSCRIBE"
,
"pattern"
,
"Listen for messages published to channels matching the given patterns"
,
6
,
"1.3.8"
},
{
"PUBLISH"
,
"channel message"
,
"Post a message to a channel"
,
6
,
"1.3.8"
},
{
"PUNSUBSCRIBE"
,
"[pattern [pattern ...]]"
,
"Stop listening for messages posted to channels matching the given patterns"
,
6
,
"1.3.8"
},
{
"QUIT"
,
"-"
,
"Close the connection"
,
8
,
"0.07"
},
{
"RANDOMKEY"
,
"-"
,
"Return a random key from the keyspace"
,
0
,
"0.07"
},
{
"RENAME"
,
"old new"
,
"Rename a key"
,
0
,
"0.07"
},
{
"RENAMENX"
,
"old new"
,
"Rename a key, only if the new key does not exist"
,
0
,
"0.07"
},
{
"RPOP"
,
"key"
,
"Remove and get the last element in a list"
,
2
,
"0.07"
},
{
"RPOPLPUSH"
,
"source destination"
,
"Remove the last element in a list, append it to another list and return it"
,
2
,
"1.1"
},
{
"RPUSH"
,
"key value"
,
"Append a value to a list"
,
2
,
"0.07"
},
{
"RPUSHX"
,
"key value"
,
"Append a value to a list, only if the list exists"
,
2
,
"2.1.1"
},
{
"SADD"
,
"key member"
,
"Add a member to a set"
,
3
,
"0.07"
},
{
"SAVE"
,
"-"
,
"Synchronously save the dataset to disk"
,
9
,
"0.07"
},
{
"SCARD"
,
"key"
,
"Get the number of members in a set"
,
3
,
"0.07"
},
{
"SDIFF"
,
"key [key ...]"
,
"Subtract multiple sets"
,
3
,
"0.100"
},
{
"SDIFFSTORE"
,
"destination key [key ...]"
,
"Subtract multiple sets and store the resulting set in a key"
,
3
,
"0.100"
},
{
"SELECT"
,
"index"
,
"Change the selected database for the current connection"
,
8
,
"0.07"
},
{
"SET"
,
"key value"
,
"Set the string value of a key"
,
1
,
"0.07"
},
{
"SETEX"
,
"key timestamp value"
,
"Set the value and expiration of a key"
,
1
,
"1.3.10"
},
{
"SETNX"
,
"key value"
,
"Set the value of a key, only if the key does not exist"
,
1
,
"0.07"
},
{
"SHUTDOWN"
,
"-"
,
"Synchronously save the dataset to disk and then shut down the server"
,
9
,
"0.07"
},
{
"SINTER"
,
"key [key ...]"
,
"Intersect multiple sets"
,
3
,
"0.07"
},
{
"SINTERSTORE"
,
"destination key [key ...]"
,
"Intersect multiple sets and store the resulting set in a key"
,
3
,
"0.07"
},
{
"SISMEMBER"
,
"key member"
,
"Determine if a given value is a member of a set"
,
3
,
"0.07"
},
{
"SLAVEOF"
,
"host port"
,
"Make the server a slave of another instance, or promote it as master"
,
9
,
"0.100"
},
{
"SMEMBERS"
,
"key"
,
"Get all the members in a set"
,
3
,
"0.07"
},
{
"SMOVE"
,
"source destination member"
,
"Move a member from one set to another"
,
3
,
"0.091"
},
{
"SORT"
,
"key [BY pattern] [LIMIT start count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]"
,
"Sort the elements in a list, set or sorted set"
,
0
,
"0.07"
},
{
"SPOP"
,
"key"
,
"Remove and return a random member from a set"
,
3
,
"0.101"
},
{
"SRANDMEMBER"
,
"key"
,
"Get a random member from a set"
,
3
,
"1.001"
},
{
"SREM"
,
"key member"
,
"Remove a member from a set"
,
3
,
"0.07"
},
{
"STRLEN"
,
"key"
,
"Get the length of the value stored in a key"
,
1
,
"2.1.2"
},
{
"SUBSCRIBE"
,
"channel"
,
"Listen for messages published to the given channels"
,
6
,
"1.3.8"
},
{
"SUBSTR"
,
"key start stop"
,
"Get a substring of the string stored at a key"
,
1
,
"1.3.4"
},
{
"SUNION"
,
"key [key ...]"
,
"Add multiple sets"
,
3
,
"0.091"
},
{
"SUNIONSTORE"
,
"destination key [key ...]"
,
"Add multiple sets and store the resulting set in a key"
,
3
,
"0.091"
},
{
"SYNC"
,
"-"
,
"Internal command used for replication"
,
9
,
"0.07"
},
{
"TTL"
,
"key"
,
"Get the time to live for a key"
,
0
,
"0.100"
},
{
"TYPE"
,
"key"
,
"Determine the type stored at key"
,
0
,
"0.07"
},
{
"UNSUBSCRIBE"
,
"[channel [channel ...]]"
,
"Stop listening for messages posted to the given channels"
,
6
,
"1.3.8"
},
{
"UNWATCH"
,
"-"
,
"Forget about all watched keys"
,
7
,
"2.1.0"
},
{
"WATCH"
,
"key [key ...]"
,
"Watch the given keys to determine execution of the MULTI/EXEC block"
,
7
,
"2.1.0"
},
{
"ZADD"
,
"key score member"
,
"Add a member to a sorted set, or update its score if it already exists"
,
4
,
"1.1"
},
{
"ZCARD"
,
"key"
,
"Get the number of members in a sorted set"
,
4
,
"1.1"
},
{
"ZCOUNT"
,
"key min max"
,
"Count the members in a sorted set with scores within the given values"
,
4
,
"1.3.3"
},
{
"ZINCRBY"
,
"key increment member"
,
"Increment the score of a member in a sorted set"
,
4
,
"1.1"
},
{
"ZINTERSTORE"
,
"destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]"
,
"Intersect multiple sorted sets and store the resulting sorted set in a new key"
,
4
,
"1.3.10"
},
{
"ZRANGE"
,
"key start stop"
,
"Return a range of members in a sorted set, by index"
,
4
,
"1.1"
},
{
"ZRANGEBYSCORE"
,
"key min max"
,
"Return a range of members in a sorted set, by score"
,
4
,
"1.050"
},
{
"ZRANK"
,
"key member"
,
"Determine the index of a member in a sorted set"
,
4
,
"1.3.4"
},
{
"ZREM"
,
"key member"
,
"Remove a member from a sorted set"
,
4
,
"1.1"
},
{
"ZREMRANGEBYRANK"
,
"key start stop"
,
"Remove all members in a sorted set within the given indexes"
,
4
,
"1.3.4"
},
{
"ZREMRANGEBYSCORE"
,
"key min max"
,
"Remove all members in a sorted set within the given scores"
,
4
,
"1.1"
},
{
"ZREVRANGE"
,
"key start stop"
,
"Return a range of members in a sorted set, by index, with scores ordered from high to low"
,
4
,
"1.1"
},
{
"ZREVRANK"
,
"key member"
,
"Determine the index of a member in a sorted set, with scores ordered from high to low"
,
4
,
"1.3.4"
},
{
"ZSCORE"
,
"key member"
,
"Get the score associated with the given member in a sorted set"
,
4
,
"1.1"
},
{
"ZUNIONSTORE"
,
"destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]"
,
"Add multiple sorted sets and store the resulting sorted set in a new key"
,
4
,
"1.3.10"
}
};
#endif
src/redis-cli.c
View file @
bc8ffafe
...
...
@@ -39,11 +39,13 @@
#include <errno.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <assert.h>
#include "hiredis.h"
#include "sds.h"
#include "zmalloc.h"
#include "linenoise.h"
#include "help.h"
#define REDIS_NOTUSED(V) ((void) V)
...
...
@@ -83,6 +85,149 @@ static long long mstime(void) {
return
mst
;
}
/*------------------------------------------------------------------------------
* Help functions
*--------------------------------------------------------------------------- */
#define CLI_HELP_COMMAND 1
#define CLI_HELP_GROUP 2
typedef
struct
{
int
type
;
int
argc
;
sds
*
argv
;
sds
full
;
/* Only used for help on commands */
struct
commandHelp
*
org
;
}
helpEntry
;
static
helpEntry
*
helpEntries
;
static
int
helpEntriesLen
;
static
void
cliInitHelp
()
{
int
commandslen
=
sizeof
(
commandHelp
)
/
sizeof
(
struct
commandHelp
);
int
groupslen
=
sizeof
(
commandGroups
)
/
sizeof
(
char
*
);
int
i
,
len
,
pos
=
0
;
helpEntry
tmp
;
helpEntriesLen
=
len
=
commandslen
+
groupslen
;
helpEntries
=
malloc
(
sizeof
(
helpEntry
)
*
len
);
for
(
i
=
0
;
i
<
groupslen
;
i
++
)
{
tmp
.
argc
=
1
;
tmp
.
argv
=
malloc
(
sizeof
(
sds
));
tmp
.
argv
[
0
]
=
sdscatprintf
(
sdsempty
(),
"@%s"
,
commandGroups
[
i
]);
tmp
.
full
=
tmp
.
argv
[
0
];
tmp
.
type
=
CLI_HELP_GROUP
;
tmp
.
org
=
NULL
;
helpEntries
[
pos
++
]
=
tmp
;
}
for
(
i
=
0
;
i
<
commandslen
;
i
++
)
{
tmp
.
argv
=
sdssplitargs
(
commandHelp
[
i
].
name
,
&
tmp
.
argc
);
tmp
.
full
=
sdsnew
(
commandHelp
[
i
].
name
);
tmp
.
type
=
CLI_HELP_COMMAND
;
tmp
.
org
=
&
commandHelp
[
i
];
helpEntries
[
pos
++
]
=
tmp
;
}
}
/* Output command help to stdout. */
static
void
cliOutputCommandHelp
(
struct
commandHelp
*
help
,
int
group
)
{
printf
(
"
\r\n
\x1b
[1m%s
\x1b
[0m
\x1b
[90m%s
\x1b
[0m
\r\n
"
,
help
->
name
,
help
->
params
);
printf
(
"
\x1b
[33msummary:
\x1b
[0m %s
\r\n
"
,
help
->
summary
);
printf
(
"
\x1b
[33msince:
\x1b
[0m %s
\r\n
"
,
help
->
since
);
if
(
group
)
{
printf
(
"
\x1b
[33mgroup:
\x1b
[0m %s
\r\n
"
,
commandGroups
[
help
->
group
]);
}
}
/* Print generic help. */
static
void
cliOutputGenericHelp
()
{
printf
(
"redis-cli %s
\r\n
"
"Type:
\"
help @<group>
\"
to get a list of commands in <group>
\r\n
"
"
\"
help <command>
\"
for help on <command>
\r\n
"
"
\"
help <tab>
\"
to get a list of possible help topics
\r\n
"
"
\"
quit
\"
to exit
\r\n
"
,
REDIS_VERSION
);
}
/* Output all command help, filtering by group or command name. */
static
void
cliOutputHelp
(
int
argc
,
char
**
argv
)
{
int
i
,
j
,
len
;
int
group
=
-
1
;
helpEntry
*
entry
;
struct
commandHelp
*
help
;
if
(
argc
==
0
)
{
cliOutputGenericHelp
();
return
;
}
else
if
(
argc
>
0
&&
argv
[
0
][
0
]
==
'@'
)
{
len
=
sizeof
(
commandGroups
)
/
sizeof
(
char
*
);
for
(
i
=
0
;
i
<
len
;
i
++
)
{
if
(
strcasecmp
(
argv
[
0
]
+
1
,
commandGroups
[
i
])
==
0
)
{
group
=
i
;
break
;
}
}
}
assert
(
argc
>
0
);
for
(
i
=
0
;
i
<
helpEntriesLen
;
i
++
)
{
entry
=
&
helpEntries
[
i
];
if
(
entry
->
type
!=
CLI_HELP_COMMAND
)
continue
;
help
=
entry
->
org
;
if
(
group
==
-
1
)
{
/* Compare all arguments */
if
(
argc
==
entry
->
argc
)
{
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
if
(
strcasecmp
(
argv
[
j
],
entry
->
argv
[
j
])
!=
0
)
break
;
}
if
(
j
==
argc
)
{
cliOutputCommandHelp
(
help
,
1
);
}
}
}
else
{
if
(
group
==
help
->
group
)
{
cliOutputCommandHelp
(
help
,
0
);
}
}
}
printf
(
"
\r\n
"
);
}
static
void
completionCallback
(
const
char
*
buf
,
linenoiseCompletions
*
lc
)
{
size_t
startpos
=
0
;
int
mask
;
int
i
;
size_t
matchlen
;
sds
tmp
;
if
(
strncasecmp
(
buf
,
"help "
,
5
)
==
0
)
{
startpos
=
5
;
while
(
isspace
(
buf
[
startpos
]))
startpos
++
;
mask
=
CLI_HELP_COMMAND
|
CLI_HELP_GROUP
;
}
else
{
mask
=
CLI_HELP_COMMAND
;
}
for
(
i
=
0
;
i
<
helpEntriesLen
;
i
++
)
{
if
(
!
(
helpEntries
[
i
].
type
&
mask
))
continue
;
matchlen
=
strlen
(
buf
+
startpos
);
if
(
strncasecmp
(
buf
+
startpos
,
helpEntries
[
i
].
full
,
matchlen
)
==
0
)
{
tmp
=
sdsnewlen
(
buf
,
startpos
);
tmp
=
sdscat
(
tmp
,
helpEntries
[
i
].
full
);
linenoiseAddCompletion
(
lc
,
tmp
);
sdsfree
(
tmp
);
}
}
}
/*------------------------------------------------------------------------------
* Networking / parsing
*--------------------------------------------------------------------------- */
...
...
@@ -252,22 +397,6 @@ static int cliReadReply() {
return
REDIS_OK
;
}
static
void
showInteractiveHelp
(
void
)
{
printf
(
"
\n
"
"Welcome to redis-cli "
REDIS_VERSION
"!
\n
"
"Just type any valid Redis command to see a pretty printed output.
\n
"
"
\n
"
"It is possible to quote strings, like in:
\n
"
" set
\"
my key
\"
\"
some string
\\
xff
\\
n
\"\n
"
"
\n
"
"You can find a list of valid Redis commands at
\n
"
" http://code.google.com/p/redis/wiki/CommandReference
\n
"
"
\n
"
"Note: redis-cli supports line editing, use up/down arrows for history."
"
\n\n
"
);
}
static
int
cliSendCommand
(
int
argc
,
char
**
argv
,
int
repeat
)
{
char
*
command
=
argv
[
0
];
size_t
*
argvlen
;
...
...
@@ -279,8 +408,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
}
config
.
raw_output
=
!
strcasecmp
(
command
,
"info"
);
if
(
!
strcasecmp
(
command
,
"help"
))
{
showInteractiveHelp
(
);
if
(
!
strcasecmp
(
command
,
"help"
)
||
!
strcasecmp
(
command
,
"?"
)
)
{
cliOutputHelp
(
--
argc
,
++
argv
);
return
REDIS_OK
;
}
if
(
!
strcasecmp
(
command
,
"shutdown"
))
config
.
shutdown
=
1
;
...
...
@@ -412,6 +541,8 @@ static void repl() {
sds
*
argv
;
config
.
interactive
=
1
;
linenoiseSetCompletionCallback
(
completionCallback
);
while
((
line
=
linenoise
(
context
?
"redis> "
:
"not connected> "
))
!=
NULL
)
{
if
(
line
[
0
]
!=
'\0'
)
{
argv
=
sdssplitargs
(
line
,
&
argc
);
...
...
@@ -430,6 +561,8 @@ static void repl() {
config
.
hostip
=
sdsnew
(
argv
[
1
]);
config
.
hostport
=
atoi
(
argv
[
2
]);
cliConnect
(
1
);
}
else
if
(
argc
==
1
&&
!
strcasecmp
(
argv
[
0
],
"clear"
))
{
linenoiseClearScreen
();
}
else
{
long
long
start_time
=
mstime
(),
elapsed
;
...
...
@@ -489,6 +622,7 @@ int main(int argc, char **argv) {
config
.
historyfile
=
NULL
;
config
.
tty
=
isatty
(
fileno
(
stdout
))
||
(
getenv
(
"FAKETTY"
)
!=
NULL
);
config
.
mb_sep
=
'\n'
;
cliInitHelp
();
if
(
getenv
(
"HOME"
)
!=
NULL
)
{
config
.
historyfile
=
malloc
(
256
);
...
...
utils/generate-command-help.rb
0 → 100755
View file @
bc8ffafe
#!/usr/bin/env ruby
GROUPS
=
[
"generic"
,
"string"
,
"list"
,
"set"
,
"sorted_set"
,
"hash"
,
"pubsub"
,
"transactions"
,
"connection"
,
"server"
].
freeze
GROUPS_BY_NAME
=
Hash
[
*
GROUPS
.
each_with_index
.
map
do
|
n
,
i
|
[
n
,
i
]
end
.
flatten
].
freeze
def
argument
arg
name
=
arg
[
"name"
].
is_a?
(
Array
)
?
arg
[
"name"
].
join
(
" "
)
:
arg
[
"name"
]
name
=
arg
[
"enum"
].
join
"|"
if
"enum"
==
arg
[
"type"
]
name
=
arg
[
"command"
]
+
" "
+
name
if
arg
[
"command"
]
if
arg
[
"multiple"
]
name
=
"
#{
name
}
[
#{
name
}
...]"
end
if
arg
[
"optional"
]
name
=
"[
#{
name
}
]"
end
name
end
def
arguments
command
return
"-"
unless
command
[
"arguments"
]
command
[
"arguments"
].
map
do
|
arg
|
argument
arg
end
.
join
" "
end
def
commands
return
@commands
if
@commands
require
"net/http"
require
"net/https"
require
"json"
require
"uri"
url
=
URI
.
parse
"https://github.com/antirez/redis-doc/raw/master/commands.json"
client
=
Net
::
HTTP
.
new
url
.
host
,
url
.
port
client
.
use_ssl
=
true
response
=
client
.
get
url
.
path
if
response
.
is_a?
(
Net
::
HTTPSuccess
)
@commands
=
JSON
.
parse
(
response
.
body
)
else
response
.
error!
end
end
def
generate_groups
GROUPS
.
map
do
|
n
|
"
\"
#{
n
}
\"
"
end
.
join
(
",
\n
"
);
end
def
generate_commands
commands
.
to_a
.
sort
do
|
x
,
y
|
x
[
0
]
<=>
y
[
0
]
end
.
map
do
|
key
,
command
|
group
=
GROUPS_BY_NAME
[
command
[
"group"
]]
if
group
.
nil?
STDERR
.
puts
"Please update groups array in
#{
__FILE__
}
"
raise
"Unknown group
#{
command
[
"group"
]
}
"
end
ret
=
<<-
SPEC
{ "
#{
key
}
",
"
#{
arguments
(
command
)
}
",
"
#{
command
[
"summary"
]
}
",
#{
group
}
,
"
#{
command
[
"since"
]
}
" }
SPEC
ret
.
strip
end
.
join
(
",
\n
"
)
end
# Write to stdout
puts
<<-
HELP_H
/* Automatically generated by
#{
__FILE__
}
, do not edit. */
#ifndef __REDIS_HELP_H
#define __REDIS_HELP_H
static char *commandGroups[] = {
#{
generate_groups
}
};
struct commandHelp {
char *name;
char *params;
char *summary;
int group;
char *since;
} commandHelp[] = {
#{
generate_commands
}
};
#endif
HELP_H
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