PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/istack.c

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