BITCOUNT key [start end] */
| 781 | |
| 782 | /* BITCOUNT key [start end] */ |
| 783 | void bitcountCommand(client *c) { |
| 784 | robj *o; |
| 785 | long start, end, strlen; |
| 786 | unsigned char *p; |
| 787 | char llbuf[LONG_STR_SIZE]; |
| 788 | |
| 789 | /* Lookup, check for type, and return 0 for non existing keys. */ |
| 790 | if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL || |
| 791 | checkType(c,o,OBJ_STRING)) return; |
| 792 | p = getObjectReadOnlyString(o,&strlen,llbuf); |
| 793 | |
| 794 | /* Parse start/end range if any. */ |
| 795 | if (c->argc == 4) { |
| 796 | if (getLongFromObjectOrReply(c,c->argv[2],&start,NULL) != C_OK) |
| 797 | return; |
| 798 | if (getLongFromObjectOrReply(c,c->argv[3],&end,NULL) != C_OK) |
| 799 | return; |
| 800 | /* Convert negative indexes */ |
| 801 | if (start < 0 && end < 0 && start > end) { |
| 802 | addReply(c,shared.czero); |
| 803 | return; |
| 804 | } |
| 805 | if (start < 0) start = strlen+start; |
| 806 | if (end < 0) end = strlen+end; |
| 807 | if (start < 0) start = 0; |
| 808 | if (end < 0) end = 0; |
| 809 | if (end >= strlen) end = strlen-1; |
| 810 | } else if (c->argc == 2) { |
| 811 | /* The whole string. */ |
| 812 | start = 0; |
| 813 | end = strlen-1; |
| 814 | } else { |
| 815 | /* Syntax error. */ |
| 816 | addReplyErrorObject(c,shared.syntaxerr); |
| 817 | return; |
| 818 | } |
| 819 | |
| 820 | /* Precondition: end >= 0 && end < strlen, so the only condition where |
| 821 | * zero can be returned is: start > end. */ |
| 822 | if (start > end) { |
| 823 | addReply(c,shared.czero); |
| 824 | } else { |
| 825 | long bytes = end-start+1; |
| 826 | |
| 827 | addReplyLongLong(c,redisPopcount(p+start,bytes)); |
| 828 | } |
| 829 | } |
| 830 | |
| 831 | /* BITPOS key bit [start [end]] */ |
| 832 | void bitposCommand(client *c) { |
nothing calls this directly
no test coverage detected