Location: PHPKode > projects > Processed Book Open Source > pbos-1.01/read.php
<?php
/**
 * Read a book's contents (or a note's contents)
 *
 * Copyright (C) 2005 Wayne Davison <hide@address.com>
 *
 * 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, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

require 'lib/main.inc';

read_page();

function read_page()
{
    global $build_tag_offsets, $tag_offsets;
    global $icon_names, $disp_mods, $map_defaults, $span_num;

    $book_num = $_GET['b'];
    $book_sect = $_GET['s'];
    $book_target = $_GET['t'] + 0;
    if (!preg_match('/^\d+;-?\d+;\d+$/',
		    join(';', array($book_num, $book_sect, $book_target)))) {
	redir_main();
	return;
    }

    open_db();
    list($uID, $scrname) = get_auth_cookie();

    add_sidebar_divider();
    add_sidebar_image('btn-library', '.');

    $do = "SELECT Title, Copyright, SectionCount, UserID, Access FROM Books WHERE BookID = $book_num LIMIT 1";
    $result = mysql_query($do) or die('SELECT failed: ' . mysql_error() . " (cmd: $do)");
    list($title, $copyright, $sect_cnt, $book_user, $access) = mysql_fetch_row($result);
    if ($book_user != $uID && $uID != 1 && !preg_match("/(^|,)($uID|0)(,|$)/", $access)) {
	close_db();
	start_content('Error');
	if ($book_sect < 0)
	    echo "Sorry -- this note is attached to a book that you don't have permission to read.";
	else
	    echo "Sorry -- you don't have permission to read this book.";
	end_content();
	return;
    }

    if ($uID)
	add_sidebar_image('btn-bookmarks', 'bkmk.php');
    add_sidebar_divider();
    add_sidebar_image('btn-sect_list', "toc.php?b=$book_num");

    if ($book_sect > 0) {
	$i = $book_sect - 1;
	$up_action = "?b=$book_num&s=$i";
	add_sidebar_image('btn-prev_sect', $up_action);
    } else
	add_sidebar_image('dbtn-prev_sect');
    if ($book_sect >= 0 && $book_sect < $sect_cnt - 1) {
	$i = $book_sect + 1;
	$dn_action = "?b=$book_num&s=$i";
	add_sidebar_image('btn-next_sect', $dn_action);
    } else
	add_sidebar_image('dbtn-next_sect');
    //if (!$note_num && $book_user == $uID || $uID == 1)
	//echo button('btn-editbook', "books.php?b=$book_num", 'width=34 height=20');

    sidebar_pg_up_dn($up_action, $dn_action);

    add_sidebar_divider();
    add_sidebar_image('btn-dissect', "dissect.php?b=$book_num&s=$book_sect");
    add_sidebar_image('btn-margin', "margin.php?b=$book_num&s=$book_sect");
    add_sidebar_image('btn-reports', "report.php?b=$book_num&s=$book_sect");

    sidebar_signin($uID, $scrname);

    start_content($title);

    $find = array(
	'/<>/',
	'/^----/',
	"/(?<!\f)'''(.*?'*)(?<!\f)'''/",
	"/(?<!\f)''(.*?'*)(?<!\f)''/",
	'/^====== (.*) ======$/',
	'/^===== (.*) =====$/',
	'/^==== (.*) ====$/',
	'/^=== (.*) ===$/',
	'/^== (.*) ==$/',
	'/^= (.*) =$/',
	'/^[*#:;]*[*#](?![*#:;]) */', // avoiding \s on purpose!
	'/^[*#:;]*:(?![*#:;]) */',
	'/^[*#:;]*;(?![*#:;]) *(.*?): */',
	'/^[*#:;]*;(?![*#:;]) */',
	'/^\{\|(.*)/',
	'/^\|\}/',
	'/^\|\+(.*)/',
	'/^\|-(.*)/',
	'/^!([^\n|]*)\| */',
	'/^! */',
	'/^\|([^\n|]*)\| */',
	'/^\| */',
	'/(?<!\f)\[\[Image:([^]<> ]+) +([^]<>]*)(?<!\f)\]\]/',
	'/(?<!\f)\[\[Image:([^]<> ]+)(?<!\f)\]\]/',
	'/(?<!\f)\[\[(\d+),(\d+[^] ]*) +([^]]+)(?<!\f)\]\]/',
	'/(?<!\f)\[\[(\d+[^] ]*) +([^]]+)(?<!\f)\]\]/',
	'/(?<!\f)\[\[([^] ]+) +([^]]+)(?<!\f)\]\]/',
	'/(?<!\f)\[\[(?!\?|[a-z]+:)([^]<> ]+)(?<!\f)\]\]/',
	'/(?<!\f)\[\[([^]<> ]+)(?<!\f)\]\]/',
	'/^(<t[dhr]\b.*?[>])\n/',
	'/\f/', // \f is internal representation of a quoting backslash.
	'/\s+$/',
	'/^\s+/',
	'/  +/');
    $repl = array(
	"\xA0", // 0xA0 = &nbsp;
	'<hr>',
	'<b>$1</b>',
	'<i>$1</i>',
	'<h6>$1</h6>',
	'<h5>$1</h5>',
	'<h4>$1</h4>',
	'<h3>$1</h3>',
	'<h2>$1</h2>',
	'<h1>$1</h1>',
	'<li>',
	'<dd>',
	'<dt>$1<dd>',
	'<dt>',
	'<table $1>',
	'</table>',
	'<caption>$1</caption>',
	'<tr $1>',
	'<th $1>',
	'<th>',
	'<td $1>',
	'<td>',
	'<img src="$1" $2 />',
	'<img src="$1" border=0 />',
	'<a href="?b=$1&s=$2">$3</a>',
	"<a href='?b=$book_num&s=$1'>$2</a>",
	'<a href="$1">$2</a>',
	'<a href="http://$1">$1</a>',
	'<a href="$1">$1</a>',
	'$1',
	'',
	'',
	'',
	' ');

    $groups = array();
    $do = "SELECT e.GroupID
	FROM EnabledGroups AS e
	LEFT JOIN Groups AS g USING(GroupID)
	WHERE e.UserID = $uID AND g.CanView REGEXP '(^|,)($uID|0)(,|$)'";
    $result = mysql_query($do) or die('SELECT failed: ' . mysql_error() . " (cmd: $do)");
    while (($row = mysql_fetch_row($result)) !== FALSE)
	$groups[$row[0]] = $row[0];
    $group_regex = '(^|,)(' . join('|', $groups) . ')(,|$)';

    if ($book_target) {
	$do = "SELECT AnchorStart
	    FROM BookAnnotations
	    WHERE ID = $book_target AND BookID = $book_num AND ParentID = $book_sect";
	$result = mysql_query($do) or die('SELECT failed: ' . mysql_error() . " (cmd: $do)");
	list($target_offset) = mysql_fetch_row($result);
	if ($target_offset == '')
	    $book_target = 0;
    }

    echo <<<EOT
