<?xml version="1.0" ?><!-- -*- SGML -*- -->
<package>
    <comment>
        Licensed to the Apache Software Foundation (ASF) under one
        or more contributor license agreements.  See the NOTICE file
        distributed with this work for additional information
        regarding copyright ownership.  The ASF licenses this file
        to you under the Apache License, Version 2.0 (the
        "License"); you may not use this file except in compliance
        with the License.  You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

        Unless required by applicable law or agreed to in writing,
        software distributed under the License is distributed on an
        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
        KIND, either express or implied.  See the License for the
        specific language governing permissions and limitations
        under the License.
    </comment>
    <job id="run_locale_utils" prompt="no">
        <?job error="false" debug="false" ?>
        <runtime>
            <description>
Checks locale utilities:
    1. Locale utilities sanity: location, output, etc;
    2. Functionality:
        - (re)generation  of databases;
            </description>
            <named helpstring="Debug output" name="d"/>
            <named helpstring="Perform sanity check" name="s"/>
            <named helpstring="Perform functionality check" name="f"/>
            <named helpstring="Path to the locale source files"
                name="i" type="string"/>
            <named helpstring="Locale name" name="l" type="string"/>
            <named helpstring="Output file" name="O" type="string"/>
            <example>cscript run_locale_utils.wsf /s /b:..\..\..\bin\11s"
            </example>
            <usage>
Usage: cscript run_locale_utils.wsf [/d] [/n] [/s] [/f [/i:@NlsDir /l:@LocaleName]] [/b:@BinDir] [/O:@Out],
where
- "/d" debug;
- "/n" no cleanup;
- "/s" tests location, output;
- "/f" tests functionality; is followed by:
    - "/i:@NlsDir>"
    - "/l:@LocaleName>";
- "/b:@BinDir";
- "/O:@OutFile"
            </usage>
        </runtime>
        <object id="fso" progid="Scripting.FileSystemObject"/>
        <object id="WshShell" progid="WScript.Shell"/>
        <script id="run_locale_utils" language="JScript">
