+#pragma mark -
+#pragma mark SCDynamicStore "cache"
+
+
+static Boolean use_cache = FALSE;
+
+static CFMutableDictionaryRef cached_keys = NULL;
+static CFMutableDictionaryRef cached_set = NULL;
+static CFMutableArrayRef cached_removals = NULL;
+static CFMutableArrayRef cached_notifys = NULL;
+
+
+static void
+cache_open(void)
+{
+ if (use_cache) {
+ // if we are already using the cache
+ cache_close();
+ }
+
+ cached_keys = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ cached_set = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ cached_removals = CFArrayCreateMutable(NULL,
+ 0,
+ &kCFTypeArrayCallBacks);
+ cached_notifys = CFArrayCreateMutable(NULL,
+ 0,
+ &kCFTypeArrayCallBacks);
+
+ use_cache = TRUE;
+ return;
+}
+
+
+static CFPropertyListRef
+cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
+{
+ CFPropertyListRef value;
+
+ value = CFDictionaryGetValue(cached_set, key);
+ if (value) {
+ // if we have "set" a new value
+ return (CFRetain(value));
+ }
+
+ if (CFArrayContainsValue(cached_removals,
+ CFRangeMake(0, CFArrayGetCount(cached_removals)),
+ key)) {
+ // if we have "removed" the key
+ _SCErrorSet(kSCStatusNoKey);
+ return NULL;
+ }
+
+ value = CFDictionaryGetValue(cached_keys, key);
+ if (value) {
+ // if we have a cached value
+ return (CFRetain(value));
+ }
+
+ value = SCDynamicStoreCopyValue(store, key);
+ if (value) {
+ CFDictionarySetValue(cached_keys, key, value);
+ }
+
+ return value;
+}
+
+
+static void
+cache_SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value)
+{
+ CFIndex i;
+
+ i = CFArrayGetFirstIndexOfValue(cached_removals,
+ CFRangeMake(0, CFArrayGetCount(cached_removals)),
+ key);
+ if (i != kCFNotFound) {
+ // if previously "removed"
+ CFArrayRemoveValueAtIndex(cached_removals, i);
+ }
+
+ CFDictionarySetValue(cached_set, key, value);
+
+ return;
+}
+
+static void
+cache_SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key)
+{
+ CFDictionaryRemoveValue(cached_set, key);
+
+ if (!CFArrayContainsValue(cached_removals,
+ CFRangeMake(0, CFArrayGetCount(cached_removals)),
+ key)) {
+ CFArrayAppendValue(cached_removals, key);
+ }
+
+ return;
+}
+
+
+static void
+cache_SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key)
+{
+ if (!CFArrayContainsValue(cached_notifys,
+ CFRangeMake(0, CFArrayGetCount(cached_notifys)),
+ key)) {
+ CFArrayAppendValue(cached_notifys, key);
+ }
+
+ return;
+}
+
+
+static void
+cache_write(SCDynamicStoreRef store)
+{
+ if ((CFDictionaryGetCount(cached_set) > 0) ||
+ (CFArrayGetCount(cached_removals) > 0) ||
+ (CFArrayGetCount(cached_notifys) > 0)) {
+ if (!SCDynamicStoreSetMultiple(store,
+ cached_set,
+ cached_removals,
+ cached_notifys)) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError()));
+ }
+ }
+
+ return;
+}
+
+
+__private_extern__
+void
+cache_close(void)
+{
+ if (!use_cache) {
+ return;
+ }
+
+ CFRelease(cached_keys);
+ CFRelease(cached_set);
+ CFRelease(cached_removals);
+ CFRelease(cached_notifys);
+
+ use_cache = FALSE;
+ return;
+}
+
+
+#pragma mark -
+#pragma mark SCDynamicStore operations
+
+
+__private_extern__
+void
+do_block(int argc, char **argv)
+{
+ Boolean enable = FALSE;
+
+ if (argc >= 1) {
+ if ((strcasecmp(argv[0], "begin") == 0) ||
+ (strcasecmp(argv[0], "start") == 0) ||
+ (strcasecmp(argv[0], "on" ) == 0) ||
+ (strcasecmp(argv[0], "1" ) == 0)) {
+ enable = TRUE;
+ } else if ((strcasecmp(argv[0], "end" ) == 0) ||
+ (strcasecmp(argv[0], "stop" ) == 0) ||
+ (strcasecmp(argv[0], "off" ) == 0) ||
+ (strcasecmp(argv[0], "0" ) == 0)) {
+ enable = FALSE;
+ } else {
+ SCPrint(TRUE, stdout, CFSTR("invalid value\n"));
+ return;
+ }
+ } else {
+ enable = !use_cache; // toggle
+ }
+
+ if (enable) {
+ // begin block of SCDynamicStore operations
+ if (use_cache) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusLocked));
+ return;
+ }
+
+ SCPrint(TRUE, stdout, CFSTR("Begin block of SCDynamicStore operations\n"));
+
+ cache_open();
+ } else {
+ CFIndex n;
+
+ // end block of SCDynamicStore operations
+ if (!use_cache) {
+ SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusNeedLock));
+ return;
+ }
+
+ n = CFDictionaryGetCount(cached_keys) +
+ CFArrayGetCount(cached_removals) +
+ CFArrayGetCount(cached_notifys);
+ SCPrint(TRUE, stdout,
+ CFSTR("End block of SCDynamicStore operations%s\n"),
+ (n > 0) ? ", posting changes" : "");
+ if (n > 0) {
+ cache_write(store);
+ }
+ cache_close();
+ }
+
+ return;
+}
+
+