#include <stdio.h>
#include <stdlib.h>
#include <netinfo/ni.h>
#include <NetInfo/nilib2.h>
#include <NetInfo/dsrecord.h>
#define forever for(;;)
#define META_IS_UNDERSCORE
typedef enum
{
TokenNULL = 0,
TokenLeftBrace = 1,
TokenRightBrace = 2,
TokenLeftParen = 3,
TokenRightParen = 4,
TokenComma = 5,
TokenSemi = 6,
TokenEqual = 7,
TokenWord = 8,
TokenCHILDREN = 9
} token_type_t;
int line_number = 1;
int record_number = 0;
char *
indent_string(int l)
{
static char line[256];
int i;
for (i = 0; i < 256; i++) line[i] = ' ';
line[l * 4] = '\0';
return line;
}
typedef struct
{
token_type_t type;
char *value;
} token_t;
token_t **tstack;
unsigned int tcount = 0;
dsrecord **store;
unsigned int store_count = 0;
FILE *fp;
char *
token_string(token_t *t)
{
if (t == NULL) return "NULL";
switch (t->type)
{
case TokenNULL: return "-nil-";
case TokenLeftBrace: return "{";
case TokenRightBrace: return "}";
case TokenLeftParen: return "(";
case TokenRightParen: return ")";
case TokenComma: return ",";
case TokenSemi: return ";";
case TokenEqual: return "=";
case TokenCHILDREN: return "CHILDREN";
case TokenWord: return t->value;
}
return "?";
}
void
freeToken(token_t *t)
{
if (t == NULL) return;
if (t->value != NULL) free(t->value);
t->value = NULL;
t->type = TokenNULL;
free(t);
}
/*
* Tokens are the characters: { } ( ) , ; =
* strings within double quotes, and a run of any non-white characters.
* White space includes spaces, tabs, and newlines.
*/
token_t *
get_token_1()
{
token_t *t;
char c;
static char x = EOF;
int run, quote, escape, len;
t = (token_t *)malloc(sizeof(token_t));
t->type = TokenNULL;
t->value = NULL;
/* Skip white space */
run = 1;
while (run == 1)
{
c = x;
x = EOF;
if (c == EOF) c = getc(fp);
if (c == EOF) return t;
if (c == ' ') continue;
if (c == '\t') continue;
if (c == '\n')
{
line_number++;
continue;
}
run = 0;
}
if ((c == '{') || (c == '}')
|| (c == '(') || (c == ')')
|| (c == ',') || (c == ';') || (c == '='))
{
if (c == '{') t->type = TokenLeftBrace;
else if (c == '}') t->type = TokenRightBrace;
else if (c == '(') t->type = TokenLeftParen;
else if (c == ')') t->type = TokenRightParen;
else if (c == ',') t->type = TokenComma;
else if (c == ';') t->type = TokenSemi;
else if (c == '=') t->type = TokenEqual;
return t;
}
escape = 0;
if (c == '\\') escape = 1;
quote = 0;
if (c == '"') quote = 1;
len = 1;
t->value = malloc(len + 1);
t->value[0] = c;
t->value[len] = '\0';
t->type = TokenWord;
run = 1;
while (run == 1)
{
c = getc(fp);
if (c == EOF) return t;
if (c == '\n') line_number++;
if (escape == 0)
{
if (quote == 0)
{
if ((c == ' ') || (c == '\t') || (c == '\n')) return t;
if ((c == '{') || (c == '}')
|| (c == '(') || (c == ')')
|| (c == ',') || (c == ';')
|| (c == '"'))
{
x = c;
return t;
}
}
if ((quote == 1) && (c == '"')) run = 0;
}
escape = 0;
if (c == '\\')
{
escape = 1;
continue;
}
t->value[len++] = c;
t->value = realloc(t->value, len + 1);
t->value[len] = '\0';
}
return t;
}
void
push_token(token_t *t)
{
if (tcount == 0)
{
tstack = (token_t **)malloc(sizeof(token_t *));
}
else
{
tstack = (token_t **)realloc(tstack, (tcount + 1) * sizeof(token_t *));
}
tstack[tcount] = t;
tcount++;
}
void
store_record(dsrecord *r)
{
if (store_count == 0)
{
store = (dsrecord **)malloc(sizeof(dsrecord *));
}
else
{
store = (dsrecord **)realloc(store, (store_count + 1) * sizeof(dsrecord *));
}
store[store_count] = dsrecord_retain(r);
store_count++;
}
dsrecord *
fetch_record(unsigned int n)
{
int i;
for (i = 0; i < store_count; i++)
{
if (store[i]->dsid == n) return dsrecord_retain(store[i]);
}
return NULL;
}
void
store_clean()
{
int i;
for (i = 0; i < store_count; i++) dsrecord_release(store[i]);
if (store_count > 0) free(store);
}
token_t *
pop_token()
{
token_t *t;
int i;
if (tcount > 0)
{
tcount--;
t = tstack[tcount];
if (tcount == 0)
{
free(tstack);
}
else
{
tstack = (token_t **)realloc(tstack, tcount * sizeof(token_t *));
}
return t;
}
t = get_token_1();
if (t->type != TokenWord)
{
return t;
}
if (!strcmp(t->value, "CHILDREN"))
{
t->type = TokenCHILDREN;
return t;
}
if (t->value[0] == '"')
{
for (i = 1; t->value[i] != '\0'; i++)
t->value[i - 1] = t->value[i];
i--;
t->value[i] = '\0';
i--;
if (t->value[i] == '"') t->value[i] = '\0';
}
return t;
}
/*
* dir ::= [{] proplist [subdirs] [}]
* proplist ::= prop*
* prop ::= key = val ;
* key ::= word
* word :: = ["] charstring ["]
* val :: = [(] word [, word]* [)]
* subdirs ::= subdirkey = [(] dir [, dir]* [)] [;]
* subdirkey ::= CHILDREN
* dir ::= number
*/
token_t *
get_list_token(int *paren)
{
token_t *t;
t = pop_token();
if (t->type == TokenLeftParen)
{
if (*paren == -1)
{
*paren = 1;
freeToken(t);
return get_list_token(paren);
}
else
{
fprintf(stderr, "Unexpected left paren \"(\" at line %d\n", line_number);
freeToken(t);
return NULL;
}
}
else if (t->type == TokenRightParen)
{
if (*paren != 1)
{
fprintf(stderr, "Unexpected right paren \")\" at line %d\n", line_number);
freeToken(t);
return NULL;
}
t->type = TokenNULL;
return t;
}
else if (t->type == TokenSemi)
{
if (*paren == 1)
{
fprintf(stderr, "Expecting right paren \")\" at line %d\n", line_number);
freeToken(t);
return NULL;
}
push_token(t);
t = (token_t *)malloc(sizeof(token_t));
t->type = TokenNULL;
return t;
}
else if (t->type == TokenComma)
{
freeToken(t);
return get_list_token(paren);
}
else if (t->type != TokenWord)
{
fprintf(stderr, "Unexpected token \"%s\" at line %d\n", token_string(t), line_number);
freeToken(t);
return NULL;
}
if (*paren == -1) *paren = 0;
return t;
}
dsrecord *
get_dir(int level)
{
token_t *t;
int braces, paren, x;
dsrecord *r, *k;
dsattribute *a;
dsdata *d;
r = dsrecord_new();
r->dsid = record_number++;
if (level == 0) r->super = r->dsid;
t = pop_token();
if (t->type == TokenNULL)
{
freeToken(t);
return r;
}
braces = 0;
if (t->type == TokenLeftBrace)
{
freeToken(t);
braces = 1;
}
else push_token(t);
forever
{
t = pop_token();
if (t->type == TokenRightBrace)
{
freeToken(t);
if (braces == 1) return r;
else
{
fprintf(stderr, "Unexpected right brace \"}\" at line %d\n", line_number);
dsrecord_release(r);
return NULL;
}
}
else if (t->type == TokenWord)
{
d = cstring_to_dsdata(t->value);
a = dsattribute_new(d);
dsdata_release(d);
freeToken(t);
dsrecord_append_attribute(r, a, SELECT_ATTRIBUTE);
t = pop_token();
if (t->type != TokenEqual)
{
fprintf(stderr, "Expecting equal \"=\" at line %d\n", line_number);
freeToken(t);
dsrecord_release(r);
return NULL;
}
freeToken(t);
paren = -1;
t = get_list_token(&paren);
forever
{
if (t == NULL)
{
dsrecord_release(r);
return NULL;
}
else if (t->type == TokenNULL) break;
d = cstring_to_dsdata(t->value);
dsattribute_append(a, d);
dsdata_release(d);
freeToken(t);
t = get_list_token(&paren);
}
dsattribute_release(a);
t = pop_token();
if (t->type != TokenSemi)
{
fprintf(stderr, "Expecting semicolon \";\" at line %d\n", line_number);
freeToken(t);
dsrecord_release(r);
return NULL;
}
freeToken(t);
}
else if (t->type == TokenCHILDREN)
{
t = pop_token();
if (t->type != TokenEqual)
{
fprintf(stderr, "Expecting equal \"=\" at line %d\n", line_number);
freeToken(t);
dsrecord_release(r);
return NULL;
}
freeToken(t);
t = pop_token();
paren = 0;
if (t->type == TokenLeftParen)
{
paren = 1;
freeToken(t);
}
else push_token(t);
forever
{
k = get_dir(level + 1);
if (k != NULL)
{
k->super = r->dsid;
store_record(k);
dsrecord_append_sub(r, k->dsid);
dsrecord_release(k);
}
t = pop_token();
if (t->type == TokenComma)
{
freeToken(t);
continue;
}
x = 0;
if (t->type == TokenRightParen)
{
x = 1;
freeToken(t);
if (paren == 0)
{
fprintf(stderr, "Unexpected right paren \")\" at line %d\n", line_number);
dsrecord_release(r);
return NULL;
}
paren = 0;
t = pop_token();
}
if (t->type == TokenSemi)
{
x = 1;
freeToken(t);
if (paren == 1)
{
fprintf(stderr, "Expecting right paren \")\" at line %d\n", line_number);
dsrecord_release(r);
return NULL;
}
}
if (x == 1) break;
}
}
else if ((level > 0) && ((t->type == TokenComma) || (t->type == TokenRightParen)))
{
push_token(t);
return r;
}
else if ((level == 0) && t->type == TokenNULL)
{
return r;
}
else
{
fprintf(stderr, "Unexpected token \"%s\" at line %d\n", token_string(t), line_number);
freeToken(t);
dsrecord_release(r);
return NULL;
}
}
dsrecord_release(r);
return NULL;
}
ni_status
destroy_children(void *domain, ni_id *dir)
{
ni_status status;
int i;
ni_idlist children;
ni_id child;
/* get a list of all my children */
NI_INIT(&children);
status = ni_children(domain, dir, &children);
if (status != NI_OK) return status;
/* destroy each child */
for (i = 0; i < children.ni_idlist_len; i++)
{
child.nii_object = children.ni_idlist_val[i];
status = ni_self(domain, &child);
if (status != NI_OK) return status;
status = ni2_destroydir(domain, &child, dir);
if (status != NI_OK) return status;
}
/* free list of child ids */
ni_idlist_free(&children);
return NI_OK;
}
ni_proplist *
dsrecord_to_proplist(dsrecord *r)
{
ni_proplist *pl;
int i, j;
ni_property p;
if (r == NULL) return NULL;
pl = (ni_proplist *)malloc(sizeof(ni_proplist));
NI_INIT(pl);
for (i = 0; i < r->count; i++)
{
NI_INIT(&p);
p.nip_name = ni_name_dup(r->attribute[i]->key->data);
for (j = 0; j < r->attribute[i]->count; j++)
{
ni_namelist_insert(&p.nip_val, r->attribute[i]->value[j]->data, NI_INDEX_NULL);
}
ni_proplist_insert(pl, p, NI_INDEX_NULL);
ni_prop_free(&p);
}
return pl;
}
int
load_record(dsrecord *r, void *domain, ni_id *dir, int level)
{
int i, x;
dsrecord *k;
ni_proplist *pl;
ni_id child_dir;
ni_status status;
if (r == NULL) return 0;
/* write input proplist to netinfo */
pl = dsrecord_to_proplist(r);
if (level == 0)
status = ni_write(domain, dir, *pl);
else
status = ni_create(domain, dir, *pl, &child_dir, NI_INDEX_NULL);
ni_proplist_free(pl);
if (status != NI_OK)
{
fprintf(stderr, "Can't %s directory: %s\n", ((level == 0) ? "write" : "create"), ni_error(status));
return -1;
}
if (level == 0)
{
status = destroy_children(domain, dir);
if (status != NI_OK)
{
fprintf(stderr, "Can't destroy child directories: %s\n", ni_error(status));
return -1;
}
}
for (i = 0; i < r->sub_count; i++)
{
k = fetch_record(r->sub[i]);
x = 0;
if (level == 0) x = load_record(k, domain, dir, level + 1);
else x = load_record(k, domain, &child_dir, level + 1);
dsrecord_release(k);
if (x != 0) return x;
}
return 0;
}
void
raw_load(void *domain, char *path, char *file)
{
dsrecord *root;
ni_status status;
ni_id nidir;
if (path[0] != '/')
{
fprintf(stderr, "Raw load requires an absolute directory pathname, found %s\n", path);
return;
}
status = ni_pathsearch(domain, &nidir, path);
if (status == NI_NODIR)
{
status = ni2_createpath(domain, &nidir, path);
if (status != NI_OK)
{
fprintf(stderr, "Can't create directory %s: %s\n", path, ni_error(status));
return;
}
}
if (status != NI_OK)
{
fprintf(stderr, "Can't access directory %s: %s\n", path, ni_error(status));
return;
}
fp = stdin;
if (file != NULL)
{
fp = fopen(file, "r");
if (fp == NULL)
{
perror(file);
return;
}
}
root = get_dir(0);
load_record(root, domain, &nidir, 0);
dsrecord_release(root);
store_clean();
}
syntax highlighted by Code2HTML, v. 0.9.1