/* Synchronet find string routines */ /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * * Copyright Rob Swindell - http://www.synchro.net/copyright.html * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * See the GNU General Public License for more details: gpl.txt or * * http://www.fsf.org/copyleft/gpl.html * * * * For Synchronet coding style and modification guidelines, see * * http://www.synchro.net/source.html * * * * Note: If this box doesn't appear square, then you need to fix your tabs. * ****************************************************************************/ #include "genwrap.h" #include "findstr.h" /****************************************************************************/ /* Pattern matching string search of 'search' in 'pattern'. */ /* pattern matching is case-insensitive */ /* patterns beginning with ';' are comments (never match) */ /* patterns beginning with '!' are reverse-matched (returns FALSE if match) */ /* patterns ending in '~' will match string anywhere (sub-string search) */ /* patterns ending in '^' will match left string fragment only */ /* patterns including '*' must match both left and right string fragments */ /* all other patterns are exact-match checking */ /****************************************************************************/ BOOL findstr_in_string(const char* search, const char* pattern) { char buf[256]; char* p = (char*)pattern; char* last; const char* splat; size_t len; BOOL found = FALSE; if(pattern == NULL) return FALSE; if(*p == ';') /* comment */ return FALSE; if(*p == '!') { /* reverse-match */ found = TRUE; p++; } if(search == NULL) return found; SAFECOPY(buf, p); p = buf; truncsp(p); len = strlen(p); if(len > 0) { last = p + len - 1; if(*last == '~') { *last = '\0'; if(strcasestr(search, p) != NULL) found = !found; } else if(*last == '^') { if(strnicmp(p, search, len - 1) == 0) found = !found; } else if((splat = strchr(p, '*')) != NULL) { int left = splat - p; int right = len - (left + 1); int slen = strlen(search); if(slen < left + right) return found; if(strnicmp(search, p, left) == 0 && strnicmp(p + left + 1, search + (slen - right), right) == 0) found = !found; } else if(stricmp(p, search) == 0) found = !found; } return found; } static uint32_t encode_ipv4_address(unsigned int byte[]) { if(byte[0] > 0xff || byte[1] > 0xff || byte[2] > 0xff || byte[3] > 0xff) return 0; return (byte[0]<<24) | (byte[1]<<16) | (byte[2]<<8) | byte[3]; } static uint32_t parse_ipv4_address(const char* str) { unsigned int byte[4]; if(str == NULL) return 0; if(sscanf(str, "%u.%u.%u.%u", &byte[0], &byte[1], &byte[2], &byte[3]) != 4) return 0; return encode_ipv4_address(byte); } static uint32_t parse_cidr(const char* p, unsigned* subnet) { unsigned int byte[4]; if(*p == '!') p++; *subnet = 0; if(sscanf(p, "%u.%u.%u.%u/%u", &byte[0], &byte[1], &byte[2], &byte[3], subnet) != 5 || *subnet > 32) return 0; return encode_ipv4_address(byte); } static BOOL is_cidr_match(const char *p, uint32_t ip_addr, uint32_t cidr, unsigned subnet) { BOOL match = FALSE; if(*p == '!') match = TRUE; if(((ip_addr ^ cidr) >> (32-subnet)) == 0) match = !match; return match; } static BOOL findstr_compare(const char* str, uint32_t ip_addr, const char* pattern) { uint32_t cidr; unsigned subnet; if(ip_addr != 0 && (cidr = parse_cidr(pattern, &subnet)) != 0) return is_cidr_match(pattern, ip_addr, cidr, subnet); return findstr_in_string(str, pattern); } /****************************************************************************/ /* Pattern matching string search of 'insearchof' in 'list'. */ /****************************************************************************/ BOOL findstr_in_list(const char* insearchof, str_list_t list) { return find2strs_in_list(insearchof, NULL, list); } /****************************************************************************/ /* Pattern matching string search of 'str1' or 'str2' in 'list'. */ /****************************************************************************/ BOOL find2strs_in_list(const char* str1, const char* str2, str_list_t list) { size_t index; BOOL found=FALSE; char* p; uint32_t ip_addr1, ip_addr2; if(list == NULL) return FALSE; ip_addr1 = parse_ipv4_address(str1); ip_addr2 = parse_ipv4_address(str2); for(index=0; list[index]!=NULL; index++) { p=list[index]; if(*p == '\0') continue; found = findstr_compare(str1, ip_addr1, p); if(!found && str2 != NULL) found = findstr_compare(str2, ip_addr2, p); if(found != (*p=='!')) break; } return found; } /****************************************************************************/ /* Pattern matching string search of 'insearchof' in 'fname'. */ /****************************************************************************/ BOOL findstr(const char* insearchof, const char* fname) { return find2strs(insearchof, NULL, fname); } /****************************************************************************/ /* Pattern matching string search of 'str1' or 'str2' in 'fname'. */ /****************************************************************************/ BOOL find2strs(const char* str1, const char* str2, const char* fname) { char str[256]; BOOL found=FALSE; FILE* fp; uint32_t ip_addr1, ip_addr2; if(fname == NULL || *fname == '\0') return FALSE; if((fp=fopen(fname,"r"))==NULL) return FALSE; ip_addr1 = parse_ipv4_address(str1); ip_addr2 = parse_ipv4_address(str2); while(!feof(fp) && !ferror(fp)) { if(!fgets(str,sizeof(str),fp)) break; char* p = str; SKIP_WHITESPACE(p); if(*p == '\0') continue; c_unescape_str(p); found = findstr_compare(str1, ip_addr1, p); if(!found && str2 != NULL) found = findstr_compare(str2, ip_addr2, p); if(found != (*p=='!')) break; } fclose(fp); return found; } static char* process_findstr_item(size_t index, char *str, void* cbdata) { SKIP_WHITESPACE(str); return c_unescape_str(str); } /****************************************************************************/ str_list_t findstr_list(const char* fname) { FILE* fp; str_list_t list; if((fp=fopen(fname,"r"))==NULL) return NULL; list=strListReadFile(fp, NULL, /* Max line length: */255); strListModifyEach(list, process_findstr_item, /* cbdata: */NULL); fclose(fp); return list; }