2 * Copyright (c) 2000-2003 Apple Computer, 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 * July 17, 2000 Allan Nathanson <ajn@apple.com>
34 #include <sys/types.h>
37 #include "cfManager.h"
42 * Opens a configuration file and returns a CFArrayRef consisting
43 * of a CFStringRef for each line.
47 configRead(const char *path
)
51 CFMutableDataRef data
;
53 CFArrayRef config
= NULL
;
55 fd
= open(path
, O_RDONLY
, 0644);
59 if (fstat(fd
, &statBuf
) < 0) {
62 if ((statBuf
.st_mode
& S_IFMT
) != S_IFREG
) {
66 data
= CFDataCreateMutable(NULL
, statBuf
.st_size
);
67 CFDataSetLength(data
, statBuf
.st_size
);
68 if(read(fd
, (void *)CFDataGetMutableBytePtr(data
), statBuf
.st_size
) != statBuf
.st_size
) {
73 str
= CFStringCreateFromExternalRepresentation(NULL
, data
, kCFStringEncodingMacRoman
);
76 config
= CFStringCreateArrayBySeparatingStrings(NULL
, str
, CFSTR("\n"));
85 CFMutableArrayRef emptyConfig
;
87 /* pretend that we found an empty file */
88 emptyConfig
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
89 CFArrayAppendValue(emptyConfig
, CFSTR(""));
90 config
= (CFArrayRef
)emptyConfig
;
97 * Writes a new configuration file with the contents of a CFArrayRef. Each
98 * element of the array is a CFStringRef.
102 configWrite(const char *path
, CFArrayRef config
)
109 str
= CFStringCreateByCombiningStrings(NULL
, config
, CFSTR("\n"));
110 data
= CFStringCreateExternalRepresentation(NULL
, str
, kCFStringEncodingMacRoman
, '.');
113 fd
= open(path
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644);
118 len
= CFDataGetLength(data
);
120 (void)write(fd
, CFDataGetBytePtr(data
), len
);
135 configSet(CFMutableArrayRef config
, CFStringRef key
, CFStringRef value
)
137 CFMutableStringRef pref
;
138 CFIndex configLen
= CFArrayGetCount(config
);
141 CFMutableStringRef newValue
;
143 CFStringRef specialChars
= CFSTR(" \"'$!|\\<>`{}[]");
144 boolean_t mustQuote
= FALSE
;
146 /* create search prefix */
147 pref
= CFStringCreateMutableCopy(NULL
, 0, key
);
148 CFStringAppend(pref
, CFSTR("="));
151 * create new / replacement value
153 * Note: Since the configuration file may be processed by a
154 * shell script we need to ensure that, if needed, the
155 * string is properly quoted.
157 newValue
= CFStringCreateMutableCopy(NULL
, 0, value
);
159 n
= CFStringGetLength(specialChars
);
160 for (i
= 0; i
< n
; i
++) {
161 CFStringRef specialChar
;
163 specialChar
= CFStringCreateWithSubstring(NULL
, specialChars
, CFRangeMake(i
, 1));
164 range
= CFStringFind(newValue
, specialChar
, 0);
165 CFRelease(specialChar
);
166 if (range
.location
!= kCFNotFound
) {
167 /* this string has at least one special character */
174 CFStringRef charsToQuote
= CFSTR("\\\"$`");
177 * in addition to quoting the entire string we also need to escape the
178 * space " " and backslash "\" characters
180 n
= CFStringGetLength(charsToQuote
);
181 for (i
= 0; i
< n
; i
++) {
182 CFStringRef quoteChar
;
185 quoteChar
= CFStringCreateWithSubstring(NULL
, charsToQuote
, CFRangeMake(i
, 1));
186 range
= CFRangeMake(0, CFStringGetLength(newValue
));
187 matches
= CFStringCreateArrayWithFindResults(NULL
,
192 CFRelease(quoteChar
);
195 CFIndex j
= CFArrayGetCount(matches
);
198 const CFRange
*range
;
200 range
= CFArrayGetValueAtIndex(matches
, j
);
201 CFStringInsert(newValue
, range
->location
, CFSTR("\\"));
207 CFStringInsert(newValue
, 0, CFSTR("\""));
208 CFStringAppend(newValue
, CFSTR("\""));
211 /* locate existing key */
212 for (i
= 0; i
< configLen
; i
++) {
213 if (CFStringHasPrefix(CFArrayGetValueAtIndex(config
, i
), pref
)) {
218 CFStringAppend(pref
, newValue
);
221 /* if replacing an existing entry */
222 CFArraySetValueAtIndex(config
, i
, pref
);
225 * if new entry, insert it just prior to the last (emtpy)
228 CFArrayInsertValueAtIndex(config
, configLen
-1, pref
);
238 configRemove(CFMutableArrayRef config
, CFStringRef key
)
240 CFMutableStringRef pref
;
241 CFIndex configLen
= CFArrayGetCount(config
);
244 /* create search prefix */
245 pref
= CFStringCreateMutableCopy(NULL
, 0, key
);
246 CFStringAppend(pref
, CFSTR("="));
248 /* locate existing key */
249 for (i
= 0; i
< configLen
; i
++) {
250 if (CFStringHasPrefix(CFArrayGetValueAtIndex(config
, i
), pref
)) {
251 /* entry found, remove it */
252 CFArrayRemoveValueAtIndex(config
, i
);