<script>
document.onmousedown = check_selection;
document.onmouseup = handle_selection;
document.checkScrollPos = 1;
document.annoTypes = new Array();
obj = document.annoTypes[0] = new Object(); obj.HelpText = "Don't create an annotation here";

EOT;
    $do = "SELECT TypeID, UserID, Name, LeftClick, HelpText, EntryType
	FROM AnnotationTypes
	ORDER BY UserID, TypeID";
    $result = mysql_query($do) or die('SELECT failed: ' . mysql_error() . " (cmd: $do)");
    while (($obj = mysql_fetch_object($result)) !== FALSE) {
	$help = preg_replace('/"/', '&quote;', $obj->HelpText);
	$disabled = $obj->EntryType == 'disabled' ? 1 : 0;
	echo <<<EOT
obj = document.annoTypes[{$obj->TypeID}] = new Object(); obj.LeftClick = '{$obj->LeftClick}'; obj.Disabled = $disabled; obj.HelpText = "$help";

EOT;
	if ($obj->EntryType == 'normal') {
	    $selmenu[$obj->UserID] .= <<<EOT
<li><a href="javascript:create_anno({$obj->TypeID})" id=atype{$obj->TypeID}>Create {$obj->Name}</a></li>
EOT;
	}
    }
    echo <<<EOT
