LPOS key element [RANK rank] [COUNT num-matches] [MAXLEN len] * * The "rank" is the position of the match, so if it is 1, the first match * is returned, if it is 2 the second match is returned and so forth. * It is 1 by default. If negative has the same meaning but the search is * performed starting from the end of the list. * * If COUNT is given, instead of returning the single element, a
| 590 | * The returned elements indexes are always referring to what LINDEX |
| 591 | * would return. So first element from head is 0, and so forth. */ |
| 592 | void lposCommand(client *c) { |
| 593 | robj_roptr o; |
| 594 | robj *ele = c->argv[2]; |
| 595 | int direction = LIST_TAIL; |
| 596 | long rank = 1, count = -1, maxlen = 0; /* Count -1: option not given. */ |
| 597 | |
| 598 | if (sdslen(szFromObj(ele)) > LIST_MAX_ITEM_SIZE) { |
| 599 | addReplyError(c, "Element too large"); |
| 600 | return; |
| 601 | } |
| 602 | |
| 603 | /* Parse the optional arguments. */ |
| 604 | for (int j = 3; j < c->argc; j++) { |
| 605 | char *opt = szFromObj(c->argv[j]); |
| 606 | int moreargs = (c->argc-1)-j; |
| 607 | |
| 608 | if (!strcasecmp(opt,"RANK") && moreargs) { |
| 609 | j++; |
| 610 | if (getLongFromObjectOrReply(c, c->argv[j], &rank, NULL) != C_OK) |
| 611 | return; |
| 612 | if (rank == 0) { |
| 613 | addReplyError(c,"RANK can't be zero: use 1 to start from " |
| 614 | "the first match, 2 from the second, ..."); |
| 615 | return; |
| 616 | } |
| 617 | } else if (!strcasecmp(opt,"COUNT") && moreargs) { |
| 618 | j++; |
| 619 | if (getPositiveLongFromObjectOrReply(c, c->argv[j], &count, |
| 620 | "COUNT can't be negative") != C_OK) |
| 621 | return; |
| 622 | } else if (!strcasecmp(opt,"MAXLEN") && moreargs) { |
| 623 | j++; |
| 624 | if (getPositiveLongFromObjectOrReply(c, c->argv[j], &maxlen, |
| 625 | "MAXLEN can't be negative") != C_OK) |
| 626 | return; |
| 627 | } else { |
| 628 | addReplyErrorObject(c,shared.syntaxerr); |
| 629 | return; |
| 630 | } |
| 631 | } |
| 632 | |
| 633 | /* A negative rank means start from the tail. */ |
| 634 | if (rank < 0) { |
| 635 | rank = -rank; |
| 636 | direction = LIST_HEAD; |
| 637 | } |
| 638 | |
| 639 | /* We return NULL or an empty array if there is no such key (or |
| 640 | * if we find no matches, depending on the presence of the COUNT option. */ |
| 641 | if ((o = lookupKeyRead(c->db,c->argv[1])) == nullptr) { |
| 642 | if (count != -1) |
| 643 | addReply(c,shared.emptyarray); |
| 644 | else |
| 645 | addReply(c,shared.null[c->resp]); |
| 646 | return; |
| 647 | } |
| 648 | if (checkType(c,o,OBJ_LIST)) return; |
| 649 |
nothing calls this directly
no test coverage detected