#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <ctype.h>
static ssize_t convert (const char *in, size_t in_len, char **out, size_t *out_size);
static void convert_error (const char *in, size_t in_len, int bad_ofs, const char *fmt, ...);
static void bail (const char *fmt, ...);
int
main (int argc, char *argv[])
{
FILE * fp;
char * in = NULL;
size_t in_size = 0;
ssize_t in_len;
char * out = NULL;
size_t out_size = 0;
ssize_t out_len;
char * p;
size_t w;
int rc;
//fp = fopen(name, "r");
//if (fp == NULL)
// bail("open %s failed", name);
fp = stdin;
while ((in_len = getline(&in, &in_size, fp)) != -1) {
out_len = convert (in, in_len, &out, &out_size);
p = out;
w = out_len;
do {
rc = write (1, p, w);
if (rc<=0) bail("failed to write %d bytes", w);
if (rc>w) bail("write of %d returned %d", w, rc);
p+=rc;
w-=rc;
} while (w);
}
if (in)
free(in);
return EXIT_SUCCESS;
}
static ssize_t
convert (const char *in, size_t in_len, char **out, size_t *out_size)
{
int expected;
const char *i, *ie = in + in_len;
char *o, *oe;
uint reg;
expected = in_len/2;
if (!*out || expected > *out_size) {
free (*out);
*out = malloc (expected);
if (!*out)
bail ("unable to allocate %d bytes", expected);
*out_size = expected;
}
o = *out;
oe = *out + *out_size;
for (i=in; i < ie; i++) {
if (! isxdigit(*i)) {
if (isalnum(*i))
convert_error (in, in_len, i-in,
"unexpected character");
continue;
}
if (ie-i < 2)
convert_error (in, in_len, i-in,
"insufficient number of hex digits");
reg = isdigit(*i)
? ( *i - '0' )
: ( tolower(*i) - 'a' );
i++;
if (! isxdigit(*i))
convert_error (in, in_len, i-in,
"hexdigit followed by a non hexdigit");
reg <<=4;
reg += isdigit(*i)
? ( *i - '0' )
: ( tolower(*i) - 'a' );
*(o++) = reg;
}
return o - *out;
}
static void
convert_error (const char *in, size_t in_len, int bad_ofs,
const char *fmt, ...)
{
va_list ap;
fprintf (stderr, "parsing error @ %d ...\n", bad_ofs);
fputs (in, stderr);
fprintf (stderr, "%*s\n", bad_ofs+1, "^");
va_start(ap, fmt);
vfprintf (stderr, fmt, ap);
va_end(ap);
fprintf (stderr, "\n");
exit (EXIT_FAILURE);
}
static void
bail (const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf (stderr, fmt, ap);
va_end(ap);
fprintf (stderr, "\n");
exit (EXIT_FAILURE);
}