+ /**
+ * There are several types of attributes, with optional
+ * [:space:] between members.
+ * Type 1:
+ * attrname[:space:]=[:space:]'CDATA'
+ * Type 2:
+ * attrname[:space:]=[:space:]"CDATA"
+ * Type 3:
+ * attr[:space:]=[:space:]CDATA
+ * Type 4:
+ * attrname
+ *
+ * We leave types 1 and 2 the same, type 3 we check for
+ * '"' and convert to """ if needed, then wrap in
+ * double quotes. Type 4 we convert into:
+ * attrname="yes".
+ */
+ $regary = sq_findnxreg($body, $pos, "[^\w\-_]");
+ if ($regary == false){
+ /**
+ * Looks like body ended before the end of tag.
+ */
+ return Array(false, false, false, $lt, strlen($body));
+ }
+ list($pos, $attname, $match) = $regary;
+ $attname = strtolower($attname);
+ /**
+ * We arrived at the end of attribute name. Several things possible
+ * here:
+ * '>' means the end of the tag and this is attribute type 4
+ * '/' if followed by '>' means the same thing as above
+ * '\s' means a lot of things -- look what it's followed by.
+ * anything else means the attribute is invalid.
+ */
+ switch($match){
+ case '/':
+ /**
+ * This is an xhtml-style tag with a closing / at the
+ * end, like so: <img src="blah"/>. Check if it's followed
+ * by the closing bracket. If not, then this tag is invalid
+ */
+ if (substr($body, $pos, 2) == "/>"){
+ $pos++;
+ $tagtype = 3;
+ } else {
+ $gt = sq_findnxstr($body, $pos, ">");
+ $retary = Array(false, false, false, $lt, $gt);
+ return $retary;
+ }
+ case '>':
+ $attary{$attname} = '"yes"';
+ return Array($tagname, $attary, $tagtype, $lt, $pos);
+ break;
+ default:
+ /**
+ * Skip whitespace and see what we arrive at.
+ */
+ $pos = sq_skipspace($body, $pos);
+ $char = substr($body, $pos, 1);
+ /**
+ * Two things are valid here:
+ * '=' means this is attribute type 1 2 or 3.
+ * \w means this was attribute type 4.
+ * anything else we ignore and re-loop. End of tag and
+ * invalid stuff will be caught by our checks at the beginning
+ * of the loop.
+ */
+ if ($char == "="){
+ $pos++;
+ $pos = sq_skipspace($body, $pos);
+ /**
+ * Here are 3 possibilities:
+ * "'" attribute type 1
+ * '"' attribute type 2
+ * everything else is the content of tag type 3
+ */
+ $quot = substr($body, $pos, 1);
+ if ($quot == "'"){
+ $regary = sq_findnxreg($body, $pos+1, "\'");
+ if ($regary == false){
+ return Array(false, false, false, $lt, strlen($body));
+ }
+ list($pos, $attval, $match) = $regary;
+ $pos++;
+ $attary{$attname} = "'" . $attval . "'";
+ } else if ($quot == '"'){
+ $regary = sq_findnxreg($body, $pos+1, '\"');
+ if ($regary == false){
+ return Array(false, false, false, $lt, strlen($body));
+ }
+ list($pos, $attval, $match) = $regary;
+ $pos++;
+ $attary{$attname} = '"' . $attval . '"';
+ } else {
+ /**
+ * These are hateful. Look for \s, or >.
+ */
+ $regary = sq_findnxreg($body, $pos, "[\s>]");
+ if ($regary == false){
+ return Array(false, false, false, $lt, strlen($body));
+ }
+ list($pos, $attval, $match) = $regary;
+ /**
+ * If it's ">" it will be caught at the top.
+ */
+ $attval = preg_replace("/\"/s", """, $attval);
+ $attary{$attname} = '"' . $attval . '"';
+ }
+ } else if (preg_match("|[\w/>]|", $char)) {
+ /**
+ * That was attribute type 4.
+ */
+ $attary{$attname} = '"yes"';
+ } else {
+ /**
+ * An illegal character. Find next '>' and return.
+ */
+ $gt = sq_findnxstr($body, $pos, ">");
+ return Array(false, false, false, $lt, $gt);
+ }
+ }
+ }
+ /**
+ * The fact that we got here indicates that the tag end was never
+ * found. Return invalid tag indication so it gets stripped.
+ */
+ return Array(false, false, false, $lt, strlen($body));
+}