Browse Source

Add hipack-get tool

The hipack-get tool can be used to obtain individual items from a HiPack
message from the CLI. For example, given a message like the following
in a file named "server.conf":

  listen: [
    { address: "127.0.0.1", port: 8080 },
    { address: "10.0.0.0", port: 80 },
  ]
  daemonize: True

Then, for example, the following commands can be used:

  % hipack-get server.conf listen 0 port
  8080
  % hipack-get server.conf listen 1
  {
    address: "10.0.0.0",
    port: 80,
  }
  %

Note how in the second invocation, the tool printed all the child items
recursively starting from the subtree pointed by the given path of keys.
Adrian Perez de Castro 5 years ago
parent
commit
758da24956
4 changed files with 182 additions and 0 deletions
  1. 1 0
      .gitignore
  2. 5 0
      Makefile
  3. 111 0
      tools/hipack-get.c
  4. 65 0
      tools/strtonum.c

+ 1 - 0
.gitignore

@@ -4,5 +4,6 @@
 *.gcda
 *.gcno
 tools/hipack-cat
+tools/hipack-get
 tools/hipack-parse
 tools/hipack-roundtrip

+ 5 - 0
Makefile

@@ -14,6 +14,7 @@ hipack-clean:
 	${RM} ${hipack} ${hipack_OBJS}
 	${RM} ${hipack_PATH}/tools/*.o \
 		${hipack_PATH}/tools/hipack-cat \
+		${hipack_PATH}/tools/hipack-get \
 		${hipack_PATH}/tools/hipack-parse \
 		${hipack_PATH}/tools/hipack-roundtrip
 
@@ -23,12 +24,16 @@ ${hipack}: ${hipack_OBJS}
 
 hipack-tools: \
 	${hipack_PATH}/tools/hipack-cat \
+	${hipack_PATH}/tools/hipack-get \
 	${hipack_PATH}/tools/hipack-parse \
 	${hipack_PATH}/tools/hipack-roundtrip
 
 ${hipack_PATH}/tools/hipack-cat: \
 	${hipack_PATH}/tools/hipack-cat.o ${hipack}
 
+${hipack_PATH}/tools/hipack-get: \
+	${hipack_PATH}/tools/hipack-get.o ${hipack}
+
 ${hipack_PATH}/tools/hipack-parse: \
 	${hipack_PATH}/tools/hipack-parse.o ${hipack}
 

+ 111 - 0
tools/hipack-get.c

@@ -0,0 +1,111 @@
+/*
+ * hipack-get.c
+ * Copyright (C) 2015 Adrian Perez <aperez@igalia.com>
+ *
+ * Distributed under terms of the MIT license.
+ */
+
+#include "../hipack.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+
+/* Make sure that strtonum() is defined as "static". */
+static long long strtonum (const char*, long long, long long, const char**);
+#include "strtonum.c"
+
+
+int
+main (int argc, const char *argv[])
+{
+    if (argc < 2) {
+        fprintf (stderr, "Usage: %s <-|PATH> [key...]\n", argv[0]);
+        return EXIT_FAILURE;
+    }
+
+    bool use_stdin = argv[1][0] == '-' && argv[1][1] == '\0';
+    FILE *fp = use_stdin ? stdin : fopen (argv[1], "rb");
+    if (!fp) {
+        fprintf (stderr, "%s: Cannot open '%s' (%s)\n",
+                 argv[0], argv[1], strerror (errno));
+        return EXIT_FAILURE;
+    }
+
+    int retcode = EXIT_SUCCESS;
+    hipack_reader_t reader = {
+        .getchar = hipack_stdio_getchar,
+        .getchar_data = fp,
+    };
+    hipack_dict_t *message = hipack_read (&reader);
+    if (!message) {
+        assert (reader.error);
+        fprintf (stderr, "line %u, column %u: %s\n",
+                 reader.error_line, reader.error_column,
+                 (reader.error == HIPACK_READ_ERROR)
+                    ? strerror (errno) : reader.error);
+        retcode = EXIT_FAILURE;
+    }
+    fclose (fp);
+
+    if (retcode != EXIT_SUCCESS)
+        return retcode;
+
+    hipack_value_t *value = &((hipack_value_t) {
+        .type   = HIPACK_DICT,
+        .v_dict = message
+    });
+
+    for (unsigned i = 2; i < argc && value; i++) {
+        switch (hipack_value_type (value)) {
+            case HIPACK_DICT: {
+                /* Use argv[i] as dictionary key. */
+                hipack_string_t *key = hipack_string_new_from_string (argv[i]);
+                value = hipack_dict_get (value->v_dict, key);
+                hipack_string_free (key);
+                break;
+            }
+            case HIPACK_LIST: {
+                /* Use argv[i] as a list index. */
+                const char *error = NULL;
+                long long index = strtonum (argv[i],
+                                            0,
+                                            hipack_list_size (value->v_list),
+                                            &error);
+                if (error) {
+                    fprintf (stderr, "%s: number '%s' is %s\n",
+                             argv[0], argv[i], error);
+                    retcode = EXIT_FAILURE;
+                    goto cleanup_dict;
+                }
+                value = HIPACK_LIST_AT (value->v_list, index);
+                break;
+            }
+            default:
+                fprintf (stderr, "%s: value is not a list or dictionary\n",
+                         argv[0]);
+                retcode = EXIT_FAILURE;
+                goto cleanup_dict;
+        }
+    }
+
+    if (value) {
+        hipack_writer_t writer = {
+            .putchar = hipack_stdio_putchar,
+            .putchar_data = stdout,
+        };
+        if (hipack_write_value (&writer, value)) {
+            fprintf (stderr, "%s: write error (%s)\n",
+                     argv[0], strerror (errno));
+            retcode = EXIT_FAILURE;
+        }
+        putchar ('\n');
+    } else {
+        fprintf (stderr, "%s: No value for the specified key.\n", argv[0]);
+        retcode = EXIT_FAILURE;
+    }
+
+cleanup_dict:
+    hipack_dict_free (message);
+    return retcode;
+}

+ 65 - 0
tools/strtonum.c

@@ -0,0 +1,65 @@
+/*	$OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $	*/
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define	INVALID		1
+#define	TOOSMALL	2
+#define	TOOLARGE	3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+    const char **errstrp)
+{
+	long long ll = 0;
+	int error = 0;
+	char *ep;
+	struct errval {
+		const char *errstr;
+		int err;
+	} ev[4] = {
+		{ NULL,		0 },
+		{ "invalid",	EINVAL },
+		{ "too small",	ERANGE },
+		{ "too large",	ERANGE },
+	};
+
+	ev[0].err = errno;
+	errno = 0;
+	if (minval > maxval) {
+		error = INVALID;
+	} else {
+		ll = strtoll(numstr, &ep, 10);
+		if (numstr == ep || *ep != '\0')
+			error = INVALID;
+		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+			error = TOOSMALL;
+		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+			error = TOOLARGE;
+	}
+	if (errstrp != NULL)
+		*errstrp = ev[error].errstr;
+	errno = ev[error].err;
+	if (error)
+		ll = 0;
+
+	return (ll);
+}