2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
31 #include <mach/mach.h>
32 #include <mach/mach_error.h>
36 #include "SCDPrivate.h"
38 #include "dictionary.h"
40 #define LINE_LENGTH 256
42 SCDSessionRef session
= NULL
;
43 SCDHandleRef data
= NULL
;
45 CFMutableArrayRef sources
= NULL
;
49 getLine(char *buf
, int len
, FILE *fp
)
53 if (fgets(buf
, len
, fp
) == NULL
)
57 if (buf
[x
-1] == '\n') {
58 /* the entire line fit in the buffer, remove the newline */
61 /* eat the remainder of the line */
64 } while ((x
!= '\n') && (x
!= EOF
));
72 getString(char **line
)
74 char *s
, *e
, c
, *string
;
75 int i
, isQuoted
= 0, escaped
= 0;
77 if (*line
== NULL
) return NULL
;
78 if (**line
== '\0') return NULL
;
80 /* Skip leading white space */
81 while (isspace(**line
)) *line
+= 1;
83 /* Grab the next string */
86 return NULL
; /* no string available */
87 } else if (*s
== '"') {
88 isQuoted
= 1; /* it's a quoted string */
92 for (e
= s
; (c
= *e
) != '\0'; e
++) {
93 if (isQuoted
&& (c
== '"'))
94 break; /* end of quoted string */
98 break; /* if premature end-of-string */
99 if ((*e
== '"') || isspace(*e
))
100 escaped
++; /* if escaped quote or white space */
102 if (!isQuoted
&& isspace(c
))
103 break; /* end of non-quoted string */
106 string
= malloc(e
- s
- escaped
+ 1);
108 for (i
= 0; s
< e
; s
++) {
110 if (!((s
[0] == '\\') && ((s
[1] == '"') || isspace(s
[1])))) i
++;
115 e
++; /* move past end of quoted string */
123 process_line(FILE *fp
)
125 char line
[LINE_LENGTH
], *s
, *arg
, **argv
= NULL
;
128 /* if end-of-file, exit */
129 if (getLine(line
, sizeof(line
), fp
) == NULL
)
132 if ((nesting
> 0) && SCDOptionGet(NULL
, kSCDOptionVerbose
)) {
133 SCDLog(LOG_NOTICE
, CFSTR("%d> %s"), nesting
, line
);
136 /* if requested, exit */
137 if (strcasecmp(line
, "exit") == 0) return FALSE
;
138 if (strcasecmp(line
, "quit") == 0) return FALSE
;
139 if (strcasecmp(line
, "q" ) == 0) return FALSE
;
141 /* break up the input line */
144 while ((arg
= getString(&s
)) != NULL
) {
146 argv
= (char **)malloc(2 * sizeof(char *));
148 argv
= (char **)realloc(argv
, ((argc
+ 2) * sizeof(char *)));
152 /* process the command */
154 argv
[argc
] = NULL
; /* just in case... */
157 do_command(argc
, argv
);
159 for (i
= 0; i
< argc
; i
++)
169 runLoopProcessInput(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *info
)
173 if (process_line(fp
) == FALSE
) {
174 /* we don't want any more input from this stream, stop listening */
175 CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
176 (CFRunLoopSourceRef
)CFArrayGetValueAtIndex(sources
, 0),
177 kCFRunLoopDefaultMode
);
179 /* we no longer need the fd (socket) */
180 CFSocketInvalidate(s
);
182 /* we no longer need to track this source */
183 CFArrayRemoveValueAtIndex(sources
, 0);
185 if (CFArrayGetCount(sources
) > 0) {
186 /* add the previous input source to the run loop */
187 CFRunLoopAddSource(CFRunLoopGetCurrent(),
188 (CFRunLoopSourceRef
)CFArrayGetValueAtIndex(sources
, 0),
189 kCFRunLoopDefaultMode
);
191 /* no more input sources, we're done! */
195 /* decrement the nesting level */
199 if (SCDOptionGet(NULL
, kSCDOptionUseCFRunLoop
)) {
200 /* debug information, diagnostics */
201 _showMachPortStatus();
203 /* if necessary, re-issue prompt */
204 if ((CFArrayGetCount(sources
) == 1) && isatty(STDIN_FILENO
)) {
215 main(int argc
, const char *argv
[])
221 /* process any arguments */
223 SCDOptionSet(NULL
, kSCDOptionUseCFRunLoop
, FALSE
);
225 while ((opt
= getopt(argc
, argv
, "dvr")) != -1)
228 SCDOptionSet(NULL
, kSCDOptionDebug
, TRUE
);
231 SCDOptionSet(NULL
, kSCDOptionVerbose
, TRUE
);
234 SCDOptionSet(NULL
, kSCDOptionUseCFRunLoop
, TRUE
);
243 /* start with an empty dictionary */
244 do_dictInit(0, NULL
);
246 if (SCDOptionGet(NULL
, kSCDOptionUseCFRunLoop
)) {
248 CFSocketContext context
= { 0, stdin
, NULL
, NULL
, NULL
};
249 CFRunLoopSourceRef rls
;
251 /* create a "socket" reference with the file descriptor associated with stdin */
252 in
= CFSocketCreateWithNative(NULL
,
254 kCFSocketReadCallBack
,
258 /* Create a run loop source for the (stdin) file descriptor */
259 rls
= CFSocketCreateRunLoopSource(NULL
, in
, nesting
);
261 /* keep track of input file sources */
262 sources
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
263 CFArrayAppendValue(sources
, rls
);
265 /* add this source to the run loop */
266 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
273 /* debug information, diagnostics */
274 _showMachPortStatus();
277 if (isatty(STDIN_FILENO
)) {
282 if (SCDOptionGet(NULL
, kSCDOptionUseCFRunLoop
)) {
283 CFRunLoopRun(); /* process input, process events */
284 ok
= FALSE
; /* if the RunLoop exited */
286 /* process command */
287 ok
= process_line(stdin
);
291 exit (EX_OK
); // insure the process exit status is 0
292 return 0; // ...and make main fit the ANSI spec.