|  | @@ -0,0 +1,421 @@
 | 
	
		
			
				|  |  | +#include "common.h"
 | 
	
		
			
				|  |  | +#include "sysvars.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <stdlib.h>
 | 
	
		
			
				|  |  | +#include <string.h>
 | 
	
		
			
				|  |  | +#include <stdio.h>
 | 
	
		
			
				|  |  | +#include <time.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifndef DEBUG
 | 
	
		
			
				|  |  | +# ifdef ON_FPGA
 | 
	
		
			
				|  |  | +#  define DEBUG 0
 | 
	
		
			
				|  |  | +# else
 | 
	
		
			
				|  |  | +#  define DEBUG 1
 | 
	
		
			
				|  |  | +# endif
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const char *sysvar_bool_tostr(sysvar_t from, char *buf)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    buf[0] = '0' + from.v_bool;
 | 
	
		
			
				|  |  | +    buf[1] = '\0';
 | 
	
		
			
				|  |  | +    return buf;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static bool sysvar_bool_fromstr(sysvar_t *to, const char *from)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    char c = from[0] | 0x20;
 | 
	
		
			
				|  |  | +    switch (c) {
 | 
	
		
			
				|  |  | +    case '1':
 | 
	
		
			
				|  |  | +    case 't':
 | 
	
		
			
				|  |  | +    case 'y':
 | 
	
		
			
				|  |  | +    case 'j':
 | 
	
		
			
				|  |  | +    case 's':
 | 
	
		
			
				|  |  | +	to->v_bool = true;
 | 
	
		
			
				|  |  | +	return true;
 | 
	
		
			
				|  |  | +    case ' ':			/* Blank or null */
 | 
	
		
			
				|  |  | +    case '0':
 | 
	
		
			
				|  |  | +    case 'f':
 | 
	
		
			
				|  |  | +    case 'n':
 | 
	
		
			
				|  |  | +	to->v_bool = false;
 | 
	
		
			
				|  |  | +	return true;
 | 
	
		
			
				|  |  | +    default:
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const struct sysvar_ops sysvar_bool_ops = {
 | 
	
		
			
				|  |  | +    .tostr = sysvar_bool_tostr,
 | 
	
		
			
				|  |  | +    .fromstr = sysvar_bool_fromstr,
 | 
	
		
			
				|  |  | +    .buflen = BOOL_BUFLEN
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const char *sysvar_int_tostr(sysvar_t from, char *buf)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    snprintf(buf, INT_BUFLEN, "%ld", from.v_int);
 | 
	
		
			
				|  |  | +    return buf;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static bool sysvar_int_fromstr(sysvar_t *to, const char *from)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    char *ep;
 | 
	
		
			
				|  |  | +    long v = strtol(from, &ep, 0);
 | 
	
		
			
				|  |  | +    if (ep == from || *ep)
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +    to->v_int = v;
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const struct sysvar_ops sysvar_int_ops = {
 | 
	
		
			
				|  |  | +    .tostr = sysvar_int_tostr,
 | 
	
		
			
				|  |  | +    .fromstr = sysvar_int_fromstr,
 | 
	
		
			
				|  |  | +    .buflen = INT_BUFLEN
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const char *sysvar_uint_tostr(sysvar_t from, char *buf)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    snprintf(buf, UINT_BUFLEN, "%lu", from.v_uint);
 | 
	
		
			
				|  |  | +    return buf;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static bool sysvar_uint_fromstr(sysvar_t *to, const char *from)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    char *ep;
 | 
	
		
			
				|  |  | +    unsigned long v = strtoul(from, &ep, 0);
 | 
	
		
			
				|  |  | +    if (ep == from || *ep)
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +    to->v_uint = v;
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const struct sysvar_ops sysvar_uint_ops = {
 | 
	
		
			
				|  |  | +    .tostr = sysvar_uint_tostr,
 | 
	
		
			
				|  |  | +    .fromstr = sysvar_uint_fromstr,
 | 
	
		
			
				|  |  | +    .buflen = UINT_BUFLEN
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const char *sysvar_str_tostr(sysvar_t from, char *buf)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    (void)buf;
 | 
	
		
			
				|  |  | +    return from.v_str;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static bool sysvar_str_fromstr(sysvar_t *to, const char *from)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    char *ns;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!from) {
 | 
	
		
			
				|  |  | +	ns = NULL;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +	ns = strdup(from);
 | 
	
		
			
				|  |  | +	if (!ns)
 | 
	
		
			
				|  |  | +	    return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    to->v_str = ns;
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static bool sysvar_str_set(sysvar_t *to, sysvar_t from)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    return sysvar_str_fromstr(to, from.v_str);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static size_t sysvar_str_datasize(sysvar_t val)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    return (val.v_str ? strlen(val.v_str) : 0) + 1;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const struct sysvar_ops sysvar_str_ops = {
 | 
	
		
			
				|  |  | +    .set = sysvar_str_set,
 | 
	
		
			
				|  |  | +    .tostr = sysvar_str_tostr,
 | 
	
		
			
				|  |  | +    .fromstr = sysvar_str_fromstr,
 | 
	
		
			
				|  |  | +    .datasize = sysvar_str_datasize
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void sysvar_tz_update(sysvar_t val, bool isset)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (isset)
 | 
	
		
			
				|  |  | +	setenv("TZ", val.v_tz, 1);
 | 
	
		
			
				|  |  | +    else
 | 
	
		
			
				|  |  | +	unsetenv("TZ");
 | 
	
		
			
				|  |  | +    tzset();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const struct sysvar_ops sysvar_tz_ops = {
 | 
	
		
			
				|  |  | +    .set = sysvar_str_set,
 | 
	
		
			
				|  |  | +    .tostr = sysvar_str_tostr,
 | 
	
		
			
				|  |  | +    .fromstr = sysvar_str_fromstr,
 | 
	
		
			
				|  |  | +    .update = sysvar_tz_update,
 | 
	
		
			
				|  |  | +    .datasize = sysvar_str_datasize
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const char *sysvar_ip_tostr(sysvar_t from, char *buf)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    union ip_bytes {
 | 
	
		
			
				|  |  | +	uint8_t b[4];
 | 
	
		
			
				|  |  | +	uint32_t l;
 | 
	
		
			
				|  |  | +    } ip;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ip.l = from.v_ip;
 | 
	
		
			
				|  |  | +    snprintf(buf, IP_BUFLEN,
 | 
	
		
			
				|  |  | +	     "%u.%u.%u.%u", ip.b[0], ip.b[1], ip.b[2], ip.b[3]);
 | 
	
		
			
				|  |  | +    return buf;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static bool sysvar_ip_fromstr(sysvar_t *to, const char *str)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    union ip_bytes {
 | 
	
		
			
				|  |  | +	uint8_t b[4];
 | 
	
		
			
				|  |  | +	uint32_t l;
 | 
	
		
			
				|  |  | +    } ip;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ip.l = 0;
 | 
	
		
			
				|  |  | +    for (int i = 0; i < 4; i++) {
 | 
	
		
			
				|  |  | +	char *ep;
 | 
	
		
			
				|  |  | +	unsigned long v = strtoul(str, &ep, 10);
 | 
	
		
			
				|  |  | +	if (ep == str || *ep != (i == 3) ? '\0' : '.' || v > 255)
 | 
	
		
			
				|  |  | +	    return false;
 | 
	
		
			
				|  |  | +	str = ep + 1;
 | 
	
		
			
				|  |  | +	ip.b[i] = v;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    to->v_ip = ip.l;
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const struct sysvar_ops sysvar_ip_ops = {
 | 
	
		
			
				|  |  | +    .tostr = sysvar_ip_tostr,
 | 
	
		
			
				|  |  | +    .fromstr = sysvar_ip_fromstr,
 | 
	
		
			
				|  |  | +    .buflen = IP_BUFLEN
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static bool sysvar_mac_set(sysvar_t *to, sysvar_t from)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    uint8_t *buf;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!from.v_mac) {
 | 
	
		
			
				|  |  | +	buf = NULL;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +	buf = malloc(6);
 | 
	
		
			
				|  |  | +	if (!buf)
 | 
	
		
			
				|  |  | +	    return false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	memcpy(buf, from.v_mac, 6);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    to->v_mac = buf;
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const char *sysvar_mac_tostr(sysvar_t from, char *buf)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const uint8_t *m = from.v_mac;
 | 
	
		
			
				|  |  | +    if (!m)
 | 
	
		
			
				|  |  | +	return NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    snprintf(buf, MAC_BUFLEN, "%x:%x:%x:%x:%x:%x",
 | 
	
		
			
				|  |  | +	     m[0], m[1], m[2], m[3], m[4], m[5]);
 | 
	
		
			
				|  |  | +    return buf;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static bool sysvar_mac_fromstr(sysvar_t *to, const char *str)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    sysvar_t from;
 | 
	
		
			
				|  |  | +    uint8_t m[6];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!str) {
 | 
	
		
			
				|  |  | +	from.v_mac = NULL;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +	for (int i = 0; i < 6; i++) {
 | 
	
		
			
				|  |  | +	    char *ep;
 | 
	
		
			
				|  |  | +	    unsigned long v = strtoul(str, &ep, 16);
 | 
	
		
			
				|  |  | +	    if (ep == str || *ep != (i == 5) ? '\0' : ':' || v > 255)
 | 
	
		
			
				|  |  | +		return false;
 | 
	
		
			
				|  |  | +	    str = ep + 1;
 | 
	
		
			
				|  |  | +	    m[i] = v;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	from.v_mac = m;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return sysvar_mac_set(to, from);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static size_t sysvar_mac_datasize(sysvar_t val)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    (void)val;
 | 
	
		
			
				|  |  | +    return 6;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const struct sysvar_ops sysvar_mac_ops = {
 | 
	
		
			
				|  |  | +    .set = sysvar_mac_set,
 | 
	
		
			
				|  |  | +    .tostr = sysvar_mac_tostr,
 | 
	
		
			
				|  |  | +    .fromstr = sysvar_mac_fromstr,
 | 
	
		
			
				|  |  | +    .buflen = MAC_BUFLEN,
 | 
	
		
			
				|  |  | +    .datasize = sysvar_mac_datasize
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* --- Generic getters/setters --- */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Contains the lowest numbered sysvar changed; or sysvar_count if nothing */
 | 
	
		
			
				|  |  | +enum sysvar_enum sysvar_changed;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +sysvar_t getvar(size_t var)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (var >= (size_t)sysvar_count)
 | 
	
		
			
				|  |  | +	return sysvar_defval[sysvar_null];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return sysvar_val[var];
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static bool do_setvar(size_t var, sysvar_t val, bool is_set)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const struct sysvar_ops *type = sysvar_types[var];
 | 
	
		
			
				|  |  | +    sysvar_t *to = &sysvar_val[var];
 | 
	
		
			
				|  |  | +    void *free_ptr = NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (type->datasize)
 | 
	
		
			
				|  |  | +	free_ptr = to->v_ptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (DEBUG) {
 | 
	
		
			
				|  |  | +	char tostr_buf[SYSVAR_BUFLEN];
 | 
	
		
			
				|  |  | +	printf("%ssetvar %zu %s <- %s\n", is_set ? "" : "un",
 | 
	
		
			
				|  |  | +	       var, sysvar_name[var],
 | 
	
		
			
				|  |  | +	       notempty(type->tostr(val, tostr_buf)));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!type->set || (type->datasize && !val.v_ptr)) {
 | 
	
		
			
				|  |  | +	sysvar_val[var] = val;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +	if (!type->set(to, val))
 | 
	
		
			
				|  |  | +	    return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (free_ptr)
 | 
	
		
			
				|  |  | +	free(free_ptr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (var < (size_t)sysvar_changed)
 | 
	
		
			
				|  |  | +	sysvar_changed = (enum sysvar_enum)var;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    sysvar_isset[var] = is_set;
 | 
	
		
			
				|  |  | +    if (type->update)
 | 
	
		
			
				|  |  | +	type->update(*to, is_set);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool setvar(size_t var, sysvar_t val)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (var >= (size_t)sysvar_count)
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return do_setvar(var, val, true);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool unsetvar(size_t var)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (var >= (size_t)sysvar_count)
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return do_setvar(var, sysvar_defval[var], false);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* --- Getters/setters converting to/from strings --- */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const char *getvar_tostr(size_t var)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    static char buf[SYSVAR_BUFLEN];
 | 
	
		
			
				|  |  | +    return getvar_tostr_r(var, buf);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const char *getvar_tostr_r(size_t var, char *buf)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (var >= (size_t)sysvar_count)
 | 
	
		
			
				|  |  | +	return NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const struct sysvar_ops *type = sysvar_types[var];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* A tostr method is required */
 | 
	
		
			
				|  |  | +    return type->tostr(sysvar_val[var], buf);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool setvar_fromstr(size_t var, const char *str)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (var >= (size_t)sysvar_count)
 | 
	
		
			
				|  |  | +	return NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!str)
 | 
	
		
			
				|  |  | +	return unsetvar(var);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const struct sysvar_ops *type = sysvar_types[var];
 | 
	
		
			
				|  |  | +    sysvar_t *to = &sysvar_val[var];
 | 
	
		
			
				|  |  | +    void *free_ptr = NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (type->datasize)
 | 
	
		
			
				|  |  | +	free_ptr = to->v_ptr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (DEBUG) {
 | 
	
		
			
				|  |  | +	printf("setvar_fromstr %zu %s <- %s\n", var, sysvar_name[var], str);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* A fromstr method is required */
 | 
	
		
			
				|  |  | +    if (!type->fromstr(to, str))
 | 
	
		
			
				|  |  | +	return false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (var < (size_t)sysvar_changed)
 | 
	
		
			
				|  |  | +	sysvar_changed = (enum sysvar_enum)var;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (free_ptr)
 | 
	
		
			
				|  |  | +	free(free_ptr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    sysvar_isset[var] = true;
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* --- Find the index of a specific variable --- */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int string_ptr_compare(const void *a, const void *b)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    const char * const *aa = a;
 | 
	
		
			
				|  |  | +    const char * const *bb = b;
 | 
	
		
			
				|  |  | +    return strcmp(*aa, *bb);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +size_t sysvar_find(size_t ns, const char *name)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (ns >= (size_t)sysvar_nscount)
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const sysvar_ns_t *nsi = &sysvar_ns[ns];
 | 
	
		
			
				|  |  | +    const char * const *varname;
 | 
	
		
			
				|  |  | +    const size_t count = nsi[1].first - nsi->first;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    varname = bsearch(&name, sysvar_name + nsi->first,
 | 
	
		
			
				|  |  | +		      count, sizeof *sysvar_name,
 | 
	
		
			
				|  |  | +		      string_ptr_compare);
 | 
	
		
			
				|  |  | +    if (!varname)
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return varname - sysvar_name;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* --- Initialization/reset to defaults --- */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void sysvar_reset(size_t ns)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    if (ns >= (size_t)sysvar_nscount)
 | 
	
		
			
				|  |  | +	return;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    enum sysvar_enum i;
 | 
	
		
			
				|  |  | +    for (i = sysvar_ns[ns].first; i < sysvar_ns[ns+1].first; i++)
 | 
	
		
			
				|  |  | +	unsetvar(i);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (sysvar_changed < i)
 | 
	
		
			
				|  |  | +	sysvar_changed = i;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void sysvar_init(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    for (enum sysvar_enum i = sysvar_null+1; i < sysvar_count; i++)
 | 
	
		
			
				|  |  | +	unsetvar(i);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    sysvar_changed = sysvar_count;
 | 
	
		
			
				|  |  | +}
 |