document.bookTarget = $book_target;
document.UserID = $uID;
</script>
<div id="pbSelMenuDiv" class="menulist" onmouseover="mousein_menu()" onmouseout="mouseout_menu()"><ul>
EOT;
    echo $selmenu[1];
    if ($uID != 1 && $selmenu[$uID])
	echo '<hr>', $selmenu[$uID];
    echo <<<EOT
<li><a href="javascript:hide_menu()" id=atype0>Cancel</a></li>
</ul></div>
<form name=selform method=post action="annotate.php?do=input&b=$book_num&s=$book_sect">
<input type=hidden name=nest>
<input type=hidden name=pos>
<input type=hidden name=sel>
<input type=hidden name=tID>
<input type=hidden name=annoID value=0>
</form>

EOT;

    if ($book_sect >= 0) {
	$do = "SELECT Text, Offsets IS NULL AS NoOffsets
	    FROM BookSections
	    WHERE BookID = $book_num AND SectionID = $book_sect
	    LIMIT 1";
    } else {
	$note_num = -$book_sect;
	$do = "SELECT _51 AS Text, NoteOffsets IS NULL AS NoOffsets, ParentID, UserID
	    FROM BookAnnotations
	    WHERE ID = $note_num AND BookID = $book_num
	    LIMIT 1";
    }
    $result = mysql_query($do) or die('SELECT failed: ' . mysql_error() . " (cmd: $do)");
    if (($obj = mysql_fetch_object($result)) === FALSE) {
	if ($book_sect == 0)
	    $text = "''No content yet.''";
	else if ($note_num)
	    $text = "'''''This note was deleted!'''''";
	else
	    $text = "'''''Error fetching book content!'''''";
    } else {
	$text = $obj->Text;
	$build_tag_offsets = $obj->NoOffsets;
	$note_parent = $obj->ParentID;
	$note_user = $obj->UserID;
    }

    $anno_attrs = get_attr_data(0);
    $disp_mods = $need_attrs = array();
    $do_vars = join(',', $icon_names);
    $marginalia = $_COOKIE['marginalia'];
    if (preg_match('/^([yn])((?: \d+,\d+,\d+,\d+)*)$/', $marginalia, $out)) {
	if ($out[1] == 'y') {
	    // Set all colors and the font variety to their default.
	    $disp_mods[] = array(0,0,1,2,0,1);
	    $disp_mods[] = array(0,0,1,4,0,1);
	    $disp_mods[] = array(0,0,1,5,0,1);
	    $disp_mods[] = array(0,0,1,6,0,1);
	}
	$min_max = array();
	foreach (explode(' ', trim($out[2])) as $set) {
	    list($tID,$aID,$method,$display) = explode(',', $set);
	    if ($tID < 0 || $aID < 0 || $display < 1 || $display > 99)
		continue;
	    if (($aID > 0 && !$anno_attrs[$aID]) || !$anno_attrs[$display])
		continue;
	    if ($method == 2 && $aID > 0) {
		$obj = $min_max[$aID];
		if (!$obj) {
		    $do = "SELECT MIN(`_$aID`) as lo, MAX(`_$aID`) as hi
			FROM BookAnnotations
			WHERE BookID = $book_num";
		    if (($result = mysql_query($do)) === FALSE
		     || ($obj = mysql_fetch_object($result)) === FALSE)
			continue;
		    $min_max[$aID] = $obj;
		}
		$min = $obj->lo;
		$max = $obj->hi;
	    } else {
		$min = 0;
		$max = 1;
	    }
	    $disp_mods[] = array($tID,$aID,$method,$display,$min,$max);
	    $need_attrs[$aID] = 1;
	}
	// ff00cc ff0066 ff0000 ff6600 ffcc00 ccff00 66ff00 00ff00 00ff66 00ffcc ??
	$map_defaults['IconTextColor'] = array('blue', 'green', '#CDAD00', 'orange', 'red');
	$map_defaults['IconBorderColor'] = $map_defaults['IconTextColor'];
	$map_defaults['IconBackgroundColor'] = array('red', 'orange', 'green', 'blue', 'black');
	$map_defaults['IconFontStyle'] = array('.i.', 'b..', 'bi.', '.ic', 'bic');
    }
    $need_attrs[50] = 1; // We need the URL.
    foreach ($anno_attrs as $aID => $aobj) {
	if (substr($aID, 0, 1) == '#')
	    continue;
	if ($need_attrs[$aID])
	    $do_vars .= ", _$aID";
    }
    #echo "#$do_vars#";
    $do = "SELECT ID, b.TypeID, b.UserID, AnchorStart, AnchorLen, $do_vars,
	    _51 != '' AS HasNote, l.Name AS AnnoType
	FROM BookAnnotations AS b LEFT JOIN AnnotationTypes AS l USING(TypeID)
	WHERE BookID = $book_num AND ParentID = $book_sect AND _99 REGEXP '$group_regex'
	ORDER BY AnchorStart";
    $link_result = mysql_query($do) or die('SELECT failed: ' . mysql_error() . " (cmd: $do)");
    if (($lnk = mysql_fetch_assoc($link_result)) !== FALSE)
	$anno_start = $lnk['AnchorStart'];
    else
        $anno_start = 9999999;

    // Make table parsing easier by transforming multi-cell-per-line syntax
    // into single-cell-per-line syntax *WITHOUT* changing the string length!
    preg_match_all('/^[|!].*$/m', $text, $table_lines, PREG_OFFSET_CAPTURE);
    foreach ($table_lines[0] as $match) {
	list($line,$line_offset) = $match;
	preg_match_all($line[0] == '!' ? '/!!/' : '/\|\|/', $line, $matches, PREG_OFFSET_CAPTURE);
	foreach ($matches[0] as $match)
	    $text[$line_offset + $match[1]] = "\n";
    }

    $cur_list = '';
    $span_num = 0;
    $offset = 0;
    $prev_pos = -1;
    $need_p = 1;
    $tag_str = '';
    $anno_data = '';
    $anno_cnt = 0;
    foreach (preg_split('/\r?\n/', $text) as $line) {
	if ($line == '') {
	    $need_p = 1;
	    $offset++;
	    continue;
	}
	$line_len = strlen($line) + 1;
	$extra_tags = array();
	if (preg_match('/^([*#:;]*;(?![*#:;]).*?):/', $line, $out))
	    $extra_tags[] = array('DD', strlen($out[1]));
	$extra = 0;
	while (1) {
	    if ($book_target && $target_offset <= $anno_start
	     && ($pos = $target_offset - $offset) < $line_len) {
		if ($pos < 0)
		    $pos = 0;
		$add = '<a name=pblnk></a>';
		$line = substr_replace($line, $add, $pos + $extra, 0);
		$extra += strlen($add);
		$book_target = 0;
	    }
	    if (($pos = $anno_start - $offset) >= $line_len)
		break;
	    if ($pos < 0)
		$pos = 0;
	    if ($pos != $prev_pos) {
		$span_num++;
		$add = "<span id=s$span_num>" . $line[$pos + $extra] . '</span>';
		$line = substr_replace($line, $add, $pos + $extra, 1);
		$extra += strlen($add) - 1;
		$prev_pos = $pos;
	    }
	    $anno_data .= get_anno_data($lnk);
	    $anno_cnt++;
	    if (($lnk = mysql_fetch_assoc($link_result)) !== FALSE)
		$anno_start = $lnk['AnchorStart'];
	    else
		$anno_start = 9999999;
	}
	$prev_pos = -1;
	if (preg_match('/^[*#:;]+/', $line, $out))
	    $new_list = preg_replace('/;/', ':', $out[0]);
	else {
	    $new_list = '';
	    if ($cur_list != '')
		$need_p = 1;
	}
	#echo ":$cur_list:$new_list:<br />";
	if ($new_list != $cur_list) {
	    $list = $new_list;
	    $cur_len = strlen($cur_list);
	    $len = strlen($list);
	    while ($len < $cur_len) {
		$list .= ' ';
		$len++;
	    }
	    while ($len > $cur_len) {
		$cur_list .= ' ';
		$cur_len++;
	    }
	    $add = array();
	    while ($list != $cur_list) {
	    #echo "<pre>!$cur_list!\n!$list!\n</pre>";
		$x = substr($cur_list, -1, 1);
		$cur_list = substr($cur_list, 0, -1);
		switch ($x) {
		case '#':
		    $tag_str = pop_tag($tag_str, 'OL');
		    echo "</ol>\n";
		    break;
		case '*':
		    $tag_str = pop_tag($tag_str, 'UL');
		    echo "</ul>\n";
		    break;
		case ':':
		    $tag_str = pop_tag($tag_str, 'DL');
		    echo "</dl>\n";
		    break;
		}
		$x = substr($list, -1, 1);
		$list = substr($list, 0, -1);
		switch ($x) {
		case '#':
		    array_unshift($add, 'ol');
		    $need_p = 0;
		    break;
		case '*':
		    array_unshift($add, 'ul');
		    $need_p = 0;
		    break;
		case ':':
		    array_unshift($add, 'dl');
		    $need_p = 0;
		    break;
		}
	    #echo "<pre>!$cur_list!\n!$list!!\n</pre>";
	    }
	    foreach ($add as $tag) {
		echo '<', $tag, ">\n";
		$tag_str = push_tag($tag_str, strtoupper($tag), $offset);
	    }
	    $cur_list = $new_list;
	}
	if ($need_p) {
	    if (!preg_match(':^(=|</?blockquote>):', $line)) {
		echo '<p>';
		$tag_str = push_tag($tag_str, 'P', $offset);
	    }
	    $need_p = 0;
	}
	$line = preg_replace($find, $repl, $line) . "\n";
	if (preg_match(':<(h[1-6]|table|tr|td|th|li|dd|dt|div|blockquote|center)[ >]:i', $line, $out)) {
	    $tag = strtoupper($out[1]);
	    preg_match(':/([A-Z]+[1-6]?)(#\d+)?/([A-Z]+[1-6]?)(#\d+)?$:', $tag_str, $out);
	    if (($top = $out[3]) == 'P')
		$top = $out[1];
	    switch ($tag) {
	    case 'TD':
	    case 'TH':
		if ($top == 'TABLE') {
		    echo '<tr>';
		    $tag_str = push_tag($tag_str, 'TR', $offset);
		} elseif ($top == 'TD')
		    echo '</td>';
		elseif ($top == 'TH')
		    echo '</th>';
		break;
	    case 'TR':
		if ($top == 'TD')
		    echo '</td></tr>';
		elseif ($top == 'TH')
		    echo '</th></tr>';
		break;
	    }
	    $tag_str = push_tag($tag_str, $tag, $offset);
	    foreach ($extra_tags as $tag_array)
		$tag_str = push_tag($tag_str, $tag_array[0], $offset + $tag_array[1]);
	}
	if (preg_match(':</(h[1-6]|table|tr|td|th|li|dd|dt|div|blockquote|center)[ >]:i', $line, $out)) {
	    $tag = strtoupper($out[1]);
	    if ($tag == 'TABLE')
		echo '</td></tr>';
	    echo $line;
	    $tag_str = pop_tag($tag_str, $tag);
	} else
	    echo $line;
	$offset += $line_len;
    }
    if ($cur_list != '') {
	for ($j = strlen($cur_list); $j--; ) {
	    switch ($cur_list[$j]) {
	    case '#':
		echo "</ol>\n";
		break;
	    case '*':
		echo "</ul>\n";
		break;
	    case ':':
		echo "</dl>\n";
		break;
	    }
	}
    }

    if ($anno_start < 9000000) { // 9999999 doesn't work here?!?
	echo '<p>';
	if ($book_target)
	    echo '<a name=pblnk></a>';
	$span_num++;
	echo "<span id=s$span_num><i>[Orphaned Annotations]</i></span>\n";
	do {
	    $lnk['AnchorLen'] = 22;
	    $anno_data .= get_anno_data($lnk);
	    $anno_cnt++;
	} while (($lnk = mysql_fetch_assoc($link_result)) !== FALSE);
    }

    if ($note_num) {
	echo "<p><a href='?b=$book_num&s=$note_parent&t=$note_num#pblnk'>[Go up a level to this note's margin icon]</a>\n";
	if ($note_user == $uID) {
	    echo ' &nbsp; ',
		button('btn-editnote',
		       "annotate.php?do=editnote&b=$book_num&s=$note_parent&a=$note_num",
		       'width=34 height=20');
	}
    } elseif ($book_sect == 0)
	echo '<p><font size=1>', $copyright, '</font></p>';

    if ($book_sect >= 0 && $book_sect < $sect_cnt - 1) {
	echo '<br clear=all><p align=center>',
	    button('btn-next_sect', $dn_action, 'width=128 height=20'),
	    '</p>';
    }
    if ($anno_data != '') {
	echo <<<EOT
<script>
document.bookNum = $book_num;
document.bookRef = '&b=$book_num';
document.sectRef = '&s=$book_sect';
document.annoData = new Array(0$anno_data);
document.annoCount = $anno_cnt;
//document.oncontextmenu = handle_selection;
</script>

EOT;
    }

    if ($build_tag_offsets) {
	if ($book_sect >= 0) {
	    $do = "UPDATE BookSections
		SET Offsets = '$tag_offsets'
		WHERE BookID = $book_num AND SectionID = $book_sect";
	} else {
	    $do = "UPDATE BookAnnotations
		SET NoteOffsets = '$tag_offsets'
		WHERE ID = $note_num AND BookID = $book_num";
	}
	mysql_query($do) or die('UPDATE failed: ' . mysql_error() . " (cmd: $do)");
	#echo "<hr><pre>\n", $tag_offsets, "\n</pre><hr>";
    }

    close_db();
    end_content();
}

