<?php
/* Heredoc extract V1.0 20210423 hman                            */
/*                 V1.5 20210507 hman Added add_jq_onready       */
/*                 V1.6 20210507 hman Added add_js               */
/*                 V1.7 20210510 hman Now sorting iterators      */
/*                                                               */
/* Extracts heredoc content (<<<MARK...MARK)                     */
/*   and strings pumped into jq_on_ready() and add_js() as well. */
/* Based on the tokenizer from tra_extract2                      */

global $remember;

function trim_once($text, $c) {
/* Just like trim(), but only 1 char trimmed */
	$tstart = 0;
	$tend = strlen($text);
	if (substr($text,0,1) === $c)
		$tstart = 1;
	if (substr($text,-1,1) === $c)
		$tend = strlen($text)-2;
		/* -2 because substr starts at 0 */

	return substr($text, $tstart, $tend);
}

function extract_php ($file) {
/* Version for PHP or Javascript files: Extract tra() and tr() enclosed original language strings. Results are */
/* output on stdout immediately, but output to file gets cached first, and written later - in order to be able */
/* to skip file name display for files without content. PHP's built-in tokenizer is utilized for the job.      */

global $remember;

	$found="";
	$foundtra=FALSE;
	$foundtr=FALSE;
	echo "\n//".trim($file,"./")."\n";
	$heredoc = FALSE;
	$jqonready = FALSE;
	$jsfound = 0;

	$data = file_get_contents($file);
	$tokens = token_get_all($data);

/* For debugging purposes uncomment */
/*	foreach ($tokens as $token) {
		if (is_array($token)) {
			echo "Line {$token[2]}: ", token_name($token[0]), " ('{$token[1]}')", PHP_EOL;
		}
	} 
	reset($tokens);*/ 
	foreach ($tokens as $token) {
		if (is_array($token)) {
			if (!$heredoc) {
				/* heredoc routine will also extract embedded HTML, but that is tolerable. */
				if (token_name($token[0]) == "T_START_HEREDOC") {
					$heredoc = TRUE;
                    			if ($jqonready) {
                        			echo "-- Info: heredoc inside add_jq_onready\n";
                        			$jqonready = FALSE;
                    			} else {
						$jsfound++;
						$newfile = $file.$jsfound . ".js";
						$remember[] = $newfile;
						echo "\n-- Info: Heredoc found, created " . $newfile . "\n";
						$fh = fopen($newfile, "w+");
						if (!$fh or feof($fh)) {
							echo "Error! Extracted file " . $newfile . " is damaged!\n";
				    			exit;
					    	}
               			     }
				}
			} else {
				if (token_name($token[0]) == "T_END_HEREDOC") {
					$heredoc = FALSE;
					fflush($fh);
					if (!fclose($fh)) {
						echo "Error! Extracted file " . $newfile . " is not closeable!\n";
					}

				} else {
					fwrite ($fh,stripslashes($token[1]));
				}
			}
			if (!$jqonready) {
			/* add_jq_onready is not easily parsed by the tokenizer, no clear end is signalled */
				if ( (token_name($token[0]) == "T_STRING") && ( ($token[1] == "add_jq_onready") || 
					($token[1] == "add_js") ) ) {
					$jsfound++;
					$jqonready = TRUE;
					$newfile = $file.$jsfound . ".js";
					$remember[] = $newfile;
					echo "\n-- Info: add_jq_onready/add_js found, created " . $newfile . "\n";
					$fh = fopen($newfile, "w+");
					if (!$fh or feof($fh)) {
						echo "Error! Extracted file " . $newfile . " is damaged!\n";
						exit;
					}

				}
			} else {
				/* Try to determine end by looking for something typically PHP */
				if ( (token_name($token[0]) == "T_OBJECT_OPERATOR") && ($token[1] == "->") ) {
				/* Stopping after the arrow operator means we do read the last object before that. */
				/* This is only to find new tra() and not to write pure JS, so that is tolerable. */
				/* Because the JS is in a quote string, stripslashing is necessary. */
					fwrite ($fh,trim_once(stripslashes($token[1]),"'"));
					fflush($fh);
					if (!fclose($fh)) {
						echo "Error! Extracted file " . $newfile . " is not closeable!\n";
					}
					$jqonready = FALSE;
				} else {
					fwrite ($fh,trim_once(stripslashes($token[1]),"'"));
				} 
			}
 		} /* end if isarray */
	} /* end foreach */
/* end of function */
}

/* Main program */
echo "\nHeredoc extract V1.7 202100510 hman\n";
echo "Extracts heredoc content (<<<MARK...MARK), add_jq_onready(), add_js().\n";
echo "Usage: Start in Tiki root dir.\n";
echo "Warning: Creates lots of extracted .js files. To make it easier\n";
echo "   to clean up afterwards, a delete script is created (Linux only).\n";

$fd = fopen("./heredoc_extract_deletescript.sh", "w+");
if (!$fd or feof($fd)) {
	echo "Error! Delete script file is damaged!\n";
	exit;
}

fwrite ($fd, "#!/bin/bash\n");
fwrite ($fd, "\n");
fwrite ($fd, "echo \"== Heredoc extractor V1.7 delete script 20210510 hman ==\"\n");
fwrite ($fd, "echo \"Linux only.\"\n\n");

$remember = [];

$dir_iterator = new RecursiveDirectoryIterator(".");
$iterator = new RecursiveIteratorIterator($dir_iterator, RecursiveIteratorIterator::SELF_FIRST);
// could use CHILD_FIRST if you so wish

/* Convert iterators to array, so we can sort them */
foreach ($iterator as $dirIt => $fileObj) {
	$paths[] = $fileObj->getPathname();
}
sort ($paths, SORT_NATURAL | SORT_FLAG_CASE);

/* Main loop to iterate through the contents of the file that was identified */
foreach ($paths as $file) {
	/* PHP file found, process if not in ignored path */
	if ((pathinfo($file, PATHINFO_EXTENSION) == "php") &&
		(strpos(pathinfo($file, PATHINFO_DIRNAME), "vendor_bundled/vendor") == 0) && 
		(strpos(pathinfo($file, PATHINFO_DIRNAME), "vendor_extra/fullcalendar-resourceviews") == 0)) {
		extract_php($file);
	}
}

echo "\n-- Summary: Created these files, script for removal generated\n";
foreach ($remember as $line) {
	echo $line."\n";
	fwrite ($fd, "rm " . $line . "\n");
}
fwrite ($fd, "\necho \"Deletion completed.\"\n");
fwrite ($fd, "echo\n");

fflush($fd);
if (!fclose($fd)) {
	echo "Error! Delete script file is not closeable!\n";
}

/* Just for looks */
echo "\n";

/* end of program */
?>
