📄 nad.c
字号:
/* * jabberd - Jabber Open Source Server * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, * Ryan Eatmon, Robert Norris * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA *//** * !!! Things to do (after 2.0) * * - make nad_find_scoped_namespace() take an element index, and only search * the scope on that element (currently, it searchs all elements from * end to start, which isn't really correct, though it works in most cases * * - new functions: * * insert one nad (or part thereof) into another nad * * clear a part of a nad (like xmlnode_hide) * * - audit use of depth array and parent (see j2 bug #792) */#include "util.h"#ifdef HAVE_EXPAT#include "expat/expat.h"#endif/* define NAD_DEBUG to get pointer tracking - great for weird bugs that you can't reproduce */#ifdef NAD_DEBUGstatic xht _nad_alloc_tracked = NULL;static xht _nad_free_tracked = NULL;static void _nad_ptr_check(const char *func, nad_t nad) { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); if(xhash_get(_nad_alloc_tracked, loc) == NULL) { fprintf(stderr, ">>> NAD OP %s: 0x%x not allocated!\n", func, (int) nad); abort(); } if(xhash_get(_nad_free_tracked, loc) != NULL) { fprintf(stderr, ">>> NAD OP %s: 0x%x previously freed!\n", func, (int) nad); abort(); } fprintf(stderr, ">>> NAD OP %s: 0x%x\n", func, (int) nad);}#else#define _nad_ptr_check(func,nad)#endif#define BLOCKSIZE 1024/** internal: do and return the math and ensure it gets realloc'd */int _nad_realloc(void **oblocks, int len){ void *nblocks; int nlen; /* round up to standard block sizes */ nlen = (((len-1)/BLOCKSIZE)+1)*BLOCKSIZE; /* keep trying till we get it */ while((nblocks = realloc(*oblocks, nlen)) == NULL) sleep(1); *oblocks = nblocks; return nlen;}/** this is the safety check used to make sure there's always enough mem */#define NAD_SAFE(blocks, size, len) if((size) > len) len = _nad_realloc((void**)&(blocks),(size));/** internal: append some cdata and return the index to it */int _nad_cdata(nad_t nad, const char *cdata, int len){ NAD_SAFE(nad->cdata, nad->ccur + len, nad->clen); memcpy(nad->cdata + nad->ccur, cdata, len); nad->ccur += len; return nad->ccur - len;}/** internal: create a new attr on any given elem */int _nad_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen){ int attr; /* make sure there's mem for us */ NAD_SAFE(nad->attrs, (nad->acur + 1) * sizeof(struct nad_attr_st), nad->alen); attr = nad->acur; nad->acur++; nad->attrs[attr].next = nad->elems[elem].attr; nad->elems[elem].attr = attr; nad->attrs[attr].lname = strlen(name); nad->attrs[attr].iname = _nad_cdata(nad,name,nad->attrs[attr].lname); if(vallen > 0) nad->attrs[attr].lval = vallen; else nad->attrs[attr].lval = strlen(val); nad->attrs[attr].ival = _nad_cdata(nad,val,nad->attrs[attr].lval); nad->attrs[attr].my_ns = ns; return attr;}/** create a new cache, simple pointer to a list of nads */nad_cache_t nad_cache_new(void){ nad_cache_t cache; while((cache = malloc(sizeof(nad_cache_t))) == NULL) sleep(1); *cache = NULL;#ifdef NAD_DEBUG if(_nad_alloc_tracked == NULL) _nad_alloc_tracked = xhash_new(501); if(_nad_free_tracked == NULL) _nad_free_tracked = xhash_new(501);#endif return cache;}/** free the cache and any nads in it */void nad_cache_free(nad_cache_t cache){ nad_t cur; while((cur = *cache) != NULL) { *cache = cur->next; free(cur->elems); free(cur->attrs); free(cur->nss); free(cur->cdata); free(cur->depths); free(cur); } free(cache);}/** get the next nad from the cache, or create some */nad_t nad_new(nad_cache_t cache){ nad_t nad;#ifndef NAD_DEBUG /* If cache==NULL, then this NAD is not in a cache */ if ((cache!=NULL) && (*cache != NULL)) { nad = *cache; *cache = nad->next; nad->ccur = nad->ecur = nad->acur = nad->ncur = 0; nad->scope = -1; nad->cache = cache; nad->next = NULL; return nad; }#endif while((nad = malloc(sizeof(struct nad_st))) == NULL) sleep(1); memset(nad,0,sizeof(struct nad_st)); nad->scope = -1; nad->cache = cache;#ifdef NAD_DEBUG { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); xhash_put(_nad_alloc_tracked, pstrdup(xhash_pool(_nad_alloc_tracked), loc), (void *) 1); } _nad_ptr_check(__func__, nad);#endif return nad;}nad_t nad_copy(nad_t nad){ nad_t copy; _nad_ptr_check(__func__, nad); if(nad == NULL) return NULL; /* create a new nad not participating in a cache */ copy = nad_new(NULL); /* if it's not large enough, make bigger */ NAD_SAFE(copy->elems, nad->elen, copy->elen); NAD_SAFE(copy->attrs, nad->alen, copy->alen); NAD_SAFE(copy->nss, nad->nlen, copy->nlen); NAD_SAFE(copy->cdata, nad->clen, copy->clen); /* copy all data */ memcpy(copy->elems, nad->elems, nad->elen); memcpy(copy->attrs, nad->attrs, nad->alen); memcpy(copy->nss, nad->nss, nad->nlen); memcpy(copy->cdata, nad->cdata, nad->clen); /* sync data */ copy->ecur = nad->ecur; copy->acur = nad->acur; copy->ncur = nad->ncur; copy->ccur = nad->ccur; copy->scope = nad->scope; return copy;}/** free nad, or plug nad back in the cache */void nad_free(nad_t nad){ if(nad == NULL) return;#ifdef NAD_DEBUG _nad_ptr_check(__func__, nad); { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); xhash_zap(_nad_alloc_tracked, loc); xhash_put(_nad_free_tracked, pstrdup(xhash_pool(_nad_free_tracked), loc), (void *) nad); }#else /* If nad->cache != NULL, then put back into cache, otherwise this nad is not in a cache */ if (nad->cache != NULL) { nad->next = *(nad->cache); *(nad->cache) = nad; return; } #endif /* Free nad */ free(nad->elems); free(nad->attrs); free(nad->cdata); free(nad->nss); free(nad->depths);#ifndef NAD_DEBUG free(nad);#endif}/** locate the next elem at a given depth with an optional matching name */int nad_find_elem(nad_t nad, int elem, int ns, const char *name, int depth){ int my_ns; int lname = 0; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur || name == NULL) return -1; /* set up args for searching */ depth = nad->elems[elem].depth + depth; if(name != NULL) lname = strlen(name); /* search */ for(elem++;elem < nad->ecur;elem++) { /* if we hit one with a depth less than ours, then we don't have the * same parent anymore, bail */ if(nad->elems[elem].depth < depth) return -1; if(nad->elems[elem].depth == depth && (lname <= 0 || (lname == nad->elems[elem].lname && strncmp(name,nad->cdata + nad->elems[elem].iname, lname) == 0)) && (ns < 0 || ((my_ns = nad->elems[elem].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0))) return elem; } return -1;}/** get a matching attr on this elem, both name and optional val */int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val){ int attr, my_ns; int lname, lval = 0; _nad_ptr_check(__func__, nad); /* make sure there are valid args */ if(elem >= nad->ecur || name == NULL) return -1; attr = nad->elems[elem].attr; lname = strlen(name); if(val != NULL) lval = strlen(val); while(attr >= 0) { /* hefty, match name and if a val, also match that */ if(lname == nad->attrs[attr].lname && strncmp(name,nad->cdata + nad->attrs[attr].iname, lname) == 0 && (lval <= 0 || (lval == nad->attrs[attr].lval && strncmp(val,nad->cdata + nad->attrs[attr].ival, lval) == 0)) && (ns < 0 || ((my_ns = nad->attrs[attr].my_ns) >= 0 && NAD_NURI_L(nad, ns) == NAD_NURI_L(nad, my_ns) && strncmp(NAD_NURI(nad, ns), NAD_NURI(nad, my_ns), NAD_NURI_L(nad, ns)) == 0))) return attr; attr = nad->attrs[attr].next; } return -1;}/** get a matching ns on this elem, both uri and optional prefix */int nad_find_namespace(nad_t nad, int elem, const char *uri, const char *prefix){ int check, ns; _nad_ptr_check(__func__, nad); if(uri == NULL) return -1; /* work backwards through our parents, looking for our namespace on each one. * if we find it, link it. if not, the namespace is undeclared - for now, just drop it */ check = elem; while(check >= 0) { ns = nad->elems[check].ns; while(ns >= 0) { if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 && (prefix == NULL || (nad->nss[ns].iprefix >= 0 && strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0))) return ns; ns = nad->nss[ns].next; } check = nad->elems[check].parent; } return -1;}/** find a namespace in scope */int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix){ int ns; _nad_ptr_check(__func__, nad); if(uri == NULL) return -1; for(ns = 0; ns < nad->ncur; ns++) { if(strlen(uri) == NAD_NURI_L(nad, ns) && strncmp(uri, NAD_NURI(nad, ns), NAD_NURI_L(nad, ns)) == 0 && (prefix == NULL || (nad->nss[ns].iprefix >= 0 && strlen(prefix) == NAD_NPREFIX_L(nad, ns) && strncmp(prefix, NAD_NPREFIX(nad, ns), NAD_NPREFIX_L(nad, ns)) == 0))) return ns; } return -1;}/** create, update, or zap any matching attr on this elem */void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen){ int attr; _nad_ptr_check(__func__, nad); /* find one to replace first */ if((attr = nad_find_attr(nad, elem, ns, name, NULL)) < 0) { /* only create new if there's a value to store */ if(val != NULL) _nad_attr(nad, elem, ns, name, val, vallen); return; } /* got matching, update value or zap */ if(val == NULL) { nad->attrs[attr].lval = nad->attrs[attr].lname = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -