151 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * ##/%% 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);
 | 
						|
			//bb_error_msg("fnmatch('%s','%s',0):%d", pattern, string, r);
 | 
						|
			*loc = c;
 | 
						|
		} else {
 | 
						|
			r = fnmatch(pattern, loc, 0);
 | 
						|
			//bb_error_msg("fnmatch('%s','%s',0):%d", pattern, loc, r);
 | 
						|
		}
 | 
						|
		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
 |