<![CDATA[
//
// run_locale_utils script for Stdcxx library
//

var dbgout     = false;
var chk_sanity = false;
var chk_func   = false;
var nlsdir     = "";
var locale_db  = "";
var bindir     = "";
var outstrm    = WScript.StdOut;
var no_clean   = false;

var locale     = "locale.exe";
var localedef  = "localedef.exe";

var TemporaryFolder = 2;
var tmpdir = fso.GetSpecialFolder(TemporaryFolder) + "\\" + fso.GetTempName();

// assertions
var assertions       = 0;
var failedassertions = 0;

var run_stdout;
var run_stderr;

var WEnv = WshShell.Environment("PROCESS");

// printf the message line to the stderr
function DebugOutLine(msg)
{
    if (dbgout)
        WScript.StdErr.WriteLine(msg);
}

// printf the message to the stderr
function DebugOut(msg)
{
    if (dbgout)
        WScript.StdErr.Write(msg);
}

// execute command and set run_stdout to the cmd stdout content;
// set run_stderr to the cmd stderr content
function Run(cmd)
{
    var exec = WshShell.Exec(cmd);
    run_stdout = "";
    run_stderr = "";
    while (0 == exec.Status) {
        WScript.Sleep(100);
        run_stdout += exec.StdOut.ReadAll();
        run_stderr += exec.StdErr.ReadAll();
    }

    run_stdout += exec.StdOut.ReadAll();
    run_stderr += exec.StdErr.ReadAll();

    return exec;
}

function Cleanup()
{
    if (!no_clean && fso.FolderExists(tmpdir))
        fso.DeleteFolder(tmpdir, true);
}

function Exit(code)
{
    Cleanup();
    WScript.Quit(code);
}

// convert number num to string with specified width
function FormatNumber(num, width)
{
    var s = num.toString();
    var spaces = width - s.length;
    for (var i = 0; i < spaces; ++i)
        s = " " + s;
    return s;
}

// create folder with intermediate folders, if needed
function CreateFolder(path)
{
    var res = true;

    if (!fso.FolderExists(path))
    {
        var parent = fso.GetParentFolderName(path);
        if (0 == parent.length)
            return false;
        res = CreateFolder(parent);
        if (res)
        {
            try
            {
                fso.CreateFolder(path);
            }
            catch (e)
            {
                res = false;
            }
        }
    }

    return res;
}

var description = new run_locale_utils; // run

//////////////////////////////////////////////////////////////////////////////
//	Function definitions - checking sanity
//////////////////////////////////////////////////////////////////////////////

function check_locale_help()
{
    DebugOut("Checking \"locale --help\" output...");

    var cmd = locale + " --help";
    var exec = Run(cmd);

    var xout = new Array("NAME", "SYNOPSIS", "DESCRIPTION");

    for (var i = 0; i < xout.length; ++i)
    {
        ++assertions;

        if (0 > run_stdout.search(xout[i]))
        {
            DebugOutLine(" incorrect.");
            DebugOutLine("ERROR: \"locale --help\" gives wrong output ("
                   + xout[i] + ").");

            ++failedassertions;

            return;
        }
    }

    DebugOutLine(" correct.");
}

function check_locale_all()
{
    DebugOut("Checking \"locale -a\" output...");

    var cmd = locale + " -a";
    var exec = Run(cmd);
    var aout = run_stdout.split("\n");

    for (var i = 0; i < aout.length; ++i)
    {
        ++assertions;

        var line = aout[i].replace("\r", "").replace("\n", "");
        
        if (0 == line.length || "C" == line)
            continue;

        if (0 > line.search(new RegExp("[a-z]\{2\}_[A-Z]\{2\}")))
        {
            DebugOutLine(" incorrect.");
            DebugOutLine("    Warning: Locale name " + line
                   + " not matching pattern.");

            ++failedassertions;

            return;
        }
    }

    DebugOutLine("check completed.");
}

function check_locale_m()
{
    DebugOut("Checking \"locale -m\" output...");

    var cmd = locale + " -m";
    var exec = Run(cmd);
    var aout = run_stdout.split("\n");

    for (var i = 0; i < aout.length; ++i)
    {
        ++assertions;

        var line = aout[i].replace("\r", "").replace("\n", "");
        
        if (0 > line.search(new RegExp(".cm")))
        {
            DebugOutLine(" incorrect.");
            DebugOutLine("ERROR: \"locale -m\" failed.");

            ++failedassertions;

            return;
        }
    }

    DebugOutLine(" correct.");
}

function check_locale_k()
{
    DebugOut("Checking \"locale -k LC_ALL\" output...")

    var cmd = locale + " -k LC_ALL";
    var exec = Run(cmd);

    var xout = new Array("upper", "lower", "space", "print", "cntrl",
        "alpha", "digit", "punct", "graph", "xdigit", "toupper",
        "tolower", "abday", "day", "abmon", "", "mon", "am_pm",
        "d_t_fmt", "d_fmt", "t_fmt", "t_fmt_ampm", "int_curr_symbol",
        "currency_symbol", "mon_decimal_point", "mon_thousands_sep",
        "mon_grouping", "positive_sign", "negative_sign", "int_frac_digits",
        "frac_digits", "p_cs_precedes", "p_sep_by_space", "n_cs_precedes",
        "n_sep_by_space", "p_sign_posn", "n_sign_posn", "decimal_point",
        "thousands_sep", "grouping");

    var any_failed = false;

    for (var i = 0; i < xout.length; ++i)
    {
        ++assertions;

        if (0 > run_stdout.search(xout[i]))
        {
            // output text only for the first failure
            if (!any_failed)
                DebugOutLine(" incorrect.");

            DebugOutLine("ERROR: \"locale -k\" gives wrong output (" +
                         + xout[i] +").");

            ++failedassertions;

            any_failed = true;

        }
    }

    if (!any_failed)
        DebugOutLine(" correct.");
}

function check_localedef_help()
{
    DebugOut("Checking \"localedef --help\" output...");

    var cmd = localedef + " --help";
    var exec = Run(cmd);

    var xout = new Array("NAME", "SYNOPSIS", "DESCRIPTION");

    for (var i = 0; i < xout.length; ++i)
    {
        ++assertions;

        if (0 > run_stdout.search(xout[i]))
        {
            DebugOutLine(" incorrect.");
            DebugOutLine("ERROR: \"localedef --help\" gives wrong output ("
                   + xout[i] + ").");

            ++failedassertions;

            return;
        }
    }

    DebugOutLine(" correct.");
}

//////////////////////////////////////////////////////////////////////////////
//	Function definitions - checking functionality
//////////////////////////////////////////////////////////////////////////////


//
// Generates one specified locale
//
function generate_locale(charmap, src, locname)
{
    var err = "Cannot generate locale database - ";

    // charmap - character map file used in generating the locale database
    // src     - source/locale definition file
    // locname - locale database name

    if (charmap == "")
    {
        outstrm.WriteLine(err + "character maps file not specified.");
        Exit(1);
    }

    if (src == "")
    {
        outstrm.WriteLine(err  + "source input file not specified.");
        Exit(1);
    }

    if (locname == "")
    {
        outstrm.WriteLine(err + "output locale name not specified.");
        Exit(1);
    }

    ++assertions;

    // Generating the database
    var cmd = localedef + " -w -c -f " + charmap
            + " -i " + src + " " + locname;
    DebugOutLine(cmd);

    var exec = Run(cmd);
    DebugOut(run_stdout);

    var retcode = exec.ExitCode;
    if (retcode)
    {
        // exit with the same status as the tool
        Exit(retcode);
    }
}

//
//
//
function dump_charmap(locname, outfile)
{
    err="Cannot create characater set description file - "

    // locname: LC_ALL value
    // outfile: output file name

    if (outfile == "")
    {
        outstrm.WriteLine(err + " - no output file specified.");
        Exit(1);
    }

    ++assertions;

    // dumping charmap
    var cmd = locale + " --charmap -l";
    DebugOutLine("LC_ALL=" + locname + " " + cmd + " > " + outfile);

    WEnv("LC_ALL") = locname;
    var exec = Run(cmd);

    DebugOut(run_stderr);

    var dmpfile = fso.CreateTextFile(outfile, true);
    if (dmpfile)
    {
        dmpfile.Write(run_stdout);
        dmpfile.Close();
    }

    var retcode = exec.ExitCode;
    if (retcode)
    {
        // exit with the same status as the tool
        Exit(retcode);
    }
}

//
// Dumps one locale database
//
function dump_locale(locname, dumpfile)
{
    var err = "Cannot dump locale database - ";

    // locname:  LC_ALL value
    // dumpfile: current locale dump file

    if (dumpfile == "")
    {
        outstrm.WriteLine(err + " - no output file specified.");
        Exit(1);
    }

    ++assertions;

    // Dumping locale database
    var cmd = locale + " -ck -h -l LC_ALL";
    DebugOutLine("LC_ALL=" + locname + " " + cmd + " > " + dumpfile);

    WEnv("LC_ALL") = locname;
    var exec = Run(cmd);

    DebugOut(run_stderr);

    var dmpfile = fso.CreateTextFile(dumpfile, true);
    if (dmpfile)
    {
        dmpfile.Write(run_stdout);
        dmpfile.Close();
    }

    var retcode = exec.ExitCode;
    if (retcode)
    {
        // exit with the same status as the tool
        Exit(retcode);
    }
}

//
// Test one locale
//
function test_locale(nlsdir, tmpdir, fname)
{
    var err = "Cannot test locale - ";

    // nlsdir  - nls subdirectory of the source directory tree
    // tmpdir  - the test (sandbox) directory
    // locname - name of the locale database
    
    if (nlsdir == "")
    {
        outstrm.WriteLine(err+ " - nls directory not specified.");
        Exit(1);
    }

    if (tmpdir == "")
    {
        outstrm.WriteLine(err + " - temporary directory not specified.");
        Exit(1);
    }

    if (fname == "")
    {
        outstrm.WriteLine(err+ " - locale database name not specified.");
        Exit(1);
    }

    // get locale's name and encoding
    var rx = new RegExp("\([^.]*\)\.\([^@]*\)\(.*\)");
    var source = fname.replace(rx, "$1$3").replace("@", ".");
    var charmap = fname.replace(rx, "$2");

    var src_path = nlsdir + "\\src\\" + source;
    var cm_path = nlsdir + "\\charmaps\\" + charmap;

    var stage_1 = tmpdir + "\\stage.1";
    var stage_2 = tmpdir + "\\stage.2";
    var stage_3 = tmpdir + "\\stage.3";

    source += ".src";

    // point locale at the original source directory
    DebugOutLine("RWSTD_SRC_ROOT=" + nlsdir);
    WEnv("RWSTD_SRC_ROOT") = nlsdir;

    // create a directory for stage 1 charmap source files
    var cm_dir1 = stage_1 + "\\charmaps";
    DebugOutLine("mkdir " + cm_dir1);
    CreateFolder(cm_dir1);

    ++assertions;

    var locname1 = stage_1 + "\\" + fname;
    var cm_path1 = cm_dir1 + "\\" + charmap;
    var src_path1 = stage_1 + "\\" + source;

    // generate stage 1 locale database from the orignal sources
    generate_locale(cm_path, src_path, locname1);

    ++assertions;

    // dump the charmap and the locale data from the database
    // to a pair of charmap and locale source files
    dump_charmap(locname1, cm_path1);
    dump_locale(locname1, src_path1);

    // create a directory for stage 2 charmap source files
    var cm_dir2 = stage_2 + "\\charmaps";
    DebugOutLine("mkdir " + cm_dir2);
    CreateFolder(cm_dir2);

    ++assertions;

    var locname2 = stage_2 + "\\" + fname;
    var cm_path2 = cm_dir2 + "\\" + charmap;
    var src_path2 = stage_2 + "\\" + source;

    // generate stage 2 locale database from the charmap and locale
    // source files produced by locale from the stage 1 database
    generate_locale(cm_path1, src_path1, locname2);

    // point locale at the stage 1 directory
    DebugOutLine("RWSTD_SRC_ROOT=" + stage_1);
    WEnv("RWSTD_SRC_ROOT") = stage_1;

    ++assertions;

    // dump the charmap and the locale data from the database
    //to a pair of charmap and locale source files
    dump_charmap(locname2, cm_path2);
    dump_locale(locname2, src_path2);

    ++assertions;

    // create a directory for stage 2 charmap source files
    var cm_dir3 = stage_3 + "\\charmaps";
    DebugOutLine("mkdir " + cm_dir3);
    CreateFolder(cm_dir3);

    ++assertions;

    var locname3 = stage_3 + "\\" + fname;
    var cm_path3 = cm_dir3 + "\\" + charmap;
    var src_path3 = stage_3 + "\\" + source;

    // generate stage 3 locale database from the charmap and locale
    // source files produced by locale from the stage 2 database
    generate_locale(cm_path2, src_path2, locname3);

    // point locale at the stage 2 directory
    DebugOutLine("RWSTD_SRC_ROOT=" + stage_2);
    WEnv("RWSTD_SRC_ROOT") = stage_2;

    ++assertions;

    // dump the charmap and the locale data from the database
    // to a pair of charmap and locale source files
    dump_charmap(locname3, cm_path3);
    dump_locale(locname3, src_path3);

    ++assertions;

    // verify that stage 1 and stage 2 charmaps are the same
    var cmd = "fc " + cm_path1 + " " + cm_path2;
    DebugOutLine(cmd);
    var retcode = Run(cmd).ExitCode;
    if (retcode)
    {
        DebugOutLine("## AssertionFailed: " + cm_path1 +
                     " and " + cm_path2 + " differ.");
        ++failedassertions;
    }

    // verify that stage 2 and stage 3 charmaps are the same
    var cmd = "fc " + cm_path2 + " " + cm_path3;
    DebugOutLine(cmd);
    var retcode = Run(cmd).ExitCode;
    if (retcode)
    {
        DebugOutLine("## AssertionFailed: " + cm_path2 +
                     " and " + cm_path3 + " differ.");
        ++failedassertions;
    }

    // verify that stage 2 and stage 3 locale sources are the same
    var cmd = "fc " + src_path2 + " " + src_path3;
    DebugOutLine(cmd);
    var retcode = Run(cmd).ExitCode;
    if (retcode)
    {
        DebugOutLine("## AssertionFailed: " + src_path2 +
                     " and " + src_path3 + " differ.");
        ++failedassertions;
    }

    if (!no_clean)
    {
        // clean up
        DebugOutLine("rm -rf " + stage_1 + " " + stage_2 + " " + stage_3);
        if (fso.FolderExists(stage_1))
            fso.DeleteFolder(stage_1, true);
        if (fso.FolderExists(stage_2))
            fso.DeleteFolder(stage_2, true);
        if (fso.FolderExists(stage_3))
            fso.DeleteFolder(stage_3, true);
    }
}

//////////////////////////////////////////////////////////////////////////////
//  Main code
//////////////////////////////////////////////////////////////////////////////

function run_locale_utils()
{
    if (WScript.Arguments.Named.Exists("d"))
        dbgout = true;

    if (WScript.Arguments.Named.Exists("s"))
        chk_sanity = true;

    if (WScript.Arguments.Named.Exists("f"))
        chk_func = true;

    if (WScript.Arguments.Named.Exists("i"))
        nlsdir = WScript.Arguments.Named("i");

    if (WScript.Arguments.Named.Exists("l"))
        locale_db = WScript.Arguments.Named("l");

    if (WScript.Arguments.Named.Exists("n"))
        no_clean = true;

    if (WScript.Arguments.Named.Exists("b"))
    {
        bindir = WScript.Arguments.Named("b");
        locale = bindir + "\\" + locale;
        localedef = bindir + "\\" + localedef;
    }

    if (WScript.Arguments.Named.Exists("O"))
    {
        var outfile = WScript.Arguments.Named("O");
        outstrm = fso.CreateTextFile(outfile, true);
        if (!outstrm)
        {
            WScript.StdErr.WriteLine("Unable to create " + outfile + ", aborting");
            WScript.Quit(2);
        }
    }

    if (chk_sanity)
    {
        // checking locale sanity
        check_locale_help();
        check_locale_all();
        check_locale_m();
        check_locale_k();
        check_localedef_help();
    
    }
    else if (chk_func)
    {
        // create the temp dir
        if (!CreateFolder(tmpdir))
        {
            WScript.StdErr.WriteLine("Unable to create " + tmpdir + ", aborting");
            WScript.Quit(1);
        }
    
        // test only one locale
        test_locale(nlsdir, tmpdir, locale_db);

        Cleanup();
    }
    else
    {
        // Invocation is wrong
        WScript.Arguments.ShowUsage();
        WScript.Quit(2);
    }

    if (assertions)
    {
        var pcnt = 100 * (assertions - failedassertions) / assertions;
        pcnt = Math.floor(pcnt + 0.5);
        outstrm.WriteLine("# +-----------------------+----------+----------+----------+");
        outstrm.WriteLine("# | DIAGNOSTIC            |  ACTIVE  |   TOTAL  | INACTIVE |");
        outstrm.WriteLine("# +-----------------------+----------+----------+----------+");
        outstrm.WriteLine("# | (S7) ASSERTION        | " + FormatNumber(failedassertions, 8)
            + " | " + FormatNumber(assertions, 8) + " | " + FormatNumber(pcnt, 7) + "% |");
        outstrm.WriteLine("# +-----------------------+----------+----------+----------+");
        outstrm.WriteLine();
    }
    outstrm.WriteLine("## Warnings = 0");
    outstrm.WriteLine("## Assertions = " + assertions);
    outstrm.WriteLine("## FailedAssertions = " + failedassertions);
    outstrm.WriteLine();
}

]]>
        </script>
    </job>
</package>
