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