#!/usr/bin/ksh93

########################################################################
#                                                                      #
#               This software is part of the ast package               #
#                    Copyright (c) 2012 Roland Mainz                   #
#                      and is licensed under the                       #
#                 Eclipse Public License, Version 1.0                  #
#                    by AT&T Intellectual Property                     #
#                                                                      #
#                A copy of the License is available at                 #
#          http://www.eclipse.org/org/documents/epl-v10.html           #
#         (with md5 checksum b35adb5213ca9657e911e9befb180842)         #
#                                                                      #
#                                                                      #
#                 Roland Mainz <roland.mainz@nrubsig.org>              #
#                                                                      #
########################################################################

#
# Copyright (c) 2012, Roland Mainz. All rights reserved.
#


# memory safeguards to prevent out-of-control memory consumption
ulimit -M $(( 1024 * 1024 ))
ulimit -v $(( 1024 * 1024 ))
ulimit -d $(( 1024 * 1024 ))

# input text


function loadlargefile
{
	typeset s
	nameref data=$1
	data=''
	s=''
	while read -n1024 s ; do
		data+="$s"$'\n'
	done <"$2"
	data+="$s"$'\n'

	return 0
}


# test data

# simple test 1:
# notes:
# - Standalone '>' is valid XML text
typeset -r xmltext=$'<h1 style=\'nice\' h="bar">> <oook:banana color="<yellow />"><oook:apple-mash color="<green />"><div style="some green"><illegal tag /><illegal2 itag=ivalue2 /><br /> a text </div>More [TEXT].<!-- a comment (<disabled>) --></h1>'

# test files
#typeset -r xmltext="$( </usr/share/libgweather/Locations.xml )" # too big
#typeset -r xmltext="$( < /usr/share/sgml/docbook/xsl-stylesheets-1.69.1-5.1/html/param.xml )"

#typeset xmltext
#loadlargefile xmltext '/usr/share/mime/packages/freedesktop.org.xml'

print -u2 -f $"%d characters to process...\n" "${#xmltext}"
	
#
# parse the XML data
#
function parse_xmltext
{
	typeset xmltext="$2"
	nameref ar="$1"
	typeset dummy

	# fixme:
	# - We want to enforce standard conformance - does ~(Exp) or ~(Ex-p) does that ?
	dummy="${xmltext//~(Ex-p)(?:
		(<!--.*-->)+?|			# xml comments
		(<[:_[:alnum:]-]+
			(?: # attributes
				[[:space:]]+
				(?: # four different types of name=value syntax
					(?:[:_[:alnum:]-]+=[^\"\'[:space:]]+?)|		#x='foo=bar huz=123'
					(?:[:_[:alnum:]-]+=\"[^\"]*?\")|		#x='foo="ba=r o" huz=123'
					(?:[:_[:alnum:]-]+=\'[^\']*?\')|		#x="foox huz=123"
					(?:[:_[:alnum:]-]+)				#x="foox huz=123"
				)
			)*
			[[:space:]]*
			\/?	# start tags which are end tags, too (like <foo\/>)
		>)+?|				# xml start tags
		(<\/[:_[:alnum:]-]+>)+?|	# xml end tags
		([^<]+)				# xml text
		)/D}"

	# debug output
#	printf $"#dummy=%q\n" "${dummy}"
#	print -v .sh.match

	# copy ".sh.match" to array "ar"
	integer i j
	for i in "${!.sh.match[@]}" ; do
		for j in "${!.sh.match[i][@]}" ; do
			[[ -v .sh.match[i][j] ]] && ar[i][j]="${.sh.match[i][j]}"
		done
	done

	return 0
}

function rebuild_xml_and_verify
{
	nameref ar="$1"
	typeset xtext="$2" # xml text

	#
	# rebuild the original text from "ar" (copy of ".sh.match")
	# and compare it to the content of "xtext"
	#
	tmpfile=$(mktemp)

	{
		# rebuild the original text, based on our matches
		nameref nodes_all=ar[0]		# contains all matches
		nameref nodes_comments=ar[1]	# contains only XML comment matches
		nameref nodes_start_tags=ar[2]	# contains only XML start tag matches
		nameref nodes_end_tags=ar[3]	# contains only XML end tag matches
		nameref nodes_text=ar[4]	# contains only XML text matches
		integer i
		for (( i = 0 ; i < ${#nodes_all[@]} ; i++ )) ; do
			[[ -v nodes_comments[i]		]] && printf '%s' "${nodes_comments[i]}"
			[[ -v nodes_start_tags[i]	]] && printf '%s' "${nodes_start_tags[i]}"
			[[ -v nodes_end_tags[i]		]] && printf '%s' "${nodes_end_tags[i]}"
			[[ -v nodes_text[i]		]] && printf '%s' "${nodes_text[i]}"
		done
		printf '\n'
	} >"${tmpfile}"

	if cmp <( printf '%s\n' "${xtext}") "${tmpfile}" ; then
		printf $"#input and output OK (%d characters).\n" "$(wc -m <"${tmpfile}")"
	else
		printf $"#difference between input and output found.\n"
		diff -u <( printf '%s\n' "${xtext}") "${tmpfile}"
	fi

	rm -f "${tmpfile}"
	return 0
}

# main
set -o nounset

builtin cmp
builtin mktemp
builtin rm
builtin wc

typeset -a xar # used to copy the data from .sh.match

parse_xmltext xar "$xmltext"
rebuild_xml_and_verify xar "$xmltext"

print -v xar

#pmap -x $$
#true