function get_anno_data($lnk)
{
    global $icon_names, $disp_mods, $map_defaults, $span_num;
    global $COLOR_LIST, $FONT_LIST;

    foreach ($disp_mods as $array) {
	list($tID,$aID,$method,$display,$min,$max) = $array;
	if ($tID > 0 && $tID != $lnk['TypeID'])
	    continue;
	if ($aID == 0)
	    $val = preg_replace('/\$_AnnoType/', $lnk['AnnoType'], $anno_attrs[$display]->DefaultValue);
	else {
	    $val = $lnk['_'.$aID];
	    if ($val == '')
		continue;
	}
	$var = $icon_names[$display];
	$val = preg_replace('/\s+/', ' ', $val);
	if ($method == 2) { // scale/map values
	    $diff = $max - $min;
	    if ($diff > 0)
		$val = ($val - $min) / $diff;
	    else
		$val = 1;
	    if ($map_defaults[$var])
		$val = $map_defaults[$var][$val * 4 + 0.5];
	    else
		$val = ((int)($val * 10000) / 100) . '%';
	} elseif ($method >= 20) {
	    $cnt = 20;
	    foreach ($FONT_LIST as $val => $font) {
		if ($cnt++ == $method)
		    break;
	    }
	} elseif ($method >= 10) {
	    $cnt = 10;
	    foreach ($COLOR_LIST as $val => $color) {
		if ($cnt++ == $method)
		    break;
	    }
	}
	$lnk[$icon_names[$display]] = $val;
    }
    $anno_text = preg_replace('/\|/', '&#124;', $lnk['IconText']);
    $anno_title = preg_replace('/\|/', '&#124;', $lnk['IconMouseoverText']);
    $fg_color = preg_replace('/[^#0-9a-z]/i', '', $lnk['IconTextColor']);
    $bg_color = preg_replace('/[^#0-9a-z]/i', '', $lnk['IconBackgroundColor']);
    $border_color = preg_replace('/[^#0-9a-z]/i', '', $lnk['IconBorderColor']);
    $font = preg_replace('/[^.ibc]/', '', $lnk['IconFontStyle']);
    $anno_url = preg_replace('/\|/', '&#124;', $lnk['_50']); // URL
    if ($anno_url == '' && $lnk['HasNote'])
	$anno_url = '&s=-' . $lnk['ID'];
    return ",\n\"" . join('|', array_map('addslashes',
	array($span_num, $lnk['ID'], $lnk['TypeID'], $lnk['UserID'], $lnk['AnchorLen'],
	      $anno_text, $anno_title, $fg_color, $bg_color, $border_color, $font, $anno_url))) . '"';
}

