Skip to content

Commit

Permalink
Add hipack-get tool
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
aperezdc committed Jul 23, 2015
1 parent 9584e64 commit 758da24
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,5 +4,6 @@
*.gcda
*.gcno
tools/hipack-cat
tools/hipack-get
tools/hipack-parse
tools/hipack-roundtrip
5 changes: 5 additions & 0 deletions Makefile
Expand Up @@ -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

Expand All @@ -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}

Expand Down
111 changes: 111 additions & 0 deletions 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 changes: 65 additions & 0 deletions 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);
}

0 comments on commit 758da24

Please sign in to comment.