/* * Copyright (c) 2005-2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // Kevin Van Vechten #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" char* cfstrdup(CFStringRef str) { char* result = NULL; if (str != NULL) { CFIndex length = CFStringGetLength(str); CFIndex size = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); result = malloc(size+1); if (result != NULL) { length = CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingUTF8, '?', 0, (UInt8*)result, size, NULL); result[length] = 0; } } return result; } CFStringRef cfstr(const char* str) { CFStringRef result = NULL; if (str) result = CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8); return result; } void cfperror(CFStringRef str) { char* cstr = cfstrdup(str); if (cstr) { fprintf(stderr, "%s", cstr); free(cstr); } } CFPropertyListRef read_plist(const char* path, const char **errstr) { CFPropertyListRef result = NULL; int fd = open(path, O_RDONLY, (mode_t)0); if (fd != -1) { struct stat sb; if (stat(path, &sb) != -1) { off_t size = sb.st_size; void* buffer = mmap(NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, (off_t)0); if (buffer != (void*)-1) { CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, buffer, size, kCFAllocatorNull); if (data) { CFStringRef str = NULL; result = CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListMutableContainers, &str); CFRelease(data); if (result == NULL && errstr) { *errstr = (const char *)cfstrdup(str); } } else { if (errstr) *errstr = "CFDataCreateWithBytesNoCopy failed"; } munmap(buffer, size); } else if (errstr) { *errstr = (const char *)strerror(errno); } } else if (errstr) { *errstr = (const char *)strerror(errno); } close(fd); } else if (errstr) { *errstr = (const char *)strerror(errno); } return result; } int write_plist_fd(int fd, CFPropertyListRef plist) { CFIndex len, n; const UInt8 *ptr; CFDataRef xmlData; errno = 0; xmlData = CFPropertyListCreateXMLData(kCFAllocatorDefault, plist); if (xmlData == NULL) { if (errno == 0) errno = ENOMEM; return -1; } len = CFDataGetLength(xmlData); ptr = CFDataGetBytePtr(xmlData); while(len > 0) { if ((n = write(fd, ptr, len)) < 0) { int save = errno; if (errno == EAGAIN || errno == EINTR) continue; CFRelease(xmlData); errno = save; return -1; } ptr += n; len -= n; } CFRelease(xmlData); return 0; } int write_plist(const char *path, CFPropertyListRef plist) { int fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644); if (fd < 0) return -1; int ret = write_plist_fd(fd, plist); close(fd); return ret; } int cfprintf(FILE* file, const char* format, ...) { char* cstr; int result; va_list args; va_start(args, format); CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull); CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args); va_end(args); cstr = cfstrdup(str); result = fprintf(file, "%s", cstr); free(cstr); CFRelease(str); CFRelease(formatStr); return result; } CFArrayRef dictionaryGetSortedKeys(CFDictionaryRef dictionary) { CFIndex count = CFDictionaryGetCount(dictionary); const void** keys = malloc(sizeof(CFStringRef) * count); CFDictionaryGetKeysAndValues(dictionary, keys, NULL); CFArrayRef keysArray = CFArrayCreate(NULL, keys, count, &kCFTypeArrayCallBacks); CFMutableArrayRef sortedKeys = CFArrayCreateMutableCopy(NULL, count, keysArray); CFRelease(keysArray); free(keys); CFArraySortValues(sortedKeys, CFRangeMake(0, count), (CFComparatorFunction)CFStringCompare, 0); return sortedKeys; } void dictionaryApplyFunctionSorted(CFDictionaryRef dict, CFDictionaryApplierFunction applier, void* context) { CFArrayRef keys = dictionaryGetSortedKeys(dict); if (keys) { CFIndex i, count = CFArrayGetCount(keys); for (i = 0; i < count; ++i) { CFTypeRef key = CFArrayGetValueAtIndex(keys, i); CFTypeRef val = CFDictionaryGetValue(dict, key); applier(key, val, context); } CFRelease(keys); } } #ifdef notdef int writePlist(FILE* f, CFPropertyListRef p, int tabs) { int result = 0; CFTypeID type = CFGetTypeID(p); if (tabs == 0) { result += fprintf(f, "// !$*UTF8*$!\n"); } char* t = malloc(tabs+1); int i; for (i = 0; i < tabs; ++i) { t[i] = '\t'; } t[tabs] = 0; if (type == CFStringGetTypeID()) { char* utf8 = cfstrdup(p); int quote = 0; for (i = 0 ;; ++i) { int c = utf8[i]; if (c == 0) break; if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '/' || c == '.' || c == '_' )) { quote = 1; break; } } if (utf8[0] == 0) quote = 1; if (quote) result += fprintf(f, "\""); for (i = 0 ;; ++i) { int c = utf8[i]; if (c == 0) break; if (c == '\"' || c == '\\') fprintf(f, "\\"); //if (c == '\n') c = 'n'; result += fprintf(f, "%c", c); } if (quote) result += fprintf(f, "\""); free(utf8); } else if (type == CFArrayGetTypeID()) { result += fprintf(f, "(\n"); int count = CFArrayGetCount(p); for (i = 0; i < count; ++i) { CFTypeRef pp = CFArrayGetValueAtIndex(p, i); result += fprintf(f, "%s\t", t); result += writePlist(f, pp, tabs+1); result += fprintf(f, ",\n"); } result += fprintf(f, "%s)", t); } else if (type == CFDictionaryGetTypeID()) { result += fprintf(f, "{\n"); CFArrayRef keys = dictionaryGetSortedKeys(p); int count = CFArrayGetCount(keys); for (i = 0; i < count; ++i) { CFStringRef key = CFArrayGetValueAtIndex(keys, i); result += fprintf(f, "\t%s", t); result += writePlist(f, key, tabs+1); result += fprintf(f, " = "); result += writePlist(f, CFDictionaryGetValue(p,key), tabs+1); result += fprintf(f, ";\n"); } CFRelease(keys); result += fprintf(f, "%s}", t); } if (tabs == 0) result += fprintf(f, "\n"); free(t); return result; } #endif /* notdef */ CFArrayRef tokenizeString(CFStringRef str) { if (!str) return NULL; CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFCharacterSetRef whitespace = CFCharacterSetCreateWithCharactersInString(NULL, CFSTR(" \t\n\r")); CFStringInlineBuffer buf; CFIndex i, length = CFStringGetLength(str); CFIndex start = 0; CFStringInitInlineBuffer(str, &buf, CFRangeMake(0, length)); for (i = 0; i < length; ++i) { UniChar c = CFStringGetCharacterFromInlineBuffer(&buf, i); if (CFCharacterSetIsCharacterMember(whitespace, c)) { if (start != kCFNotFound) { CFStringRef sub = CFStringCreateWithSubstring(NULL, str, CFRangeMake(start, i - start)); start = kCFNotFound; CFArrayAppendValue(result, sub); CFRelease(sub); } } else if (start == kCFNotFound) { start = i; } } if (start != kCFNotFound) { CFStringRef sub = CFStringCreateWithSubstring(NULL, str, CFRangeMake(start, i - start)); CFArrayAppendValue(result, sub); CFRelease(sub); } CFRelease(whitespace); return result; } // appends each element that does not already exist in the array void arrayAppendArrayDistinct(CFMutableArrayRef array, CFArrayRef other) { CFIndex i, count = CFArrayGetCount(other); CFRange range = CFRangeMake(0, CFArrayGetCount(array)); for (i = 0; i < count; ++i) { CFTypeRef o = CFArrayGetValueAtIndex(other, i); if (!CFArrayContainsValue(array, range, o)) { CFArrayAppendValue(array, o); } } } int is_file(const char* path) { struct stat sb; return (stat(path, &sb) == 0 && S_ISREG(sb.st_mode)); } void upper_ident(char *str) { char *cp; for(cp = str; *cp; cp++) { if (islower(*cp)) *cp = toupper(*cp); else if (!isalnum(*cp) && *cp != '_') *cp = '_'; } } /* * lockfilelink - uses file link count to atomically lock a file. This * algorithm works even on buggy NFS filesystems. */ const char * lockfilebylink(const char *lockfile) { struct timeval t; char *linkfile; int fd; struct stat st; int n = 60; // retry 60 times; once per second // First, make sure the lock file exists if ((fd = open(lockfile, O_RDONLY|O_CREAT, 0644)) < 0) return NULL; close(fd); // Make a unique link file name if (gettimeofday(&t, NULL) < 0) return NULL; asprintf(&linkfile, "%s.%d-%lx.%x", lockfile, getpid(), t.tv_sec, t.tv_usec); if (linkfile == NULL) return NULL; while(n-- > 0) { if (link(lockfile, linkfile) < 0) { free((void *)linkfile); return NULL; } if (stat(linkfile, &st) < 0) { unlink(linkfile); free((void *)linkfile); return NULL; } // if the link count for the link file is 2, we have it if (st.st_nlink == 2) return linkfile; // Otherwise, remove the link file, sleep and try again unlink(linkfile); sleep(1); } // Timed out unlink(linkfile); free((void *)linkfile); return NULL; } void unlockfilebylink(const char *linkfile) { unlink(linkfile); free((void *)linkfile); }