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_
| 4060 | * On error (format specifier error) NULL is returned and nothing is |
| 4061 | * allocated. On success the argument vector is returned. */ |
| 4062 | robj **moduleCreateArgvFromUserFormat(const char *cmdname, const char *fmt, int *argcp, int *flags, va_list ap) { |
| 4063 | int argc = 0, argv_size, j; |
| 4064 | robj **argv = NULL; |
| 4065 | |
| 4066 | /* As a first guess to avoid useless reallocations, size argv to |
| 4067 | * hold one argument for each char specifier in 'fmt'. */ |
| 4068 | argv_size = strlen(fmt)+1; /* +1 because of the command name. */ |
| 4069 | argv = (robj**)zrealloc(argv,sizeof(robj*)*argv_size, MALLOC_LOCAL); |
| 4070 | |
| 4071 | /* Build the arguments vector based on the format specifier. */ |
| 4072 | argv[0] = createStringObject(cmdname,strlen(cmdname)); |
| 4073 | argc++; |
| 4074 | |
| 4075 | /* Create the client and dispatch the command. */ |
| 4076 | const char *p = fmt; |
| 4077 | while(*p) { |
| 4078 | if (*p == 'c') { |
| 4079 | char *cstr = va_arg(ap,char*); |
| 4080 | argv[argc++] = createStringObject(cstr,strlen(cstr)); |
| 4081 | } else if (*p == 's') { |
| 4082 | robj *obj = (robj*)va_arg(ap,void*); |
| 4083 | if (obj->getrefcount(std::memory_order_relaxed) == OBJ_STATIC_REFCOUNT) |
| 4084 | obj = createStringObject(szFromObj(obj),sdslen(szFromObj(obj))); |
| 4085 | else |
| 4086 | incrRefCount(obj); |
| 4087 | argv[argc++] = obj; |
| 4088 | } else if (*p == 'b') { |
| 4089 | char *buf = va_arg(ap,char*); |
| 4090 | size_t len = va_arg(ap,size_t); |
| 4091 | argv[argc++] = createStringObject(buf,len); |
| 4092 | } else if (*p == 'l') { |
| 4093 | long long ll = va_arg(ap,long long); |
| 4094 | argv[argc++] = createObject(OBJ_STRING,sdsfromlonglong(ll)); |
| 4095 | } else if (*p == 'v') { |
| 4096 | /* A vector of strings */ |
| 4097 | robj **v = (robj**)va_arg(ap, void*); |
| 4098 | size_t vlen = va_arg(ap, size_t); |
| 4099 | |
| 4100 | /* We need to grow argv to hold the vector's elements. |
| 4101 | * We resize by vector_len-1 elements, because we held |
| 4102 | * one element in argv for the vector already */ |
| 4103 | argv_size += vlen-1; |
| 4104 | argv = (robj**)zrealloc(argv,sizeof(robj*)*argv_size, MALLOC_LOCAL); |
| 4105 | |
| 4106 | size_t i = 0; |
| 4107 | for (i = 0; i < vlen; i++) { |
| 4108 | incrRefCount(v[i]); |
| 4109 | argv[argc++] = v[i]; |
| 4110 | } |
| 4111 | } else if (*p == '!') { |
| 4112 | if (flags) (*flags) |= REDISMODULE_ARGV_REPLICATE; |
| 4113 | } else if (*p == 'A') { |
| 4114 | if (flags) (*flags) |= REDISMODULE_ARGV_NO_AOF; |
| 4115 | } else if (*p == 'R') { |
| 4116 | if (flags) (*flags) |= REDISMODULE_ARGV_NO_REPLICAS; |
| 4117 | } else { |
| 4118 | goto fmterr; |
| 4119 | } |
no test coverage detected