1/* istack.c -- inline stack for compatibility with Mosaic 2 3 (c) 1998-2006 (W3C) MIT, ERCIM, Keio University 4 See tidy.h for the copyright notice. 5 6 CVS Info : 7 8 $Author$ 9 $Date$ 10 $Revision$ 11 12*/ 13 14#include "tidy-int.h" 15#include "lexer.h" 16#include "attrs.h" 17#include "streamio.h" 18#include "tmbstr.h" 19 20/* duplicate attributes */ 21AttVal *TY_(DupAttrs)( TidyDocImpl* doc, AttVal *attrs) 22{ 23 AttVal *newattrs; 24 25 if (attrs == NULL) 26 return attrs; 27 28 newattrs = TY_(NewAttribute)(); 29 *newattrs = *attrs; 30 newattrs->next = TY_(DupAttrs)( doc, attrs->next ); 31 newattrs->attribute = TY_(tmbstrdup)(attrs->attribute); 32 newattrs->value = TY_(tmbstrdup)(attrs->value); 33 newattrs->dict = TY_(FindAttribute)(doc, newattrs); 34 newattrs->asp = attrs->asp ? TY_(CloneNode)(doc, attrs->asp) : NULL; 35 newattrs->php = attrs->php ? TY_(CloneNode)(doc, attrs->php) : NULL; 36 return newattrs; 37} 38 39static Bool IsNodePushable( Node *node ) 40{ 41 if (node->tag == NULL) 42 return no; 43 44 if (!(node->tag->model & CM_INLINE)) 45 return no; 46 47 if (node->tag->model & CM_OBJECT) 48 return no; 49 50 return yes; 51} 52 53/* 54 push a copy of an inline node onto stack 55 but don't push if implicit or OBJECT or APPLET 56 (implicit tags are ones generated from the istack) 57 58 One issue arises with pushing inlines when 59 the tag is already pushed. For instance: 60 61 <p><em>text 62 <p><em>more text 63 64 Shouldn't be mapped to 65 66 <p><em>text</em></p> 67 <p><em><em>more text</em></em> 68*/ 69void TY_(PushInline)( TidyDocImpl* doc, Node *node ) 70{ 71 Lexer* lexer = doc->lexer; 72 IStack *istack; 73 74 if (node->implicit) 75 return; 76 77 if ( !IsNodePushable(node) ) 78 return; 79 80 if ( !nodeIsFONT(node) && TY_(IsPushed)(doc, node) ) 81 return; 82 83 /* make sure there is enough space for the stack */ 84 if (lexer->istacksize + 1 > lexer->istacklength) 85 { 86 if (lexer->istacklength == 0) 87 lexer->istacklength = 6; /* this is perhaps excessive */ 88 89 lexer->istacklength = lexer->istacklength * 2; 90 lexer->istack = (IStack *)MemRealloc(lexer->istack, 91 sizeof(IStack)*(lexer->istacklength)); 92 } 93 94 istack = &(lexer->istack[lexer->istacksize]); 95 istack->tag = node->tag; 96 97 istack->element = TY_(tmbstrdup)(node->element); 98 istack->attributes = TY_(DupAttrs)( doc, node->attributes ); 99 ++(lexer->istacksize); 100} 101 102static void PopIStack( TidyDocImpl* doc ) 103{ 104 Lexer* lexer = doc->lexer; 105 IStack *istack; 106 AttVal *av; 107 108 --(lexer->istacksize); 109 istack = &(lexer->istack[lexer->istacksize]); 110 111 while (istack->attributes) 112 { 113 av = istack->attributes; 114 istack->attributes = av->next; 115 TY_(FreeAttribute)( doc, av ); 116 } 117 MemFree(istack->element); 118} 119 120static void PopIStackUntil( TidyDocImpl* doc, TidyTagId tid ) 121{ 122 Lexer* lexer = doc->lexer; 123 IStack *istack; 124 125 while (lexer->istacksize > 0) 126 { 127 PopIStack( doc ); 128 istack = &(lexer->istack[lexer->istacksize]); 129 if ( istack->tag->id == tid ) 130 break; 131 } 132} 133 134/* pop inline stack */ 135void TY_(PopInline)( TidyDocImpl* doc, Node *node ) 136{ 137 Lexer* lexer = doc->lexer; 138 139 if (node) 140 { 141 if ( !IsNodePushable(node) ) 142 return; 143 144 /* if node is </a> then pop until we find an <a> */ 145 if ( nodeIsA(node) ) 146 { 147 PopIStackUntil( doc, TidyTag_A ); 148 return; 149 } 150 } 151 152 if (lexer->istacksize > 0) 153 { 154 PopIStack( doc ); 155 156 /* #427822 - fix by Randy Waki 7 Aug 00 */ 157 if (lexer->insert >= lexer->istack + lexer->istacksize) 158 lexer->insert = NULL; 159 } 160} 161 162Bool TY_(IsPushed)( TidyDocImpl* doc, Node *node ) 163{ 164 Lexer* lexer = doc->lexer; 165 int i; 166 167 for (i = lexer->istacksize - 1; i >= 0; --i) 168 { 169 if (lexer->istack[i].tag == node->tag) 170 return yes; 171 } 172 173 return no; 174} 175 176/* 177 Test whether the last element on the stack has the same type than "node". 178*/ 179Bool TY_(IsPushedLast)( TidyDocImpl* doc, Node *element, Node *node ) 180{ 181 Lexer* lexer = doc->lexer; 182 183 if ( element && !IsNodePushable(element) ) 184 return no; 185 186 if (lexer->istacksize > 0) { 187 if (lexer->istack[lexer->istacksize - 1].tag == node->tag) { 188 return yes; 189 } 190 } 191 192 return no; 193} 194 195/* 196 This has the effect of inserting "missing" inline 197 elements around the contents of blocklevel elements 198 such as P, TD, TH, DIV, PRE etc. This procedure is 199 called at the start of ParseBlock. when the inline 200 stack is not empty, as will be the case in: 201 202 <i><h1>italic heading</h1></i> 203 204 which is then treated as equivalent to 205 206 <h1><i>italic heading</i></h1> 207 208 This is implemented by setting the lexer into a mode 209 where it gets tokens from the inline stack rather than 210 from the input stream. 211*/ 212int TY_(InlineDup)( TidyDocImpl* doc, Node* node ) 213{ 214 Lexer* lexer = doc->lexer; 215 int n; 216 217 if ((n = lexer->istacksize - lexer->istackbase) > 0) 218 { 219 lexer->insert = &(lexer->istack[lexer->istackbase]); 220 lexer->inode = node; 221 } 222 223 return n; 224} 225 226/* 227 defer duplicates when entering a table or other 228 element where the inlines shouldn't be duplicated 229*/ 230void TY_(DeferDup)( TidyDocImpl* doc ) 231{ 232 doc->lexer->insert = NULL; 233 doc->lexer->inode = NULL; 234} 235 236Node *TY_(InsertedToken)( TidyDocImpl* doc ) 237{ 238 Lexer* lexer = doc->lexer; 239 Node *node; 240 IStack *istack; 241 uint n; 242 243 /* this will only be NULL if inode != NULL */ 244 if (lexer->insert == NULL) 245 { 246 node = lexer->inode; 247 lexer->inode = NULL; 248 return node; 249 } 250 251 /* 252 If this is the "latest" node then update 253 the position, otherwise use current values 254 */ 255 256 if (lexer->inode == NULL) 257 { 258 lexer->lines = doc->docIn->curline; 259 lexer->columns = doc->docIn->curcol; 260 } 261 262 node = TY_(NewNode)(lexer); 263 node->type = StartTag; 264 node->implicit = yes; 265 node->start = lexer->txtstart; 266 /* #431734 [JTidy bug #226261 (was 126261)] - fix by Gary Peskin 20 Dec 00 */ 267 node->end = lexer->txtend; /* was : lexer->txtstart; */ 268 istack = lexer->insert; 269 270#if 0 && defined(_DEBUG) 271 if ( lexer->istacksize == 0 ) 272 fprintf( stderr, "0-size istack!\n" ); 273#endif 274 275 node->element = TY_(tmbstrdup)(istack->element); 276 node->tag = istack->tag; 277 node->attributes = TY_(DupAttrs)( doc, istack->attributes ); 278 279 /* advance lexer to next item on the stack */ 280 n = (uint)(lexer->insert - &(lexer->istack[0])); 281 282 /* and recover state if we have reached the end */ 283 if (++n < lexer->istacksize) 284 lexer->insert = &(lexer->istack[n]); 285 else 286 lexer->insert = NULL; 287 288 return node; 289} 290 291/* 292 * local variables: 293 * mode: c 294 * indent-tabs-mode: nil 295 * c-basic-offset: 4 296 * eval: (c-set-offset 'substatement-open 0) 297 * end: 298 */ 299