<?php
/* Parse html files library module.
   Copyright 2009, Future Lab.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, get a copy via the Internet at
   http://gnu.org/copyleft/gpl.html or write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   MA 02111-1307 USA

   You can contact the author via email at rsmereka@future-lab.com

   Original version, Apr/2009, Rick Smereka */

define('HTML_NEXT_TYPE_TAG', 0);
define('HTML_NEXT_TYPE_TEXT', 1);
define('CR', chr(13));
define('LF', chr(10));

// global vars
$html_line_pos = -1;        // byte position in line
$html_line_num = 0;         // line number in file
$html_line = '';            // line contents
$html_strip_quotes = true;  // strip single and double quotes from tags?

function html_scan_until($handle, $trig, $typ, &$sout)
{
   /* Scan the html stream until a certain string (the trigger)
      is found. The stream handle is expected in 'handle', 'trig'
      must contain the string to trigger on (the trigger string should
      be specified in upper case). The trigger may be an empty string
      which indicates to search only for a specific trigger type and
      not to be concerned about the actual value. 'typ' must contain
      the trigger type (HTML_NEXT_TYPE_TAG or HTML_NEXT_TYPE_TEXT).
      Function returns the return value from 'html_next' with
      'sout' containing the found string. */
   $sout = '';
   $process = false;

   // basic check
   if ($typ != HTML_NEXT_TYPE_TAG && $typ != HTML_NEXT_TYPE_TEXT)
      return(false);

   $ret = html_next($handle, $buf, $hn_typ);
   // echo "html_scan_until:buf=$buf,hn_typ=$hn_typ,ret=$ret,trig=$trig\n";

   while($ret)
      {
      // scan only for type
      if (alltrim($trig) == '')
         {
         // echo "blank trigger\n";

         if ($hn_typ == $typ)
            {
            $process = true;
            $sout = $buf;
            return($ret);
            }

         $ret = html_next($handle, $buf, $hn_typ);
         continue;
         }

      // comparison is case insensitive
      // echo "tmp=$tmp,hn_typ=$hn_typ,typ=$typ\n";

      if (stristr($buf, $trig) != false && $hn_typ == $typ)
         {
         $process = true;
         break;
         }
      else
         $ret = html_next($handle, $buf, $hn_typ);
      }

   if ($process)
      {
      $sout = $buf;
      return($ret);
      }

   return($ret);
}

function html_next($handle, &$sout, &$tout)
{
   /* Scan the input html stream for the very next html tag or text.
      The open file handle is expected in 'handle'. 'sout'
      will contain the captured string upon success. 'tout'
      will also contain a string type (HTML_NEXT_TYPE_TAG or
      HTML_NEXT_TYPE_TEXT). Returns 'true' if 'eof' was not encountered,
      'false' otherwise. Note that 'sout' and 'tout' may contain
      valid values even if the function returns false upon 'eof'. */
   global $html_line, $html_line_pos, $html_line_num, $html_strip_quotes;

   $done = false;
   $ret = '';

   while(!$done)
      {
      // if byte position on the line is out of range, fetch new line
      // echo "html_next:lpos=$html_line_pos,lnum=$html_line_num\n";
      $fetch = false;

      if ($html_line_pos == -1)
         $fetch = true;

      if (!$fetch)
         {
         $len = strlen($html_line);
         // echo "html_next:lpos=$html_line_pos,len=$len\n";
     
         if ($html_line_pos >= $len)
            $fetch = true;
         }

      if ($fetch)
         {
         $tmp = fgets($handle);

         if (feof($handle))
            {
            $sout = $ret;
            return(false);
            }

         $html_line_num++;
         $html_line_pos = 0;

         // trim and remove line delimiters
         $tmp = alltrim($tmp);
         $tmp = strtr($tmp, CR, '');
         $html_line = strtr($tmp, LF, '');
         $len = strlen($html_line);
         // echo $html_line . "\n";
         }

      $ch = substr($html_line, $html_line_pos, 1);

      switch($ch)
         {
         case '<':
            $html_line_pos++;
            $ch = substr($html_line, $html_line_pos, 1);

            // scan until close
            while($html_line_pos < $len)
               {
               if ($ch == '>')
                  {
                  $html_line_pos++;
                  $done = true;
                  $typ = HTML_NEXT_TYPE_TAG;
                  break;
                  }

               if (!$done)
                  {
                  $ret .= $ch;
                  $html_line_pos++;
                  $ch = substr($html_line, $html_line_pos, 1);
                  }
               }

            break;

         default:
            // accumulate until next tag
            while($html_line_pos < $len)
               {
               if ($ch == '<')
                  {
                  // $html_line_pos++;
                  $done = true;
                  $typ = HTML_NEXT_TYPE_TEXT;
                  break;
                  }

               if (!$done)
                  {
                  $ret .= $ch;
                  $html_line_pos++;
                  $ch = substr($html_line, $html_line_pos, 1);
                  }
               }
         }
      }

   // strip quotes if html tag and requested
   if ($html_strip_quotes)
      if ($typ == HTML_NEXT_TYPE_TAG)
         {
         $tmp = str_replace('"', '', $ret);
         $ret = str_replace("'", '', $tmp);
         }

   $sout = $ret;
   $tout = $typ;
   return(true);
}
?>