function push_tag($tag_str, $tag, $offset)
{
    global $depth_count;
    global $build_tag_offsets, $tag_offsets;

    if ($tag != 'TABLE')
	$tag_str = preg_replace(':/P(#\d+)?$:', '', $tag_str);
    if ($tag == 'TR')
	$tag_str = preg_replace(':/(TD|TH)(#\d+)?$:', '', $tag_str);
    elseif ($tag == 'DD')
	$tag_str = preg_replace(':/DT(#\d+)?$:', '', $tag_str);
    elseif ($tag == 'DT')
	$tag_str = preg_replace(':/DD(#\d+)?$:', '', $tag_str);
    if (preg_match('/^(LI|DT|DD|TD|TH|TR)$/', $tag))
	$tag_str = preg_replace(':/'.$tag.'(#\d+)?$:', '', $tag_str);
    $tag_str .= '/' . $tag;
    $cnt = ++$depth_count[$tag_str];
    if ($cnt > 1)
	$tag_str .= '#' . $cnt;
    if ($build_tag_offsets)
	$tag_offsets .= $tag_str . ':' . $offset . "\n";
    return $tag_str;
}

function pop_tag($tag_str, $tag)
{
    while (preg_match(':/([A-Z]+[1-6]?)(#\d+)?$:', $tag_str, $out)) {
	$pop = $out[1];
	if ($pop != $tag && $pop != 'P') {
	    switch ($tag) {
	    case 'TABLE':
		if (!preg_match('/^(TD|TH|TR)$/', $pop))
		    return $tag_str; // Impossible...
		break;
	    case 'OL':
	    case 'UL':
		if ($pop != 'LI')
		    return $tag_str; // Impossible...
		break;
	    case 'DL':
		if ($pop != 'DD' && $pop != 'DT')
		    return $tag_str; // Impossible...
		break;
	    }
	}
	$tag_str = preg_replace(':/([A-Z]+[1-6]?)(#\d+)?$:', '', $tag_str);
	if ($pop == $tag)
	    break;
    }
    return $tag_str;
}

?>
Return current item: Processed Book Open Source