1
0
Files
irix-657m-src/eoe/cmd/ns/nsd/attr.c
2022-09-29 17:59:04 +03:00

470 lines
8.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <ns_api.h>
#include <ns_daemon.h>
nsd_attr_t *__nsd_attrs = 0;
/*
** This routine walks the stack freeing every record.
*/
void
nsd_attr_clear(nsd_attr_t *root) {
nsd_attr_t *na;
while (root && (--root->a_nlink <= 0)) {
na = root;
root = root->a_next;
if (na->a_value) {
free(na->a_value);
}
if (na->a_data && na->a_free) {
(*na->a_free)(na->a_data);
}
free(na);
}
}
int
nsd_attr_data_set(nsd_attr_t *na, void *data, int len, void (*dfree)(void *))
{
if (na) {
if (na->a_data && na->a_free) {
(*na->a_free)(na->a_data);
}
na->a_data = data;
na->a_size = len;
na->a_free = dfree;
return NSD_OK;
}
return NSD_ERROR;
}
/*
** This just pushes an attribute onto the given attribute stack.
*/
nsd_attr_t *
nsd_attr_append(nsd_attr_t **root, char *key, char *value, int append)
{
nsd_attr_t *na, *end;
char *nval;
int len;
if (! key) {
return (nsd_attr_t *)0;
}
if (! root) {
root = &__nsd_attrs;
}
end = *root;
/*
** Look for a duplicate.
*/
for (na = *root; na && na->a_key; na = na->a_next) {
end = na;
if (strcasecmp(key, na->a_key) == 0) {
/*
** Replace value with new one, carefully.
*/
len = strlen(value);
nval = (char *)nsd_malloc(len + 1);
if (! nval) {
return (nsd_attr_t *)0;
} else {
memcpy(nval, value, len + 1);
free(na->a_value);
na->a_value = nval;
na->a_size = len;
return (na);
}
}
}
/*
** Allocate space for new attribute.
*/
len = strlen(key);
na = (nsd_attr_t *)nsd_calloc(1, sizeof(nsd_attr_t) + len + 1);
if (! na) {
return (nsd_attr_t *)0;
}
/*
** Duplicate the key. Appended onto structure.
*/
na->a_key = (char *)(na + 1);
memcpy(na->a_key, key, len);
/*
** Duplicate the value.
*/
if (value) {
len = strlen(value);
na->a_value = nsd_malloc(len + 1);
if (! na->a_value) {
free(na), free(na->a_key);
return (nsd_attr_t *)0;
}
memcpy(na->a_value, value, len + 1);
na->a_size = len;
}
na->a_nlink++;
if (append) {
/*
** put attribute at the end of this files attributes
*/
if (! *root) {
*root = na;
}
if (end) {
na->a_next = end->a_next;
end->a_next = na;
}
} else {
/*
** Push attribute onto list.
*/
if (*root) {
na->a_next = *root;
}
*root = na;
}
return na;
}
nsd_attr_t *
nsd_attr_store(nsd_attr_t **root, char *key, char *value) {
return nsd_attr_append(root, key, value, FALSE);
}
/*
** This is a link from the end of one list to the beginning of another.
*/
nsd_attr_t *
nsd_attr_continue(nsd_attr_t **root, nsd_attr_t *cont)
{
nsd_attr_t *na, **end;
if (! root || ! cont) {
return (nsd_attr_t *)0;
}
/*
** Find end of current list.
*/
for (end = root; *end && (*end)->a_key; end = &(*end)->a_next);
if (*end) {
nsd_attr_clear((*end)->a_next);
(*end)->a_next = cont;
cont->a_nlink++;
return *end;
} else {
na = (nsd_attr_t *)nsd_calloc(1, sizeof(nsd_attr_t));
if (! na) {
return (nsd_attr_t *)0;
}
na->a_next = cont;
cont->a_nlink++;
*end = na;
na->a_nlink++;
return na;
}
}
/*
** This just walks the stack looking for the given attribute.
*/
nsd_attr_t *
nsd_attr_fetch(nsd_attr_t *root, char *key)
{
nsd_attr_t *na;
if (! key) {
return (nsd_attr_t *)0;
}
if (! root) {
root = __nsd_attrs;
}
for (na = root; na && (!na->a_key || strcasecmp(na->a_key, key));
na = na->a_next);
return na;
}
long
nsd_attr_fetch_long(nsd_attr_t *list, char *key, int base, long def)
{
nsd_attr_t *na;
char *p;
long result;
/*
** strtol does not want a NULL passed to it
*/
na = nsd_attr_fetch(list, key);
if (na && na->a_value) {
result = strtol(na->a_value, &p, base);
if (! p) {
result = def;
}
} else {
result = def;
}
return result;
}
/*
** A boolean is a string like "true" or "false", or a number like 0 or 1,
** or an empty string which just means true. If the attribute is not
** found we return the default.
*/
int
nsd_attr_fetch_bool(nsd_attr_t *list, char *key, int def)
{
nsd_attr_t *na;
char *p;
int result;
na = nsd_attr_fetch(list, key);
if (! na) {
return def;
}
if (! na->a_value) {
return TRUE;
}
result = strtol(na->a_value, &p, 10);
if (p == na->a_value) {
if (na->a_value[0] == 't' || na->a_value[0] == 'T') {
return TRUE;
} else {
return FALSE;
}
}
return result;
}
char *
nsd_attr_fetch_string(nsd_attr_t *list, char *key, char *def)
{
nsd_attr_t *na;
na = nsd_attr_fetch(list, key);
if (na) {
return na->a_value;
} else {
return def;
}
}
/*
** This removes an attribute record from the given stack and frees up
** the space.
*/
int
nsd_attr_delete(nsd_attr_t **root, char *key) {
nsd_attr_t *cna, *lna;
if (! root) {
return NSD_ERROR;
}
for (cna = *root, lna = (nsd_attr_t *)0; cna && cna->a_key;
lna = cna, cna = cna->a_next) {
if (strcasecmp(key, cna->a_key) == 0) {
if (lna) {
lna->a_next = cna->a_next;
} else {
*root = cna->a_next;
}
cna->a_next = (nsd_attr_t *)0;
nsd_attr_clear(cna);
return NSD_OK;
}
}
return NSD_ERROR;
}
/*
** This routine creates a copy of an attribute list.
*/
nsd_attr_t *
nsd_attr_copy(nsd_attr_t *list)
{
nsd_attr_t *result, *na;
int len;
for (result = (nsd_attr_t *)0; list && list->a_key;
list = list->a_next) {
len = strlen(list->a_key);
na = (nsd_attr_t *)nsd_calloc(1, sizeof(nsd_attr_t) + len + 1);
if (! na) {
nsd_logprintf(NSD_LOG_RESOURCE,
"nsd_attr_copy: failed malloc\n");
nsd_attr_clear(result);
return (nsd_attr_t *)0;
}
na->a_key = (char *)(na + 1);;
memcpy(na->a_key, list->a_key, len);
if (list->a_value) {
len = strlen(list->a_value);
na->a_value = (char *)nsd_malloc(len + 1);
if (! na->a_value) {
nsd_logprintf(NSD_LOG_RESOURCE,
"nsd_attr_copy: failed malloc\n");
free(na);
nsd_attr_clear(result);
return (nsd_attr_t *)0;
}
memcpy(na->a_value, list->a_value, len + 1);
na->a_size = len;
}
na->a_nlink++;
na->a_next = result;
result = na;
}
return result;
}
/*
** This routine will verify that the first attribute is strickly a
** subset of the second list. No continuations are followed on the
** first list.
*/
int
nsd_attr_subset(nsd_attr_t *sublist, nsd_attr_t *list)
{
nsd_attr_t *ap;
/*
** For every attribute in sublist there must be a matching
** attribute in list.
*/
for (; sublist && sublist->a_key; sublist = sublist->a_next) {
if (!(ap = nsd_attr_fetch(list, sublist->a_key)) ||
(strcasecmp(ap->a_value, sublist->a_value) != 0)) {
return NSD_ERROR;
}
}
return NSD_OK;
}
/*
** This function will parse a string of the format [<key> = <value>]+
** and create a list attached to the passed in callout.
*/
int
nsd_attr_parse(nsd_attr_t **list, char *line, int lineno, char *filename)
{
char *p, *q;
nsd_attr_t *attr;
int len;
if (! list) {
list = &__nsd_attrs;
}
if (! filename) {
filename = "request";
}
for (p = line; p && *p; ) {
/*
** Skip whitespace.
*/
for (; *p && (isspace(*p) || (*p == '(') || (*p == ',')); p++);
if (! *p || (*p == ')')) {
break;
}
/*
** key continues until = or whitespace.
*/
len = strcspn(p, " \t\n=,)");
attr = (nsd_attr_t *)nsd_calloc(1, sizeof(nsd_attr_t) + len+1);
if (! attr) {
nsd_logprintf(NSD_LOG_RESOURCE, "nsd_attr_parse: malloc failed\n");
return NSD_ERROR;
}
attr->a_key = (char *)(attr + 1);;
memcpy(attr->a_key, p, len);
for (q = p + len; *q && (isspace(*q) || *q == '='); q++);
if (! *q || *q == ',') {
len = 0;
p = q;
} else if (*q == '"') {
/*
** quoted string - value continues until matching
** quote.
*/
p = strchr(++q, '"');
if (!p) {
if (lineno) {
nsd_logprintf(NSD_LOG_OPER,
"nsd_attr_parse: error in %s at %d+%d: unterminated string\n",
filename, lineno, p-line);
} else {
nsd_logprintf(NSD_LOG_OPER,
"nsd_attr_parse: unterminated string in: %s\n",
line);
}
nsd_attr_clear(attr);
return NSD_ERROR;
}
len = p++ - q;
} else {
/*
** value continues until a space or the end.
*/
len = strcspn(q, " \t\n,)");
p = q + len;
}
if (len > 0) {
attr->a_value = (char *)nsd_malloc(len + 1);
if (! attr->a_value) {
nsd_logprintf(NSD_LOG_RESOURCE,
"nsd_attr_parse: malloc failed\n");
nsd_attr_clear(attr);
return NSD_ERROR;
}
memcpy(attr->a_value, q, len);
attr->a_value[len] = (char)0;
attr->a_size = len;
}
attr->a_nlink++;
attr->a_next = *list;
*list = attr;
}
return NSD_OK;
}