#include "configd.h"
#include "pattern.h"
typedef struct {
CFMutableArrayRef pInfo;
regex_t *preg;
} addContext, *addContextRef;
static __inline__ void
my_CFDictionaryApplyFunction(CFDictionaryRef theDict,
CFDictionaryApplierFunction applier,
void *context)
{
CFAllocatorRef myAllocator;
CFDictionaryRef myDict;
myAllocator = CFGetAllocator(theDict);
myDict = CFDictionaryCreateCopy(myAllocator, theDict);
CFDictionaryApplyFunction(myDict, applier, context);
CFRelease(myDict);
return;
}
static void
identifyKeyForPattern(const void *key, void *val, void *context)
{
CFStringRef storeKey = (CFStringRef)key;
CFDictionaryRef storeValue = (CFDictionaryRef)val;
CFMutableArrayRef pInfo = ((addContextRef)context)->pInfo;
regex_t * preg = ((addContextRef)context)->preg;
CFIndex len;
int reError;
char str_q[256];
char * str = str_q;
if (!CFDictionaryContainsKey(storeValue, kSCDData)) {
return;
}
len = CFStringGetLength(storeKey) + 1;
if (len > (CFIndex)sizeof(str_q))
str = CFAllocatorAllocate(NULL, len, 0);
if (_SC_cfstring_to_cstring(storeKey, str, len, kCFStringEncodingASCII) == NULL) {
SCLog(TRUE, LOG_DEBUG, CFSTR("identifyKeyForPattern(): could not convert store key to C string"));
goto done;
}
reError = regexec(preg, str, 0, NULL, 0);
switch (reError) {
case 0 :
CFArrayAppendValue(pInfo, storeKey);
break;
case REG_NOMATCH :
break;
default : {
char reErrBuf[256];
(void)regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
SCLog(TRUE, LOG_DEBUG, CFSTR("identifyKeyForPattern regexec(): %s"), reErrBuf);
break;
}
}
done :
if (str != str_q) CFAllocatorDeallocate(NULL, str);
return;
}
__private_extern__ Boolean
patternCompile(CFStringRef pattern, regex_t *preg, CFStringRef *error)
{
Boolean append = FALSE;
Boolean insert = FALSE;
CFIndex len = 0;
Boolean ok;
char str_q[256];
char * str = str_q;
if (!CFStringHasPrefix(pattern, CFSTR("^"))) {
insert = TRUE;
}
if (!CFStringHasSuffix(pattern, CFSTR("$")) ||
CFStringHasSuffix(pattern, CFSTR("\\$"))) {
append = TRUE;
}
if (insert || append) {
pattern = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("%s%@%s"),
insert ? "^" : "",
pattern,
append ? "$" : "");
}
(void)CFStringGetBytes(pattern,
CFRangeMake(0, CFStringGetLength(pattern)),
kCFStringEncodingASCII,
0,
FALSE,
NULL,
0,
&len);
if (++len > (CFIndex)sizeof(str_q)) {
str = CFAllocatorAllocate(NULL, len, 0);
}
ok = (_SC_cfstring_to_cstring(pattern, str, len, kCFStringEncodingASCII) != NULL);
if (insert || append) {
CFRelease(pattern);
}
if (ok) {
int reError;
reError = regcomp(preg, str, REG_EXTENDED);
if (reError != 0) {
char reErrBuf[256];
(void)regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
*error = CFStringCreateWithCString(NULL, reErrBuf, kCFStringEncodingASCII);
#ifdef DEBUG
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("patternCompile regcomp(%s) failed: %s"), str, reErrBuf);
#endif
ok = FALSE;
}
} else {
*error = CFRetain(CFSTR("could not convert pattern to regex string"));
#ifdef DEBUG
SCLog(_configd_verbose, LOG_DEBUG, CFSTR("%@"), *error);
#endif
}
if (str != str_q) CFAllocatorDeallocate(NULL, str);
return ok;
}
__private_extern__
CFMutableArrayRef
patternCopy(CFStringRef pattern)
{
CFArrayRef pInfo;
pInfo = CFDictionaryGetValue(patternData, pattern);
return pInfo ? CFArrayCreateMutableCopy(NULL, 0, pInfo) : NULL;
}
__private_extern__
CFMutableArrayRef
patternNew(CFStringRef pattern)
{
addContext context;
CFStringRef err;
CFMutableArrayRef pInfo;
CFMutableDataRef pRegex;
CFArrayRef pSessions;
pInfo = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
pRegex = CFDataCreateMutable(NULL, sizeof(regex_t));
CFDataSetLength(pRegex, sizeof(regex_t));
if (!patternCompile(pattern, (regex_t *)CFDataGetBytePtr(pRegex), &err)) {
CFRelease(err);
CFRelease(pRegex);
CFRelease(pInfo);
return NULL;
}
CFArrayAppendValue(pInfo, pRegex);
pSessions = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(pInfo, pSessions);
CFRelease(pSessions);
context.pInfo = pInfo;
context.preg = (regex_t *)CFDataGetBytePtr(pRegex);
my_CFDictionaryApplyFunction(storeData,
(CFDictionaryApplierFunction)identifyKeyForPattern,
&context);
CFRelease(pRegex);
return pInfo;
}
__private_extern__
Boolean
patternAddSession(CFStringRef pattern, CFNumberRef sessionNum)
{
CFIndex i;
CFIndex n;
CFMutableArrayRef pInfo;
CFMutableArrayRef pSessions;
pInfo = patternCopy(pattern);
if (!pInfo) {
pInfo = patternNew(pattern);
if (!pInfo) {
return FALSE;
}
}
pSessions = (CFMutableArrayRef)CFArrayGetValueAtIndex(pInfo, 1);
pSessions = CFArrayCreateMutableCopy(NULL, 0, pSessions);
CFArrayAppendValue(pSessions, sessionNum);
CFArraySetValueAtIndex(pInfo, 1, pSessions);
CFRelease(pSessions);
CFDictionarySetValue(patternData, pattern, pInfo);
n = CFArrayGetCount(pInfo);
for (i = 2; i < n; i++) {
CFStringRef matchingKey;
matchingKey = CFArrayGetValueAtIndex(pInfo, i);
_addWatcher(sessionNum, matchingKey);
}
CFRelease(pInfo);
return TRUE;
}
__private_extern__
void
patternRemoveSession(CFStringRef pattern, CFNumberRef sessionNum)
{
CFIndex i;
CFIndex n;
CFMutableArrayRef pInfo;
CFDataRef pRegex;
CFMutableArrayRef pSessions;
pInfo = patternCopy(pattern);
n = CFArrayGetCount(pInfo);
for (i = 2; i < n; i++) {
CFStringRef matchingKey;
matchingKey = CFArrayGetValueAtIndex(pInfo, i);
_removeWatcher(sessionNum, matchingKey);
}
pSessions = (CFMutableArrayRef)CFArrayGetValueAtIndex(pInfo, 1);
n = CFArrayGetCount(pSessions);
if (n > 1) {
pSessions = CFArrayCreateMutableCopy(NULL, 0, pSessions);
i = CFArrayGetFirstIndexOfValue(pSessions, CFRangeMake(0, n), sessionNum);
CFArrayRemoveValueAtIndex(pSessions, i);
CFArraySetValueAtIndex(pInfo, 1, pSessions);
CFRelease(pSessions);
CFDictionarySetValue(patternData, pattern, pInfo);
} else {
pRegex = CFArrayGetValueAtIndex(pInfo, 0);
regfree((regex_t *)CFDataGetBytePtr(pRegex));
CFDictionaryRemoveValue(patternData, pattern);
}
CFRelease(pInfo);
return;
}
static void
addKeyForPattern(const void *key, void *val, void *context)
{
CFStringRef pattern = (CFStringRef)key;
CFArrayRef pInfo = (CFArrayRef)val;
CFStringRef storeKey = (CFStringRef)context;
CFIndex len;
regex_t *preg;
int reError;
char str_q[256];
char * str = str_q;
len = CFStringGetLength(storeKey) + 1;
if (len > (CFIndex)sizeof(str_q))
str = CFAllocatorAllocate(NULL, len, 0);
if (_SC_cfstring_to_cstring(storeKey, str, len, kCFStringEncodingASCII) == NULL) {
SCLog(TRUE, LOG_DEBUG, CFSTR("addKeyForPattern(): could not convert store key to C string"));
goto done;
}
preg = (regex_t *)CFDataGetBytePtr(CFArrayGetValueAtIndex(pInfo, 0));
reError = regexec(preg, str, 0, NULL, 0);
switch (reError) {
case 0 : {
CFIndex i;
CFIndex n;
CFMutableArrayRef pInfo_new;
CFArrayRef pSessions;
pSessions = CFArrayGetValueAtIndex(pInfo, 1);
n = CFArrayGetCount(pSessions);
for (i = 0; i < n; i++) {
CFNumberRef sessionNum = CFArrayGetValueAtIndex(pSessions, i);
_addWatcher(sessionNum, storeKey);
}
pInfo_new = CFArrayCreateMutableCopy(NULL, 0, pInfo);
CFArrayAppendValue(pInfo_new, storeKey);
CFDictionarySetValue(patternData, pattern, pInfo_new);
CFRelease(pInfo_new);
break;
}
case REG_NOMATCH :
break;
default : {
char reErrBuf[256];
(void)regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
SCLog(TRUE, LOG_DEBUG, CFSTR("addKeyForPattern regexec(): %s"), reErrBuf);
break;
}
}
done :
if (str != str_q) CFAllocatorDeallocate(NULL, str);
return;
}
__private_extern__
void
patternAddKey(CFStringRef key)
{
my_CFDictionaryApplyFunction(patternData,
(CFDictionaryApplierFunction)addKeyForPattern,
(void *)key);
return;
}
static void
removeKeyFromPattern(const void *key, void *val, void *context)
{
CFStringRef pattern = (CFStringRef)key;
CFArrayRef pInfo = (CFArrayRef)val;
CFStringRef storeKey = (CFStringRef)context;
CFIndex i;
CFIndex n;
CFMutableArrayRef pInfo_new;
CFArrayRef pSessions;
n = CFArrayGetCount(pInfo);
if (n <= 2) {
return;
}
i = CFArrayGetFirstIndexOfValue(pInfo, CFRangeMake(2, n-2), storeKey);
if (i == kCFNotFound) {
return;
}
pInfo_new = CFArrayCreateMutableCopy(NULL, 0, pInfo);
CFArrayRemoveValueAtIndex(pInfo_new, i);
pSessions = CFArrayGetValueAtIndex(pInfo_new, 1);
n = CFArrayGetCount(pSessions);
for (i = 0; i < n; i++) {
CFNumberRef sessionNum = CFArrayGetValueAtIndex(pSessions, i);
_removeWatcher(sessionNum, storeKey);
}
CFDictionarySetValue(patternData, pattern, pInfo_new);
CFRelease(pInfo_new);
return;
}
__private_extern__
void
patternRemoveKey(CFStringRef key)
{
my_CFDictionaryApplyFunction(patternData,
(CFDictionaryApplierFunction)removeKeyFromPattern,
(void *)key);
return;
}