/*
* Tool for decoding compact index values for testing.
* Copyright © 2012 Nick Bowler
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#define PROGNAME "decodeindex"
static const char *progname = PROGNAME;
static const unsigned char sopts[] = "VH";
static const struct option lopts[] = {
{ "version", 0, NULL, 'V' },
{ "help", 0, NULL, 'H' },
{ 0 }
};
/*
* Decode a hexadecimal string into a sequence of bytes. If there are an
* odd number of nibbles, treat the first character as the least significant
* nibble of the first byte. The result is written to the buffer specified by
* buf. At most n bytes are written to the buffer.
*
* Returns the number of bytes that would be written provided that n was large
* enough, or (size_t)-1 if the input is not valid.
*/
static size_t decode_hex(const char *hex, unsigned char *buf, size_t n)
{
size_t len, count = 0;
char tmp[] = "00";
for (len = 0; hex[len]; len++) {
if (!isxdigit(hex[len]))
return -1;
}
if (!len)
return 0;
switch (len % 2) {
while (len > 0) {
case 0: tmp[0] = *hex++; len--;
case 1: tmp[1] = *hex++; len--;
if (count < n)
buf[count] = strtoul(tmp, NULL, 16);
count++;
}
}
return count;
}
static void print_usage(FILE *f)
{
fprintf(f, "Usage: %s [options] index [index ...]\n", progname);
}
static void print_version(void)
{
printf("%s (%s) %s\n", PROGNAME, PACKAGE_NAME, PACKAGE_VERSION);
puts("Copyright (C) 2012 Nick Bowler.");
puts("License GPLv3+: GNU GPL version 3 or later .");
puts("This is free software: you are free to change and redistribute it.");
puts("There is NO WARRANTY, to the extent permitted by law.");
}
static void print_bytes(FILE *f, int indent, void *buf, size_t n)
{
fprintf(f, "%*s", indent, "");
for (size_t i = 0; i < n; i++)
fprintf(f, "%*s%.2hhx", i != 0, "", ((unsigned char *)buf)[i]);
putc('\n', f);
}
static int print_index(const char *hex)
{
unsigned char buf[32];
long index = 0;
size_t n, rc;
int ret = -1;
n = decode_hex(hex, buf, sizeof buf);
if (n == -1) {
fprintf(stderr, "%s: invalid hex sequence: %s\n",
progname, hex);
goto out;
} else if (n == 0) {
fprintf(stderr, "%s: empty argument\n", progname);
goto out;
} else if (n > sizeof buf) {
fprintf(stderr, "%s: hex sequence too long: %s\n",
progname, hex);
goto out;
}
rc = upkg_decode_index(&index, buf, n);
if (rc == 0) {
fprintf(stderr, "%s: invalid index encoding:\n", progname);
print_bytes(stderr, 4, buf, n);
goto out;
} else if (rc < n) {
fprintf(stderr, "%s: trailing bytes in argument:\n", progname);
print_bytes(stderr, 4, buf+rc, n-rc);
/* Non-fatal */
}
ret = 0;
out:
printf("%ld\n", index);
return ret;
}
int main(int argc, char **argv)
{
int opt, ret = EXIT_SUCCESS;
if (argc > 0)
progname = argv[0];
while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
switch (opt) {
case 'V':
print_version();
return EXIT_SUCCESS;
case 'H':
print_usage(stdout);
return EXIT_SUCCESS;
default:
print_usage(stderr);
return EXIT_FAILURE;
}
}
if (!argv[optind]) {
print_usage(stderr);
return EXIT_FAILURE;
}
for (int i = optind; i < argc; i++) {
if (print_index(argv[i]) != 0) {
ret = EXIT_FAILURE;
}
}
return ret;
}