2 * Copyright (c) 2000-2005, 2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * November 9, 2000 Allan Nathanson <ajn@apple.com>
34 #include <sys/types.h>
41 #pragma mark SCDynamicStore "cache"
44 static Boolean use_cache
= FALSE
;
46 static CFMutableDictionaryRef cached_keys
= NULL
;
47 static CFMutableDictionaryRef cached_set
= NULL
;
48 static CFMutableArrayRef cached_removals
= NULL
;
49 static CFMutableArrayRef cached_notifys
= NULL
;
56 // if we are already using the cache
60 cached_keys
= CFDictionaryCreateMutable(NULL
,
62 &kCFTypeDictionaryKeyCallBacks
,
63 &kCFTypeDictionaryValueCallBacks
);
64 cached_set
= CFDictionaryCreateMutable(NULL
,
66 &kCFTypeDictionaryKeyCallBacks
,
67 &kCFTypeDictionaryValueCallBacks
);
68 cached_removals
= CFArrayCreateMutable(NULL
,
70 &kCFTypeArrayCallBacks
);
71 cached_notifys
= CFArrayCreateMutable(NULL
,
73 &kCFTypeArrayCallBacks
);
80 static CFPropertyListRef
81 cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store
, CFStringRef key
)
83 CFPropertyListRef value
;
85 value
= CFDictionaryGetValue(cached_set
, key
);
87 // if we have "set" a new value
88 return (CFRetain(value
));
91 if (CFArrayContainsValue(cached_removals
,
92 CFRangeMake(0, CFArrayGetCount(cached_removals
)),
94 // if we have "removed" the key
95 _SCErrorSet(kSCStatusNoKey
);
99 value
= CFDictionaryGetValue(cached_keys
, key
);
101 // if we have a cached value
102 return (CFRetain(value
));
105 value
= SCDynamicStoreCopyValue(store
, key
);
107 CFDictionarySetValue(cached_keys
, key
, value
);
115 cache_SCDynamicStoreSetValue(SCDynamicStoreRef store
, CFStringRef key
, CFPropertyListRef value
)
119 i
= CFArrayGetFirstIndexOfValue(cached_removals
,
120 CFRangeMake(0, CFArrayGetCount(cached_removals
)),
122 if (i
!= kCFNotFound
) {
123 // if previously "removed"
124 CFArrayRemoveValueAtIndex(cached_removals
, i
);
127 CFDictionarySetValue(cached_set
, key
, value
);
133 cache_SCDynamicStoreRemoveValue(SCDynamicStoreRef store
, CFStringRef key
)
135 CFDictionaryRemoveValue(cached_set
, key
);
137 if (!CFArrayContainsValue(cached_removals
,
138 CFRangeMake(0, CFArrayGetCount(cached_removals
)),
140 CFArrayAppendValue(cached_removals
, key
);
148 cache_SCDynamicStoreNotifyValue(SCDynamicStoreRef store
, CFStringRef key
)
150 if (!CFArrayContainsValue(cached_notifys
,
151 CFRangeMake(0, CFArrayGetCount(cached_notifys
)),
153 CFArrayAppendValue(cached_notifys
, key
);
161 cache_write(SCDynamicStoreRef store
)
163 if ((CFDictionaryGetCount(cached_set
) > 0) ||
164 (CFArrayGetCount(cached_removals
) > 0) ||
165 (CFArrayGetCount(cached_notifys
) > 0)) {
166 if (!SCDynamicStoreSetMultiple(store
,
170 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
186 CFRelease(cached_keys
);
187 CFRelease(cached_set
);
188 CFRelease(cached_removals
);
189 CFRelease(cached_notifys
);
197 #pragma mark SCDynamicStore operations
202 do_block(int argc
, char **argv
)
204 Boolean enable
= FALSE
;
207 if ((strcasecmp(argv
[0], "begin") == 0) ||
208 (strcasecmp(argv
[0], "start") == 0) ||
209 (strcasecmp(argv
[0], "on" ) == 0) ||
210 (strcasecmp(argv
[0], "1" ) == 0)) {
212 } else if ((strcasecmp(argv
[0], "end" ) == 0) ||
213 (strcasecmp(argv
[0], "stop" ) == 0) ||
214 (strcasecmp(argv
[0], "off" ) == 0) ||
215 (strcasecmp(argv
[0], "0" ) == 0)) {
218 SCPrint(TRUE
, stdout
, CFSTR("invalid value\n"));
222 enable
= !use_cache
; // toggle
226 // begin block of SCDynamicStore operations
228 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusLocked
));
232 SCPrint(TRUE
, stdout
, CFSTR("Begin block of SCDynamicStore operations\n"));
238 // end block of SCDynamicStore operations
240 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusNeedLock
));
244 n
= CFDictionaryGetCount(cached_keys
) +
245 CFArrayGetCount(cached_removals
) +
246 CFArrayGetCount(cached_notifys
);
247 SCPrint(TRUE
, stdout
,
248 CFSTR("End block of SCDynamicStore operations%s\n"),
249 (n
> 0) ? ", posting changes" : "");
260 static CFComparisonResult
261 sort_keys(const void *p1
, const void *p2
, void *context
) {
262 CFStringRef key1
= (CFStringRef
)p1
;
263 CFStringRef key2
= (CFStringRef
)p2
;
264 return CFStringCompare(key1
, key2
, 0);
273 do_list(int argc
, char **argv
)
279 CFMutableArrayRef sortedList
;
281 pattern
= CFStringCreateWithCString(NULL
,
282 (argc
>= 1) ? argv
[0] : ".*",
283 kCFStringEncodingUTF8
);
285 list
= SCDynamicStoreCopyKeyList(store
, pattern
);
288 if (SCError() != kSCStatusOK
) {
289 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
293 SCPrint(TRUE
, stdout
, CFSTR(" no keys.\n"));
298 n
= CFDictionaryGetCount(cached_set
);
300 const void * cachedKeys_q
[N_QUICK
];
301 const void ** cachedKeys
= cachedKeys_q
;
303 if (n
> (CFIndex
)(sizeof(cachedKeys_q
) / sizeof(CFStringRef
))) {
304 cachedKeys
= CFAllocatorAllocate(NULL
, n
* sizeof(CFStringRef
), 0);
306 CFDictionaryGetKeysAndValues(cached_set
, cachedKeys
, NULL
);
307 list
= CFArrayCreate(NULL
, cachedKeys
, n
, &kCFTypeArrayCallBacks
);
308 if (cachedKeys
!= cachedKeys_q
) {
309 CFAllocatorDeallocate(NULL
, cachedKeys
);
312 SCPrint(TRUE
, stdout
, CFSTR(" no keys.\n"));
317 } else if (use_cache
&&
318 ((CFDictionaryGetCount(cached_set
) > 0) || (CFArrayGetCount(cached_removals
) > 0))) {
319 SCPrint(TRUE
, stdout
,
320 CFSTR(" Note: SCDynamicStore transactions in progress, key list (below) may be out of date.\n\n"));
323 listCnt
= CFArrayGetCount(list
);
324 sortedList
= CFArrayCreateMutableCopy(NULL
, listCnt
, list
);
326 CFArraySortValues(sortedList
,
327 CFRangeMake(0, listCnt
),
332 for (i
= 0; i
< listCnt
; i
++) {
335 CFSTR(" subKey [%d] = %@\n"),
337 CFArrayGetValueAtIndex(sortedList
, i
));
340 SCPrint(TRUE
, stdout
, CFSTR(" no keys.\n"));
342 CFRelease(sortedList
);
350 do_add(int argc
, char **argv
)
354 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
358 if (!SCDynamicStoreAddValue(store
, key
, value
)) {
359 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
364 val
= cache_SCDynamicStoreCopyValue(store
, key
);
367 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists
));
369 cache_SCDynamicStoreSetValue(store
, key
, value
);
374 if (!SCDynamicStoreAddTemporaryValue(store
, key
, value
)) {
375 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
380 val
= cache_SCDynamicStoreCopyValue(store
, key
);
383 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists
));
385 if (!SCDynamicStoreAddTemporaryValue(store
, key
, value
)) {
386 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
388 // and save the temp value in the cache too!
389 cache_SCDynamicStoreSetValue(store
, key
, value
);
402 do_get(int argc
, char **argv
)
405 CFPropertyListRef newValue
;
407 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
409 newValue
= SCDynamicStoreCopyValue(store
, key
);
411 newValue
= cache_SCDynamicStoreCopyValue(store
, key
);
414 if (newValue
== NULL
) {
415 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
420 CFRelease(value
); /* we have new information, release the old */
430 do_set(int argc
, char **argv
)
434 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
436 if (!SCDynamicStoreSetValue(store
, key
, value
)) {
437 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
440 cache_SCDynamicStoreSetValue(store
, key
, value
);
449 do_show(int argc
, char **argv
)
452 CFPropertyListRef newValue
;
454 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
458 newValue
= SCDynamicStoreCopyValue(store
, key
);
460 newValue
= cache_SCDynamicStoreCopyValue(store
, key
);
465 patterns
= CFArrayCreate(NULL
, (const void **)&key
, 1, &kCFTypeArrayCallBacks
);
467 newValue
= SCDynamicStoreCopyMultiple(store
, NULL
, patterns
);
470 CFMutableDictionaryRef newDict
;
472 newDict
= CFDictionaryCreateMutable(NULL
,
474 &kCFTypeDictionaryKeyCallBacks
,
475 &kCFTypeDictionaryValueCallBacks
);
476 keys
= SCDynamicStoreCopyKeyList(store
, key
);
481 n
= CFArrayGetCount(keys
);
482 for (i
= 0; i
< n
; i
++) {
483 CFStringRef storeKey
;
486 storeKey
= CFArrayGetValueAtIndex(keys
, i
);
487 storeVal
= cache_SCDynamicStoreCopyValue(store
, storeKey
);
488 if (storeVal
!= NULL
) {
489 CFDictionarySetValue(newDict
, storeKey
, storeVal
);
496 if ((CFDictionaryGetCount(cached_set
) > 0) || (CFArrayGetCount(cached_removals
) > 0)) {
497 SCPrint(TRUE
, stdout
, CFSTR(" Note: SCDynamicStore locked, keys included (below) may be out of date.\n\n"));
506 if (newValue
== NULL
) {
507 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
511 SCPrint(TRUE
, stdout
, CFSTR("%@\n"), newValue
);
519 do_remove(int argc
, char **argv
)
523 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
525 if (!SCDynamicStoreRemoveValue(store
, key
)) {
526 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
529 cache_SCDynamicStoreRemoveValue(store
, key
);
538 do_notify(int argc
, char **argv
)
542 key
= CFStringCreateWithCString(NULL
, argv
[0], kCFStringEncodingUTF8
);
544 if (!SCDynamicStoreNotifyValue(store
, key
)) {
545 SCPrint(TRUE
, stdout
, CFSTR(" %s\n"), SCErrorString(SCError()));
548 cache_SCDynamicStoreNotifyValue(store
, key
);