mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-27 08:22:31 +00:00
240 lines
5.8 KiB
C
240 lines
5.8 KiB
C
|
/* libanode: the Anode C reference implementation
|
||
|
* Copyright (C) 2009-2010 Adam Ierymenko <adam.ierymenko@gmail.com>
|
||
|
*
|
||
|
* 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 <http://www.gnu.org/licenses/>. */
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "dictionary.h"
|
||
|
|
||
|
static const char *EMPTY_STR = "";
|
||
|
|
||
|
void AnodeDictionary_clear(struct AnodeDictionary *d)
|
||
|
{
|
||
|
struct AnodeDictionaryEntry *e,*ne;
|
||
|
int oldcs;
|
||
|
unsigned int i;
|
||
|
|
||
|
oldcs = d->case_sensitive;
|
||
|
|
||
|
for(i=0;i<ANODE_DICTIONARY_FIXED_HASH_TABLE_SIZE;++i) {
|
||
|
e = d->ht[i];
|
||
|
while (e) {
|
||
|
ne = e->next;
|
||
|
if ((e->key)&&(e->key != EMPTY_STR)) free((void *)e->key);
|
||
|
if ((e->value)&&(e->value != EMPTY_STR)) free((void *)e->value);
|
||
|
free((void *)e);
|
||
|
e = ne;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Anode_zero((void *)d,sizeof(struct AnodeDictionary));
|
||
|
|
||
|
d->case_sensitive = oldcs;
|
||
|
}
|
||
|
|
||
|
void AnodeDictionary_put(struct AnodeDictionary *d,const char *key,const char *value)
|
||
|
{
|
||
|
struct AnodeDictionaryEntry *e;
|
||
|
char *p1;
|
||
|
const char *p2;
|
||
|
unsigned int bucket = (d->case_sensitive) ? AnodeDictionary__get_bucket(key) : AnodeDictionary__get_bucket_ci(key);
|
||
|
unsigned int len,i;
|
||
|
|
||
|
e = d->ht[bucket];
|
||
|
while (e) {
|
||
|
if (((d->case_sensitive) ? Anode_streq(key,e->key) : Anode_strcaseeq(key,e->key))) {
|
||
|
if (!d->case_sensitive) {
|
||
|
p1 = e->key;
|
||
|
p2 = key;
|
||
|
while (*p2) *(p1++) = *(p2++);
|
||
|
}
|
||
|
|
||
|
len = 0;
|
||
|
while (value[len]) ++len;
|
||
|
if (len) {
|
||
|
if ((e->value)&&(e->value != EMPTY_STR))
|
||
|
e->value = (char *)realloc((void *)e->value,len + 1);
|
||
|
else e->value = (char *)malloc(len + 1);
|
||
|
for(i=0;i<len;++i) e->value[i] = value[i];
|
||
|
e->value[i] = (char)0;
|
||
|
} else {
|
||
|
if ((e->value)&&(e->value != EMPTY_STR)) free((void *)e->value);
|
||
|
e->value = (char *)EMPTY_STR;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
e = e->next;
|
||
|
}
|
||
|
|
||
|
e = (struct AnodeDictionaryEntry *)malloc(sizeof(struct AnodeDictionaryEntry));
|
||
|
|
||
|
len = 0;
|
||
|
while (key[len]) ++len;
|
||
|
if (len) {
|
||
|
e->key = (char *)malloc(len + 1);
|
||
|
for(i=0;i<len;++i) e->key[i] = key[i];
|
||
|
e->key[i] = (char)0;
|
||
|
} else e->key = (char *)EMPTY_STR;
|
||
|
|
||
|
len = 0;
|
||
|
while (value[len]) ++len;
|
||
|
if (len) {
|
||
|
e->value = (char *)malloc(len + 1);
|
||
|
for(i=0;i<len;++i) e->value[i] = value[i];
|
||
|
e->value[i] = (char)0;
|
||
|
} else e->value = (char *)EMPTY_STR;
|
||
|
|
||
|
e->next = d->ht[bucket];
|
||
|
d->ht[bucket] = e;
|
||
|
|
||
|
++d->size;
|
||
|
}
|
||
|
|
||
|
void AnodeDictionary_read(
|
||
|
struct AnodeDictionary *d,
|
||
|
char *in,
|
||
|
const char *line_breaks,
|
||
|
const char *kv_breaks,
|
||
|
const char *comment_chars,
|
||
|
char escape_char,
|
||
|
int trim_whitespace_from_keys,
|
||
|
int trim_whitespace_from_values)
|
||
|
{
|
||
|
char *line = in;
|
||
|
char *key;
|
||
|
char *value;
|
||
|
char *p1,*p2,*p3;
|
||
|
char last = ~escape_char;
|
||
|
int eof_state = 0;
|
||
|
|
||
|
for(;;) {
|
||
|
if ((!*in)||((Anode_strchr(line_breaks,*in))&&((last != escape_char)||(!escape_char)))) {
|
||
|
if (!*in)
|
||
|
eof_state = 1;
|
||
|
else *in = (char)0;
|
||
|
|
||
|
if ((*line)&&((comment_chars)&&(!Anode_strchr(comment_chars,*line)))) {
|
||
|
key = line;
|
||
|
|
||
|
while (*line) {
|
||
|
if ((Anode_strchr(kv_breaks,*line))&&((last != escape_char)||(!escape_char))) {
|
||
|
*(line++) = (char)0;
|
||
|
break;
|
||
|
} else last = *(line++);
|
||
|
}
|
||
|
while ((*line)&&(Anode_strchr(kv_breaks,*line))&&((last != escape_char)||(!escape_char)))
|
||
|
last = *(line++);
|
||
|
value = line;
|
||
|
|
||
|
if (escape_char) {
|
||
|
p1 = key;
|
||
|
while (*p1) {
|
||
|
if (*p1 == escape_char) {
|
||
|
p2 = p1;
|
||
|
p3 = p1 + 1;
|
||
|
while (*p3)
|
||
|
*(p2++) = *(p3++);
|
||
|
*p2 = (char)0;
|
||
|
}
|
||
|
++p1;
|
||
|
}
|
||
|
p1 = value;
|
||
|
while (*p1) {
|
||
|
if (*p1 == escape_char) {
|
||
|
p2 = p1;
|
||
|
p3 = p1 + 1;
|
||
|
while (*p3)
|
||
|
*(p2++) = *(p3++);
|
||
|
*p2 = (char)0;
|
||
|
}
|
||
|
++p1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (trim_whitespace_from_keys)
|
||
|
Anode_trim(key);
|
||
|
if (trim_whitespace_from_values)
|
||
|
Anode_trim(value);
|
||
|
|
||
|
AnodeDictionary_put(d,key,value);
|
||
|
}
|
||
|
|
||
|
if (eof_state)
|
||
|
break;
|
||
|
else line = in + 1;
|
||
|
}
|
||
|
last = *(in++);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
long AnodeDictionary_write(
|
||
|
struct AnodeDictionary *d,
|
||
|
char *out,
|
||
|
long out_size,
|
||
|
const char *line_break,
|
||
|
const char *kv_break)
|
||
|
{
|
||
|
struct AnodeDictionaryEntry *e;
|
||
|
const char *tmp;
|
||
|
long ptr = 0;
|
||
|
unsigned int bucket;
|
||
|
|
||
|
if (out_size <= 0)
|
||
|
return -1;
|
||
|
|
||
|
for(bucket=0;bucket<ANODE_DICTIONARY_FIXED_HASH_TABLE_SIZE;++bucket) {
|
||
|
e = d->ht[bucket];
|
||
|
while (e) {
|
||
|
tmp = e->key;
|
||
|
if (tmp) {
|
||
|
while (*tmp) {
|
||
|
out[ptr++] = *tmp++;
|
||
|
if (ptr >= (out_size - 1)) return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tmp = kv_break;
|
||
|
if (tmp) {
|
||
|
while (*tmp) {
|
||
|
out[ptr++] = *tmp++;
|
||
|
if (ptr >= (out_size - 1)) return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tmp = e->value;
|
||
|
if (tmp) {
|
||
|
while (*tmp) {
|
||
|
out[ptr++] = *tmp++;
|
||
|
if (ptr >= (out_size - 1)) return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tmp = line_break;
|
||
|
if (tmp) {
|
||
|
while (*tmp) {
|
||
|
out[ptr++] = *tmp++;
|
||
|
if (ptr >= (out_size - 1)) return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
e = e->next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
out[ptr] = (char)0;
|
||
|
|
||
|
return ptr;
|
||
|
}
|