123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- /*
- * ##/%% variable matching code ripped out of ash shell for code sharing
- *
- * This code is derived from software contributed to Berkeley by
- * Kenneth Almquist.
- *
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- *
- * Copyright (c) 1989, 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
- * was re-ported from NetBSD and debianized.
- */
- #ifdef STANDALONE
- # include <stdbool.h>
- # include <stdio.h>
- # include <stdlib.h>
- # include <string.h>
- # include <unistd.h>
- # define FAST_FUNC /* nothing */
- # define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN /* nothing */
- # define POP_SAVED_FUNCTION_VISIBILITY /* nothing */
- #else
- # include "libbb.h"
- #endif
- #include <fnmatch.h>
- #include "match.h"
- char* FAST_FUNC scan_and_match(char *string, const char *pattern, unsigned flags)
- {
- char *loc;
- char *end;
- unsigned len = strlen(string);
- int early_exit;
- /* We can stop the scan early only if the string part
- * we are matching against is shrinking, and the pattern has
- * an unquoted "star" at the corresponding end. There are two cases.
- * Case 1:
- * "qwerty" does not match against pattern "*zy",
- * no point in trying to match "werty", "erty" etc:
- */
- early_exit = (flags == (SCAN_MOVE_FROM_LEFT + SCAN_MATCH_RIGHT_HALF) && pattern[0] == '*');
- if (flags & SCAN_MOVE_FROM_LEFT) {
- loc = string;
- end = string + len + 1;
- } else {
- loc = string + len;
- end = string - 1;
- if (flags == (SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF)) {
- /* Case 2:
- * "qwerty" does not match against pattern "qz*",
- * no point in trying to match "qwert", "qwer" etc:
- */
- const char *p = pattern + strlen(pattern);
- if (--p >= pattern && *p == '*') {
- early_exit = 1;
- while (--p >= pattern && *p == '\\')
- early_exit ^= 1;
- }
- }
- }
- while (loc != end) {
- char c;
- int r;
- c = *loc;
- if (flags & SCAN_MATCH_LEFT_HALF) {
- *loc = '\0';
- r = fnmatch(pattern, string, 0);
- *loc = c;
- } else {
- r = fnmatch(pattern, loc, 0);
- }
- if (r == 0) /* match found */
- return loc;
- if (early_exit) {
- #ifdef STANDALONE
- printf("(early exit) ");
- #endif
- break;
- }
- if (flags & SCAN_MOVE_FROM_LEFT) {
- loc++;
- } else {
- loc--;
- }
- }
- return NULL;
- }
- #ifdef STANDALONE
- int main(int argc, char *argv[])
- {
- char *string;
- char *op;
- char *pattern;
- char *loc;
- setvbuf(stdout, NULL, _IONBF, 0);
- if (!argv[1]) {
- puts(
- "Usage: match <test> [test...]\n\n"
- "Where a <test> is the form: <string><op><match>\n"
- "This is to test the shell ${var#val} expression type.\n\n"
- "e.g. `match 'abc#a*'` -> bc"
- );
- return 1;
- }
- while (*++argv) {
- size_t off;
- unsigned scan_flags;
- string = *argv;
- off = strcspn(string, "#%");
- if (!off) {
- printf("invalid format\n");
- continue;
- }
- op = string + off;
- scan_flags = pick_scan(op[0], op[1]);
- printf("'%s': flags:%x, ", string, scan_flags);
- pattern = op + 1;
- if (op[0] == op[1])
- pattern++;
- op[0] = '\0';
- loc = scan_and_match(string, pattern, scan_flags);
- if (scan_flags & SCAN_MATCH_LEFT_HALF) {
- printf("'%s'\n", loc);
- } else {
- if (loc)
- *loc = '\0';
- printf("'%s'\n", string);
- }
- }
- return 0;
- }
- #endif
|