/*################################################################################### # # Embperl - Copyright (c) 1997-2008 Gerald Richter / ecos gmbh www.ecos.de # Embperl - Copyright (c) 2008-2015 Gerald Richter # Embperl - Copyright (c) 2015-2023 actevy.io # # You may distribute under the terms of either the GNU General Public # License or the Artistic License, as specified in the Perl README file. # # THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED # WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. # ###################################################################################*/ #include "ep.h" #include "epmacro.h" /* --- don't use Perl's memory management here --- */ #ifndef DMALLOC #undef malloc #undef realloc #undef strdup #undef free #endif HV * pStringTableHash ; /* Hash to translate strings to index number */ HE * * pStringTableArray ; /* Array with pointers to strings */ static tStringIndex * pFreeStringsNdx ; /* List of freed string indexes */ tDomTree * pDomTrees ; static tIndexShort * pFreeDomTrees ; static int nMemUsage = 0 ; static int numNodes = 0 ; static int numLevelLookup = 0 ; static int numLevelLookupItem = 0 ; static int numAttr = 0 ; static int numStr = 0 ; static int numReplace = 0 ; tIndex xNoName = 0 ; tIndex xDomTreeAttr = 0 ; tIndex xDocument ; tIndex xDocumentFraq ; tIndex xOrderIndexAttr ; static tUInt8 * MemFree[4196] ; static tUInt8 * pMemLast = NULL ; static tUInt8 * pMemEnd = NULL ; struct tPad { tNodeData Nodes [1024] ; } ; typedef struct tPad tPad ; #define LEVELHASHSIZE 8 /* ------------------------------------------------------------------------ */ /* */ /* mydie */ /* */ /* Fatal Error */ /* */ /* ------------------------------------------------------------------------ */ void mydie (/*in*/ tApp * a, char * msg) { epaTHX_ LogErrorParam (a, 9999, msg, "") ; puts (msg) ; #ifdef EPDEBUG #if defined (__GNUC__) && defined (__i386__) __asm__ ("int $0x03\n") ; #endif #endif exit (1) ; } /* ------------------------------------------------------------------------ */ /* */ /* Node memory management */ /* */ /* ------------------------------------------------------------------------ */ #ifdef DMALLOC tNodeData * dom_malloc_dbg (/*in*/ tApp * a, size_t nSize, int * pCounter, char * fn, int l) #else tNodeData * dom_malloc (/*in*/ tApp * a, size_t nSize, int * pCounter) #endif { epaTHX_ int nFree = (nSize+7)>>3 ; void * pNew ; if (nFree > sizeof (MemFree) / sizeof (void *)) mydie (a, "Node to huge for dom_malloc") ; if ((pNew = MemFree[nFree])) { /* --- take one entry off the free list --- */ MemFree[nFree] = *((tUInt8 * *)pNew) ; (*pCounter)++ ; return pNew ; } nSize = nFree * 8 ; /* --- make dividable by 8 --- */ if (pMemLast + nSize < pMemEnd) { /* --- take space at the end of the pad --- */ pNew = pMemLast ; pMemLast += nSize ; (*pCounter)++ ; return pNew ; } /* --- Pad full -> alloc new one --- */ #ifdef DMALLOC pMemLast = _malloc_leap(fn, l, sizeof (tPad)) ; #else pMemLast = malloc(sizeof (tPad)) ; #endif if (pMemLast == NULL) { char buf[256] ; sprintf (buf, "dom_malloc: Out of memory (%u bytes)", (unsigned int)sizeof (tPad)) ; mydie (a, buf) ; } nMemUsage += sizeof (tPad) ; pMemEnd = pMemLast + sizeof (tPad) ; pNew = pMemLast ; pMemLast += nSize ; (*pCounter)++ ; return pNew ; } #ifdef DMALLOC #undef dom_malloc #define dom_malloc(a,n,p) dom_malloc_dbg ((a),(n),(p),__FILE__,__LINE__) #endif void dom_free (/*in*/ tApp * a, tNodeData * pNode, int * pCounter) { int nSize = sizeof (tNodeData) + pNode -> numAttr * sizeof (tAttrData) ; int nFree = (nSize+7)>>3 ; void * pFree ; if (nFree > sizeof (MemFree) / sizeof (void *)) mydie (a, "Node to huge for dom_malloc") ; /* --- add to the free list --- */ pFree = MemFree[nFree] ; MemFree[nFree] = (tUInt8 *)pNode ; *((tUInt8 * *)pNode) = pFree ; (*pCounter)-- ; return ; } void dom_free_size (/*in*/ tApp * a, void * pNode, int nSize, int * pCounter) { int nFree = (nSize+7)>>3 ; void * pFree ; if (nFree > sizeof (MemFree) / sizeof (void *)) mydie (a, "Node to huge for dom_malloc") ; /* --- add to the free list --- */ pFree = MemFree[nFree] ; MemFree[nFree] = (tUInt8 *)pNode ; *((tUInt8 * *)pNode) = pFree ; (*pCounter)-- ; return ; } tNodeData * dom_realloc (/*in*/ tApp * a, tNodeData * pNode, size_t nSize) { int nOldSize = sizeof (tNodeData) + pNode -> numAttr * sizeof (tAttrData) ; tNodeData * pNew ; int n ; if (((tUInt8 *)pNode) + nOldSize == pMemLast) { /* --- expand --- */ if (((tUInt8 *)pNode) + nSize < pMemEnd) { /* --- take space at the end of the pad --- */ pMemLast = ((tUInt8 *)pNode) + nSize ; return pNode ; } } pNew = dom_malloc (a, nSize, &n) ; memcpy (pNew, pNode, nOldSize) ; dom_free (a, pNode, &n) ; return pNew ; } /* ------------------------------------------------------------------------ */ /* */ /* general memory management */ /* */ /* ------------------------------------------------------------------------ */ void * str_malloc (/*in*/ tApp * a, size_t n) { epaTHX_ void * m = malloc(n + sizeof (size_t)) ; size_t * m_size; if (m) { nMemUsage += n ; /* make the following in multiple step, so sun-cc is happy... */ m_size = (size_t *) m; *m_size = n; m_size++; m = (void *) m_size ; } else { char buf[256] ; /* sprintf (buf, "%zu bytes", n) ; LogErrorParam (a, rcOutOfMemory, "str_malloc failed", buf) ; */ sprintf (buf, "str_malloc: Out of memory (%u bytes)", (unsigned int)(n + sizeof (size_t))) ; mydie (a, buf) ; } return m ; } #ifdef DMALLOC void * str_malloc_dbg (/*in*/ tApp * a, size_t n, char * fn, int l) { epaTHX_ void * m = _malloc_leap(fn, l, n + sizeof (size_t)) ; size_t * m_size; if (m) { nMemUsage += n ; /* make the following in multiple step, so sun-cc is happy... */ m_size = (size_t *) m; *m_size = n; m_size++; m = (void *) m_size ; } else { char buf[256] ; /* sprintf (buf, "%zu bytes", n) ; LogErrorParam (a, rcOutOfMemory, "str_malloc_dbg failed", buf) ; */ sprintf (buf, "str_malloc: Out of memory (%u bytes)", n + sizeof (size_t)) ; mydie (a, buf) ; } return m ; } #endif void * str_realloc (/*in*/ tApp * a, void * s, size_t n) { epaTHX_ void * m = ((size_t *)s) - 1 ; size_t * m_size; nMemUsage -= *((size_t *)m) ; if ((m = realloc (m, n + sizeof (size_t)))) { nMemUsage += n ; /* make the following in multiple step, so sun-cc is happy... */ m_size = (size_t *) m; *m_size = n; m_size++; m = (void *) m_size ; } else { char buf[256] ; /* sprintf (buf, "%zu bytes", n) ; LogErrorParam (a, rcOutOfMemory, "str_realloc failed", buf) ; */ sprintf (buf, "str_realloc: Out of memory (%u bytes)", (unsigned int)(n + sizeof (size_t))) ; mydie (a, buf) ; } return m ; } #ifdef DMALLOC void * str_realloc_dbg (/*in*/ tApp * a, void * s, size_t n, char * fn, int l) { epaTHX_ void * m = ((size_t *)s) - 1 ; size_t * m_size; nMemUsage -= *((size_t *)m) ; if ((m = _realloc_leap (fn, l, m, n + sizeof (size_t)))) { nMemUsage += n ; /* make the following in multiple step, so sun-cc is happy... */ m_size = (size_t *) m; *m_size = n; m_size++; m = (void *) m_size ; } else { char buf[256] ; /* sprintf (buf, "%zu bytes", n) ; LogErrorParam (a, rcOutOfMemory, "str_realloc failed", buf) ; */ sprintf (buf, "str_realloc: Out of memory (%u bytes)", n + sizeof (size_t)) ; mydie (a, buf) ; } return m ; } #endif void str_free (/*in*/ tApp * a, void * s) { epaTHX_ void * m = ((size_t *)s) - 1 ; nMemUsage -= *((size_t *)m) ; free (m) ; } /* forward */ static int DomTree_free (pTHX_ SV * pSV, MAGIC * mg) ; /* ------------------------------------------------------------------------ */ /* */ /* ArrayNew */ /* */ /*! * * \_en * Create a new dynamic array * * @param pArray Pointer to pointer that will hold new array * @param nAdd Number of items that should be added when array * must be extented * @param nElementSize Size of one element * \endif * * \_de * Erstellt eine neues dynamisches Array * * @param pArray Zeiger auf den Zeiger der auf das neue Array zeigt * @param nAdd Anzahl der Element die hinzugef?gt werden, wenn * das Array vergr??ert werden mu? * @param nElementSize Gr??e eines Elements * \endif * * ------------------------------------------------------------------------ */ #ifdef DMALLOC int ArrayNew_dbg (/*in*/ tApp * a, /*in*/ const tArray * pArray, /*in*/ int nAdd, /*in*/ int nElementSize, /*in*/ char * sFile, /*in*/ int nLine) #else int ArrayNew (/*in*/ tApp * a, /*in*/ const tArray * pArray, /*in*/ int nAdd, /*in*/ int nElementSize) #endif { struct tArrayCtrl * pNew ; #ifdef DMALLOC if ((pNew = str_malloc_dbg (a, nAdd * nElementSize + sizeof (struct tArrayCtrl), sFile, nLine)) == NULL) return 0 ; #else if ((pNew = str_malloc (a, nAdd * nElementSize + sizeof (struct tArrayCtrl))) == NULL) return 0 ; #endif memset (pNew, 0, nAdd * nElementSize + sizeof (struct tArrayCtrl)) ; *(void * *)pArray = (struct tArray *)(pNew + 1) ; pNew -> nMax = nAdd ; pNew -> nAdd = nAdd ; pNew -> nFill = 0 ; pNew -> nElementSize = nElementSize ; #ifdef DMALLOC strncpy (pNew -> sSig, "ARY ", sizeof (pNew -> sSig)) ; pNew -> sFile = sFile ; pNew -> nLine = nLine ; #endif return ok ; } /* ------------------------------------------------------------------------ */ /* */ /* ArrayNewZero */ /* */ /*! * * \_en * Create a new dynamic array and set it's content to all zero * * @param pArray Pointer to pointer that will hold new array * @param nAdd Number of items that should be added when array * must be extented * @param nElementSize Size of one element * \endif * * \_de * Erstellt eine neues dynamisches Array und setzt seinen Inhalt auf Null * * @param pArray Zeiger auf den Zeiger der auf das neue Array zeigt * @param nAdd Anzahl der Element die hinzugef?gt werden, wenn * das Array vergr??ert werden mu? * @param nElementSize Gr??e eines Elements * \endif * * ------------------------------------------------------------------------ */ #ifdef DMALLOC int ArrayNewZero_dbg (/*in*/ tApp * a, /*in*/ const tArray * pArray, /*in*/ int nAdd, /*in*/ int nElementSize, /*in*/ char * sFile, /*in*/ int nLine) #else int ArrayNewZero (/*in*/ tApp * a, /*in*/ const tArray * pArray, /*in*/ int nAdd, /*in*/ int nElementSize) #endif { struct tArrayCtrl * pNew ; #ifdef DMALLOC if ((pNew = str_malloc_dbg (a, nAdd * nElementSize + sizeof (struct tArrayCtrl), sFile, nLine)) == NULL) return 0 ; #else if ((pNew = str_malloc (a, nAdd * nElementSize + sizeof (struct tArrayCtrl))) == NULL) return 0 ; #endif memset (pNew, 0, nAdd * nElementSize + sizeof (struct tArrayCtrl)) ; *(void * *)pArray = (struct tArray *)(pNew + 1) ; pNew -> nMax = nAdd ; pNew -> nAdd = nAdd ; pNew -> nFill = 0 ; pNew -> nElementSize = nElementSize ; #ifdef DMALLOC strncpy (pNew -> sSig, "ARY ", sizeof (pNew -> sSig)) ; pNew -> sFile = sFile ; pNew -> nLine = nLine ; #endif memset (pNew+1, 0, nAdd * nElementSize) ; return ok ; } /* ------------------------------------------------------------------------ */ /* */ /* ArrayFree */ /* */ /* Create a new dynamic array */ /* */ /* ------------------------------------------------------------------------ */ int ArrayFree (/*in*/ tApp * a, /*in*/ const tArray * pArray) { if ((*(void * *)pArray)) { struct tArrayCtrl * pCtrl = ((struct tArrayCtrl *)(*(void * *)pArray)) - 1 ; #ifdef DMALLOC if (strncmp (pCtrl -> sSig, "ARY ", sizeof (pCtrl -> sSig)) != 0) { LogErrorParam (a, rcCleanupErr, "ArrayFree Signature", pCtrl -> sSig) ; } strncpy (pCtrl -> sSig, "ARYFR", sizeof (pCtrl -> sSig)) ; #endif str_free (a, pCtrl) ; (*(void * *)pArray) = NULL ; } return ok ; } /* ------------------------------------------------------------------------ */ /* */ /* ArrayClone */ /* */ /* Create a new dynamic array as exact copy of old one */ /* */ /* ------------------------------------------------------------------------ */ #ifdef DMALLOC int ArrayClone_dbg (/*in*/ tApp * a, /*in*/ const tArray * pOrgArray, /*out*/ const tArray * pNewArray, /*in*/ char * sFile, /*in*/ int nLine) #else int ArrayClone (/*in*/ tApp * a, /*in*/ const tArray * pOrgArray, /*out*/ const tArray * pNewArray) #endif { if (pOrgArray) { struct tArrayCtrl * pNew ; struct tArrayCtrl * pCtrl = ((struct tArrayCtrl *)(*(void * *)pOrgArray)) - 1 ; int size = pCtrl -> nFill * pCtrl -> nElementSize + sizeof (struct tArrayCtrl) ; #ifdef DMALLOC if ((pNew = str_malloc_dbg (a, size, sFile, nLine)) == NULL) return 0 ; #else if ((pNew = str_malloc (a, size)) == NULL) return 0 ; #endif memcpy (pNew, pCtrl, size) ; *(void * *)pNewArray = (struct tArray *)(pNew + 1) ; pNew -> nMax = pCtrl -> nFill ; } else { *(void * *)pNewArray = NULL ; } return ok ; } /* ------------------------------------------------------------------------ */ /* */ /* ArrayAdd */ /* */ /* Make space for numElements in Array and return index of first one */ /* */ /* ------------------------------------------------------------------------ */ int ArrayAdd (/*in*/ tApp * a, /*in*/ const tArray * pArray, /*in*/ int numElements) { struct tArrayCtrl * pCtrl = ((struct tArrayCtrl *)(*(void * *)pArray)) - 1 ; int nNdx ; if (pCtrl -> nFill + numElements > pCtrl -> nMax) { struct tArrayCtrl * pNew ; int nNewMax = pCtrl -> nFill + numElements + pCtrl -> nAdd ; #ifdef DMALLOC if ((pNew = str_realloc_dbg (a, pCtrl, nNewMax * pCtrl -> nElementSize + sizeof (struct tArrayCtrl), pCtrl -> sFile, pCtrl -> nLine)) == NULL) return 0 ; #else if ((pNew = str_realloc (a, pCtrl, nNewMax * pCtrl -> nElementSize + sizeof (struct tArrayCtrl))) == NULL) return 0 ; #endif *(void * *)pArray = (struct tArray *)(pNew + 1) ; pNew -> nMax = nNewMax ; pCtrl = pNew ; } nNdx = pCtrl -> nFill ; pCtrl -> nFill += numElements ; return nNdx ; } /* ------------------------------------------------------------------------ */ /* */ /* ArraySub */ /* */ /* Remove numElemenets from the end of the array. Does not reallocate memory*/ /* Returns -1 if less then numElemenets are avialable */ /* */ /* ------------------------------------------------------------------------ */ int ArraySub (/*in*/ tApp * a, /*in*/ const tArray * pArray, /*in*/ int numElements) { struct tArrayCtrl * pCtrl = ((struct tArrayCtrl *)(*(void * *)pArray)) - 1 ; if (pCtrl -> nFill < numElements) return -1 ; else pCtrl -> nFill -= numElements ; return pCtrl -> nFill ; } /* ------------------------------------------------------------------------ */ /* */ /* ArraySet */ /* */ /* Make space that at least numElements in the Array */ /* */ /* ------------------------------------------------------------------------ */ int ArraySet (/*in*/ tApp * a, /*in*/ const tArray * pArray, /*in*/ int numElements) { struct tArrayCtrl * pCtrl = ((struct tArrayCtrl *)(*(void * *)pArray)) - 1 ; char * p ; if (numElements > pCtrl -> nMax) { struct tArrayCtrl * pNew ; int nNewMax = pCtrl -> nFill + pCtrl -> nAdd ; if (nNewMax < numElements) nNewMax = numElements + pCtrl -> nAdd ; #ifdef DMALLOC if ((pNew = str_realloc_dbg (a, pCtrl, nNewMax * pCtrl -> nElementSize + sizeof (struct tArrayCtrl), pCtrl -> sFile, pCtrl -> nLine)) == NULL) return 0 ; #else if ((pNew = str_realloc (a, pCtrl, nNewMax * pCtrl -> nElementSize + sizeof (struct tArrayCtrl))) == NULL) { return 0 ; } #endif p = (char *)(pNew + 1) ; *(void * *)pArray = (struct tArray *)p ; memset (p + pNew -> nMax * pNew -> nElementSize, 0, (nNewMax - pNew -> nMax) * pNew -> nElementSize) ; pNew -> nMax = nNewMax ; pCtrl = pNew ; } return numElements ; } /* ------------------------------------------------------------------------ */ /* */ /* ArraySetSize */ /* */ /* Make space for exact numElements in the Array */ /* */ /* ------------------------------------------------------------------------ */ int ArraySetSize (/*in*/ tApp * a, /*in*/ const tArray * pArray, /*in*/ int numElements) { struct tArrayCtrl * pCtrl = ((struct tArrayCtrl *)(*(void * *)pArray)) - 1 ; if (numElements > pCtrl -> nMax) ArraySet (a, pArray, numElements) ; pCtrl -> nFill = numElements ; return numElements ; } /* ------------------------------------------------------------------------ */ /* */ /* ArrayGetSize */ /* */ /* Get size of Array */ /* */ /* ------------------------------------------------------------------------ */ int ArrayGetSize (/*in*/ tApp *a, /*in*/ const tArray * pArray) { struct tArrayCtrl * pCtrl = ((struct tArrayCtrl *)(pArray)) - 1 ; return pCtrl -> nFill ; } /* ------------------------------------------------------------------------ */ /* */ /* StringNew */ /* */ /* create a new string */ /* */ /* ------------------------------------------------------------------------ */ #ifdef DMALLOC void StringNew_dbg (/*in*/ tApp * a, /*in*/ char * * pArray, /*in*/ int nAdd, /*in*/ char * sFile, /*in*/ int nLine) #else void StringNew (/*in*/ tApp * a, /*in*/ char * * pArray, /*in*/ int nAdd) #endif { if ((*(void * *)pArray) == NULL) #ifdef DMALLOC ArrayNew_dbg (a, pArray, nAdd, sizeof (char), sFile, nLine) ; #else ArrayNew (a, pArray, nAdd, sizeof (char)) ; #endif else ArraySetSize (a, pArray, 0); } /* ------------------------------------------------------------------------ */ /* */ /* StringFree */ /* */ /* Free String memory */ /* */ /* ------------------------------------------------------------------------ */ void StringFree (/*in*/ tApp * a, /*in*/ char * * pArray) { if ((*(void * *)pArray) != NULL) ArrayFree (a, pArray) ; } /* ------------------------------------------------------------------------ */ /* */ /* StringAdd */ /* */ /* append to string */ /* */ /* ------------------------------------------------------------------------ */ int StringAdd (/*in*/ tApp * a, /*in*/ char * * pArray, /*in*/ const char * sAdd, /*in*/ int nLen) { int nIndex ; int nFill ; if (nLen == 0) nLen = strlen (sAdd) ; nFill = ArrayGetSize (a, *pArray) ; /* make sure we always have a trailing zero */ ArraySet(a, pArray, nFill + nLen + 1) ; nIndex = ArrayAdd (a, pArray, nLen) ; memcpy ((*pArray)+nIndex, sAdd, nLen) ; return nIndex ; } /* ------------------------------------------------------------------------ */ /* */ /* String2Ndx */ /* */ /* Convert String to an index, if string already exists return index of */ /* existing string */ /* */ /* ------------------------------------------------------------------------ */ tStringIndex String2NdxInc (/*in*/ tApp * a, /*in*/ const char * sText, /*in*/ int nLen, /*in*/ int bInc) { epaTHX_ SV * * ppSV ; SV * pSVKey ; SV * pSVNdx ; HE * pHEKey ; int nNdx ; if (sText == NULL) return 0 ; if ((ppSV = hv_fetch (pStringTableHash, (char *)sText, nLen, 0)) != NULL) { /*lprintf (a, "String2Ndx type=%d iok=%d flg=%x\n", *ppSV?SvTYPE(*ppSV):-1, SvIOK (*ppSV), SvFLAGS(*ppSV)) ;*/ if (*ppSV != NULL && SvIOKp (*ppSV)) /* use SvIOKp to avoid problems with tainting */ { if (bInc) SvREFCNT_inc (*ppSV) ; nNdx = SvIVX (*ppSV) ; /* if (nNdx < 6 || nNdx == 92) lprintf (a, "old string %s (#%d) refcnt=%d\n", Ndx2String (nNdx), nNdx, SvREFCNT(*ppSV)) ; */ return nNdx ; } } /* new string */ nNdx = ArraySub (a, &pFreeStringsNdx, 1) ; if (nNdx != (tIndex)(-1)) nNdx = pFreeStringsNdx[nNdx] ; else nNdx = ArrayAdd (a, &pStringTableArray, 1) ; pSVNdx = newSVivDBG1 (nNdx, sText) ; SvTAINTED_off (pSVNdx) ; if (bInc) SvREFCNT_inc (pSVNdx) ; pSVKey = newSVpv (nLen?(char *)sText:"", nLen) ; pHEKey = hv_store_ent (pStringTableHash, pSVKey, pSVNdx, 0) ; SvREFCNT_dec (pSVKey) ; pStringTableArray[nNdx] = pHEKey ; numStr++ ; /* if (nNdx < 6 || nNdx == 124) lprintf (a, "new string %s (#%d) refcnt=%d\n", Ndx2String (nNdx), nNdx, SvREFCNT(pSVNdx)) ; */ return nNdx ; } /* ------------------------------------------------------------------------ */ /* */ /* String2UniqueNdx */ /* */ /* Convert String to an unique index */ /* A string lookup will always return the index of the first string */ /* */ /* */ /* ------------------------------------------------------------------------ */ tStringIndex String2UniqueNdx (/*in*/ tApp * a, /*in*/ const char * sText, /*in*/ int nLen) { epaTHX_ SV * pSVKey ; SV * pSVNdx ; HE * pHEKey ; int nNdx ; if (sText == NULL) return 0 ; /* new string */ nNdx = ArraySub (a, &pFreeStringsNdx, 1) ; if (nNdx != (tIndex)(-1)) nNdx = pFreeStringsNdx[nNdx] ; else nNdx = ArrayAdd (a, &pStringTableArray, 1) ; pSVKey = newSVpv (nLen?(char *)sText:"", nLen) ; pHEKey = hv_fetch_ent (pStringTableHash, pSVKey, 0, 0) ; if (!pHEKey) { pSVNdx = newSVivDBG1 (nNdx, sText) ; SvTAINTED_off (pSVNdx) ; SvREFCNT_inc (pSVNdx) ; pHEKey = hv_store_ent (pStringTableHash, pSVKey, pSVNdx, 0) ; } pStringTableArray[nNdx] = pHEKey ; numStr++ ; return nNdx ; } /* ------------------------------------------------------------------------ */ /* */ /* NdxStringFree */ /* */ /* Free one reference to a string */ /* */ /* ------------------------------------------------------------------------ */ void NdxStringFree (/*in*/ tApp * a, /*in*/ tStringIndex nNdx) { epaTHX_ HE * pHE = pStringTableArray[nNdx] ; if (pHE) { SV * pSVNdx = HeVAL (pHE) ; SvREFCNT_dec (pSVNdx) ; /* if (nNdx < 6 || nNdx == 92) lprintf (a, "free string %s (#%d) refcnt=%d\n", Ndx2String (nNdx), nNdx, SvREFCNT(pSVNdx)) ; */ if (SvREFCNT(pSVNdx) == 1) { int n ; /* lprintf (a, "delete string %s (#%d)\n", Ndx2String (nNdx), nNdx) ; */ hv_delete (pStringTableHash, HeKEY (pHE), HeKLEN(pHE), 0) ; pStringTableArray[nNdx] = NULL ; n = ArrayAdd (a, &pFreeStringsNdx, 1) ; pFreeStringsNdx[n] = nNdx ; numStr-- ; } } } #ifdef EPDEBUG /* ------------------------------------------------------------------------ */ /* */ /* DEBUG support */ /* */ /* */ /* */ /* ------------------------------------------------------------------------ */ #define ASSERT_DOMTREE_VALID(a,n) embperl_Assert_DomTree_Valid(a,n,"",__FILE__,__LINE__) #define ASSERT_NODE_VALID(a,n) embperl_Assert_Node_Valid(a,n,"",__FILE__,__LINE__) #define ASSERT_ATTR_VALID(a,n) embperl_Assert_Attr_Valid(a,n,NULL,"",__FILE__,__LINE__) void embperl_Assert_Node_Valid (/*in*/tApp * a, tNodeData *pNode, char * prefix, char * fn, int line) ; void embperl_Assert_DomTree_Valid (/*in*/tApp * a, tDomTree *pDomTree, char * prefix, char * fn, int line) { tDomTree * pLookupDomTree ; char buf[2048] ; if (!pDomTree) return ; if (pDomTree -> xNdx == 0) { sprintf(buf, "%s DomTree is deleted: %s(%d)\n", prefix, fn, line) ; mydie (NULL, buf) ; } pLookupDomTree = DomTree_self(pDomTree -> xNdx) ; if (pDomTree != pLookupDomTree) { sprintf(buf, "%sAddress of DomTree %d does not match Lookup Table: %s(%d)\n", prefix, pDomTree -> xNdx, fn, line) ; mydie (NULL, buf) ; } } void embperl_Assert_Attr_Valid (/*in*/tApp * a, tAttrData *pAttr, tNodeData *pNode, char * prefix, char * fn, int line) { tAttrData * pLookupAttr ; tNodeData *pLookupNode ; tDomTree *pLookupDomTree ; char buf[2048] ; tIndex xFirstAttr ; if (!pAttr) return ; pLookupNode = Attr_selfNode (pAttr) ; pLookupDomTree = DomTree_self(pLookupNode -> xDomTree) ; pLookupAttr = Attr_self (pLookupDomTree, pAttr -> xNdx) ; if (pAttr != pLookupAttr) { sprintf(buf, "%sAddress of Attr %ld does not match Lookup Table: %s(%d)\n", prefix, pAttr -> xNdx, fn, line) ; mydie (NULL, buf) ; } if (pNode) { if (pNode != pLookupNode) { sprintf(buf, "%sAddress of Node of Attr (Node %ld DomTree %d) does not match Node: %s(%d)\n", prefix, pNode -> xNdx, pNode -> xDomTree, fn, line) ; mydie (NULL, buf) ; } } else { sprintf(buf, "%sAttr %ld: ", prefix, pAttr -> xNdx) ; embperl_Assert_Node_Valid(a,pLookupNode, buf, fn, line) ; } if (pAttr -> bFlags & aflgAttrChilds) { sprintf(buf, "%sAttr %ld aflgAttrChilds: ", prefix, pAttr -> xNdx) ; pLookupNode = Node_selfLevel (a, pLookupDomTree, pAttr -> xValue, pLookupNode -> nRepeatLevel) ; xFirstAttr = pLookupNode -> xNdx ; while (pLookupNode) { embperl_Assert_Node_Valid(a,pLookupNode, buf, fn, line) ; pLookupNode = Node_selfNextSibling (a, pLookupDomTree, pLookupNode, pLookupNode -> nRepeatLevel) ; if (pLookupNode) { if (pLookupNode -> xNdx == xFirstAttr ) { sprintf(buf, "%sAttr %ld aflgAttrChilds FirstNode found second time %ld", prefix, pAttr -> xNdx, pLookupNode -> xNdx) ; mydie (a, buf) ; } } } } } void embperl_Assert_Node_Valid (/*in*/tApp * a, tNodeData *pNode, char * prefix, char * fn, int line) { tDomTree * pDomTree ; tNodeData *pLookupNode ; tNodeData *pFirstChild ; tAttrData *pAttr ; int n ; char buf[2048] ; if (!pNode) return ; n = ArrayGetSize (a, pDomTrees) ; if (pNode -> xDomTree >= n || pNode -> xDomTree < 0) { sprintf(buf, "%s DomTree %d out of range (max=%d): %s(%d)\n", prefix, pNode -> xDomTree, n, fn, line) ; mydie (NULL, buf) ; } pDomTree = DomTree_self (pNode -> xDomTree) ; sprintf(buf, "%sDomTree of Node %ld DomTree %d: ", prefix, pNode -> xNdx, pNode -> xDomTree) ; embperl_Assert_DomTree_Valid(a,pDomTree, buf, fn, line) ; pLookupNode = Node_selfLevel(a, pDomTree, pNode -> xNdx, pNode -> nRepeatLevel) ; if (pNode != pLookupNode) { sprintf(buf, "%sAddress of Node %ld DomTree %d does not match Lookup Table: %s(%d)\n", prefix, pNode -> xNdx, pNode -> xDomTree, fn, line) ; mydie (NULL, buf) ; } if (pNode -> xChilds && pNode -> nType != ntypDocumentFraq && pNode -> nType != ntypDocument) { tIndex xNull = xNode_selfLevelNull(pDomTree, pNode) ; pLookupNode = Node_self(pDomTree, xNull) ; pFirstChild = Node_selfLevel(a, pDomTree, pNode -> xChilds, pNode -> nRepeatLevel) ; if (pFirstChild -> xParent != pNode -> xNdx && pFirstChild -> xParent != xNull) { sprintf(buf, "%sParent (xParent=%ld) of first Child (Node %ld DomTree %d) does not point to myself (Node %ld DomTree %d NullNode=%ld): %s(%d)\n", prefix, pFirstChild -> xParent, pFirstChild -> xNdx, pFirstChild -> xDomTree, pNode -> xNdx, pNode -> xDomTree, xNull, fn, line) ; mydie (NULL, buf) ; } if (pNode -> nRepeatLevel > 0 && pFirstChild -> xParent != pNode -> xNdx) { tNodeData * pParent = Node_selfLevel(a, pDomTree, pFirstChild -> xParent, pNode -> nRepeatLevel) ; if (pNode != pParent ) { sprintf(buf, "%sLevel %d Level Parent of first Child (Node %ld DomTree %d) does not point to myself (Node %ld) but to Node %ld: %s(%d)\n", prefix, pNode -> nRepeatLevel, pFirstChild -> xNdx, pFirstChild -> xDomTree, pNode -> xNdx, pParent -> xNdx, fn, line) ; mydie (NULL, buf) ; } } } if (!*prefix && pNode -> xParent) { sprintf(buf, "%sParent of Node %ld DomTree %d: ", prefix, pNode -> xNdx, pNode -> xDomTree) ; pLookupNode = Node_selfLevel(a, pDomTree, pNode -> xParent, pNode -> nRepeatLevel) ; if (pLookupNode -> nType == ntypAttr) embperl_Assert_Attr_Valid(a, (tAttrData *)pLookupNode, NULL, buf, fn, line) ; else embperl_Assert_Node_Valid(a, pLookupNode, buf, fn, line) ; } if (!*prefix && pNode -> xNext) { sprintf(buf, "%sNext of Node %ld DomTree %d: ", prefix, pNode -> xNdx, pNode -> xDomTree) ; pLookupNode = Node_selfLevel(a, pDomTree, pNode -> xNext, pNode -> nRepeatLevel) ; embperl_Assert_Node_Valid(a,pLookupNode, buf, fn, line) ; } if (!*prefix && pNode -> xPrev) { sprintf(buf, "%sPrev of Node %ld DomTree %d: ", prefix, pNode -> xNdx, pNode -> xDomTree) ; pLookupNode = Node_selfLevel(a, pDomTree, pNode -> xPrev, pNode -> nRepeatLevel) ; embperl_Assert_Node_Valid(a,pLookupNode, buf, fn, line) ; } pAttr = (tAttrData * )(pNode + 1) ; n = pNode -> numAttr ; sprintf(buf, "%sAttr of Node %ld DomTree %d: ", prefix, pNode -> xNdx, pNode -> xDomTree) ; while (n) { embperl_Assert_Attr_Valid(a,pAttr, pNode, buf, fn, line) ; n-- ; pAttr++ ; } } #else #define ASSERT_DOMTREE_VALID(a,n) #define ASSERT_NODE_VALID(a,n) #define ASSERT_ATTR_VALID(a,n) #endif /* ------------------------------------------------------------------------ */ /* */ /* DomInit */ /* */ /* */ /* */ /* ------------------------------------------------------------------------ */ int DomInit (/*in*/ tApp * a) { epaTHX_ SV * pSVKey ; SV * pSVNdx ; HE * pHEKey ; tNodeData testnode ; tAttrData testattr ; if (((char *)(&testnode.nType) - (char *)&testnode) != ((char *)(&testattr.nType) - (char *)&testattr)) { mydie (a, "Attr.nType and Node.nType are not at the same offset. There is a problem with the typedefinitions in epdom.h") ; } if (((char *)(&testnode.xNdx) - (char *)&testnode) != ((char *)(&testattr.xNdx) - (char *)&testattr)) { mydie (a, "Attr.xNdx and Node.xNdx are not at the same offset. There is a problem with the typedefinitions in epdom.h") ; } if (((char *)(&testnode.xChilds) - (char *)&testnode) != ((char *)(&testattr.xValue) - (char *)&testattr)) { mydie (a, "Attr.xValue and Node.xChilds are not at the same offset. There is a problem with the typedefinitions in epdom.h") ; } if (sizeof(testnode.xChilds) != sizeof (testattr.xValue)) { mydie (a, "Attr.xValue and Node.xChilds do not have the same size. There is a problem with the typedefinitions in epdom.h") ; } pStringTableHash = newHV () ; ArrayNew (a, &pStringTableArray, 256, sizeof (HE *)) ; ArrayNew (a, &pFreeStringsNdx, 256, sizeof (tStringIndex *)) ; ArrayAdd (a, &pStringTableArray, 2) ; /* NULL */ pSVNdx = newSViv (0) ; SvREFCNT_inc (pSVNdx) ; pSVKey = newSVpv ("", 0) ; pHEKey = hv_store_ent (pStringTableHash, pSVKey, pSVNdx, 0) ; pStringTableArray[0] = pHEKey ; /* "" */ pSVNdx = newSViv (1) ; SvREFCNT_inc (pSVNdx) ; pSVKey = newSVpv ("", 0) ; pHEKey = hv_store_ent (pStringTableHash, pSVKey, pSVNdx, 0) ; pStringTableArray[1] = pHEKey ; numStr+=2 ; xNoName = String2Ndx (a, "", 8) ; xDomTreeAttr = String2Ndx (a, "", 9) ; xDocument = String2Ndx (a, "Document", 8) ; xDocumentFraq = String2Ndx (a, "DocumentFraq", 12) ; xOrderIndexAttr = String2Ndx (a, "", 10) ; ArrayNew (a, &pDomTrees, 64, sizeof (tDomTree)) ; ArrayAdd (a, &pDomTrees, 1) ; memset (&pDomTrees[0], 0, sizeof (tDomTree)) ; ArrayNew (a, &pFreeDomTrees, 64, sizeof (tIndex)) ; return ok ; } /* ------------------------------------------------------------------------ */ /* */ /* DomStats */ /* */ /* print statistics */ /* */ /* ------------------------------------------------------------------------ */ void DomStats (/*in*/ tApp * a) { lprintf (a, "[%d]PERF: DOMSTAT: MemUsage = %d Bytes numNodes = %d numLevelLookup = %d numLevelLookupItem = %d numStr = %d numReplace = %d \n", a -> pThread -> nPid, nMemUsage, numNodes, numLevelLookup, numLevelLookupItem, numStr, numReplace) ; #ifdef DMALLOC dmalloc_message ("[%d]PERF: DOMSTAT: MemUsage = %d Bytes numNodes = %d numLevelLookup = %d numLevelLookupItem = %d numStr = %d numReplace = %d \n", a -> pThread -> nPid, nMemUsage, numNodes, numLevelLookup, numLevelLookupItem, numStr, numReplace) ; #endif } /* ------------------------------------------------------------------------ */ /* */ /* DomTree_alloc */ /* */ /* Alloc storage for a new DomTree and associate it with a SV. deleteing */ /* the SV will delete the DomTree also */ /* */ /* ------------------------------------------------------------------------ */ MGVTBL DomTree_mvtTab = { NULL, NULL, NULL, NULL, DomTree_free } ; tDomTree * DomTree_alloc (tApp * a) { tDomTree * pDomTree ; tIndexShort n ; SV * pSV ; struct magic * pMagic ; epaTHX_ n = ArraySub (a, &pFreeDomTrees, 1) ; if (n != (tIndex)(-1)) n = pFreeDomTrees[n] ; else n = ArrayAdd (a, &pDomTrees, 1) ; pDomTree = DomTree_self (n) ; memset (pDomTree, 0, sizeof (*pDomTree)) ; pSV = newSViv (n) ; sv_magic (pSV, pSV, 0, NULL, n) ; pMagic = mg_find (pSV, 0) ; if (pMagic) pMagic -> mg_virtual = &DomTree_mvtTab ; else { LogErrorParam (a, rcMagicError, "", "") ; } pDomTree -> pDomTreeSV = pSV ; pDomTree -> xNdx = n ; pDomTree -> xSourceNdx = n ; return pDomTree ; } /* ------------------------------------------------------------------------ */ /* */ /* DomTree_new */ /* */ /* */ /* */ /* ------------------------------------------------------------------------ */ int DomTree_new (/*in*/ tApp * a, tDomTree * * pNewLookup) { epaTHX_ tDomTree * pDomTree ; pDomTree = DomTree_alloc (a) ; ArrayNew (a, &pDomTree -> pLookup, 256, sizeof (tLookupItem)) ; ArrayAdd (a, &pDomTree -> pLookup, 1) ; pDomTree -> pCheckpoints = NULL ; pDomTree -> pDependsOn = newAV () ; *pNewLookup = pDomTree ; return pDomTree -> xNdx ; } /* ------------------------------------------------------------------------ */ /* */ /* DomTree_dodelete */ /* */ /* Frees all memory allocated by this DomTree */ /* */ /* ------------------------------------------------------------------------ */ static int DomTree_dodelete (/*in*/ tApp * a, tDomTree * pDomTree) { epaTHX_ tLookupItem * pLookup = pDomTree -> pLookup ; int numLookup ; tIndexShort xDomTree = pDomTree -> xNdx ; tIndex xNdx ; tIndex xNode = -1 ; tRepeatLevelLookup * pLookupLevelNode ; tRepeatLevelLookupItem * pLookupLevelNodeLevel ; tRepeatLevelLookupItem * pItem ; tRepeatLevelLookupItem * pNext ; int n ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgDOM) lprintf (a, "[%d]Delete: DomTree = %d SVs=%d\n", a -> pThread -> nPid, pDomTree -> xNdx, sv_count) ; if (!xDomTree) { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgDOM) lprintf (a, "[%d]Delete: Already deleted DomTree = %d SVs=%d\n", a -> pThread -> nPid, pDomTree -> xNdx, sv_count) ; return ok ; } numLookup = ArrayGetSize (a, pLookup) ; pLookup += numLookup - 1 ; while (numLookup-- > 0) { tNodeData * pNode = pLookup -> pLookup ; if (pNode && pNode -> nType != (tNodeType)ntypAttr && xDomTree == pNode -> xDomTree) { /* lprintf (a, "delete typ=%d Pad xNdx=%d\n", pPad -> nType, pPad -> xNdx) ; */ int n = pNode -> numAttr ; tAttrData * pAttr = Node_selfFirstAttr(pNode) ; while (n--) { /* pDomTree -> pLookup[pAttr -> xNdx] = NULL ; */ if (pAttr -> bFlags) { if (pAttr -> xName) NdxStringFree (a, pAttr -> xName) ; if (pAttr -> xValue && (pAttr -> bFlags & aflgAttrValue)) NdxStringFree (a, pAttr -> xValue) ; } pAttr++ ; } /* lprintf (a, "delete typ=%d Node xNdx=%d\n", pNode -> nType, pNode -> xNdx) ; */ /* pDomTree -> pLookup[pNode -> xNdx] = NULL ; */ if (pNode -> nText) NdxStringFree (a, pNode -> nText) ; xNode = pNode -> xNdx ; dom_free (a, pNode, &numNodes) ; } else { xNode = -1 ; pNode = NULL ; } if ((pLookupLevelNode = pLookup -> pLookupLevel) && (pLookupLevelNode -> xNullNode == xNode || pNode == NULL)) { pLookupLevelNodeLevel = pLookupLevelNode -> items ; n = pLookupLevelNode -> numItems ; while (n-- > 0) { pNext = pLookupLevelNodeLevel -> pNext ; while (pNext) { pItem = pNext ; pNext = pItem -> pNext ; dom_free_size (a, pItem, sizeof (tRepeatLevelLookupItem), &numLevelLookupItem) ; } pLookupLevelNodeLevel++ ; } dom_free_size (a, pLookupLevelNode, sizeof (tRepeatLevelLookup) + sizeof (tRepeatLevelLookupItem) * (pLookupLevelNode -> numItems - 1), &numLevelLookup) ; } pLookup-- ; } ArrayFree (a, &pDomTree -> pLookup) ; ArrayFree (a, &pDomTree -> pCheckpoints) ; if (pDomTree -> pSV) SvREFCNT_dec (pDomTree -> pSV) ; if (pDomTree -> pDependsOn) { /* int i ; for (i = 0 ; i <= AvFILL (pDomTree -> pDependsOn); i++) { SV * pSV = *av_fetch (pDomTree -> pDependsOn, i, 0) ; lprintf (a, "pDependsOn DomTree #%d type = %d cnt=%d n=%d\n", i, SvTYPE(pSV), SvREFCNT(pSV), SvIVX(pSV)) ; } */ av_clear (pDomTree -> pDependsOn) ; SvREFCNT_dec (pDomTree -> pDependsOn) ; } xNdx = ArrayAdd (a, &pFreeDomTrees, 1) ; pDomTree -> xNdx = 0 ; pFreeDomTrees[xNdx] = xDomTree ; #if defined (_MDEBUG) && defined (WIN32) _ASSERTE( _CrtCheckMemory( ) ); #endif return ok ; } /* ------------------------------------------------------------------------ */ /* */ /* DomTree_free */ /* */ /* Frees all memory allocated by this DomTree */ /* Do not call directly. Is called by Perl when RefCnt goes to zero */ /* */ /* */ /* ------------------------------------------------------------------------ */ static int DomTree_free (pTHX_ SV * pSV, MAGIC * mg) { if (mg && mg -> mg_len && !PL_in_clean_all) return DomTree_dodelete (CurrApp, DomTree_self (mg -> mg_len)) ; else return ok ; } /* ------------------------------------------------------------------------ */ /* */ /* DomTree_delete */ /* */ /* Frees all memory allocated by this DomTree */ /* */ /* ------------------------------------------------------------------------ */ int DomTree_delete (/*in*/ tApp * a, tDomTree * pDomTree) { epaTHX_ SvREFCNT_dec (pDomTree -> pDomTreeSV) ; return ok ; } /* ------------------------------------------------------------------------ */ /* */ /* DomTree_clone */ /* */ /* */ /* */ /* ------------------------------------------------------------------------ */ int DomTree_clone (/*in*/ tApp * a, /*in*/ tDomTree * pOrgDomTree, /*out*/tDomTree * * pNewDomTree, /*in*/ int bForceDocFraq) { epaTHX_ tDomTree * pDomTree ; tNodeData * pDocument ; tIndex xOrgDomTree = pOrgDomTree -> xNdx ; pDomTree = DomTree_alloc (a) ; pDomTree -> pDependsOn = newAV () ; pOrgDomTree = DomTree_self (xOrgDomTree) ; /* relookup in case it has moved */ pDomTree -> xDocument = pOrgDomTree -> xDocument ; pDomTree -> xSourceNdx= pOrgDomTree -> xNdx ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgDOM) lprintf (a, "[%d]DOM: DomTree %d depends on DomTree %d\n", a -> pThread -> nPid, pDomTree -> xNdx, pOrgDomTree -> xNdx) ; av_push (pDomTree -> pDependsOn, SvREFCNT_inc (pOrgDomTree -> pDomTreeSV)) ; pDomTree -> xFilename = pOrgDomTree -> xFilename ; ArrayClone (a, &pOrgDomTree -> pLookup, &pDomTree -> pLookup) ; ArrayClone (a, &pOrgDomTree -> pCheckpoints, &pDomTree -> pCheckpoints) ; if ((pDomTree -> pSV = pOrgDomTree -> pSV)) SvREFCNT_inc (pDomTree -> pSV) ; pDocument = Node_self (pDomTree, pDomTree -> xDocument) ; if (bForceDocFraq || pDocument -> nType == ntypDocumentFraq) { tAttrData * pAttr; pDocument = Node_selfCloneNode (a, pDomTree, pDocument, 0, 1) ; pAttr = Element_selfSetAttribut (a, pDomTree, pDocument, 0, NULL, xDomTreeAttr, (char *)&pDomTree -> xNdx, sizeof (pDomTree -> xNdx)) ; pAttr -> bFlags = aflgOK ; /* reset string value flag */ pDomTree -> xDocument = pDocument -> xNdx ; pDocument -> nType = ntypDocumentFraq ; if (pDocument -> nText != xDocumentFraq) { NdxStringFree (a, pDocument -> nText) ; pDocument -> nText = xDocumentFraq ; NdxStringRefcntInc (a, xDocumentFraq) ; } } *pNewDomTree = pDomTree ; return pDomTree -> xNdx ; } /*--------------------------------------------------------------------------- * DomTree_checkpoint */ /*! * * \_en * Compare checkpoint from program execution with list build during * compilation and change the DomTree and repeat level according to the * program flow * * @param r Embperl request data * @param xDomTree current DomTree we are working on * @param nRunCheckpoint Number of checkpoint that was just executed * \endif * * \_de * Vergeleicht den Checkpoint von der Programmausf?hrung mit dem Checkpoint * beim Compilieren und ?ndert den DomTree entsprechend dem Programmflu? ab * * @param r Embperl Requestdaten * @param xDomTree akuteller DomTree der bearbeitet wird * @param nRunCheckpoint Nummer des Checkpoints der gerade abgearbeitet * wurde * \endif * * ------------------------------------------------------------------------ */ void DomTree_checkpoint (tReq * r, tIndex nRunCheckpoint) { epTHX_ tApp * a = r -> pApp ; tIndex nCompileCheckpoint = r -> Component.nCurrCheckpoint ; tDomTree * pDomTree = DomTree_self (r -> Component.xCurrDomTree) ; tDomTreeCheckpoint * pCheckpoints = pDomTree -> pCheckpoints ; tDomTreeCheckpointStatus * pCheckpointStatus = &pDomTree -> pCheckpointStatus[nRunCheckpoint] ; if (r -> Component.nPhase != phRun) return ; if (!pDomTree -> xDocument) { /* first checkpoint in sub -> set xDocument */ tNodeData * pDocument ; tAttrData * pAttr ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: Start Sub DomTree=%d xx -> %d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nRunCheckpoint, sv_count) ; pDomTree -> xDocument = pCheckpoints[nRunCheckpoint].xNode ; pDocument = Node_self (pDomTree, pDomTree -> xDocument) ; pAttr = Element_selfSetAttribut (a, pDomTree, pDocument, 0, NULL, xDomTreeAttr, (char *)&pDomTree -> xNdx, sizeof (pDomTree -> xNdx)) ; pAttr -> bFlags = aflgOK ; /* reset string value flag */ pDocument = Node_self (pDomTree, pDomTree -> xDocument) ; pDocument -> nType = ntypDocumentFraq ; if (pDocument -> nText != xDocumentFraq) { NdxStringFree (a, pDocument -> nText) ; pDocument -> nText = xDocumentFraq ; NdxStringRefcntInc (a, xDocumentFraq) ; } r -> Component.nCurrCheckpoint = nRunCheckpoint+1 ; r -> Component.nCurrRepeatLevel = 0 ; return ; } r -> Component.bSubNotEmpty = 1 ; pCheckpointStatus -> nRepeatLevel = r -> Component.nCurrRepeatLevel ; pCheckpointStatus -> nCompileCheckpoint = nCompileCheckpoint ; pCheckpointStatus -> xJumpFromNode = 0 ; if (nRunCheckpoint == nCompileCheckpoint) { if (pCheckpoints[nCompileCheckpoint].xNode != -1) { tNodeData * pCompileNode = Node_selfLevel (a, pDomTree, pCheckpoints[nCompileCheckpoint].xNode, r -> Component.nCurrRepeatLevel) ; tNodeData * pPrevNode = Node_selfPreviousSibling (a, pDomTree, pCompileNode, r -> Component.nCurrRepeatLevel) ; if (pPrevNode && pPrevNode -> xNext != pCompileNode -> xNdx) { pPrevNode = Node_selfCondCloneNode (a, pDomTree, pPrevNode, r -> Component.nCurrRepeatLevel) ; pPrevNode -> xNext = pCompileNode -> xNdx ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: end of loop DomTree=%d Index=%d Node=%d(%d) RepeatLevel=%d Line=%d -> Index=%d Node=%d(%d) Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), r -> Component.nCurrRepeatLevel, pPrevNode -> nLinenumber, nRunCheckpoint, pCompileNode -> xNdx, xNode_selfLevelNull(pDomTree,pCompileNode), pCompileNode -> nLinenumber, sv_count) ; } } if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: ok DomTree=%d %d -> %d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, nRunCheckpoint, sv_count) ; r -> Component.nCurrCheckpoint++ ; return ; } if (nRunCheckpoint > nCompileCheckpoint) { tNodeData * pCompileNode = Node_selfLevel (a, pDomTree, pCheckpoints[nCompileCheckpoint].xNode, r -> Component.nCurrRepeatLevel) ; if (pCheckpoints[nRunCheckpoint].xNode == -1) { pCompileNode = Node_selfCondCloneNode (a, pDomTree, pCompileNode , r -> Component.nCurrRepeatLevel) ; pCompileNode -> bFlags |= nflgStopOutput ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: stop output DomTree=%d Index=%d Node=%d(%d) Line=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pCompileNode -> xNdx, xNode_selfLevelNull(pDomTree,pCompileNode), pCompileNode -> nLinenumber) ; return ; } else { tNodeData * pRunNode = Node_selfLevel (a, pDomTree, pCheckpoints[nRunCheckpoint].xNode, r -> Component.nCurrRepeatLevel) ; tNodeData * pPrevNode = Node_selfPreviousSibling (a, pDomTree, pCompileNode, r -> Component.nCurrRepeatLevel) ; tNodeData * pCompileParent = NodeAttr_selfParentNode (pDomTree, pCompileNode, r -> Component.nCurrRepeatLevel) ; tNodeData * pRunParent = NodeAttr_selfParentNode (pDomTree, pRunNode, r -> Component.nCurrRepeatLevel) ; if (pPrevNode) pPrevNode = Node_selfCondCloneNode (a, pDomTree, pPrevNode, r -> Component.nCurrRepeatLevel) ; else { pPrevNode = Node_selfCondCloneNode (a, pDomTree, pCompileNode, r -> Component.nCurrRepeatLevel) ; pPrevNode -> bFlags |= nflgIgnore ; } if (pCompileParent -> xNdx == pRunParent -> xNdx ) { pRunNode = Node_selfCondCloneNode (a, pDomTree, pRunNode, r -> Component.nCurrRepeatLevel) ; pRunNode -> xPrev = pPrevNode -> xNdx ; pPrevNode -> xNext = pRunNode -> xNdx ; pRunNode -> bFlags |= nflgNewLevelPrev ; pPrevNode -> bFlags |= nflgNewLevelNext ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump forward DomTree=%d Index=%d Node=%d(%d) Line=%d -> Index=%d Node=%d(%d) Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree,pRunNode), pRunNode -> nLinenumber, sv_count) ; } else if (pCompileParent && pRunParent) { tNodeData * pCompileParent2 = NodeAttr_selfParentNode (pDomTree, pCompileParent, r -> Component.nCurrRepeatLevel) ; tNodeData * pRunParent2 = NodeAttr_selfParentNode (pDomTree, pRunParent, r -> Component.nCurrRepeatLevel) ; if (pCompileParent2 && pCompileParent2 -> xNdx == pRunParent -> xNdx) { pPrevNode = Node_selfCondCloneNode (a, pDomTree, pCompileParent, r -> Component.nCurrRepeatLevel) ; pRunNode = Node_selfCondCloneNode (a, pDomTree, pRunNode, r -> Component.nCurrRepeatLevel) ; pRunNode -> xPrev = pPrevNode -> xNdx ; pPrevNode -> xNext = pRunNode -> xNdx ; pPrevNode -> xChilds = 0 ; pRunNode -> bFlags |= nflgNewLevelPrev ; pPrevNode -> bFlags |= nflgNewLevelNext ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump forward last child DomTree=%d Index=%d Node=%d(%d) Line=%d -> Index=%d Node=%d(%d) Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree,pRunNode), pRunNode -> nLinenumber, sv_count) ; } else if (pCompileParent2 && pRunParent2 && pCompileParent2 -> xNdx == pRunParent2 -> xNdx ) { if (pRunParent -> nType != ntypAttr && pCompileParent -> nType != ntypAttr) { pRunParent = Node_selfCondCloneNode (a, pDomTree, pRunParent, r -> Component.nCurrRepeatLevel) ; pCompileParent = Node_selfCondCloneNode (a, pDomTree, pCompileParent, r -> Component.nCurrRepeatLevel) ; pRunParent -> xPrev = pCompileParent -> xNdx ; pCompileParent -> xNext = pRunParent -> xNdx ; pRunParent -> bFlags |= nflgNewLevelPrev ; pCompileParent -> bFlags |= nflgNewLevelNext ; } else { int nCompile = Attr_selfAttrNum(((tAttrData *)pCompileParent)) ; int nRun = Attr_selfAttrNum(((tAttrData *)pRunParent)) ; int i ; pCompileParent2 = Node_selfLevel (a, pDomTree, pCompileParent2 -> xNdx, r -> Component.nCurrRepeatLevel) ; pCompileParent2 = Node_selfCondCloneNode (a, pDomTree, pCompileParent2, r -> Component.nCurrRepeatLevel) ; for (i = nRun - 1 ; i > nCompile; i--) { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) { tAttrData * pAttr = Element_selfGetNthAttribut (a, pDomTree, pCompileParent2, i) ; lprintf (a, "[%d]Checkpoint: remove attr #%d flags=%x attr=%d node=%d\n", a -> pThread -> nPid, i, pAttr -> bFlags, pAttr ->xNdx, pCompileParent2 -> xNdx) ; } Element_selfRemoveNthAttribut (a, pDomTree, pCompileParent2, r -> Component.nCurrRepeatLevel, i) ; } } pPrevNode -> xNext = Node_selfFirstChild (a, pDomTree, pCompileParent, r -> Component.nCurrRepeatLevel) -> xNdx ; pPrevNode -> bFlags |= nflgNewLevelNext ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump forward2 DomTree=%d Index=%d Node=%d(%d),%d,%d Line=%d -> Index=%d Node=%d(%d),%d,%d Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), pCompileParent -> xNdx, pCompileParent2?pCompileParent2 -> xNdx:-1, pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree,pRunNode), pRunParent -> xNdx, pRunParent2?pRunParent2 -> xNdx:-1, pRunNode -> nLinenumber, sv_count) ; } else { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump forward2 DomTree=%d Index=%d Node=%d(%d),%d,%d Line=%d -> Index=%d Node=%d(%d),%d,%d Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), pCompileParent -> xNdx, pCompileParent2?pCompileParent2 -> xNdx:-1, pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree,pRunNode), pRunParent -> xNdx, pRunParent2?pRunParent2 -> xNdx:-1, pRunNode -> nLinenumber, sv_count) ; Perl_croak(aTHX_ "Unstructured forward jump, %s. Start and End (Line %d - Line %d) of block does not match.", DomTree_filename(r -> Component.xCurrDomTree), pPrevNode -> nLinenumber, pRunNode -> nLinenumber) ; } } else { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump forward DomTree=%d Index=%d Node=%d Line=%d -> Index=%d Node=%d Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, pRunNode -> nLinenumber, sv_count) ; Perl_croak(aTHX_ "Unstructured forward jump, %s. Start and End (Line %d - Line %d) of block does not match.", DomTree_filename(r -> Component.xCurrDomTree), pPrevNode -> nLinenumber, pRunNode -> nLinenumber) ; } r -> Component.nCurrCheckpoint = nRunCheckpoint + 1 ; return ; } } { tNodeData * pCompileNode = Node_selfLevel (a, pDomTree, pCheckpoints[nCompileCheckpoint].xNode, r -> Component.nCurrRepeatLevel) ; tNodeData * pRunNode = Node_selfLevel (a, pDomTree, pCheckpoints[nRunCheckpoint].xNode, (tRepeatLevel)(r -> Component.nCurrRepeatLevel+1)) ; tNodeData * pPrevNode = Node_selfPreviousSibling (a, pDomTree, pCompileNode, r -> Component.nCurrRepeatLevel) ; tNodeData * pCompileParent = NodeAttr_selfParentNode (pDomTree, pCompileNode, r -> Component.nCurrRepeatLevel) ; tNodeData * pCompileParent2= NodeAttr_selfParentNode (pDomTree, pCompileParent, r -> Component.nCurrRepeatLevel) ; tNodeData * pRunParent = NodeAttr_selfParentNode (pDomTree, pRunNode, r -> Component.nCurrRepeatLevel) ; tNodeData * pRunParent2 = NodeAttr_selfParentNode (pDomTree, pRunParent, r -> Component.nCurrRepeatLevel) ; if (pPrevNode) pPrevNode = Node_selfCondCloneNode (a, pDomTree, pPrevNode, r -> Component.nCurrRepeatLevel) ; else { pPrevNode = Node_selfCondCloneNode (a, pDomTree, pCompileNode, r -> Component.nCurrRepeatLevel) ; pPrevNode -> bFlags |= nflgIgnore ; } if (pCompileParent -> xNdx == pRunParent -> xNdx) { r -> Component.nCurrRepeatLevel++ ; pRunNode = Node_selfCondCloneNode (a, pDomTree, pRunNode, r -> Component.nCurrRepeatLevel) ; pRunNode -> xPrev = pPrevNode -> xNdx ; pPrevNode -> xNext = pRunNode -> xNdx ; pRunNode -> bFlags |= nflgNewLevelPrev ; pPrevNode -> bFlags |= nflgNewLevelNext ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump backward DomTree=%d Index=%d Node=%d(%d) RepeatLevel=%d Line=%d -> Index=%d Node=%d(%d) Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree, pPrevNode), r -> Component.nCurrRepeatLevel, pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree, pRunNode), pRunNode -> nLinenumber, sv_count) ; } else if (pRunParent2 && pCompileParent2 && pCompileParent2 -> xNdx == pRunParent2 -> xNdx) { pPrevNode = Node_selfPreviousSibling (a, pDomTree, pCompileParent, r -> Component.nCurrRepeatLevel) ; if (pPrevNode) pPrevNode = Node_selfCondCloneNode (a, pDomTree, pPrevNode, r -> Component.nCurrRepeatLevel) ; else { pPrevNode = Node_selfCondCloneNode (a, pDomTree, pCompileParent, r -> Component.nCurrRepeatLevel) ; pPrevNode -> bFlags |= nflgIgnore ; } r -> Component.nCurrRepeatLevel++ ; pRunNode = Node_selfCondCloneNode (a, pDomTree, pRunParent, r -> Component.nCurrRepeatLevel) ; pRunNode -> xPrev = pPrevNode -> xNdx ; pPrevNode -> xNext = pRunNode -> xNdx ; pRunNode -> bFlags |= nflgNewLevelPrev ; pPrevNode -> bFlags |= nflgNewLevelNext ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump backward parent DomTree=%d Index=%d Node=%d RepeatLevel=%d Line=%d -> Index=%d Node=%d Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, r -> Component.nCurrRepeatLevel, pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, pRunNode -> nLinenumber, sv_count) ; } else if (xNode_selfLevelNull(pDomTree,pPrevNode) == xNode_selfLevelNull(pDomTree,pRunParent)) { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump backward2 DomTree=%d Index=%d Node=%d(%d),%d(%d) Line=%d -> Index=%d Node=%d(%d),%d(%d) Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), pCompileParent -> xNdx, xNode_selfLevelNull(pDomTree,pCompileParent), pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree,pRunNode), pRunParent -> xNdx, xNode_selfLevelNull(pDomTree,pRunParent), pRunNode -> nLinenumber, sv_count) ; pPrevNode = Node_selfLastChild (a, pDomTree, pPrevNode, r -> Component.nCurrRepeatLevel) ; pPrevNode = Node_selfCondCloneNode (a, pDomTree, pPrevNode, r -> Component.nCurrRepeatLevel) ; r -> Component.nCurrRepeatLevel++ ; pRunNode = Node_selfCondCloneNode (a, pDomTree, pRunNode, r -> Component.nCurrRepeatLevel) ; pRunNode -> xPrev = pPrevNode -> xNdx ; pPrevNode -> xNext = pRunNode -> xNdx ; pRunNode -> bFlags |= nflgNewLevelPrev ; pPrevNode -> bFlags |= nflgNewLevelNext ; pCheckpointStatus -> xJumpFromNode = pPrevNode -> xNdx ; pCheckpointStatus -> xJumpToNode = pRunNode -> xNdx ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump backward last child DomTree=%d Index=%d Node=%d(%d) RepeatLevel=%d Line=%d -> Index=%d Node=%d(%d) Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), r -> Component.nCurrRepeatLevel, pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree,pRunNode), pRunNode -> nLinenumber, sv_count) ; } else if (pRunParent2 && xNode_selfLevelNull(pDomTree,pPrevNode) == xNode_selfLevelNull(pDomTree,pRunParent2)) { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump backward2 DomTree=%d Index=%d Node=%d(%d),%d(%d) Line=%d -> Index=%d Node=%d(%d),%d(%d) Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), pCompileParent -> xNdx, xNode_selfLevelNull(pDomTree,pCompileParent), pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree,pRunNode), pRunParent -> xNdx, xNode_selfLevelNull(pDomTree,pRunParent), pRunNode -> nLinenumber, sv_count) ; pPrevNode = Node_selfLastChild (a, pDomTree, pPrevNode, r -> Component.nCurrRepeatLevel) ; pPrevNode = Node_selfLastChild (a, pDomTree, pPrevNode, r -> Component.nCurrRepeatLevel) ; pPrevNode = Node_selfCondCloneNode (a, pDomTree, pPrevNode, r -> Component.nCurrRepeatLevel) ; r -> Component.nCurrRepeatLevel++ ; pRunNode = Node_selfCondCloneNode (a, pDomTree, pRunNode, r -> Component.nCurrRepeatLevel) ; pRunNode -> xPrev = pPrevNode -> xNdx ; pPrevNode -> xNext = pRunNode -> xNdx ; pRunNode -> bFlags |= nflgNewLevelPrev ; pPrevNode -> bFlags |= nflgNewLevelNext ; pCheckpointStatus -> xJumpFromNode = pPrevNode -> xNdx ; pCheckpointStatus -> xJumpToNode = pRunNode -> xNdx ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump backward last child 2 DomTree=%d Index=%d Node=%d(%d) RepeatLevel=%d Line=%d -> Index=%d Node=%d(%d) Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), r -> Component.nCurrRepeatLevel, pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree,pRunNode), pRunNode -> nLinenumber, sv_count) ; } else { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: jump backward2 DomTree=%d Index=%d Node=%d(%d),%d(%d) Line=%d -> Index=%d Node=%d(%d),%d(%d) Line=%d SVs=%d\n", a -> pThread -> nPid, r -> Component.xCurrDomTree, nCompileCheckpoint, pPrevNode -> xNdx, xNode_selfLevelNull(pDomTree,pPrevNode), pCompileParent -> xNdx, xNode_selfLevelNull(pDomTree,pCompileParent), pPrevNode -> nLinenumber, nRunCheckpoint, pRunNode -> xNdx, xNode_selfLevelNull(pDomTree,pRunNode), pRunParent -> xNdx, xNode_selfLevelNull(pDomTree,pRunParent), pRunNode -> nLinenumber, sv_count) ; Perl_croak(aTHX_ "Unstructured backward jump, %s. Start and End (Line %d - Line %d) of block does not match.", DomTree_filename(r -> Component.xCurrDomTree), pPrevNode -> nLinenumber, pRunNode -> nLinenumber) ; } } r -> Component.nCurrCheckpoint = nRunCheckpoint + 1 ; } /*--------------------------------------------------------------------------*/ /* */ /* DomTree_discardAfterCheckpoint */ /* */ /*! * * \_en * Discard anything in the tree from the checkpoint given in nRunCheckpoint * * @param r Embperl request data * @param xDomTree current DomTree we are working on * @param nRunCheckpoint Number of checkpoint from on which the output should * discared * \endif * * \_de * * Verwrirft alles ab dem in nRunCheckpoint ?bergebenen Punkt * * @param r Embperl Requestdaten * @param xDomTree akuteller DomTree der bearbeitet wird * @param nRunCheckpoint Nummer des Checkpoints ab dem aller Output * verworfen wird * \endif * * ------------------------------------------------------------------------ */ void DomTree_discardAfterCheckpoint (tReq * r, tIndex nRunCheckpoint) { epTHX_ tApp * a = r -> pApp ; tIndex xDomTree = r -> Component.xCurrDomTree ; tDomTree * pDomTree = DomTree_self (xDomTree) ; tDomTreeCheckpointStatus * pCheckpointStatus = &pDomTree -> pCheckpointStatus[nRunCheckpoint] ; r -> Component.nCurrRepeatLevel = pCheckpointStatus -> nRepeatLevel ; r -> Component.nCurrCheckpoint = pCheckpointStatus -> nCompileCheckpoint ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: discard all from checkpoint=%d DomTree=%d new RepeatLevel=%d new Checkpoint=%d\n", a -> pThread -> nPid, nRunCheckpoint, r -> Component.xCurrDomTree, r -> Component.nCurrRepeatLevel, r -> Component.nCurrCheckpoint) ; if (pCheckpointStatus -> xJumpFromNode) { tNodeData * pLastChild = Node_self (pDomTree, pCheckpointStatus -> xJumpFromNode) ; tNodeData * pParent = Node_self (pDomTree, pLastChild -> xParent) ; tNodeData * pFirstChild = Node_self (pDomTree, pParent -> xChilds) ; if (pCheckpointStatus -> xJumpToNode) { tIndex n = ArrayGetSize (a, pDomTree -> pLookup) ; tIndex i ; for (i = pCheckpointStatus -> xJumpToNode; i < n; i++) { tNodeData * pNode = Node_self (pDomTree, i) ; if (pNode && pNode -> nType != ntypAttr) { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: discard all from checkpoint=%d DomTree=%d remove node %d\n", a -> pThread -> nPid, nRunCheckpoint, r -> Component.xCurrDomTree, i) ; Node_selfRemoveChild (a, pDomTree, pParent -> xNdx, pNode) ; } } } if (pFirstChild) { pFirstChild = Node_selfCondCloneNode (a, pDomTree, pFirstChild, pFirstChild -> nRepeatLevel) ; pFirstChild -> xPrev = pLastChild -> xNdx ; pLastChild -> xNext = pFirstChild -> xNdx ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgCheckpoint) lprintf (a, "[%d]Checkpoint: discard all from table Parent=%d FirstChild=%d LastChild=%d\n", a -> pThread -> nPid, pParent -> xNdx, pFirstChild -> xNdx, pLastChild -> xNdx) ; } } } /* ------------------------------------------------------------------------ interface Node { # NodeType const unsigned short ELEMENT_NODE = 1; const unsigned short ATTRIBUTE_NODE = 2; const unsigned short TEXT_NODE = 3; const unsigned short CDATA_SECTION_NODE = 4; const unsigned short ENTITY_REFERENCE_NODE = 5; const unsigned short ENTITY_NODE = 6; const unsigned short PROCESSING_INSTRUCTION_NODE = 7; const unsigned short COMMENT_NODE = 8; const unsigned short DOCUMENT_NODE = 9; const unsigned short DOCUMENT_TYPE_NODE = 10; const unsigned short DOCUMENT_FRAGMENT_NODE = 11; const unsigned short NOTATION_NODE = 12; readonly attribute DOMString nodeName; attribute DOMString nodeValue; # raises(DOMException) on setting # raises(DOMException) on retrieval readonly attribute unsigned short nodeType; readonly attribute Node parentNode; readonly attribute NodeList childNodes; readonly attribute Node firstChild; readonly attribute Node lastChild; readonly attribute Node previousSibling; readonly attribute Node nextSibling; readonly attribute NamedNodeMap attributes; # Modified in DOM Level 2: readonly attribute Document ownerDocument; Node insertBefore(in Node newChild, in Node refChild) raises(DOMException); Node replaceChild(in Node newChild, in Node oldChild) raises(DOMException); Node removeChild(in Node oldChild) raises(DOMException); Node appendChild(in Node newChild) raises(DOMException); boolean hasChildNodes(); Node cloneNode(in boolean deep); # Introduced in DOM Level 2: void normalize(); # Introduced in DOM Level 2: boolean supports(in DOMString feature, in DOMString version); # Introduced in DOM Level 2: readonly attribute DOMString namespaceURI; # Introduced in DOM Level 2: attribute DOMString prefix; # raises(DOMException) on setting # Introduced in DOM Level 2: readonly attribute DOMString localName; }; */ /* ------------------------------------------------------------------------ */ /* */ /* Node_selfLevelItem */ /* */ /*! * \_en * returns the node with index xNode and repeat level nLevel. If there is * node node in this repeat level, the node from the source DomTree with * level zero is returned * * @param pDomTree current DomTree we are working on * @param xNode node index * @param nRepeatLevel repeat level * * @note Don't use this function directly, use the macro Node_selfLevel * \endif * * \_de * Liefert den Node mit dem Index xNode und dem RepeatLevel nLevel. Wenn * dieser nicht existiert wird der Node mit Index Null aus dem Source * DomTree zur?ck geliefert * * @param pDomTree DomTree der den Node enth?lt * @param pNode Node Index * @param nRepeatLevel RepeatLevel * * @note Dieser Funtkion sollte nicht direkt aufgerufen werden, sondern * das Makro Node_selfLevel * \endif * * ------------------------------------------------------------------------ */ tNodeData * Node_selfLevelItem (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xNode, /*in*/ tRepeatLevel nLevel) { tRepeatLevelLookup * pLookupLevelNode ; tLookupItem * pLookup ; pLookupLevelNode = pDomTree -> pLookup[xNode].pLookupLevel ; if (pLookupLevelNode) { register tRepeatLevelLookupItem * pLookupLevelNodeLevel = &pLookupLevelNode -> items[nLevel & pLookupLevelNode -> nMask] ; register tNodeData * pLnNode = pLookupLevelNodeLevel -> pNode ; if (!pLnNode) { pLookup = DomTree_self(pDomTree -> xSourceNdx) -> pLookup ; if (ArrayGetSize(a, pLookup) > xNode) return ((struct tNodeData *)(pLookup[xNode].pLookup)) ; else return ((struct tNodeData *)(pDomTree -> pLookup[xNode].pLookup)) ; } if (pLnNode -> nRepeatLevel == nLevel) return pLnNode ; while ((pLookupLevelNodeLevel = pLookupLevelNodeLevel -> pNext)) { pLnNode = pLookupLevelNodeLevel -> pNode ; if (pLnNode -> nRepeatLevel == nLevel) return pLnNode ; } } pLookup = DomTree_self(pDomTree -> xSourceNdx) -> pLookup ; if (ArrayGetSize(a, pLookup) > xNode) return ((struct tNodeData *)(pLookup[xNode].pLookup)) ; return ((struct tNodeData *)(pDomTree -> pLookup[xNode].pLookup)) ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_cloneNode */ /* */ /*! * \_en * clones a node * * @param pDomTree current DomTree we are working on * @param pNode node that should be cloned * @param nRepeatLevel repeat level for new node * @param bDeep determines how children are handled * - 1 clone children also * - 0 clone no children * - -1 clone no attributes and no children * \endif * * \_de * Cloned einen Node * * @param pDomTree DomTree der den Node enth?lt * @param pNode Node der gecloned werden soll * @param nRepeatLevel RepeatLevel f?r neuen Node * @param bDeep legt fest wie Kindelemente behandelt werden * - 1 cloned Kindelemente * - 0 cloned keine Kindelemente * - -1 cloned keine Attribute und keine Kindelemente * \endif * * ------------------------------------------------------------------------ */ tNodeData * Node_selfCloneNode (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ int bDeep) { epaTHX_ int len = sizeof (tNodeData) + (bDeep == -1?0:pNode -> numAttr * sizeof (tAttrData)) ; tNode xNewNode ; tNodeData * pNew ; ASSERT_NODE_VALID(a,pNode) ; if ((pNew = dom_malloc (a, len, &numNodes)) == NULL) return NULL ; memcpy (pNew, pNode, len) ; xNewNode = ArrayAdd (a, &pDomTree -> pLookup, 1) ; pDomTree -> pLookup[xNewNode].pLookup = pNew ; pDomTree -> pLookup[xNewNode].pLookupLevel = NULL ; pNew -> xNdx = xNewNode ; pNew -> xDomTree = pDomTree -> xNdx ; pNew -> nRepeatLevel = nRepeatLevel ; if (pNew -> nText) NdxStringRefcntInc (a, pNew -> nText) ; if (bDeep == -1) pNew -> numAttr = 0 ; else { tAttrData * pAttr = (tAttrData * )(pNew + 1) ; int n = pNew -> numAttr ; while (n) { xNewNode = ArrayAdd (a, &pDomTree -> pLookup, 1) ; pDomTree -> pLookup[xNewNode].pLookup = pAttr ; pDomTree -> pLookup[xNewNode].pLookupLevel = NULL ; pAttr -> xNdx = xNewNode ; if (pAttr -> xName) NdxStringRefcntInc (a, pAttr -> xName) ; if (pAttr -> xValue && (pAttr -> bFlags & aflgAttrValue)) NdxStringRefcntInc (a, pAttr -> xValue) ; n-- ; pAttr++ ; } } if (bDeep < 1) pNew -> xChilds = 0 ; return pNew ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_cloneNode */ /* */ /*! * \_en * clones a node * * @param pDomTree current DomTree we are working on * @param xNode node that should be cloned * @param nRepeatLevel repeat level for new node * @param bDeep determines how children are handled * - 1 clone children also * - 0 clone no children * - -1 clone no attributes and no children * \endif * * \_de * Cloned einen Node * * @param pDomTree DomTree der den Node enth?lt * @param xNode Node der gecloned werden soll * @param nRepeatLevel RepeatLevel f?r neuen Node * @param bDeep legt fest wie Kindelemente behandelt werden * - 1 cloned Kindelemente * - 0 cloned keine Kindelemente * - -1 cloned keine Attribute und keine Kindelemente * \endif * * ------------------------------------------------------------------------ */ tNode Node_cloneNode (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xNode, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ int bDeep) { tNodeData * pNew = Node_selfCloneNode (a, pDomTree, Node_self (pDomTree, xNode), nRepeatLevel, bDeep) ; if (pNew) return pNew -> xNdx ; return 0 ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_selfCondCloneNode */ /* */ /*! * \_en * clone a node if it's part of a different DomTree or has a different * repeat level in preparation for a modification. This is part of the * copy on write stragtegie. As long as a node isn't written to it may * point to another node from which the current DomTree was copied or * within a different repeat level. Before writing to the node this * function has to be called to make sure we are modifing the right node * * @note Most times you will not call this function directly. All functions * that operates on the DomTree makes sure to call this function first * for you * * @param pDomTree current DomTree we are working on * @param pNode node that should be cloned * @param nRepeatLevel repeat level for new node * \endif * * \_de * Cloned einen Node wenn dieser Teil eines anderen DomTree oder eines * anderen RepeatLevel ist. Dies ist Teil der "copy on write" Strategie * solange ein Node nicht beschrieben wird, kann dieser als Zeiger auf * einen anderen Node in einem DomTree oder RepeatLevel aus dem er kopiert * wurde sein. Sobald der Node ge?ndert werden mu?, mu? diese Funktion * aufgerufen werden um sicherzustellen das der korekte Node modifiziert * wird. * * @note In den meisten F?llen ist es nicht n?tig diese Funktion direkt * aufzurufen, da alle Funktionen die den DomTree modifizieren * dies sicherstellen. * * @param pDomTree DomTree der den Node enth?lt * @param pNode Node der gecloned werden soll * @param nRepeatLevel RepeatLevel f?r neuen Node * \endif * * ------------------------------------------------------------------------ */ tNodeData * Node_selfCondCloneNode (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel) { epaTHX_ int len ; tNodeData * pNew ; tAttrData * pAttr ; int n ; tLookupItem * pLookup ; tNode xNdx ; tRepeatLevelLookup * pLookupLevelNode ; tRepeatLevelLookupItem * pLookupLevelNodeLevel ; ASSERT_NODE_VALID(a,pNode) ; if (pNode -> nType == ntypAttr) mydie (a, "Node expected, but Attribute found. Maybe unclosed quote?") ; if (pNode -> xDomTree == pDomTree -> xNdx && pNode -> nRepeatLevel == nRepeatLevel) return pNode ; /* lprintf(a, "selfCondCloneNode 1 node=%d repeatlevel=%d\n", pNode -> xNdx, nRepeatLevel) ; */ if (nRepeatLevel == 0) { pLookup = pDomTree -> pLookup ; len = sizeof (tNodeData) + pNode -> numAttr * sizeof (tAttrData) ; xNdx = pNode -> xNdx ; if ((pLookup[xNdx].pLookup = pNew = dom_malloc (a, len, &numNodes)) == NULL) return NULL ; ASSERT_NODE_VALID(a,pNode) ; memcpy (pNew, pNode, len) ; pNew -> xDomTree = pDomTree -> xNdx ; if (pNew -> nText) NdxStringRefcntInc (a, pNew -> nText) ; pAttr = (tAttrData * )(pNew + 1) ; n = pNew -> numAttr ; while (n) { pLookup[pAttr -> xNdx].pLookup = pAttr ; if (pAttr -> xName) NdxStringRefcntInc (a, pAttr -> xName) ; if (pAttr -> xValue && (pAttr -> bFlags & aflgAttrValue)) NdxStringRefcntInc (a, pAttr -> xValue) ; n-- ; pAttr++ ; } ASSERT_NODE_VALID(a,pNew) ; return pNew ; } if (!(pNew = Node_selfCloneNode (a, pDomTree, pNode, nRepeatLevel, 1))) return NULL ; pLookup = pDomTree -> pLookup ; pLookupLevelNode = pLookup[pNode -> xNdx].pLookupLevel ; if (!pLookupLevelNode) { if ((pLookupLevelNode = pLookup[pNode -> xNdx].pLookupLevel = (tRepeatLevelLookup *)dom_malloc (a, sizeof (tRepeatLevelLookup) + sizeof (tRepeatLevelLookupItem) * (LEVELHASHSIZE - 1), &numLevelLookup)) == NULL) return NULL ; pLookupLevelNode -> nMask = LEVELHASHSIZE - 1 ; pLookupLevelNode -> numItems = LEVELHASHSIZE ; pLookupLevelNode -> xNullNode = pNode -> xNdx ; memset (pLookupLevelNode -> items, 0, sizeof (*pLookupLevelNodeLevel) * LEVELHASHSIZE) ; } pLookup[pNew -> xNdx].pLookupLevel = pLookupLevelNode ; pLookupLevelNodeLevel= &pLookupLevelNode -> items[nRepeatLevel & pLookupLevelNode -> nMask] ; if (pLookupLevelNodeLevel -> pNode) { tRepeatLevelLookupItem * pNewItem = (tRepeatLevelLookupItem *)dom_malloc (a, sizeof (tRepeatLevelLookupItem), &numLevelLookupItem) ; if (!pNewItem) return NULL ; pNewItem -> pNode = pLookupLevelNodeLevel -> pNode ; pNewItem -> pNext = pLookupLevelNodeLevel -> pNext ; pLookupLevelNodeLevel -> pNode = pNew ; pLookupLevelNodeLevel -> pNext = pNewItem ; } else { pLookupLevelNodeLevel -> pNode = pNew ; } ASSERT_NODE_VALID(a,pNew) ; return pNew ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_selfForceLevel */ /* */ /*! * \_en * returns a pointer to a node for a given index and repeat level. If the * node does not exist in the current DomTree or RepeatLevel it is created * * @param pDomTree current DomTree we are working on * @param xNode index for node * @param nRepeatLevel repeat level for node * \endif * * \_de * Liefert einen Zeiger auf eine Node zu einen gegebenen Index und RepeatLevel. * Existiert der Node noch nicht in diesem DomTree oder RepeatLevel wird er * erzeugt * * @param pDomTree DomTree der den Node enth?lt * @param xNode index f?r Node * @param nRepeatLevel RepeatLevel f?r Node * \endif * * ------------------------------------------------------------------------ */ tNodeData * Node_selfForceLevel(/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xNode, /*in*/ tRepeatLevel nRepeatLevel) { tNodeData * pNode = Node_selfLevel (a, pDomTree, xNode, nRepeatLevel) ; return Node_selfCondCloneNode (a, pDomTree, pNode, nRepeatLevel) ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_newAndAppend */ /* */ /* Create new node and append it to parent */ /* */ /* ------------------------------------------------------------------------ */ tNodeData * Node_newAndAppend (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tIndex xParent, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ tIndex * pxChilds, /*in*/ tSInt32 nLinenumber, /*in*/ tSInt32 nSize) { tIndex xChilds = pxChilds?*pxChilds:0 ; tNodeData * pNewChild ; tIndex xNdx = ArrayAdd (a, &pDomTree -> pLookup, 1) ; if (nSize == 0) nSize = sizeof (tNodeData) ; if ((pDomTree -> pLookup[xNdx].pLookup = pNewChild = dom_malloc (a, nSize, &numNodes)) == NULL) return NULL ; pDomTree -> pLookup[xNdx].pLookupLevel = NULL ; memset (pNewChild, 0, nSize) ; pNewChild -> xParent = xParent ; pNewChild -> xNdx = xNdx ; pNewChild -> nLinenumber = (tUInt16)nLinenumber ; pNewChild -> bFlags = nflgOK ; pNewChild -> xDomTree = pDomTree -> xNdx ; pNewChild -> nRepeatLevel = nRepeatLevel ; if (xChilds) { /* --- attribute has already children, get the first and last one --- */ tNodeData * pFirstChild = Node_selfLevel (a, pDomTree, xChilds, nRepeatLevel) ; tNodeData * pLastChild = Node_selfLevel (a, pDomTree, pFirstChild -> xPrev, nRepeatLevel) ; pFirstChild = Node_selfCondCloneNode (a, pDomTree, pFirstChild, nRepeatLevel) ; pLastChild = Node_selfCondCloneNode (a, pDomTree, pLastChild, nRepeatLevel) ; pNewChild -> xNext = pFirstChild -> xNdx ; pNewChild -> xPrev = pLastChild -> xNdx ; pFirstChild -> xPrev = xNdx ; pLastChild -> xNext = xNdx ; } else /* --- attribute has no children, get a new one --- */ { pNewChild -> xPrev = xNdx ; pNewChild -> xNext = xNdx ; if (pxChilds) *pxChilds = xNdx ; } return pNewChild ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_selfExpand */ /* */ /*! * \_en * Expand a node to hold more attributes * * @param pNode Node to expand * @param numOldAttr number of Attributes in the old node that must * be relocated (-1 to take form pNode) * @param numNewAttr new number of attributes * @return The node with space for numNewAttr * * @warning The node may have a new memory address after this function * \endif * * \_de * Expandiert einen Node um mehr Attribute aufzunehmen * * @param pNode Node der expandiert werden soll * @param numOldAttr Anzahl der Attribute die Relokiert werden m?ssen * (-1 um alle Attribute zu relokieren) * @param numNewAttr Neue Anzahl der Attribute * @return Den Node mit platz f?r numNewAttr * * @warning Der Node liegt nach dem Aufruf dieser Funktion u.U. an * anderen Speicheradresse * \endif * * ------------------------------------------------------------------------ */ tNodeData * Node_selfExpand (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNodeData * pNode, /*in*/ tUInt16 numOldAttr, /*in*/ tUInt16 numNewAttr) { tNodeData * pNewChild ; tNode xNdx = pNode -> xNdx ; int nSize = sizeof (tNodeData) + numNewAttr * sizeof (tAttrData) ; if ((pNewChild = dom_realloc (a, pNode, nSize)) == NULL) return NULL ; if (pNewChild != pNode) { tAttrData * pAttr = ((struct tAttrData * )(pNewChild + 1)) ; tLookupItem * pLookup = pDomTree -> pLookup ; tRepeatLevelLookup *pLookupLevelNode= pLookup[xNdx].pLookupLevel ; if (numOldAttr == (tUInt16) -1) numOldAttr = pNewChild -> numAttr ; pLookup[xNdx].pLookup = pNewChild ; if (pLookupLevelNode) { tRepeatLevel nLevel = pNewChild -> nRepeatLevel ; register tRepeatLevelLookupItem * pLookupLevelNodeLevel = &pLookupLevelNode -> items[nLevel & pLookupLevelNode -> nMask] ; register tNodeData * pLnNode = pLookupLevelNodeLevel -> pNode ; if (pLnNode && pLnNode -> nRepeatLevel == nLevel) pLookupLevelNodeLevel -> pNode = pNewChild ; else { while ((pLookupLevelNodeLevel = pLookupLevelNodeLevel -> pNext)) { pLnNode = pLookupLevelNodeLevel -> pNode ; if (pLnNode -> nRepeatLevel == nLevel) { pLookupLevelNodeLevel -> pNode = pNewChild ; break ; } } } } while (numOldAttr--) { pLookup[pAttr -> xNdx].pLookup = pAttr ; pLookup[pAttr -> xNdx].pLookupLevel = NULL ; pAttr++ ; } } return pNewChild ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_appendChild */ /* */ /* Append a child node to a parent node */ /* */ /* ------------------------------------------------------------------------ */ tNode Node_appendChild (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xParent, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ tNodeType nType, /*in*/ int bForceAttrValue, /*in*/ const char * sText, /*in*/ int nTextLen, /*in*/ int nLevel, /*in*/ int nLinenumber, /*in*/ const char * sLogMsg) { epaTHX_ tNodeData * pParent; tIndex xText ; pParent = Node_self (pDomTree, xParent) ; /* --- clone node if it doesn't live in the current DomTree -- */ if (pParent) { if (pParent -> nType == ntypAttr) { tNodeData * pNode = Attr_selfNode (((tAttrData *)pParent)) ; pNode = Node_selfCondCloneNode (a, pDomTree, pNode, nRepeatLevel) ; pParent = Node_self (pDomTree, xParent) ; /* relookup in case of node move */ } else { pParent = Node_selfCondCloneNode (a, pDomTree, pParent, nRepeatLevel) ; } } if (nType == ntypAttr) { /* add new attribute to node */ struct tAttrData * pNew ; tIndex xNdx ; pParent = Node_selfExpand (a, pDomTree, pParent, (tUInt16)-1, (tUInt16)(pParent -> numAttr + 1)) ; pNew = ((struct tAttrData * )(pParent + 1)) + pParent -> numAttr ; xNdx = ArrayAdd (a, &pDomTree -> pLookup, 1) ; pDomTree -> pLookup[xNdx].pLookup = (struct tNodeData *)pNew ; pDomTree -> pLookup[xNdx].pLookupLevel = NULL ; pNew -> xName = sText?String2NdxNoInc (a, sText, nTextLen):nTextLen ; NdxStringRefcntInc (a, pNew -> xName) ; pNew -> xValue = 0 ; pNew -> bFlags = aflgOK ; pNew -> nType = nType ; pNew -> xNdx = xNdx ; pNew -> nNodeOffset = ((tUInt8 *)pNew) - ((tUInt8 *)pParent) ; pParent -> numAttr++ ; numAttr++ ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgParse) lprintf (a, "[%d]PARSE: AddNode: +%02d %*s Attribut parent=%d node=%d type=%d text=%*.*s (#%d) %s\n", a -> pThread -> nPid, nLevel, nLevel * 2, "", xParent, xNdx, nType, sText?nTextLen:0, sText?nTextLen:1000, sText?sText:Ndx2String (nTextLen), sText?String2NdxNoInc (a, sText, nTextLen):nTextLen, sLogMsg?sLogMsg:"") ; return xNdx ; } if ((bForceAttrValue || nType == ntypAttrValue) && (pParent -> nType != ntypAttr || (pParent -> bFlags & aflgAttrChilds) == 0)) { /* --- add value of attribute, to non attribute parent node */ /* first add dummy attribute to parent with xNoName as name index */ /* if this attribute already exist, append the new value as new _child_ */ /* to that attribute. This means, that an attribute can have multiple */ /* child(values), in which case we set the aflgAttrChilds flag */ struct tAttrData * pNew = (struct tAttrData * )pParent ; int bAddChild = 0 ; if (pNew -> nType != ntypAttr) { /* --- parent is not a attribute --- */ if (nType == ntypAttrValue) { int i ; for (i = 0; i < nTextLen; i++) { if (!isspace (sText[i])) break ; } if (i == nTextLen) return 1 ; /* do not add only spaces as cdata inside a tag */ } pNew = ((tAttrData *)(pParent + 1)) + pParent -> numAttr - 1 ; /* get last attribute of node */ if (pParent -> numAttr == 0 || pNew -> xName != xNoName || bForceAttrValue > 1) { /* --- add dummy attribute --- */ if (!(xParent = Node_appendChild (a, pDomTree, xParent, nRepeatLevel, ntypAttr, 0, NULL, xNoName, nLevel, nLinenumber, ""))) return 0 ; nLevel++ ; pNew = Attr_self (pDomTree, xParent) ; } else { /* --- dummy attribute already exist, reuse it --- */ xParent = pNew -> xNdx ; bAddChild = 1 ; nLevel++ ; } } if (!bAddChild && !bForceAttrValue) { /* we have an simple attribute, now put the value into it */ pNew -> xValue = sText?String2NdxNoInc (a, sText, nTextLen):nTextLen ; NdxStringRefcntInc (a, pNew -> xValue) ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgParse) lprintf (a, "[%d]PARSE: AddNode: +%02d %*s AttributValue parent=%d node=%d type=%d text=%*.*s (#%d) %s\n", a -> pThread -> nPid, nLevel, nLevel * 2, "", xParent, pNew -> xNdx, nType, sText?nTextLen:0, sText?nTextLen:1000, sText?sText:Ndx2String (nTextLen), sText?String2NdxNoInc (a, sText, nTextLen):nTextLen, sLogMsg?sLogMsg:"") ; pNew -> bFlags |= aflgAttrValue ; return xParent ; } else /* --- we have to add a new child to the attribute, so set the attribute as parent --- */ pParent = (tNodeData *)pNew ; } /* --- if we come we here we have add a new child node --- */ { struct tNodeData * pNew ; tIndex xOldValue = 0 ; if (pParent && pParent -> nType == ntypAttr) { /* --- we add a new child to an attribute --- */ if (((tAttrData *)pParent) -> bFlags & aflgAttrValue) { xOldValue = ((tAttrData *)pParent) -> xValue ; ((tAttrData *)pParent) -> xValue = 0 ; pNew = Node_newAndAppend (a, pDomTree, xParent, nRepeatLevel, &(((tAttrData *)pParent) -> xValue), nLinenumber, 0) ; pNew -> nType = ntypAttrValue ; pNew -> nText = xOldValue ; } ((tAttrData *)pParent) -> bFlags &= ~aflgAttrValue ; ((tAttrData *)pParent) -> bFlags |= aflgAttrChilds ; pNew = Node_newAndAppend (a, pDomTree, xParent, nRepeatLevel, &(((tAttrData *)pParent) -> xValue), nLinenumber, 0) ; } else { pNew = Node_newAndAppend (a, pDomTree, xParent, nRepeatLevel, pParent?&(pParent -> xChilds):NULL, nLinenumber, 0) ; } if (sText) xText = String2Ndx (a, sText, nTextLen) ; else { NdxStringRefcntInc(a, nTextLen) ; xText = nTextLen ; } pNew -> nType = nType ; pNew -> nText = xText ; if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgParse) lprintf (a, "[%d]PARSE: AddNode: +%02d %*s Element parent=%d node=%d type=%d text=%*.*s (#%d) %s\n", a -> pThread -> nPid, nLevel, nLevel * 2, "", xParent, pNew -> xNdx, nType, sText?nTextLen:0, sText?nTextLen:1000, sText?sText:Ndx2String (nTextLen), sText?String2NdxNoInc (a, sText, nTextLen):nTextLen, sLogMsg?sLogMsg:"") ; return pNew -> xNdx ; } } /* ------------------------------------------------------------------------ */ /* */ /* Node_removeChild */ /* */ /* Remove a child node */ /* */ /* ------------------------------------------------------------------------ */ tNodeData * Node_selfRemoveChild (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xParent, /*in*/ tNodeData * pChild) { struct tNodeData * pParent = Node_self (pDomTree, pChild -> xParent) ; if (pChild -> xNext == pChild -> xNdx) { /* --- the only child --- */ pParent -> xChilds = 0 ; } else { tNodeData * pPrev = Node_self (pDomTree, pChild -> xPrev) ; tNodeData * pNext = Node_self (pDomTree, pChild -> xNext) ; if (pParent -> xChilds == pChild -> xNdx) { /* --- the first child --- */ pParent -> xChilds = pChild -> xNext ; } if (pPrev && pPrev -> xNext == pChild -> xNdx) { tNodeData * pNextL = Node_selfLevel (a, pDomTree, pChild -> xNext, pChild -> nRepeatLevel) ; pPrev -> xNext = pNextL -> xNdx ; } if (pNext && pNext -> xPrev == pChild -> xNdx) { tNodeData * pPrevL = Node_selfLevel (a, pDomTree, pChild -> xPrev, pChild -> nRepeatLevel) ; pNext -> xPrev = pPrevL -> xNdx ; } } pDomTree -> pLookup[pChild -> xNdx].pLookup = NULL ; { tRepeatLevelLookup * pLookupLevelNode = pDomTree -> pLookup[pChild -> xNdx].pLookupLevel ; if (pLookupLevelNode) { register tRepeatLevelLookupItem * pLookupLevelNodeLevel = &pLookupLevelNode -> items[pChild -> nRepeatLevel & pLookupLevelNode -> nMask] ; tRepeatLevelLookupItem * pLast = NULL ; while (pLookupLevelNodeLevel && pLookupLevelNodeLevel -> pNode != pChild) { pLast = pLookupLevelNodeLevel ; pLookupLevelNodeLevel = pLookupLevelNodeLevel -> pNext ; } if (pLookupLevelNodeLevel) { if (pLast) { pLast -> pNext = pLookupLevelNodeLevel -> pNext ; dom_free_size (a, pLookupLevelNodeLevel, sizeof (tRepeatLevelLookupItem), &numLevelLookupItem) ; } else if (pLookupLevelNodeLevel -> pNext) { pLast = pLookupLevelNodeLevel -> pNext ; pLookupLevelNodeLevel -> pNode = pLast -> pNode ; pLookupLevelNodeLevel -> pNext = pLast -> pNext ; dom_free_size (a, pLast, sizeof (tRepeatLevelLookupItem), &numLevelLookupItem) ; } else { pLookupLevelNodeLevel -> pNode = NULL ; } } if (pLookupLevelNode -> xNullNode != pChild -> xNdx) pDomTree -> pLookup[pChild -> xNdx].pLookupLevel = NULL ; } } dom_free (a, pChild, &numNodes) ; return NULL ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_removeChild */ /* */ /* Remove a child node */ /* */ /* ------------------------------------------------------------------------ */ tNode Node_removeChild (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xParent, /*in*/ tNode xChild, /*in*/ tRepeatLevel nRepeatLevel) { Node_selfRemoveChild (a, pDomTree, xParent, Node_selfLevel (a, pDomTree, xChild, nRepeatLevel)) ; return 0 ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_replaceChild */ /* */ /* Replaces the node pointed by pOldChildDomTree/xOldChild/nOldRepeatLevel, */ /* with the node pointed by pDomTree/xNode/nRepeatLevel */ /* */ /* ------------------------------------------------------------------------ */ tNode Node_replaceChildWithNode (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xNode, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ tDomTree * pOldChildDomTree, /*in*/ tNode xOldChild, /*in*/ tRepeatLevel nOldRepeatLevel) { epaTHX_ tNodeData * pNode = Node_selfLevel (a, pDomTree, xNode, nRepeatLevel) ; tNodeData * pOldChild = Node_selfCondCloneNode (a, pOldChildDomTree, Node_selfLevel (a, pOldChildDomTree, xOldChild, nOldRepeatLevel), nOldRepeatLevel) ; int len = sizeof (tNodeData) + pNode -> numAttr * sizeof (tAttrData) ; int numAttr = pOldChild -> numAttr ; tAttrData * pAttr ; int n ; tLookupItem * pLookup ; pOldChild = Node_selfExpand (a, pOldChildDomTree, pOldChild, 0, pNode -> numAttr) ; if (pOldChild -> nText) NdxStringFree (a, pOldChild -> nText) ; pAttr = ((struct tAttrData * )(pOldChild + 1)) ; n = pOldChild -> numAttr ; while (n > 0) { if (pAttr -> xName) NdxStringFree (a, pAttr -> xName) ; if (pAttr -> xValue && (pAttr -> bFlags & aflgAttrValue)) NdxStringFree (a, pAttr -> xValue) ; n-- ; pAttr++ ; } memcpy (pOldChild, pNode, len) ; if (pOldChild -> nText) NdxStringRefcntInc (a, pOldChild -> nText) ; pOldChild -> xDomTree = pDomTree -> xNdx ; pOldChild -> xNdx = xOldChild ; pAttr = ((struct tAttrData * )(pOldChild + 1)) ; n = pNode -> numAttr ; pLookup = pDomTree -> pLookup ; while (n > 0) { if (pAttr -> xName) NdxStringRefcntInc (a, pAttr -> xName) ; if (pAttr -> xValue && (pAttr -> bFlags & aflgAttrValue)) NdxStringRefcntInc (a, pAttr -> xValue) ; pLookup[pAttr -> xNdx].pLookup = pAttr ; n-- ; pAttr++ ; } pAttr = ((struct tAttrData * )(pOldChild + 1)) + pOldChild -> numAttr ; n = numAttr - pNode -> numAttr ; while (n > 0) { pAttr -> bFlags = nflgDeleted ; if (pAttr -> xName) NdxStringFree (a, pAttr -> xName) ; if (pAttr -> xValue && (pAttr -> bFlags & aflgAttrValue)) NdxStringFree (a, pAttr -> xValue) ; n-- ; pAttr++ ; } if (pOldChild -> nType == ntypDocument) { pOldChild -> nType = ntypDocumentFraq ; if (pOldChild -> nText != xDocumentFraq) { NdxStringFree (a, pOldChild -> nText) ; pOldChild -> nText = xDocumentFraq ; NdxStringRefcntInc (a, xDocumentFraq) ; } } if (pOldChild -> nType == ntypDocumentFraq) { tAttrData * pAttr = Element_selfSetAttribut (a, pOldChildDomTree, pOldChild, nOldRepeatLevel, NULL, xDomTreeAttr, (char *)&pDomTree -> xNdx, sizeof (pDomTree -> xNdx)) ; pAttr -> bFlags = aflgOK ; /* reset string value flag */ } if (pOldChildDomTree -> xNdx != pDomTree -> xNdx) { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgDOM) lprintf (a, "[%d]DOM: DomTree %d depends on DomTree %d\n", a -> pThread -> nPid, pOldChildDomTree -> xNdx, pDomTree -> xNdx) ; av_push (pOldChildDomTree -> pDependsOn, SvREFCNT_inc (pDomTree -> pDomTreeSV)) ; } return pOldChild -> xNdx ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_insertBefore */ /* */ /* Inserts a child node before another node */ /* */ /* ------------------------------------------------------------------------ */ tNode Node_insertBefore_CDATA (/*in*/ tApp * a, /*in*/ const char * sText, /*in*/ int nTextLen, /*in*/ int nEscMode, /*in*/ tDomTree * pRefNodeDomTree, /*in*/ tNode xRefNode, /*in*/ tRepeatLevel nRefRepeatLevel) { tNodeData * pRefNode = Node_selfLevel (a, pRefNodeDomTree, xRefNode, nRefRepeatLevel) ; tNodeData * pPrevNode = Node_selfPreviousSibling (a, pRefNodeDomTree, pRefNode, nRefRepeatLevel) ; tNodeData * pNew = Node_newAndAppend (a, pRefNodeDomTree, pRefNode -> xParent, nRefRepeatLevel, NULL, pRefNode -> nLinenumber, sizeof (tNodeData)) ; pNew -> xChilds = 0 ; pNew -> bFlags = 0 ; if (nEscMode != -1) { pNew -> nType = (nEscMode & 8)?ntypText:((nEscMode & 3)?ntypTextHTML:ntypCDATA) ; pNew -> bFlags &= ~(nflgEscUTF8 + nflgEscUrl + nflgEscChar) ; pNew -> bFlags |= (nEscMode ^ nflgEscChar) & (nflgEscUTF8 + nflgEscUrl + nflgEscChar) ; } else pNew -> nType = ntypCDATA ; pNew -> nText = String2Ndx (a, sText, nTextLen) ; pRefNode = Node_selfCondCloneNode (a, pRefNodeDomTree, pRefNode, nRefRepeatLevel) ; if (pPrevNode) pPrevNode = Node_selfCondCloneNode (a, pRefNodeDomTree, pPrevNode, nRefRepeatLevel) ; else { tNodeData * pParent ; if ((pParent = Node_selfLevel (a, pRefNodeDomTree, pRefNode -> xParent, nRefRepeatLevel)) == NULL || pParent -> xChilds != pRefNode -> xPrev) pPrevNode = Node_selfLevel (a, pRefNodeDomTree, pRefNode -> xPrev, nRefRepeatLevel) ; /* first one */ else pPrevNode = NULL ; } if (pPrevNode) { pPrevNode -> xNext = pNew -> xNdx ; pNew -> xPrev = pPrevNode -> xNdx ; } else pNew -> xPrev = pRefNode -> xPrev ; pRefNode -> xPrev = pNew -> xNdx ; pNew -> xNext = pRefNode -> xNdx ; return pNew -> xNdx ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_insertAfter */ /* */ /* Inserts a child node after another node */ /* */ /* ------------------------------------------------------------------------ */ tNode Node_insertAfter (/*in*/ tApp * a, /*in*/ tDomTree * pNewNodeDomTree, /*in*/ tNode xNewNode, /*in*/ tRepeatLevel nNewRepeatLevel, /*in*/ tDomTree * pRefNodeDomTree, /*in*/ tNode xRefNode, /*in*/ tRepeatLevel nRefRepeatLevel) { epaTHX_ tNodeData * pNewNode = Node_selfLevel (a, pNewNodeDomTree, xNewNode, nNewRepeatLevel) ; tNodeData * pRefNode = Node_selfLevel (a, pRefNodeDomTree, xRefNode, nRefRepeatLevel) ; tNodeData * pNxtNode = Node_selfNextSibling (a, pRefNodeDomTree, pRefNode, nRefRepeatLevel) ; if (pNewNodeDomTree != pRefNodeDomTree) { tNodeData * pNew = Node_newAndAppend (a, pRefNodeDomTree, pRefNode -> xParent, nRefRepeatLevel, NULL, pNewNode -> nLinenumber, sizeof (tNodeData) /* + pNewNode -> numAttr * sizeof (tAttrData) (attributes are NOT copied !!)*/) ; pNew -> nText = pNewNode -> nText ; pNew -> xChilds = pNewNode -> xChilds ; pNew -> nType = pNewNode -> nType ; pNew -> bFlags = pNewNode -> bFlags ; if (pNew -> nText) NdxStringRefcntInc (a, pNew -> nText) ; pNewNode = pNew ; } pRefNode = Node_selfCondCloneNode (a, pRefNodeDomTree, pRefNode, nRefRepeatLevel) ; if (pNxtNode) pNxtNode = Node_selfCondCloneNode (a, pRefNodeDomTree, pNxtNode, nRefRepeatLevel) ; else { tNodeData * pParent ; if ((pParent = Node_selfLevel (a, pRefNodeDomTree, pRefNode -> xParent, nRefRepeatLevel)) == NULL || pParent -> xChilds != pRefNode -> xNext) pNxtNode = Node_selfLevel (a, pRefNodeDomTree, pRefNode -> xNext, nRefRepeatLevel) ; /* first one */ else pNxtNode = NULL ; } if (pNxtNode) { pNxtNode -> xPrev = pNewNode -> xNdx ; pNewNode -> xNext = pNxtNode -> xNdx ; } else pNewNode -> xNext = pRefNode -> xNext ; pRefNode -> xNext = pNewNode -> xNdx ; pNewNode -> xPrev = pRefNode -> xNdx ; if (pNewNode -> nType == ntypDocument) { pNewNode -> nType = ntypDocumentFraq ; if (pNewNode -> nText != xDocumentFraq) { NdxStringFree (a, pNewNode -> nText) ; pNewNode -> nText = xDocumentFraq ; NdxStringRefcntInc (a, xDocumentFraq) ; } } if (pNewNode -> nType == ntypDocumentFraq) { tAttrData * pAttr = Element_selfSetAttribut (a, pRefNodeDomTree, pNewNode, nRefRepeatLevel, NULL, xDomTreeAttr, (char *)&pNewNodeDomTree -> xNdx, sizeof (pNewNodeDomTree -> xNdx)) ; pAttr -> bFlags = aflgOK ; /* reset string value flag */ } if (pRefNodeDomTree -> xNdx != pNewNodeDomTree -> xNdx) { if ((a -> pCurrReq?a -> pCurrReq -> Component.Config.bDebug:a -> Config.bDebug) & dbgDOM) lprintf (a, "[%d]DOM: DomTree %d depends on DomTree %d\n", a -> pThread -> nPid, pRefNodeDomTree -> xNdx, pNewNodeDomTree -> xNdx) ; av_push (pRefNodeDomTree -> pDependsOn, SvREFCNT_inc (pNewNodeDomTree -> pDomTreeSV)) ; } return pNewNode -> xNdx ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_insertAfter_CDATA */ /* */ /* Inserts a cdata after another node */ /* */ /* ------------------------------------------------------------------------ */ tNode Node_insertAfter_CDATA (/*in*/ tApp * a, /*in*/ const char * sText, /*in*/ int nTextLen, /*in*/ int nEscMode, /*in*/ tDomTree * pRefNodeDomTree, /*in*/ tNode xRefNode, /*in*/ tRepeatLevel nRefRepeatLevel) { tNodeData * pRefNode = Node_selfLevel (a, pRefNodeDomTree, xRefNode, nRefRepeatLevel) ; tNodeData * pNxtNode = Node_selfNextSibling (a, pRefNodeDomTree, pRefNode, nRefRepeatLevel) ; tNodeData * pNew = Node_newAndAppend (a, pRefNodeDomTree, pRefNode -> xParent, nRefRepeatLevel, NULL, pRefNode -> nLinenumber, sizeof (tNodeData)) ; pNew -> xChilds = 0 ; pNew -> bFlags = 0 ; if (nEscMode != -1) { pNew -> nType = (nEscMode & 8)?ntypText:((nEscMode & 3)?ntypTextHTML:ntypCDATA) ; pNew -> bFlags &= ~(nflgEscUTF8 + nflgEscUrl + nflgEscChar) ; pNew -> bFlags |= (nEscMode ^ nflgEscChar) & (nflgEscUTF8 + nflgEscUrl + nflgEscChar) ; } else pNew -> nType = ntypCDATA ; pNew -> nText = String2Ndx (a, sText, nTextLen) ; pRefNode = Node_selfCondCloneNode (a, pRefNodeDomTree, pRefNode, nRefRepeatLevel) ; if (pNxtNode) pNxtNode = Node_selfCondCloneNode (a, pRefNodeDomTree, pNxtNode, nRefRepeatLevel) ; else { tNodeData * pParent ; if ((pParent = Node_selfLevel (a, pRefNodeDomTree, pRefNode -> xParent, nRefRepeatLevel)) == NULL || pParent -> xChilds != pRefNode -> xNext) pNxtNode = Node_selfLevel (a, pRefNodeDomTree, pRefNode -> xNext, nRefRepeatLevel) ; /* first one */ else pNxtNode = NULL ; } if (pNxtNode) { pNxtNode -> xPrev = pNew -> xNdx ; pNew -> xNext = pNxtNode -> xNdx ; } else pNew -> xNext = pRefNode -> xNext ; pRefNode -> xNext = pNew -> xNdx ; pNew -> xPrev = pRefNode -> xNdx ; return pNew -> xNdx ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_replaceChild */ /* */ /* Replace child node */ /* */ /* ------------------------------------------------------------------------ */ tNode Node_replaceChildWithCDATA (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xOldChild, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ const char * sText, /*in*/ int nTextLen, /*in*/ int nEscMode, /*in*/ int bFlags) { tNodeData * pOldChild ; tStringIndex n ; numReplace++ ; /* *** lprintf (a, "rp1--> SVs=%d %s DomTree Old=%d\n", sv_count, sText?sText:"", Node_selfDomTree (Node_self (pDomTree, xOldChild))) ; */ pOldChild = Node_selfCondCloneNode (a, pDomTree, Node_selfLevel (a, pDomTree, xOldChild, nRepeatLevel), nRepeatLevel) ; if (nEscMode != -1) { pOldChild -> nType = (nEscMode & 8)?ntypText:((nEscMode & 3)?ntypTextHTML:ntypCDATA) ; pOldChild -> bFlags &= ~(nflgEscUTF8 + nflgEscUrl + nflgEscChar) ; pOldChild -> bFlags |= (nEscMode ^ nflgEscChar) & (nflgEscUTF8 + nflgEscUrl + nflgEscChar) ; } else pOldChild -> nType = ntypCDATA ; n = pOldChild -> nText ; pOldChild -> nText = String2Ndx (a, sText, nTextLen) ; pOldChild -> xChilds = 0 ; pOldChild -> bFlags |= bFlags ; if (n) NdxStringFree (a, n) ; /* *** lprintf (a, "rp<-- nText=%d sText=>%*.*s< nTextLen = %d SVs=%d\n", pOldChild -> nText, nTextLen,nTextLen, sText?sText:"", nTextLen, sv_count) ; */ return pOldChild -> xNdx ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_selfLastChild */ /* */ /* Get last child node */ /* */ /* ------------------------------------------------------------------------ */ tNodeData * Node_selfLastChild (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel) { if (pNode -> xChilds) return Node_selfLevel (a, pDomTree, Node_selfFirstChild (a, pDomTree, pNode, nRepeatLevel) -> xPrev, nRepeatLevel) ; return 0 ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_selfNthChild (pNode, nChildNo) ; */ /* */ /* Get nth child node */ /* */ /* ------------------------------------------------------------------------ */ struct tNodeData * Node_selfNthChild (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ struct tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ int nChildNo) { if (pNode -> xChilds) { tNodeData * pChild ; tNodeData * pFirstChild = Node_selfFirstChild (a, pDomTree, pNode, nRepeatLevel) ; if (nChildNo == 0) return pFirstChild ; pChild = pFirstChild ; do { pChild = Node_selfNotNullLevel (a, pDomTree, pChild -> xNext, nRepeatLevel) ; if (nChildNo-- < 2) return pChild ; } while (nChildNo > 1 && pChild != pFirstChild) ; } return 0 ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_nextSibling (xNode) ; */ /* */ /* Get next sibling node */ /* */ /* ------------------------------------------------------------------------ */ tNodeData * Node_selfNextSibling (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel) { tNodeData * pParent ; tNodeData * pNxt ; if (pNode -> nType == ntypAttr || pNode -> xNext == pNode -> xNdx) return NULL ; if ((pParent = Node_selfLevel (a, pDomTree, pNode -> xParent, nRepeatLevel)) != NULL) { if (pParent -> xChilds == pNode -> xNext) return NULL ; } if (pNode -> bFlags & nflgNewLevelNext) pNxt = Node_self (pDomTree, pNode -> xNext) ; else pNxt = Node_selfLevel (a, pDomTree, pNode -> xNext, nRepeatLevel) ; /* if (pParent && pNxt -> nRepeatLevel) { if (pParent -> xChilds == xNode_selfLevelNull(pDomTree,pNxt) ) return NULL ; } */ if (!pParent) { if (pNxt -> nType == ntypDocumentFraq) return NULL ; } return pNxt ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_nextSibling (xNode) ; */ /* */ /* Get next sibling node */ /* */ /* ------------------------------------------------------------------------ */ tNode Node_nextSibling (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xNode, /*in*/ tRepeatLevel nRepeatLevel) { tNodeData * pNode = Node_selfNotNullLevel (a, pDomTree, xNode, nRepeatLevel) ; tNodeData * pParent ; if (pNode -> nType == ntypAttr || pNode -> xNext == pNode -> xNdx) return 0 ; pParent = Node_selfLevel (a, pDomTree, pNode -> xParent, nRepeatLevel) ; if (pParent -> xChilds == pNode -> xNext) return 0 ; return pNode -> xNext ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_previousSibling (xNode) ; */ /* */ /* Get previous sibling node */ /* */ /* ------------------------------------------------------------------------ */ tNodeData * Node_selfPreviousSibling (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel) { tNodeData * pParent ; if (pNode -> nType == ntypAttr || pNode -> xPrev == pNode -> xNdx) return 0 ; pParent = Node_selfLevel (a, pDomTree, pNode -> xParent, nRepeatLevel) ; if (pParent -> xChilds == pNode -> xNdx) return 0 ; if (pNode -> bFlags & nflgNewLevelPrev) return Node_self (pDomTree, pNode -> xPrev) ; else return Node_selfLevel (a, pDomTree, pNode -> xPrev, nRepeatLevel) ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_previousSibling (xNode) ; */ /* */ /* Get previous sibling node */ /* */ /* ------------------------------------------------------------------------ */ tNode Node_previousSibling (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xNode, /*in*/ tRepeatLevel nRepeatLevel) { tNodeData * pNode = Node_selfNotNullLevel (a, pDomTree, xNode, nRepeatLevel) ; tNodeData * pParent ; if (pNode -> nType == ntypAttr || pNode -> xPrev == pNode -> xNdx) return 0 ; pParent = Node_selfLevel (a, pDomTree, pNode -> xParent, nRepeatLevel) ; if (pParent -> xChilds == pNode -> xNdx) return 0 ; return pNode -> xPrev ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_childsText (a, xNode) ; */ /* */ /* Get the text of all child nodes in one string */ /* */ /* ------------------------------------------------------------------------ */ char * Node_childsText (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ tNode xNode, /*in*/ tRepeatLevel nRepeatLevel, /*i/o*/ char * * ppText, /*in*/ int bDeep) { tNodeData * pParent = Node_selfLevel (a, pDomTree, xNode, nRepeatLevel) ; tNodeData * pNode ; char * sNodeText ; char * sText = ppText?*ppText:NULL ; if (pParent) { if (sText == NULL) StringNew (a, &sText, 1024) ; pNode = Node_selfFirstChild (a, pDomTree, pParent, nRepeatLevel) ; while (pNode) { sNodeText = Node_selfNodeName(pNode) ; StringAdd (a, &sText, sNodeText, 0) ; if (bDeep) Node_childsText (a, pDomTree, pNode -> xNdx, nRepeatLevel, &sText, 1) ; pNode = Node_selfNextSibling (a, pDomTree, pNode, nRepeatLevel) ; } } if (ppText) *ppText = sText ; return sText ; } /* ------------------------------------------------------------------------ */ /* */ /* Node_toString */ /* */ /* */ /* */ /* ------------------------------------------------------------------------ */ static tNodeData * Node_toString2 (/*i/o*/ register req * r, /*in*/ tDomTree * pDomTree, /*in*/ tNode xNode, /*in*/ tRepeatLevel * pRepeatLevel) { epTHX_ tApp * a = r -> pApp ; tRepeatLevel nRepeatLevel = *pRepeatLevel ; tNodeData * pNode = Node_self (pDomTree, xNode) ; tNodeData * pLast ; struct tCharTrans * pChar2Html ; if (!pNode) return NULL ; if (r -> Config.nOutputEscCharset == ocharsetLatin1) pChar2Html = Char2Html ; else if (r -> Config.nOutputEscCharset == ocharsetLatin2) pChar2Html = Char2HtmlLatin2 ; else pChar2Html = Char2HtmlMin ; if (pNode -> nType == ntypDocumentFraq) { int o = pDomTree -> xNdx ; tAttrData * pAttr = Element_selfGetAttribut (a, pDomTree, pNode, NULL, xDomTreeAttr) ; if (pAttr) { char * p ; char * pNdx ; pNdx = Attr_selfValue(a, pDomTree, pAttr, nRepeatLevel, &p) ; pDomTree = DomTree_self (*(tIndexShort *)pNdx) ; } if (r -> Component.Config.bDebug & dbgOutput) lprintf (a, "[%d]toString: ** Switch from DomTree=%d to new DomTree=%d\n", r -> pThread -> nPid, o, pDomTree -> xNdx) ; } pNode = Node_selfFirstChild (a, pDomTree, pNode, nRepeatLevel) ; while (pNode) { if (pNode -> bFlags & nflgStopOutput) { if (r -> Component.Config.bDebug & dbgOutput) lprintf (a, "[%d]toString: Node=%d(%d) RepeatLevel=%d type=%d flags=%x -> stop output\n", r -> pThread -> nPid, pNode -> xNdx, xNode_selfLevelNull(pDomTree,pNode), nRepeatLevel, pNode -> nType, pNode -> bFlags) ; return NULL ; } if (r -> Component.Config.bDebug & dbgOutput) lprintf (a, "[%d]toString: Node=%d(%d) RepeatLevel=%d type=%d flags=%x text=>%s<= (#%d) SVs=%d\n", r -> pThread -> nPid, pNode -> xNdx, xNode_selfLevelNull(pDomTree,pNode), nRepeatLevel, pNode -> nType, pNode -> bFlags, Ndx2String (pNode -> nText), pNode -> nText, sv_count) ; if (pNode -> nType == ntypDocumentFraq) { Node_toString (r, pDomTree, pNode -> xNdx, 0) ; } else { if (pNode -> bFlags & nflgIgnore) ; else if (pNode -> nType == ntypTag || pNode -> nType == ntypStartTag || pNode -> nType == ntypProcessingInstr) { int n = pNode -> numAttr ; struct tAttrData * pAttr = (struct tAttrData *)(pNode + 1) ; char * pNodeName = Node_selfNodeName (pNode) ; char * pNodeStart ; char * pNodeEnd ; char * p ; int nNodeStartLen ; int nNodeEndLen ; int nNodeNameLen ; int nLastLen ; if (*pNodeName) { if (*pNodeName == ':') { pNodeStart = ++pNodeName ; nNodeStartLen = 0 ; nNodeEndLen = 0 ; while (*pNodeName && *pNodeName != ':') { nNodeStartLen++ ; pNodeName++ ; } if (*pNodeName == ':') { pNodeEnd = ++pNodeName ; while (*pNodeName && *pNodeName != ':') { nNodeEndLen++ ; pNodeName++ ; } } else pNodeEnd = "" ; if (*pNodeName == ':') pNodeName++ ; nNodeNameLen = 0 ; p = pNodeName ; while (*p && *p != ':') { p++ ; nNodeNameLen++ ; } } else if (pNode -> nType == ntypProcessingInstr) { pNodeStart = "" ; nNodeStartLen = 2 ; nNodeEndLen = 2 ; nNodeNameLen = strlen (pNodeName) ; } else { nNodeStartLen = 1 ; nNodeEndLen = r -> Config.nOutputMode == omodeXml && pNode -> nType == ntypTag?3:1 ; nNodeNameLen = strlen (pNodeName) ; pNodeStart = "<" ; pNodeEnd = nNodeEndLen == 3?" />":">" ; } owrite (r, pNodeStart, nNodeStartLen) ; owrite (r, pNodeName, nNodeNameLen) ; if (*pNodeName) nLastLen = 1 ; else nLastLen = 0 ; while (n--) { if (pAttr -> bFlags) { char * s ; int l ; if (nLastLen) { oputc (r, ' ') ; nLastLen = 0 ; } if (pAttr -> xName != xNoName) { Ndx2StringLen (pAttr -> xName,s,l) ; owrite (r, s, l); nLastLen += l ; } if (pAttr -> xValue) { if (pAttr -> xName != xNoName) { if (pAttr -> bFlags & aflgSingleQuote) oputs (r, "='") ; else oputs (r, "=\"") ; } if (pAttr -> bFlags & aflgAttrChilds) { tAttrData * pAttrNode = (tAttrData * )Node_toString2 (r, pDomTree, pAttr -> xNdx, &nRepeatLevel) ; if (pAttrNode && pAttrNode != pAttr) { pAttr = pAttrNode ; pNode = Attr_selfNode(pAttr) ; n = pNode -> numAttr - Attr_selfAttrNum (pAttr) - 1 ; if (n < 0) n = 0 ; } nLastLen++ ; } else { Ndx2StringLen (pAttr -> xValue, s, l) ; while (isspace (*s) && l > 0) s++, l-- ; /*OutputEscape (r, s, l, (pAttr -> bFlags & aflgEscXML)?Char2XML:(pAttr -> bFlags & aflgEscUrl)?Char2Url:Char2Html, (char)((pAttr -> bFlags & aflgEscChar)?'\\':0)) ;*/ owrite (r, s, l) ; nLastLen += l ; } if (pAttr -> xName != xNoName) { if (pAttr -> bFlags & aflgSingleQuote) oputc (r, '\'') ; else oputc (r, '"') ; } } } pAttr++ ; } owrite (r, pNodeEnd, nNodeEndLen) ; } } else if (pNode -> nType == ntypText) { char * s ; int l ; Ndx2StringLen (pNode -> nText,s,l) ; OutputEscape (r, s, l, Char2XML, (char)((pNode -> bFlags & nflgEscChar)?'\\':0)) ; } else if (pNode -> nType == ntypTextHTML) { char * s ; int l ; Ndx2StringLen (pNode -> nText,s,l) ; OutputEscape (r, s, l, (pNode -> bFlags & nflgEscUTF8)?(pNode -> bFlags & nflgEscUrl)?Char2Url:Char2HtmlMin:(pNode -> bFlags & nflgEscUrl)?Char2Url:pChar2Html, (char)((pNode -> bFlags & nflgEscChar)?'\\':0)) ; } else { char * s ; int l ; Ndx2StringLen (pNode -> nText,s,l) ; owrite (r, s, l); } Node_toString2 (r, pDomTree, pNode -> xNdx, &nRepeatLevel) ; if (pNode -> nType == ntypStartTag && (pNode -> bFlags & nflgIgnore) == 0) { char * pNodeName = Node_selfNodeName (pNode) ; if (*pNodeName == ':') { int i = 4 ; while (i > 0 && *pNodeName) if (*pNodeName++ == ':') i-- ; if (*pNodeName) oputs (r, pNodeName) ; } else { oputs (r, "') ; } } } pLast = pNode ; pNode = Node_selfNextSibling (a, pDomTree, pNode, nRepeatLevel) ; if (pNode && pLast -> bFlags & nflgNewLevelNext) nRepeatLevel = pNode -> nRepeatLevel ; } *pRepeatLevel = nRepeatLevel ; return NULL ; } #if 0 if (nOrderNdx == nOrderIndexNode) nOrderNdx++ ; if (pNode -> nType == ntypDocumentFraq) pNextNode = NULL ; else pNextNode = Node_selfFirstChild (a, pDomTree, pNode, nRepeatLevel) ; if (pNextNode == NULL) { pNextNode = Node_selfNextSibling (a, pDomTree, pNode, nRepeatLevel) ; while (pNextNode == NULL) { pNextNode = Node_selfParentNode (pDomTree, pNode, nRepeatLevel) ; if (pNextNode == NULL || pNextNode == pFirstNode || pNextNode -> nType == ntypAttr) { return bCheckpointFound?pNextNode:NULL ; } pNode = pNextNode ; pNextNode = Node_selfNextSibling (a, pDomTree, pNextNode, nRepeatLevel) ; if (pNode -> nType == ntypStartTag && (pNode -> bFlags & nflgIgnore) == 0) { char * pNodeName = Node_selfNodeName (pNode) ; if (*pNodeName == ':') { int i = 4 ; while (i > 0 && *pNodeName) if (*pNodeName++ == ':') i-- ; if (*pNodeName) oputs (r, pNodeName) ; } else { oputs (r, "') ; } pLastStartTag = Node_selfParentNode (pDomTree, pNextNode?pNextNode:pNode, nRepeatLevel) ; } } } pNode = pNextNode ; } *pOrderNdx = nOrderNdx ; return NULL ; } #endif void Node_toString (/*i/o*/ register req * r, /*in*/ tDomTree * pDomTree, /*in*/ tNode xNode, /*in*/ tRepeatLevel nRepeatLevel) { Node_toString2 (r, pDomTree, xNode, &nRepeatLevel) ; } /* ------------------------------------------------------------------------ */ /* */ /* NodeList_toString */ /* */ /* */ /* */ /* ------------------------------------------------------------------------ */ void NodeList_toString (/*in*/ tDomTree * pDomTree, /*in*/ tNode xNode) { } /* ------------------------------------------------------------------------ interface Element : Node { readonly attribute DOMString tagName; DOMString getAttribute(in DOMString name); void setAttribute(in DOMString name, in DOMString value) raises(DOMException); void removeAttribute(in DOMString name) raises(DOMException); Attr getAttributeNode(in DOMString name); Attr setAttributeNode(in Attr newAttr) raises(DOMException); Attr removeAttributeNode(in Attr oldAttr) raises(DOMException); NodeList getElementsByTagName(in DOMString name); # Introduced in DOM Level 2: DOMString getAttributeNS(in DOMString namespaceURI, in DOMString localName); # Introduced in DOM Level 2: void setAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName, in DOMString value) raises(DOMException); # Introduced in DOM Level 2: void removeAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException); # Introduced in DOM Level 2: Attr getAttributeNodeNS(in DOMString namespaceURI, in DOMString localName); # Introduced in DOM Level 2: Attr setAttributeNodeNS(in Attr newAttr) raises(DOMException); # Introduced in DOM Level 2: NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName); # Introduced in DOM Level 2: boolean hasAttribute(in DOMString name); # Introduced in DOM Level 2: boolean hasAttributeNS(in DOMString namespaceURI, in DOMString localName); }; ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* */ /* Element_selfGetAttribut */ /* */ /* Get attribute value of Element by name */ /* */ /* ------------------------------------------------------------------------ */ tAttrData * Element_selfGetAttribut (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ struct tNodeData * pNode, /*in*/ const char * sAttrName, /*in*/ int nAttrNameLen) { int nAttrName = sAttrName?String2NdxNoInc (a, sAttrName, nAttrNameLen):nAttrNameLen ; struct tAttrData * pAttr = (struct tAttrData * )(pNode + 1) ; int n = pNode -> numAttr ; while (n > 0 && (nAttrName != pAttr -> xName || !pAttr -> bFlags)) { n-- ; pAttr++ ; } if (n) return pAttr ; return NULL ; } /* ------------------------------------------------------------------------ */ /* */ /* Element_selfGetNthAttribut */ /* */ /* Get attribute value of Element by index */ /* */ /* ------------------------------------------------------------------------ */ tAttrData * Element_selfGetNthAttribut (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ struct tNodeData * pNode, /*in*/ int n) { struct tAttrData * pAttr = (struct tAttrData * )(pNode + 1) ; int num = pNode -> numAttr ; if (n < 0 || n >= num) return NULL ; return pAttr + n ; } /* ------------------------------------------------------------------------ */ /* */ /* Element_selfSetAttribut */ /* */ /* Set attribute value of Element by name */ /* */ /* ------------------------------------------------------------------------ */ tAttrData * Element_selfSetAttribut (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ struct tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ const char * sAttrName, /*in*/ int nAttrNameLen, /*in*/ const char * sNewValue, /*in*/ int nNewValueLen) { epaTHX_ tAttrData * pAttr ; tNode xAttr ; tNodeData * pNewNode ; pNode = Node_selfCondCloneNode (a, pDomTree, pNode, nRepeatLevel) ; pAttr = Element_selfGetAttribut (a, pDomTree, pNode, sAttrName, nAttrNameLen) ; if (pAttr) { tIndex xValue = sNewValue?String2NdxNoInc (a, sNewValue, nNewValueLen):nNewValueLen ; NdxStringRefcntInc (a, xValue) ; if (pAttr -> xValue && (pAttr -> bFlags & aflgAttrValue)) NdxStringFree (a, pAttr -> xValue) ; pAttr -> bFlags |= aflgAttrValue ; pAttr -> bFlags &= ~aflgAttrChilds ; pAttr -> xValue = xValue ; return pAttr ; } pNewNode = pNode ; xAttr = Node_appendChild (a, pDomTree, pNewNode -> xNdx, nRepeatLevel, ntypAttr, 0, sAttrName, nAttrNameLen, 0, pNewNode -> nLinenumber, NULL) ; Node_appendChild (a, pDomTree, xAttr, nRepeatLevel, ntypAttrValue, 0, sNewValue, nNewValueLen, 0, pNewNode -> nLinenumber, NULL) ; return (tAttrData *)Node_self(pDomTree, xAttr) ; } /* ------------------------------------------------------------------------ */ /* */ /* Element_selfRemoveAttribut */ /* */ /* Remove attribute of Element by name */ /* */ /* ------------------------------------------------------------------------ */ tAttrData * Element_selfRemoveAttributPtr (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ struct tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ tAttrData * pAttr) { pNode = Node_selfCondCloneNode (a, pDomTree, pNode, nRepeatLevel) ; if (pAttr) { if (pAttr -> xName) NdxStringFree (a, pAttr -> xName) ; if (pAttr -> xValue && (pAttr -> bFlags & aflgAttrValue)) NdxStringFree (a, pAttr -> xValue) ; pAttr -> bFlags = 0 ; } /* int nCopyAttr ; if (pAttr) { nAttr = pAttr - ((struct tAttrData * )(pNode + 1)) ; pNode -> numAttr-- ; nCopyAttr = pNode -> numAttr - nAttr ; if (nCopyAttr) { memcpy (pAttr, pAttr + 1, nCopyAttr * sizeof (tAttrData)) ; while (nCopyAttr--) { pDomTree -> pLookup[pAttr -> xNdx] = pAttr ; pAttr++ ; } } } */ return pAttr ; } tAttrData * Element_selfRemoveAttribut (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ struct tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ const char * sAttrName, /*in*/ int nAttrNameLen) { tAttrData * pAttr ; pNode = Node_selfCondCloneNode (a, pDomTree, pNode, nRepeatLevel) ; pAttr = Element_selfGetAttribut (a, pDomTree, pNode, sAttrName, nAttrNameLen) ; return Element_selfRemoveAttributPtr (a, pDomTree, pNode, nRepeatLevel, pAttr) ; } tAttrData * Element_selfRemoveNthAttribut (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ struct tNodeData * pNode, /*in*/ tRepeatLevel nRepeatLevel, /*in*/ int n) { tAttrData * pAttr ; pNode = Node_selfCondCloneNode (a, pDomTree, pNode, nRepeatLevel) ; pAttr = Element_selfGetNthAttribut (a, pDomTree, pNode, n) ; return Element_selfRemoveAttributPtr (a, pDomTree, pNode, nRepeatLevel, pAttr) ; } /* ------------------------------------------------------------------------ interface Attr : Node { readonly attribute DOMString name; readonly attribute boolean specified; attribute DOMString value; # raises(DOMException) on setting # Introduced in DOM Level 2: readonly attribute Element ownerElement; }; ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ /* */ /* Attr_selfValue */ /* */ /* */ /* */ /* ------------------------------------------------------------------------ */ char * Attr_selfValue (/*in*/ tApp * a, /*in*/ tDomTree * pDomTree, /*in*/ struct tAttrData * pAttr, /*in*/ tRepeatLevel nRepeatLevel, /*out*/ char * * ppAttr) { struct tNodeData * pNode ; struct tNodeData * pAttrNode ; tIndex xFirstAttr ; ASSERT_ATTR_VALID(a,pAttr) ; if (!pAttr || pAttr -> bFlags == aflgDeleted) return NULL ; /* lprintf (a, "selvalue 1 f=%x a=%x aa=%x an=%d off=%d av=%d\n", pAttr -> bFlags , aflgAttrChilds, pAttr, pAttr -> xNdx, pAttr -> nNodeOffset, pAttr -> xValue) ; */ pAttrNode = Attr_selfNode(pAttr) ; ASSERT_NODE_VALID(a,pAttrNode) ; /* lprintf (a, "selvalue f=%x a=%x aa=%x an=%d off=%d av=%d na=%x nn=%d a\n", pAttr -> bFlags , aflgAttrChilds, pAttr, pAttr -> xNdx, pAttr -> nNodeOffset, pAttr -> xValue, pAttrNode, pAttrNode -> xNdx) ; */ pNode = Node_selfLevel (a, pDomTree, pAttrNode -> xNdx, nRepeatLevel) ; ASSERT_NODE_VALID(a,pNode) ; /* lprintf (a, "selvalue f=%x a=%x aa=%x an=%d off=%d av=%d na=%x nn=%d node=%x\n", pAttr -> bFlags , aflgAttrChilds, pAttr, pAttr -> xNdx, pAttr -> nNodeOffset, pAttr -> xValue, pAttrNode, pAttrNode -> xNdx, pNode) ;*/ if (pNode != pAttrNode) { pAttr = Element_selfGetAttribut (a, pDomTree, pNode, NULL, pAttr -> xName) ; if (!pAttr) return NULL ; } ASSERT_ATTR_VALID(a,pAttr) ; ASSERT_NODE_VALID(a,pNode) ; ASSERT_NODE_VALID(a,pAttrNode) ; /*lprintf (a, "selvalue f=%x a=%x aa=%x an=%d off=%d av=%d na=%x nn=%d a\n", pAttr -> bFlags , aflgAttrChilds, pAttr, pAttr -> xNdx, pAttr -> nNodeOffset, pAttr -> xValue, pAttrNode, pAttrNode -> xNdx) ;*/ if ((pAttr -> bFlags & aflgAttrChilds) == 0) return Ndx2String (pAttr -> xValue) ; pNode = Node_selfLevel (a, pDomTree, pAttr -> xValue, nRepeatLevel) ; StringNew (a, ppAttr, 512) ; xFirstAttr = pNode -> xNdx ; while (pNode) { char * s ; int l ; ASSERT_NODE_VALID(a,pNode) ; /*lprintf (a, "selvalue f=%x node=%x nodendx=%d aa=%x an=%d off=%d av=%d na=%x nn=%d a\n", pAttr -> bFlags , pNode, pNode -> xNdx, pAttr, pAttr -> xNdx, pAttr -> nNodeOffset, pAttr -> xValue, pAttrNode, pAttrNode -> xNdx) ;*/ if ((pNode -> bFlags & nflgIgnore) == 0) { Ndx2StringLen (pNode -> nText,s,l) ; StringAdd (a, ppAttr, s, l) ; } pNode = Node_selfNextSibling (a, pDomTree, pNode, nRepeatLevel) ; if (!pNode || pNode -> xNdx == xFirstAttr) break ; } return *ppAttr ; }