blob: 6d36dd13dd57e5d88284f2567d52c3508d430617 [file] [log] [blame]
#include <getopt.h>
#include "cli.h"
const char* cli_info_purpose = "A flexible command-line interface for the FSEvents API";
const char* cli_info_usage = "Usage: fsevent_watch [OPTIONS]... [PATHS]...";
const char* cli_info_help[] = {
" -h, --help you're looking at it",
" -V, --version print version number and exit",
" -p, --show-plist display the embedded Info.plist values",
" -s, --since-when=EventID fire historical events since ID",
" -l, --latency=seconds latency period (default='0.5')",
" -n, --no-defer enable no-defer latency modifier",
" -r, --watch-root watch for when the root path has changed",
// " -i, --ignore-self ignore current process",
" -F, --file-events provide file level event data",
" -f, --format=name output format (classic, niw, \n"
" tnetstring, otnetstring)",
0
};
static void default_args (struct cli_info* args_info)
{
args_info->since_when_arg = kFSEventStreamEventIdSinceNow;
args_info->latency_arg = 0.5;
args_info->no_defer_flag = false;
args_info->watch_root_flag = false;
args_info->ignore_self_flag = false;
args_info->file_events_flag = false;
args_info->mark_self_flag = false;
args_info->format_arg = kFSEventWatchOutputFormatOTNetstring;
}
static void cli_parser_release (struct cli_info* args_info)
{
unsigned int i;
for (i=0; i < args_info->inputs_num; ++i) {
free(args_info->inputs[i]);
}
if (args_info->inputs_num) {
free(args_info->inputs);
}
args_info->inputs_num = 0;
}
void cli_parser_init (struct cli_info* args_info)
{
default_args(args_info);
args_info->inputs = 0;
args_info->inputs_num = 0;
}
void cli_parser_free (struct cli_info* args_info)
{
cli_parser_release(args_info);
}
static void cli_print_info_dict (const void *key,
const void *value,
void *context)
{
CFStringRef entry = CFStringCreateWithFormat(NULL, NULL,
CFSTR("%@:\n %@"), key, value);
if (entry) {
CFShow(entry);
CFRelease(entry);
}
}
void cli_show_plist (void)
{
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFRetain(mainBundle);
CFDictionaryRef mainBundleDict = CFBundleGetInfoDictionary(mainBundle);
if (mainBundleDict) {
CFRetain(mainBundleDict);
printf("Embedded Info.plist metadata:\n\n");
CFDictionaryApplyFunction(mainBundleDict, cli_print_info_dict, NULL);
CFRelease(mainBundleDict);
}
CFRelease(mainBundle);
printf("\n");
}
void cli_print_version (void)
{
printf("%s %s\n\n", CLI_NAME, CLI_VERSION);
#ifdef COMPILED_AT
printf("Compiled at: %s\n", COMPILED_AT);
#endif
#ifdef COMPILER
printf("Compiled with: %s\n", COMPILER);
#endif
#ifdef TARGET_CPU
printf("Compiled for: %s\n", TARGET_CPU);
#endif
printf("\n");
}
void cli_print_help (void)
{
cli_print_version();
printf("\n%s\n", cli_info_purpose);
printf("\n%s\n", cli_info_usage);
printf("\n");
int i = 0;
while (cli_info_help[i]) {
printf("%s\n", cli_info_help[i++]);
}
}
int cli_parser (int argc, const char** argv, struct cli_info* args_info)
{
static struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "show-plist", no_argument, NULL, 'p' },
{ "since-when", required_argument, NULL, 's' },
{ "latency", required_argument, NULL, 'l' },
{ "no-defer", no_argument, NULL, 'n' },
{ "watch-root", no_argument, NULL, 'r' },
{ "ignore-self", no_argument, NULL, 'i' },
{ "file-events", no_argument, NULL, 'F' },
{ "mark-self", no_argument, NULL, 'm' },
{ "format", required_argument, NULL, 'f' },
{ 0, 0, 0, 0 }
};
const char* shortopts = "hVps:l:nriFf:";
int c = -1;
while ((c = getopt_long(argc, (char * const*)argv, shortopts, longopts, NULL)) != -1) {
switch(c) {
case 's': // since-when
args_info->since_when_arg = strtoull(optarg, NULL, 0);
break;
case 'l': // latency
args_info->latency_arg = strtod(optarg, NULL);
break;
case 'n': // no-defer
args_info->no_defer_flag = true;
break;
case 'r': // watch-root
args_info->watch_root_flag = true;
break;
case 'i': // ignore-self
args_info->ignore_self_flag = true;
break;
case 'F': // file-events
args_info->file_events_flag = true;
break;
case 'm': // mark-self
args_info->mark_self_flag = true;
break;
case 'f': // format
if (strcmp(optarg, "classic") == 0) {
args_info->format_arg = kFSEventWatchOutputFormatClassic;
} else if (strcmp(optarg, "niw") == 0) {
args_info->format_arg = kFSEventWatchOutputFormatNIW;
} else if (strcmp(optarg, "tnetstring") == 0) {
args_info->format_arg = kFSEventWatchOutputFormatTNetstring;
} else if (strcmp(optarg, "otnetstring") == 0) {
args_info->format_arg = kFSEventWatchOutputFormatOTNetstring;
} else {
fprintf(stderr, "Unknown output format: %s\n", optarg);
exit(EXIT_FAILURE);
}
break;
case 'V': // version
cli_print_version();
exit(EXIT_SUCCESS);
case 'p': // show-plist
cli_show_plist();
exit(EXIT_SUCCESS);
case 'h': // help
case '?': // invalid option
case ':': // missing argument
cli_print_help();
exit((c == 'h') ? EXIT_SUCCESS : EXIT_FAILURE);
}
}
if (optind < argc) {
int i = 0;
args_info->inputs_num = (unsigned int)(argc - optind);
args_info->inputs =
(char**)(malloc ((args_info->inputs_num)*sizeof(char*)));
while (optind < argc)
if (argv[optind++] != argv[0]) {
args_info->inputs[i++] = strdup(argv[optind-1]);
}
}
return EXIT_SUCCESS;
}