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: arnaud02 $
9 $Date: 2006/02/17 18:01:12 $
10 $Revision: 1.18 $
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 */
DupAttrs(TidyDocImpl * doc,AttVal * attrs)21 AttVal *DupAttrs( TidyDocImpl* doc, AttVal *attrs)
22 {
23 AttVal *newattrs;
24
25 if (attrs == NULL)
26 return attrs;
27
28 newattrs = NewAttribute();
29 *newattrs = *attrs;
30 newattrs->next = DupAttrs( doc, attrs->next );
31 newattrs->attribute = tmbstrdup(attrs->attribute);
32 newattrs->value = tmbstrdup(attrs->value);
33 newattrs->dict = FindAttribute(doc, newattrs);
34 newattrs->asp = attrs->asp ? CloneNode(doc, attrs->asp) : NULL;
35 newattrs->php = attrs->php ? CloneNode(doc, attrs->php) : NULL;
36 return newattrs;
37 }
38
IsNodePushable(Node * node)39 static 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 */
PushInline(TidyDocImpl * doc,Node * node)69 void 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) && 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 = tmbstrdup(node->element);
98 istack->attributes = DupAttrs( doc, node->attributes );
99 ++(lexer->istacksize);
100 }
101
PopIStack(TidyDocImpl * doc)102 static 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 FreeAttribute( doc, av );
116 }
117 MemFree(istack->element);
118 }
119
PopIStackUntil(TidyDocImpl * doc,TidyTagId tid)120 static 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 */
PopInline(TidyDocImpl * doc,Node * node)135 void 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
IsPushed(TidyDocImpl * doc,Node * node)162 Bool 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 */
IsPushedLast(TidyDocImpl * doc,Node * element,Node * node)179 Bool 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 */
InlineDup(TidyDocImpl * doc,Node * node)212 int 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 */
DeferDup(TidyDocImpl * doc)230 void DeferDup( TidyDocImpl* doc )
231 {
232 doc->lexer->insert = NULL;
233 doc->lexer->inode = NULL;
234 }
235
InsertedToken(TidyDocImpl * doc)236 Node *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 = 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 = tmbstrdup(istack->element);
276 node->tag = istack->tag;
277 node->attributes = 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