#include "errcode.h"
#include "util.h"
#include "parse.h"
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int duplicate_name(char **d, const char *s, size_t n)
{
char *dup;
size_t len;
if (!d || !s)
return -err_internal;
len = strnlen(s, n);
if (n <= len)
return -err_name_too_long;
dup = malloc(len + 1);
if (!dup)
return -err_no_mem;
*d = memcpy(dup, s, len);
dup[len] = 0;
return 0;
}
int str_to_uint64(const char *str, uint64_t *val, int base)
{
char *endptr;
uint64_t x;
if (!str || !val)
return -err_internal;
errno = 0;
x = strtoull(str, &endptr, base);
if (errno == EINVAL)
return -err_parse_int;
if (errno == ERANGE)
return -err_parse_int_too_big;
if (str == endptr || *endptr != '\0')
return -err_parse_int;
*val = x;
return 0;
}
int str_to_uint32(const char *str, uint32_t *val, int base)
{
uint64_t x;
int errcode;
if (!str || !val)
return -err_internal;
errcode = str_to_uint64(str, &x, base);
if (errcode < 0)
return errcode;
if (UINT32_MAX < x)
return -err_parse_int_too_big;
*val = (uint32_t) x;
return 0;
}
int str_to_uint16(const char *str, uint16_t *val, int base)
{
uint64_t x;
int errcode;
if (!str || !val)
return -err_internal;
errcode = str_to_uint64(str, &x, base);
if (errcode < 0)
return errcode;
if (UINT16_MAX < x)
return -err_parse_int_too_big;
*val = (uint16_t) x;
return 0;
}
int str_to_uint8(const char *str, uint8_t *val, int base)
{
uint64_t x;
int errcode;
if (!str || !val)
return -err_internal;
errcode = str_to_uint64(str, &x, base);
if (errcode < 0)
return errcode;
if (UINT8_MAX < x)
return -err_parse_int_too_big;
*val = (uint8_t) x;
return 0;
}
int do_bug_on(int cond, const char *condstr, const char *file, int line)
{
if (cond)
fprintf(stderr, "%s:%d: internal error: %s\n", file, line,
condstr);
return cond;
}
struct label *l_alloc(void)
{
return calloc(1, sizeof(struct label));
}
void l_free(struct label *l)
{
if (!l)
return;
l_free(l->next);
free(l->name);
free(l);
}
int l_append(struct label *l, const char *name, uint64_t addr)
{
int errcode;
size_t nlen;
if (bug_on(!l))
return -err_internal;
if (bug_on(!name))
return -err_internal;
nlen = strnlen(name, (size_t) l_max);
if ((size_t) l_max <= nlen)
return -err_label_name;
while (l->next) {
l = l->next;
if (strcmp(l->name, name) == 0)
return -err_label_not_unique;
}
l->next = l_alloc();
if (!l->next)
return -err_no_mem;
errcode = duplicate_name(&l->next->name, name, nlen+1);
if (errcode < 0)
goto error;
l->next->addr = addr;
return 0;
error:
free(l->next->name);
free(l->next);
l->next = NULL;
return errcode;
}
int l_lookup(const struct label *l, uint64_t *addr,
const char *name)
{
if (bug_on(!l))
return -err_internal;
if (bug_on(!addr))
return -err_internal;
if (bug_on(!name))
return -err_internal;
*addr = 0;
while (l->next) {
l = l->next;
if (strcmp(l->name, name) == 0) {
*addr = l->addr;
return 0;
}
}
return -err_no_label;
}
struct label *l_find(struct label *l, const char *name)
{
if (bug_on(!l))
return NULL;
if (bug_on(!name))
return NULL;
while (l->next) {
l = l->next;
if (bug_on(!l->name))
continue;
if (strcmp(l->name, name) == 0)
return l;
}
return NULL;
}