/*********************************************************************** * Copyright (C) 1995 Joe English * Freely redistributable *********************************************************************** * * node.c,v 1.14 1999/01/22 02:08:06 joe Exp * * Author: Joe English * Created: 6 Jan 1995 * Description: Routines to manage ESIS tree nodes. * * 1999/01/22 02:08:06 * 1.14 */ #include #include #include "project.h" #include "strmap.h" #include "strmgt.h" #include "pile.h" #include "esis.h" #include "esisp.h" /*+++ ESIS node free list management: * Nodes are allocated from 'malloc' a chunk at a time; * freed nodes are added to a free list (chained by the 'next' pointer) * and recycled. Nodes are not returned to the malloc() pool. * This approach helps avoid fragmentation and excessive * 'malloc' overhead. */ static ESISNodeRec *freelist = 0; #define FREELIST_CHUNKSIZE 1024 ESISNode allocnode(void) { ESISNode p; if (!freelist) /* extend freelist */ { int n = FREELIST_CHUNKSIZE; /* grab a new chunk from system */ freelist = malloc(n*sizeof(ESISNodeRec)); /* %%% check */ /* string up a freelist: */ freelist->next = 0; while (--n) { ++freelist; freelist->next = freelist - 1; } } p = freelist; freelist = freelist->next; return p; } void freenode(ESISNode p) { p->next = freelist; freelist = p; } /* Constructor: * Initialize node and update tree structure. * %%% Check this code. */ ESISNode esis_create_node( ESISNodeType type, ESISToken name, ESISNode parent, ESISNode prev, int isatt) { ESISNode p = allocnode(); p->type = type; ASSERT(!name||name == intern(name), "Non-interned name passed to create_node") p->name = name; p->attributes = p->children = p->reference = p->link = 0; p->text = 0; p->properties = 0; /* created when needed */ /* Tree structure: */ p->parent = parent; p->prev = prev; if (prev) { p->next = prev->next; prev->next = p; } else if (isatt) { /* first attribute */ p->next = parent ? parent->attributes: 0; if (parent) parent->attributes = p; } else { /* first child */ p->next = parent ? parent->children : 0; if (parent) parent->children = p; } /* pathloc fields: */ p->pathno = p->width = -1; p->height = p->depth = -1; return p; } /* %%% missing destructor (!) */ #if 0 ESISNode old_esis_create_node(ESISNodeType type, ESISNode parent, ESISNode esib) { return create_node(type, NULL, parent, esib, 0); } #endif /* High-level: */ ESISNode esis_create_attribute(ESISNode node, ESISToken name, char *attval) { ESISNode n = esis_create_node(EN_AT,name,node,0,1); n->text = attval; return n; } ESISBuilder esis_builder_start(void) { ESISBuilder ep = malloc(sizeof(*ep)); if (!ep) return 0; ep->rootnode = ep->curnode = ep->wrptr = 0; ep->pathno = 1; ep->datapile = pcreate(); ep->rootnode = esis_open_node(ep,EN_SD); ep->rootnode->depth = 0; ep->rootnode->pathno = -1; ep->curnode = ep->rootnode; ep->wrptr = 0; return ep; } ESISDocument esis_builder_finish(ESISBuilder ep) { ESISDocument doc = malloc(sizeof(*doc)); doc->rootnode = ep->rootnode; doc->datapile = ep->datapile; ep->datapile = NULL; free(ep); return doc; } void esis_free_document(ESISDocument doc) { if (doc->datapile) pdestroy(doc->datapile); /* %%% free nodes */ free(doc); } ESISNode esis_open_node(ESISBuilder ep, ESISNodeType type) { ESISNode n; n = esis_create_node(type, NULL, ep->curnode, ep->wrptr, 0); n->pathno = ep->pathno; n->height = 1; n->depth = ep->curnode ? ep->curnode->depth + 1 : 1; ep->curnode = n; ep->wrptr = 0; return n; } extern ESISNode esis_close_node(ESISBuilder ep) { ep->wrptr = ep->curnode; ep->curnode = ep->curnode->parent; if (ep->pathno == ep->wrptr->pathno) { ep->wrptr->width = 1; ++ep->pathno; } else { ep->wrptr->width = ep->pathno - ep->wrptr->pathno; } if (ep->curnode && ep->curnode->height <= ep->wrptr->height) { ep->curnode->height = ep->wrptr->height + 1; } return ep->wrptr; } ESISNode esis_create_datanode(ESISBuilder ep, ESISNodeType type, char *text) { ESISNode n; n = esis_create_node(type, NULL, ep->curnode, ep->wrptr, 0); n->text = text; ep->wrptr = n; return n; } /* * Entity definitions are stored in the attribute list * of the document root. This is questionable... */ ESISNode esis_create_entity(ESISBuilder ep, ESISToken name) { ESISNode entity = esis_create_node(EN_ENTITY,name,ep->rootnode,0,1); ASSERT(name == intern(name), "Non-interned name passed to create_entity") return entity; } static ESISNode findent(ESISNode nd, ESISToken ename) { for (nd = nd->attributes; nd; nd = nd->next) if (nd->type == EN_ENTITY && nd->name == ename) return nd; return 0; } ESISNode esis_find_entity(ESISBuilder ep, ESISToken name) { ASSERT(name == intern(name), "Non-interned name passed to create_entity") return findent(ep->rootnode, name); } ESISNode esis_entity(ESISNode nd, const char *ename) { return findent(esis_docroot(nd), intern(ename)); }