]> sjero.net Git - wget/blobdiff - src/html-parse.c
Updated config.guess, config.sub, install.sh.
[wget] / src / html-parse.c
index a72688e3fa4aeacb58c2de87ea02e5a84e674cef..692e0de4b8c463d0eaa36bd4d3d34f7f42147f41 100644 (file)
@@ -1,6 +1,6 @@
 /* HTML parser for Wget.
    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2007 Free Software Foundation, Inc.
+   2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
@@ -17,15 +17,16 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
 
-In addition, as a special exception, the Free Software Foundation
-gives permission to link the code of its release of Wget with the
-OpenSSL project's "OpenSSL" library (or with modified versions of it
-that use the same license as the "OpenSSL" library), and distribute
-the linked executables.  You must obey the GNU General Public License
-in all respects for all of the code used other than "OpenSSL".  If you
-modify this file, you may extend this exception to your version of the
-file, but you are not obligated to do so.  If you do not wish to do
-so, delete this exception statement from your version.  */
+Additional permission under GNU GPL version 3 section 7
+
+If you modify this program, or any covered work, by linking or
+combining it with the OpenSSL project's OpenSSL library (or a
+modified version of that library), containing parts covered by the
+terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
+grants you additional permission to convey the resulting work.
+Corresponding Source for a non-source form of such a combination
+shall include the source code for the parts of OpenSSL used as well
+as that of the covered work.  */
 
 /* The only entry point to this module is map_html_tags(), which see.  */
 
@@ -88,7 +89,7 @@ so, delete this exception statement from your version.  */
 /* To test as standalone, compile with `-DSTANDALONE -I.'.  You'll
    still need Wget headers to compile.  */
 
-#include <config.h>
+#include "wget.h"
 
 #ifdef STANDALONE
 # define I_REALLY_WANT_CTYPE_MACROS
@@ -99,7 +100,7 @@ so, delete this exception statement from your version.  */
 #include <string.h>
 #include <assert.h>
 
-#include "wget.h"
+#include "utils.h"
 #include "html-parse.h"
 
 #ifdef STANDALONE
@@ -271,6 +272,94 @@ struct pool {
    to "<foo", but "&lt,foo" to "<,foo".  */
 #define SKIP_SEMI(p, inc) (p += inc, p < end && *p == ';' ? ++p : p)
 
+struct tagstack_item {
+  const char *tagname_begin;
+  const char *tagname_end;
+  const char *contents_begin;
+  struct tagstack_item *prev;
+  struct tagstack_item *next;
+};
+
+struct tagstack_item *
+tagstack_push (struct tagstack_item **head, struct tagstack_item **tail)
+{
+  struct tagstack_item *ts = xmalloc(sizeof(struct tagstack_item));
+  if (*head == NULL)
+    {
+      *head = *tail = ts;
+      ts->prev = ts->next = NULL;
+    }
+  else
+    {
+      (*tail)->next = ts;
+      ts->prev = *tail;
+      *tail = ts;
+      ts->next = NULL;
+    }
+
+  return ts;
+}
+
+/* remove ts and everything after it from the stack */
+void
+tagstack_pop (struct tagstack_item **head, struct tagstack_item **tail,
+              struct tagstack_item *ts)
+{
+  if (*head == NULL)
+    return;
+
+  if (ts == *tail)
+    {
+      if (ts == *head)
+        {
+          xfree (ts);
+          *head = *tail = NULL;
+        }
+      else
+        {
+          ts->prev->next = NULL;
+          *tail = ts->prev;
+          xfree (ts);
+        }
+    }
+  else
+    {
+      if (ts == *head)
+        {
+          *head = NULL;
+        }
+      *tail = ts->prev;
+
+      if (ts->prev)
+        {
+          ts->prev->next = NULL;
+        }
+      while (ts)
+        {
+          struct tagstack_item *p = ts->next;
+          xfree (ts);
+          ts = p;
+        }
+    }
+}
+
+struct tagstack_item *
+tagstack_find (struct tagstack_item *tail, const char *tagname_begin,
+               const char *tagname_end)
+{
+  int len = tagname_end - tagname_begin;
+  while (tail)
+    {
+      if (len == (tail->tagname_end - tail->tagname_begin))
+        {
+          if (0 == strncasecmp (tail->tagname_begin, tagname_begin, len))
+            return tail;
+        }
+      tail = tail->prev;
+    }
+  return NULL;
+}
+
 /* Decode the HTML character entity at *PTR, considering END to be end
    of buffer.  It is assumed that the "&" character that marks the
    beginning of the entity has been seen at *PTR-1.  If a recognized
@@ -756,6 +845,9 @@ map_html_tags (const char *text, int size,
   bool attr_pair_resized = false;
   struct attr_pair *pairs = attr_pair_initial_storage;
 
+  struct tagstack_item *head = NULL;
+  struct tagstack_item *tail = NULL;
+
   if (!size)
     return;
 
@@ -822,6 +914,18 @@ map_html_tags (const char *text, int size,
       goto look_for_tag;
     tag_name_end = p;
     SKIP_WS (p);
+
+    if (!end_tag)
+      {
+        struct tagstack_item *ts = tagstack_push (&head, &tail);
+        if (ts)
+          {
+            ts->tagname_begin  = tag_name_begin;
+            ts->tagname_end    = tag_name_end;
+            ts->contents_begin = NULL;
+          }
+      }
+
     if (end_tag && *p != '>')
       goto backout_tag;
 
@@ -983,6 +1087,11 @@ map_html_tags (const char *text, int size,
         ++nattrs;
       }
 
+    if (!end_tag && tail && (tail->tagname_begin == tag_name_begin))
+      {
+        tail->contents_begin = p+1;
+      }
+
     if (uninteresting_tag)
       {
         ADVANCE (p);
@@ -994,6 +1103,7 @@ map_html_tags (const char *text, int size,
     {
       int i;
       struct taginfo taginfo;
+      struct tagstack_item *ts = NULL;
 
       taginfo.name      = pool.contents;
       taginfo.end_tag_p = end_tag;
@@ -1010,6 +1120,23 @@ map_html_tags (const char *text, int size,
       taginfo.attrs = pairs;
       taginfo.start_position = tag_start_position;
       taginfo.end_position   = p + 1;
+      taginfo.contents_begin = NULL;
+      taginfo.contents_end = NULL;
+
+      if (end_tag)
+        {
+          ts = tagstack_find (tail, tag_name_begin, tag_name_end);
+          if (ts)
+            {
+              if (ts->contents_begin)
+                {
+                  taginfo.contents_begin = ts->contents_begin;
+                  taginfo.contents_end   = tag_start_position;
+                }
+              tagstack_pop (&head, &tail, ts);
+            }
+        }
+
       mapfun (&taginfo, maparg);
       ADVANCE (p);
     }
@@ -1029,6 +1156,8 @@ map_html_tags (const char *text, int size,
   POOL_FREE (&pool);
   if (attr_pair_resized)
     xfree (pairs);
+  /* pop any tag stack that's left */
+  tagstack_pop (&head, &tail, head);
 }
 
 #undef ADVANCE