<?PHP

/* Merge language V1.0 20200912 hman                                                   */
/*  V1.1 20201014 hman, fixed output                                                   */
/*  V1.2 20201015 hman, check routine added                                            */
/*  V1.3 20201017 hman, added commentary                                               */
/* V1.31 20210305 hman, changed output of 'changed'                                    */
/*  V1.4 20210327 hman, array_merge MUST NOT be used, array_replace replaces it        */
/*  V1.5 20210328 hman, added syntax check (empty key or value)                        */
/*                                                                                     */
/* Merges the associative arrays of language.php und custom.php of a Tiki localization */
/*                                                                                     */
/* To be run in the directory containing the localization files.                       */
/* - Known limitations: key/value pairs cannot extend over more than one line          */
/* - Not tested for more than 2 key repetitions or for DBCS                            */
/* + Checks both language and custom.php for duplicate entries                         */
/* + It creates these new files:                                                       */
/*   - duplicate_error_lang: duplicate keys in checked files.                          */
/*   - merge_lang: merge of custom and language.php (array_merge).                     */
/*   - new_lang: what has been added (array_diff_key).                                 */
/*   - changed_lang: what has been changed (array_intersect).                          */
/*   - unchanged_lang: what has not been touched (array_diff_key reversed).            */ 

/* global definitions, so they can be used in functions */
global $url, $bannerId, $td, $tikidomain, $prefs;

/* dummy variables preset because we don't have real Tiki variables at hand */
$url = "URLSTRING";
$bannerId = 0;
$td = "TDSTRING";
$tikidomain = "TIKIDOMAINSTRING";
$prefs = "PREFSSTRING";

function chk_file($filename) {
/* Check a given file for incorrect syntax (empty/missing key or value). Then */
/* check for duplicates. PHP would only overwrite old key/value pairs, this */
/* function finds them, so they can be manually compared and eliminated */

	if ( file_exists("./duplicat_error_lang.txt") ) {
	/* tell user file pre-exists */
		echo "-- Error! File ./duplicate_error_lang.txt already exists! Appending.\n";
	}
	/* file for duplicate error logging */
	$fe = fopen("./duplicate_error_lang.txt", "a+");

	/* read the input file given, skip \n */
	$fl = file($filename,FILE_IGNORE_NEW_LINES);

	if (!$fl) {
		echo "-- Error! File " . $filename . " cannot be opened!\n";
		return;
	}

	echo "== Checking file ". $filename . "\n";
	fwrite ($fe, "== Checking file ". $filename . "\n");

	$array = array();
	$linenos = array();

	$linecount = 0;

	foreach ($fl as $line)
	{	
		$linecount++;

		If ( ($line != "<?php") AND ($line != "") AND ($line != "\n") AND ($line != "\$lang = [") AND ($line != "];") AND ($line != "\$lang_custom = array(") AND ($line != ");") AND ($line != "\$lang = array_merge(\$lang, \$lang_custom);") ) {

			list($key, $value) = explode(' => ', $line, 2) + array(NULL, NULL);
			/* Check for syntax errors (empty key or value) */
			if (empty($key)) {
				echo "-- Error! Empty key in line " . $linecount . " for value='" . $value."'\n";
				fwrite ($fe, "-- Error! Empty key in line " . $linecount . " for value='" . $value."'\n");
			}
			if (empty($value)) {
 				echo "-- Error! Empty value in line " . $linecount . " for key='" . $key."'\n";
				fwrite ($fe, "-- Error! Empty value in line " . $linecount . " for key='" . $key."'\n");
			}

			/* Check for double entries */
			if (array_key_exists ($key, $array)) {
				/* previous definition */
				echo "-- Duplicate: key in line " . $linenos[$key] ."\n";
				echo $key . " => ". $array[$key] . "\n";
				/* duplicate definition */
				echo "   is identical with line " . $linecount . ".\n";
				echo $key . " => ". $value . "\n\n";
				/* same as above, log in file */
				fwrite ($fe, "-- Duplicate: key in line " . $linenos[$key] ."\n");
				fwrite ($fe,  $key . " => ". $array[$key] . "\n");
				fwrite ($fe, "   is identical with line " . $linecount . ".\n");
				fwrite ($fe,  $key . " => ". $value . "\n\n");
			}
			

			if ($value !== NULL)
			{
				/* remember keys and their line numbers */
				$array[$key] = $value;
				$linenos[$key] = $linecount;
		    	}	
		}

	}
	echo "== Check completed.\n";
	fwrite ($fe, "== Check completed.\n"); 

	fflush ($fe);
	if (!fclose($fe)) {
   		echo "-- Error! Output file ./duplicate_error_lang.txt is not closeable! Exiting.\n";
		exit;
	}
}
/* end function */

