summaryrefslogtreecommitdiffstats
path: root/tools/plistutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/plistutil.c')
-rw-r--r--tools/plistutil.c70
1 files changed, 68 insertions, 2 deletions
diff --git a/tools/plistutil.c b/tools/plistutil.c
index 84e7add..6e697cf 100644
--- a/tools/plistutil.c
+++ b/tools/plistutil.c
@@ -40,11 +40,12 @@
#ifdef _MSC_VER
#pragma warning(disable:4996)
#define STDIN_FILENO _fileno(stdin)
+#define strtok_r strtok_s
#endif
typedef struct _options
{
- char *in_file, *out_file;
+ char *in_file, *out_file, *nodepath;
uint8_t in_fmt, out_fmt; // fmts 0 = undef, 1 = bin, 2 = xml, 3 = json, 4 = openstep
uint8_t flags;
} options_t;
@@ -70,6 +71,7 @@ static void print_usage(int argc, char *argv[])
printf(" If omitted, XML will be converted to binary,\n");
printf(" and binary to XML.\n");
printf(" -p, --print FILE Print the PList in human-readable format.\n");
+ printf(" -n, --nodepath PATH Restrict output to nodepath defined by PATH.\n");
printf(" -c, --compact JSON and OpenStep only: Print output in compact form.\n");
printf(" By default, the output will be pretty-printed.\n");
printf(" -s, --sort Sort all dictionary nodes lexicographically by key\n");
@@ -96,6 +98,7 @@ static options_t *parse_arguments(int argc, char *argv[])
{ "compact", no_argument, 0, 'c' },
{ "sort", no_argument, 0, 's' },
{ "print", required_argument, 0, 'p' },
+ { "nodepath", required_argument, 0, 'n' },
{ "debug", no_argument, 0, 'd' },
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'v' },
@@ -103,7 +106,7 @@ static options_t *parse_arguments(int argc, char *argv[])
};
int c;
- while ((c = getopt_long(argc, argv, "i:o:f:csp:dhv", long_options, NULL)) != -1)
+ while ((c = getopt_long(argc, argv, "i:o:f:csp:n:dhv", long_options, NULL)) != -1)
{
switch (c)
{
@@ -175,6 +178,15 @@ static options_t *parse_arguments(int argc, char *argv[])
break;
}
+ case 'n':
+ if (!optarg || optarg[0] == '\0') {
+ fprintf(stderr, "ERROR: --extract needs a node path\n");
+ free(options);
+ return NULL;
+ }
+ options->nodepath = optarg;
+ break;
+
case 'd':
options->flags |= OPT_DEBUG;
break;
@@ -326,6 +338,60 @@ int main(int argc, char *argv[])
{
input_res = plist_from_memory(plist_entire, read_size, &root_node, NULL);
if (input_res == PLIST_ERR_SUCCESS) {
+
+ if (options->nodepath) {
+ char *copy = strdup(options->nodepath);
+ char *tok, *saveptr = NULL;
+ if (!copy) {
+ plist_free(root_node);
+ free(plist_entire);
+ free(options);
+ return 1;
+ }
+
+ plist_t current = root_node;
+ for (tok = strtok_r(copy, "/", &saveptr); tok; tok = strtok_r(NULL, "/", &saveptr)) {
+ if (*tok == '\0') continue;
+ switch (plist_get_node_type(current)) {
+ case PLIST_DICT:
+ current = plist_dict_get_item(current, tok);
+ break;
+ case PLIST_ARRAY: {
+ char* endp = NULL;
+ uint32_t idx = strtoul(tok, &endp, 10);
+ if (endp == tok || *endp != '\0') {
+ current = NULL;
+ break;
+ }
+ if (idx >= plist_array_get_size(current)) {
+ current = NULL;
+ break;
+ }
+ current = plist_array_get_item(current, idx);
+ break;
+ }
+ default:
+ current = NULL;
+ break;
+ }
+ if (!current) {
+ break;
+ }
+ }
+ free(copy);
+ if (current) {
+ plist_t destnode = plist_copy(current);
+ plist_free(root_node);
+ root_node = destnode;
+ } else {
+ fprintf(stderr, "ERROR: nodepath '%s' is invalid\n", options->nodepath);
+ plist_free(root_node);
+ free(plist_entire);
+ free(options);
+ return 1;
+ }
+ }
+
if (options->flags & OPT_SORT) {
plist_sort(root_node);
}