Returns an array of robj pointers, and populates *argc with the number * of items, by parsing the format specifier "fmt" as described for * the RM_Call(), RM_Replicate() and other module APIs. * * The integer pointed by 'flags' is populated with flags according * to special modifiers in "fmt". For now only one exists: * * "!" -> REDISMODULE_ARGV_REPLICATE * "A" -> REDISMODULE_ARGV_
| 3972 | * On error (format specifier error) NULL is returned and nothing is |
| 3973 | * allocated. On success the argument vector is returned. */ |
| 3974 | robj **moduleCreateArgvFromUserFormat(const char *cmdname, const char *fmt, int *argcp, int *flags, va_list ap) { |
| 3975 | int argc = 0, argv_size, j; |
| 3976 | robj **argv = NULL; |
| 3977 | |
| 3978 | /* As a first guess to avoid useless reallocations, size argv to |
| 3979 | * hold one argument for each char specifier in 'fmt'. */ |
| 3980 | argv_size = strlen(fmt)+1; /* +1 because of the command name. */ |
| 3981 | argv = zrealloc(argv,sizeof(robj*)*argv_size); |
| 3982 | |
| 3983 | /* Build the arguments vector based on the format specifier. */ |
| 3984 | argv[0] = createStringObject(cmdname,strlen(cmdname)); |
| 3985 | argc++; |
| 3986 | |
| 3987 | /* Create the client and dispatch the command. */ |
| 3988 | const char *p = fmt; |
| 3989 | while(*p) { |
| 3990 | if (*p == 'c') { |
| 3991 | char *cstr = va_arg(ap,char*); |
| 3992 | argv[argc++] = createStringObject(cstr,strlen(cstr)); |
| 3993 | } else if (*p == 's') { |
| 3994 | robj *obj = va_arg(ap,void*); |
| 3995 | if (obj->refcount == OBJ_STATIC_REFCOUNT) |
| 3996 | obj = createStringObject(obj->ptr,sdslen(obj->ptr)); |
| 3997 | else |
| 3998 | incrRefCount(obj); |
| 3999 | argv[argc++] = obj; |
| 4000 | } else if (*p == 'b') { |
| 4001 | char *buf = va_arg(ap,char*); |
| 4002 | size_t len = va_arg(ap,size_t); |
| 4003 | argv[argc++] = createStringObject(buf,len); |
| 4004 | } else if (*p == 'l') { |
| 4005 | long long ll = va_arg(ap,long long); |
| 4006 | argv[argc++] = createObject(OBJ_STRING,sdsfromlonglong(ll)); |
| 4007 | } else if (*p == 'v') { |
| 4008 | /* A vector of strings */ |
| 4009 | robj **v = va_arg(ap, void*); |
| 4010 | size_t vlen = va_arg(ap, size_t); |
| 4011 | |
| 4012 | /* We need to grow argv to hold the vector's elements. |
| 4013 | * We resize by vector_len-1 elements, because we held |
| 4014 | * one element in argv for the vector already */ |
| 4015 | argv_size += vlen-1; |
| 4016 | argv = zrealloc(argv,sizeof(robj*)*argv_size); |
| 4017 | |
| 4018 | size_t i = 0; |
| 4019 | for (i = 0; i < vlen; i++) { |
| 4020 | incrRefCount(v[i]); |
| 4021 | argv[argc++] = v[i]; |
| 4022 | } |
| 4023 | } else if (*p == '!') { |
| 4024 | if (flags) (*flags) |= REDISMODULE_ARGV_REPLICATE; |
| 4025 | } else if (*p == 'A') { |
| 4026 | if (flags) (*flags) |= REDISMODULE_ARGV_NO_AOF; |
| 4027 | } else if (*p == 'R') { |
| 4028 | if (flags) (*flags) |= REDISMODULE_ARGV_NO_REPLICAS; |
| 4029 | } else { |
| 4030 | goto fmterr; |
| 4031 | } |
no test coverage detected