function outputarr($outputfile, $arrout, $comment) {
/* This function outputs the given array to the given output file, introducing */
/* a comment in the second line */

	if ( file_exists($outputfile) ) {
		echo "-- Error! File " . $outputfile . " already exists! Skipping.\n";
		return;
	}
	$fo = fopen($outputfile, "a+");

	if (!$fo or feof($fo)) {
		echo "-- Error! Outputfile " . $outputfile . " is damaged! Exiting.\n";
		exit;
	}

	/* write header */
	$output = "<?php\n";
	fwrite($fo,$output);

	$output = "/* " . $comment . " */\n";
	fwrite($fo,$output);

	$output = "\n\$lang = [\n";
	fwrite($fo,$output);

	foreach ($arrout as $key => $value) {
    		$outputstring= "\"".addcslashes($key,"\n\r\t\$\"\\")."\" => \"".addcslashes($value,"\n\r\t\$\"\\")."\",\n";
    		fwrite($fo, $outputstring);
	}

	/* write footer */
	$output = "];\n";
	fwrite($fo,$output);

	/* flush cache and close */
	fflush ($fo);
	if (!fclose($fo)) {
   		echo "-- Error! Output file " . $outputfile . " is not closeable! Exiting.\n";
		exit;
	}
}
/* end function */

/* Main program */
echo "\n";
echo "=== Merge language V1.5 20210328 hman\n\n";
echo "Merges the associative arrays of language.php und custom.php of a Tiki\n";
echo "localization. To be run in the directory containing the localization files.\n";
echo "Bugfixed version with array_replace instead of array_merge and syntax check.\n\n";

/* Check both files for double key definitions */
chk_file("./language.php");
chk_file("./custom.php");

/* Separation just for looks */
echo "\n";

/* Attn: order of includes is _intentionally_ reversed, */
/* so we can get both $lang and $lang_custom            */
/* ($lang must be initialized or PHP will complain)     */

$lang = array();
include('./custom.php');
include('./language.php');

/* Now perform the four possible array combinations to enable the user to inspect the outcome */

echo "== Merging ./language.php & ./custom.php\n";
/* DO NOT use array_merge, because it won't handle numeric keys correctly! */
$merge = array_replace($lang, $lang_custom);
outputarr ("./merge_lang.txt", $merge, "Merged arrays of language.php and custom.php to replace language.php.");

echo "== Finding new, added key/value pairs\n";
$diff = array_diff_key($lang_custom, $lang);
outputarr ("./new_lang.txt", $diff, "Key/value pairs that do not exist in language.php and were added in custom.php.");

echo "== Finding changes in key/value pairs\n";
$diff = array_intersect_key($lang_custom, $lang);
outputarr ("./changed_lang.txt", $diff, "Key/value pairs from language.php that were changed in custom.php.");

echo "== Finding unchanged key/value pairs\n";
$diff = array_diff_key($lang, $lang_custom);
outputarr ("./unchanged_lang.txt", $diff, "Key/value pairs from language.php that were not touched in custom.php.");

/* end of program */
?>
