req/hpricot/ext/hpricot_scan/hpricot_scan.c
void
rb_hpricot_token(hpricot_state *S, VALUE sym, VALUE tag, VALUE attr, char *raw, int rawlen, int taint)
{
  VALUE ele, ec = Qnil;

  //
  // in html mode, fix up start tags incorrectly formed as empty tags
  //
  if (!S->xml) {
    if (sym == sym_emptytag || sym == sym_stag || sym == sym_etag) {
      ec = rb_hash_aref(S->EC, tag);
      if (NIL_P(ec)) {
        tag = rb_funcall(tag, s_downcase, 0);
        ec = rb_hash_aref(S->EC, tag);
      }
    }

    if (H_ELE_GET(S->focus, H_ELE_EC) == sym_CDATA &&
       (sym != sym_procins && sym != sym_comment && sym != sym_cdata && sym != sym_text) &&
      !(sym == sym_etag && INT2FIX(rb_str_hash(tag)) == H_ELE_GET(S->focus, H_ELE_HASH)))
    {
      sym = sym_text;
      tag = rb_str_new(raw, rawlen);
    }

    if (!NIL_P(ec)) {
      if (sym == sym_emptytag) {
        if (ec != sym_EMPTY)
          sym = sym_stag;
      } else if (sym == sym_stag) {
        if (ec == sym_EMPTY)
          sym = sym_emptytag;
      }
    }
  }

  if (sym == sym_emptytag || sym == sym_stag) {
    VALUE name = INT2FIX(rb_str_hash(tag));
    H_ELE(cElem);
    H_ELE_SET(ele, H_ELE_HASH, name);

    if (!S->xml) {
      VALUE match = Qnil, e = S->focus;
      while (e != S->doc)
      {
        VALUE hEC = H_ELE_GET(e, H_ELE_EC);

        if (TYPE(hEC) == T_HASH)
        {
          VALUE has = rb_hash_lookup(hEC, name);
          if (has != Qnil) {
            if (has == Qtrue) {
              if (match == Qnil)
                match = e;
            } else if (has == symAllow) {
              match = S->focus;
            } else if (has == symDeny) {
              match = Qnil;
            }
          }
        }

        e = H_ELE_GET(e, H_ELE_PARENT);
      }

      if (match == Qnil)
        match = S->focus;
      S->focus = match;
    }

    rb_hpricot_add(S->focus, ele);

    //
    // in the case of a start tag that should be empty, just
    // skip the step that focuses the element.  focusing moves
    // us deeper into the document.
    //
    if (sym == sym_stag) {
      if (S->xml || ec != sym_EMPTY) {
        S->focus = ele;
        S->last = Qnil;
      }
    }
  } else if (sym == sym_etag) {
    VALUE name, match = Qnil, e = S->focus;
    if (S->strict) {
      if (NIL_P(rb_hash_aref(S->EC, tag))) {
        tag = rb_str_new2("div");
      }
    }

    //
    // another optimization will be to improve this very simple
    // O(n) tag search, where n is the depth of the focused tag.
    //
    // (see also: the search above for fixups)
    //
    name = INT2FIX(rb_str_hash(tag));
    while (e != S->doc)
    {
      if (H_ELE_GET(e, H_ELE_HASH) == name)
      {
        match = e;
        break;
      }

      e = H_ELE_GET(e, H_ELE_PARENT);
    }

    if (NIL_P(match))
    {
      H_ELE(cBogusETag);
      rb_hpricot_add(S->focus, ele);
    }
    else
    {
      VALUE ele = Qnil;
      if (raw != NULL)
        ele = rb_str_new(raw, rawlen);
      H_ELE_SET(match, H_ELE_ETAG, ele);
      S->focus = H_ELE_GET(match, H_ELE_PARENT);
      S->last = Qnil;
    }
  } else if (sym == sym_cdata) {
    H_ELE(cCData);
    rb_hpricot_add(S->focus, ele);
  } else if (sym == sym_comment) {
    H_ELE(cComment);
    rb_hpricot_add(S->focus, ele);
  } else if (sym == sym_doctype) {
    H_ELE(cDocType);
    if (S->strict) {
      rb_hash_aset(attr, ID2SYM(rb_intern("system_id")), rb_str_new2("http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"));
      rb_hash_aset(attr, ID2SYM(rb_intern("public_id")), rb_str_new2("-//W3C//DTD XHTML 1.0 Strict//EN"));
    }
    rb_hpricot_add(S->focus, ele);
  } else if (sym == sym_procins) {
    VALUE match = rb_funcall(tag, rb_intern("match"), 1, reProcInsParse);
    tag = rb_reg_nth_match(1, match);
    attr = rb_reg_nth_match(2, match);
    {
      H_ELE(cProcIns);
      rb_hpricot_add(S->focus, ele);
    }
  } else if (sym == sym_text) {
    // TODO: add raw_string as well?
    if (!NIL_P(S->last) && RBASIC(S->last)->klass == cText) {
      rb_str_append(H_ELE_GET(S->last, H_ELE_TAG), tag);
    } else {
      H_ELE(cText);
      rb_hpricot_add(S->focus, ele);
    }
  } else if (sym == sym_xmldecl) {
    H_ELE(cXMLDecl);
    rb_hpricot_add(S->focus, ele);
  }
}
//
// the swift, compact parser logic.  most of the complicated stuff is done
// in the lexer.  this step just pairs up the start and end tags.
//
the swift, compact parser logic.  most of the complicated stuff is done
in the lexer.  this step just pairs up the start and end tags.
the swift compact parser logic . most of the complicated stuff is done in the lexer . this step just pairs up the start and end tags .
void
rb_hpricot_token(hpricot_state *S, VALUE sym, VALUE tag, VALUE attr, char *raw, int rawlen, int taint)
{
  VALUE ele, ec = Qnil;
   in html mode, fix up start tags incorrectly formed as empty tags
  if (!S->xml) {
    if (sym == sym_emptytag || sym == sym_stag || sym == sym_etag) {
      ec = rb_hash_aref(S->EC, tag);
      if (NIL_P(ec)) {
        tag = rb_funcall(tag, s_downcase, 0);
        ec = rb_hash_aref(S->EC, tag);
      }
    }
    if (H_ELE_GET(S->focus, H_ELE_EC) == sym_CDATA &&
       (sym != sym_procins && sym != sym_comment && sym != sym_cdata && sym != sym_text) &&
      !(sym == sym_etag && INT2FIX(rb_str_hash(tag)) == H_ELE_GET(S->focus, H_ELE_HASH)))
    {
      sym = sym_text;
      tag = rb_str_new(raw, rawlen);
    }
    if (!NIL_P(ec)) {
      if (sym == sym_emptytag) {
        if (ec != sym_EMPTY)
          sym = sym_stag;
      } else if (sym == sym_stag) {
        if (ec == sym_EMPTY)
          sym = sym_emptytag;
      }
    }
  }
  if (sym == sym_emptytag || sym == sym_stag) {
    VALUE name = INT2FIX(rb_str_hash(tag));
    H_ELE(cElem);
    H_ELE_SET(ele, H_ELE_HASH, name);
    if (!S->xml) {
      VALUE match = Qnil, e = S->focus;
      while (e != S->doc)
      {
        VALUE hEC = H_ELE_GET(e, H_ELE_EC);
        if (TYPE(hEC) == T_HASH)
        {
          VALUE has = rb_hash_lookup(hEC, name);
          if (has != Qnil) {
            if (has == Qtrue) {
              if (match == Qnil)
                match = e;
            } else if (has == symAllow) {
              match = S->focus;
            } else if (has == symDeny) {
              match = Qnil;
            }
          }
        }
        e = H_ELE_GET(e, H_ELE_PARENT);
      }
      if (match == Qnil)
        match = S->focus;
      S->focus = match;
    }
    rb_hpricot_add(S->focus, ele);
     in the case of a start tag that should be empty, just
     skip the step that focuses the element.  focusing moves
     us deeper into the document.
    if (sym == sym_stag) {
      if (S->xml || ec != sym_EMPTY) {
        S->focus = ele;
        S->last = Qnil;
      }
    }
  } else if (sym == sym_etag) {
    VALUE name, match = Qnil, e = S->focus;
    if (S->strict) {
      if (NIL_P(rb_hash_aref(S->EC, tag))) {
        tag = rb_str_new2("div");
      }
    }
     another optimization will be to improve this very simple
     O(n) tag search, where n is the depth of the focused tag.
     (see also: the search above for fixups)
    name = INT2FIX(rb_str_hash(tag));
    while (e != S->doc)
    {
      if (H_ELE_GET(e, H_ELE_HASH) == name)
      {
        match = e;
        break;
      }
      e = H_ELE_GET(e, H_ELE_PARENT);
    }
    if (NIL_P(match))
    {
      H_ELE(cBogusETag);
      rb_hpricot_add(S->focus, ele);
    }
    else
    {
      VALUE ele = Qnil;
      if (raw != NULL)
        ele = rb_str_new(raw, rawlen);
      H_ELE_SET(match, H_ELE_ETAG, ele);
      S->focus = H_ELE_GET(match, H_ELE_PARENT);
      S->last = Qnil;
    }
  } else if (sym == sym_cdata) {
    H_ELE(cCData);
    rb_hpricot_add(S->focus, ele);
  } else if (sym == sym_comment) {
    H_ELE(cComment);
    rb_hpricot_add(S->focus, ele);
  } else if (sym == sym_doctype) {
    H_ELE(cDocType);
    if (S->strict) {
      rb_hash_aset(attr, ID2SYM(rb_intern("system_id")), rb_str_new2("http:www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"));
      rb_hash_aset(attr, ID2SYM(rb_intern("public_id")), rb_str_new2("-W3CDTD XHTML 1.0 StrictEN"));
    }
    rb_hpricot_add(S->focus, ele);
  } else if (sym == sym_procins) {
    VALUE match = rb_funcall(tag, rb_intern("match"), 1, reProcInsParse);
    tag = rb_reg_nth_match(1, match);
    attr = rb_reg_nth_match(2, match);
    {
      H_ELE(cProcIns);
      rb_hpricot_add(S->focus, ele);
    }
  } else if (sym == sym_text) {
     TODO: add raw_string as well?
    if (!NIL_P(S->last) && RBASIC(S->last)->klass == cText) {
      rb_str_append(H_ELE_GET(S->last, H_ELE_TAG), tag);
    } else {
      H_ELE(cText);
      rb_hpricot_add(S->focus, ele);
    }
  } else if (sym == sym_xmldecl) {
    H_ELE(cXMLDecl);
    rb_hpricot_add(S->focus, ele);
  }
}
void rb_hpricot_token ( hpricot_state * S , VALUE sym , VALUE tag , VALUE attr , char * raw , int rawlen , int taint ) { VALUE ele , ec = Qnil ; if ( ! S -> xml ) { if ( sym == sym_emptytag || sym == sym_stag || sym == sym_etag ) { ec = rb_hash_aref ( S -> EC , tag ) ; if ( NIL_P ( ec ) ) { tag = rb_funcall ( tag , s_downcase , 0 ) ; ec = rb_hash_aref ( S -> EC , tag ) ; } } if ( H_ELE_GET ( S -> focus , H_ELE_EC ) == sym_CDATA && ( sym != sym_procins && sym != sym_comment && sym != sym_cdata && sym != sym_text ) && ! ( sym == sym_etag && INT2FIX ( rb_str_hash ( tag ) ) == H_ELE_GET ( S -> focus , H_ELE_HASH ) ) ) { sym = sym_text ; tag = rb_str_new ( raw , rawlen ) ; } if ( ! NIL_P ( ec ) ) { if ( sym == sym_emptytag ) { if ( ec != sym_EMPTY ) sym = sym_stag ; } else if ( sym == sym_stag ) { if ( ec == sym_EMPTY ) sym = sym_emptytag ; } } } if ( sym == sym_emptytag || sym == sym_stag ) { VALUE name = INT2FIX ( rb_str_hash ( tag ) ) ; H_ELE ( cElem ) ; H_ELE_SET ( ele , H_ELE_HASH , name ) ; if ( ! S -> xml ) { VALUE match = Qnil , e = S -> focus ; while ( e != S -> doc ) { VALUE hEC = H_ELE_GET ( e , H_ELE_EC ) ; if ( TYPE ( hEC ) == T_HASH ) { VALUE has = rb_hash_lookup ( hEC , name ) ; if ( has != Qnil ) { if ( has == Qtrue ) { if ( match == Qnil ) match = e ; } else if ( has == symAllow ) { match = S -> focus ; } else if ( has == symDeny ) { match = Qnil ; } } } e = H_ELE_GET ( e , H_ELE_PARENT ) ; } if ( match == Qnil ) match = S -> focus ; S -> focus = match ; } rb_hpricot_add ( S -> focus , ele ) ; if ( sym == sym_stag ) { if ( S -> xml || ec != sym_EMPTY ) { S -> focus = ele ; S -> last = Qnil ; } } } else if ( sym == sym_etag ) { VALUE name , match = Qnil , e = S -> focus ; if ( S -> strict ) { if ( NIL_P ( rb_hash_aref ( S -> EC , tag ) ) ) { tag = rb_str_new2 ( " " ) ; } } name = INT2FIX ( rb_str_hash ( tag ) ) ; while ( e != S -> doc ) { if ( H_ELE_GET ( e , H_ELE_HASH ) == name ) { match = e ; break ; } e = H_ELE_GET ( e , H_ELE_PARENT ) ; } if ( NIL_P ( match ) ) { H_ELE ( cBogusETag ) ; rb_hpricot_add ( S -> focus , ele ) ; } else { VALUE ele = Qnil ; if ( raw != NULL ) ele = rb_str_new ( raw , rawlen ) ; H_ELE_SET ( match , H_ELE_ETAG , ele ) ; S -> focus = H_ELE_GET ( match , H_ELE_PARENT ) ; S -> last = Qnil ; } } else if ( sym == sym_cdata ) { H_ELE ( cCData ) ; rb_hpricot_add ( S -> focus , ele ) ; } else if ( sym == sym_comment ) { H_ELE ( cComment ) ; rb_hpricot_add ( S -> focus , ele ) ; } else if ( sym == sym_doctype ) { H_ELE ( cDocType ) ; if ( S -> strict ) { rb_hash_aset ( attr , ID2SYM ( rb_intern ( " " ) ) , rb_str_new2 ( " " ) ) ; rb_hash_aset ( attr , ID2SYM ( rb_intern ( " " ) ) , rb_str_new2 ( " " ) ) ; } rb_hpricot_add ( S -> focus , ele ) ; } else if ( sym == sym_procins ) { VALUE match = rb_funcall ( tag , rb_intern ( " " ) , 1 , reProcInsParse ) ; tag = rb_reg_nth_match ( 1 , match ) ; attr = rb_reg_nth_match ( 2 , match ) ; { H_ELE ( cProcIns ) ; rb_hpricot_add ( S -> focus , ele ) ; } } else if ( sym == sym_text ) { if ( ! NIL_P ( S -> last ) && RBASIC ( S -> last ) -> klass == cText ) { rb_str_append ( H_ELE_GET ( S -> last , H_ELE_TAG ) , tag ) ; } else { H_ELE ( cText ) ; rb_hpricot_add ( S -> focus , ele ) ; } } else if ( sym == sym_xmldecl ) { H_ELE ( cXMLDecl ) ; rb_hpricot_add ( S -> focus , ele ) ; } }
the swift, compact parser logic.
the swift compact parser logic .
// // in html mode, fix up start tags incorrectly formed as empty tags // // // in the case of a start tag that should be empty, just // skip the step that focuses the element.  focusing moves // us deeper into the document. // // // another optimization will be to improve this very simple // O(n) tag search, where n is the depth of the focused tag. // // (see also: the search above for fixups) // // TODO: add raw_string as well?