2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * Modification History
29 * April 23, 2003 Allan Nathanson <ajn@apple.com>
41 * - pattern matching information is maintained in a dictionary (patternData).
42 * - the dictionary "key" is the regular expression being matched
43 * - the dictionary "value" is a CFArray with the following contents
44 * [0] = CFData consisting of the pre-compiled regular expression
45 * [1] = CFArray[CFNumber] consisting of the sessions watching this pattern
46 * [2-n] = dynamic store keys which match this pattern
51 CFMutableArrayRef pInfo
;
53 } addContext
, *addContextRef
;
56 static __inline__
void
57 my_CFDictionaryApplyFunction(CFDictionaryRef theDict
,
58 CFDictionaryApplierFunction applier
,
61 CFAllocatorRef myAllocator
;
62 CFDictionaryRef myDict
;
64 myAllocator
= CFGetAllocator(theDict
);
65 myDict
= CFDictionaryCreateCopy(myAllocator
, theDict
);
66 CFDictionaryApplyFunction(myDict
, applier
, context
);
73 identifyKeyForPattern(const void *key
, void *val
, void *context
)
75 CFStringRef storeKey
= (CFStringRef
)key
;
76 CFDictionaryRef storeValue
= (CFDictionaryRef
)val
;
77 CFMutableArrayRef pInfo
= ((addContextRef
)context
)->pInfo
;
78 regex_t
* preg
= ((addContextRef
)context
)->preg
;
85 if (!CFDictionaryContainsKey(storeValue
, kSCDData
)) {
86 /* if no data (yet) */
90 /* convert store key to C string */
91 len
= CFStringGetLength(storeKey
) + 1;
92 if (len
> (CFIndex
)sizeof(str_q
))
93 str
= CFAllocatorAllocate(NULL
, len
, 0);
94 if (_SC_cfstring_to_cstring(storeKey
, str
, len
, kCFStringEncodingASCII
) == NULL
) {
95 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("could not convert store key to C string"));
99 /* compare store key to new notification keys regular expression pattern */
100 reError
= regexec(preg
, str
, 0, NULL
, 0);
103 /* we've got a match */
104 CFArrayAppendValue(pInfo
, storeKey
);
112 (void)regerror(reError
, preg
, reErrBuf
, sizeof(reErrBuf
));
113 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("regexec(): %s"), reErrBuf
);
120 if (str
!= str_q
) CFAllocatorDeallocate(NULL
, str
);
125 __private_extern__ Boolean
126 patternCompile(CFStringRef pattern
, regex_t
*preg
, CFStringRef
*error
)
128 Boolean append
= FALSE
;
129 Boolean insert
= FALSE
;
135 if (!CFStringHasPrefix(pattern
, CFSTR("^"))) {
139 if (!CFStringHasSuffix(pattern
, CFSTR("$")) ||
140 CFStringHasSuffix(pattern
, CFSTR("\\$"))) {
144 /* if regex pattern is not bounded at both ends */
145 if (insert
|| append
) {
146 pattern
= CFStringCreateWithFormat(NULL
,
154 (void)CFStringGetBytes(pattern
,
155 CFRangeMake(0, CFStringGetLength(pattern
)),
156 kCFStringEncodingASCII
,
162 if (++len
> (CFIndex
)sizeof(str_q
)) {
163 str
= CFAllocatorAllocate(NULL
, len
, 0);
165 ok
= (_SC_cfstring_to_cstring(pattern
, str
, len
, kCFStringEncodingASCII
) != NULL
);
166 if (insert
|| append
) {
172 reError
= regcomp(preg
, str
, REG_EXTENDED
);
176 (void)regerror(reError
, preg
, reErrBuf
, sizeof(reErrBuf
));
177 *error
= CFStringCreateWithCString(NULL
, reErrBuf
, kCFStringEncodingASCII
);
178 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("regcomp(%s) failed: %s"), str
, reErrBuf
);
182 *error
= CFRetain(CFSTR("could not convert pattern to regex string"));
183 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("%@"), *error
);
186 if (str
!= str_q
) CFAllocatorDeallocate(NULL
, str
);
193 patternCopy(CFStringRef pattern
)
197 pInfo
= CFDictionaryGetValue(patternData
, pattern
);
198 return pInfo
? CFArrayCreateMutableCopy(NULL
, 0, pInfo
) : NULL
;
204 patternNew(CFStringRef pattern
)
208 CFMutableArrayRef pInfo
;
209 CFMutableDataRef pRegex
;
210 CFArrayRef pSessions
;
212 /* create the pattern info */
213 pInfo
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
215 /* compile the regular expression from the pattern string. */
216 pRegex
= CFDataCreateMutable(NULL
, sizeof(regex_t
));
217 CFDataSetLength(pRegex
, sizeof(regex_t
));
218 if (!patternCompile(pattern
, (regex_t
*)CFDataGetBytePtr(pRegex
), &err
)) {
225 /* add the compiled regular expression to the pattern info */
226 CFArrayAppendValue(pInfo
, pRegex
);
228 /* add the initial (empty) list of sessions watching this pattern */
229 pSessions
= CFArrayCreate(NULL
, NULL
, 0, &kCFTypeArrayCallBacks
);
230 CFArrayAppendValue(pInfo
, pSessions
);
231 CFRelease(pSessions
);
233 /* identify/add all existing keys that match the specified pattern */
234 context
.pInfo
= pInfo
;
235 context
.preg
= (regex_t
*)CFDataGetBytePtr(pRegex
);
236 my_CFDictionaryApplyFunction(storeData
,
237 (CFDictionaryApplierFunction
)identifyKeyForPattern
,
247 patternAddSession(CFStringRef pattern
, CFNumberRef sessionNum
)
251 CFMutableArrayRef pInfo
;
252 CFMutableArrayRef pSessions
;
254 /* find (or create new instance of) this pattern */
255 pInfo
= patternCopy(pattern
);
258 pInfo
= patternNew(pattern
);
264 /* add this session as a pattern watcher */
265 pSessions
= (CFMutableArrayRef
)CFArrayGetValueAtIndex(pInfo
, 1);
266 pSessions
= CFArrayCreateMutableCopy(NULL
, 0, pSessions
);
267 CFArrayAppendValue(pSessions
, sessionNum
);
268 CFArraySetValueAtIndex(pInfo
, 1, pSessions
);
269 CFRelease(pSessions
);
271 /* update pattern watcher info */
272 CFDictionarySetValue(patternData
, pattern
, pInfo
);
274 /* add this session as a watcher of any existing keys */
275 n
= CFArrayGetCount(pInfo
);
276 for (i
= 2; i
< n
; i
++) {
277 CFStringRef matchingKey
;
279 matchingKey
= CFArrayGetValueAtIndex(pInfo
, i
);
280 _addWatcher(sessionNum
, matchingKey
);
290 patternRemoveSession(CFStringRef pattern
, CFNumberRef sessionNum
)
294 CFMutableArrayRef pInfo
;
296 CFMutableArrayRef pSessions
;
298 /* find instance of this pattern */
299 pInfo
= patternCopy(pattern
);
301 /* remove this session as a watcher from all matching keys */
302 n
= CFArrayGetCount(pInfo
);
303 for (i
= 2; i
< n
; i
++) {
304 CFStringRef matchingKey
;
306 matchingKey
= CFArrayGetValueAtIndex(pInfo
, i
);
307 _removeWatcher(sessionNum
, matchingKey
);
310 /* remove session from watchers */
311 pSessions
= (CFMutableArrayRef
)CFArrayGetValueAtIndex(pInfo
, 1);
312 n
= CFArrayGetCount(pSessions
);
314 /* if other sessions are watching this pattern */
316 pSessions
= CFArrayCreateMutableCopy(NULL
, 0, pSessions
);
317 i
= CFArrayGetFirstIndexOfValue(pSessions
, CFRangeMake(0, n
), sessionNum
);
318 CFArrayRemoveValueAtIndex(pSessions
, i
);
319 CFArraySetValueAtIndex(pInfo
, 1, pSessions
);
320 CFRelease(pSessions
);
322 CFDictionarySetValue(patternData
, pattern
, pInfo
);
324 /* if no other sessions are watching this pattern */
326 pRegex
= CFArrayGetValueAtIndex(pInfo
, 0);
327 regfree((regex_t
*)CFDataGetBytePtr(pRegex
));
328 CFDictionaryRemoveValue(patternData
, pattern
);
337 addKeyForPattern(const void *key
, void *val
, void *context
)
339 CFStringRef pattern
= (CFStringRef
)key
;
340 CFArrayRef pInfo
= (CFArrayRef
)val
;
341 CFStringRef storeKey
= (CFStringRef
)context
;
349 /* convert store key to C string */
350 len
= CFStringGetLength(storeKey
) + 1;
351 if (len
> (CFIndex
)sizeof(str_q
))
352 str
= CFAllocatorAllocate(NULL
, len
, 0);
353 if (_SC_cfstring_to_cstring(storeKey
, str
, len
, kCFStringEncodingASCII
) == NULL
) {
354 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("could not convert store key to C string"));
358 /* compare new store key to regular expression pattern */
359 preg
= (regex_t
*)CFDataGetBytePtr(CFArrayGetValueAtIndex(pInfo
, 0));
360 reError
= regexec(preg
, str
, 0, NULL
, 0);
368 CFMutableArrayRef pInfo_new
;
369 CFArrayRef pSessions
;
372 pSessions
= CFArrayGetValueAtIndex(pInfo
, 1);
373 n
= CFArrayGetCount(pSessions
);
374 for (i
= 0; i
< n
; i
++) {
375 CFNumberRef sessionNum
= CFArrayGetValueAtIndex(pSessions
, i
);
377 _addWatcher(sessionNum
, storeKey
);
380 /* add key, update pattern watcher info */
381 pInfo_new
= CFArrayCreateMutableCopy(NULL
, 0, pInfo
);
382 CFArrayAppendValue(pInfo_new
, storeKey
);
383 CFDictionarySetValue(patternData
, pattern
, pInfo_new
);
384 CFRelease(pInfo_new
);
393 (void)regerror(reError
, preg
, reErrBuf
, sizeof(reErrBuf
));
394 SCLog(_configd_verbose
, LOG_DEBUG
, CFSTR("regexec(): %s"), reErrBuf
);
401 if (str
!= str_q
) CFAllocatorDeallocate(NULL
, str
);
408 patternAddKey(CFStringRef key
)
410 my_CFDictionaryApplyFunction(patternData
,
411 (CFDictionaryApplierFunction
)addKeyForPattern
,
419 removeKeyFromPattern(const void *key
, void *val
, void *context
)
421 CFStringRef pattern
= (CFStringRef
)key
;
422 CFArrayRef pInfo
= (CFArrayRef
)val
;
423 CFStringRef storeKey
= (CFStringRef
)context
;
427 CFMutableArrayRef pInfo_new
;
428 CFArrayRef pSessions
;
430 n
= CFArrayGetCount(pInfo
);
432 /* if no keys match this pattern */
436 i
= CFArrayGetFirstIndexOfValue(pInfo
, CFRangeMake(2, n
-2), storeKey
);
438 /* if this key wasn't matched by this pattern */
442 /* remove key from pattern info */
443 pInfo_new
= CFArrayCreateMutableCopy(NULL
, 0, pInfo
);
444 CFArrayRemoveValueAtIndex(pInfo_new
, i
);
446 /* remove watchers */
447 pSessions
= CFArrayGetValueAtIndex(pInfo_new
, 1);
448 n
= CFArrayGetCount(pSessions
);
449 for (i
= 0; i
< n
; i
++) {
450 CFNumberRef sessionNum
= CFArrayGetValueAtIndex(pSessions
, i
);
452 _removeWatcher(sessionNum
, storeKey
);
455 CFDictionarySetValue(patternData
, pattern
, pInfo_new
);
456 CFRelease(pInfo_new
);
463 patternRemoveKey(CFStringRef key
)
465 my_CFDictionaryApplyFunction(patternData
,
466 (CFDictionaryApplierFunction
)removeKeyFromPattern
,