/*
** Unicode Bidirectional Algorithm
** Reference Implementation
** Copyright 2016, Unicode, Inc. All rights reserved.
** Unpublished rights reserved under U.S. copyright laws.
*/
/*
* bidiref.c
*
* Unicode Bidirectional Algorithm (UBA)
* Reference Implementation
*
* This reference implementation is deliberately designed to
* be literal and to explicitly follow the UBA specification
* in UAX #9 for didactic reasons. It is not optimized, nor
* intended as a direct guide to how to build an efficient
* implementation. Instead, it is designed to make the steps
* of the algorithm clear, so as to provide unambiguous
* interpretation of the intended results of the UBA in all
* input cases.
*/
/*
* Change history:
*
* 2013-May-31 kenw Created to match UBA 6.2.0 spec and
* UBA 6.3.0 spec.
* 2013-Jun-02 kenw Reworked to put the UBA and initial
* table loading into a dll (or static
* library) with a public API.
* 2013-Jun-07 kenw Added Trace14.
* 2013-Jun-19 kenw Added Trace15.
* 2013-Jun-21 kenw Tweaks for U_Int_32 definition.
* 2013-Jun-26 kenw Version 1.5.
* 2013-Jun-27 kenw Version 1.6. (Various bug fixes)
* 2013-Jun-29 kenw Version 1.7. (Bug fix in N0)
* 2013-Jul-08 kenw Version 1.8. (Bug fix in br_DropSequence)
* 2014-Apr-17 kenw Version 7.0.0. Update for Unicode 7.0
* and synch bidiref version to the standard.
* 2015-Jun-04 kenw Further updates for Unicode 7.0.
* 2015-Jun-05 kenw Version 8.0.0.
* 2015-Aug-19 kenw Add flag to support continue on test err.
* 2015-Dec-04 kenw Updated build date.
* 2016-Sep-22 kenw Version 9.0.0. Add input path setting.
* 2016-Oct-06 kenw Update version string date, tweak usage msg.
*/
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "bidirefp.h"
static char versionString[] = "bidiref version 9.0.0, 2016-10-06\n";
static char infile[] = "BidiRefTest.txt"; /* default file name */
/*
* Set the MAXARGLEN value fairly high, to allow fully-qualified
* input file names.
*/
#define MAXARGLEN (512)
char inputFileName[MAXARGLEN];
char datapath[MAXARGLEN];
int debugLevel; /* Set level for debug output */
int staticTest; /* Use static test string(s) */
/*
* Note: The following flag, if it proves useful, could be
* upgraded for set/reset through an API, to allow active
* control by an application running test cases.
*/
int continueOnTestErr; /* Don't stop if test case fails. */
/***********************************************************/
/*
* SetInitialTraceFlags
*
* Adjust the initial traceFlags value based on the
* overall debug level chosen at the command line or
* at runtime.
*/
static void SetInitialTraceFlags ( void )
{
TraceOn ( Trace0 );
TraceOn ( Trace15 );
if ( debugLevel > 0 )
{
TraceOn ( Trace1 | Trace2 );
}
if ( debugLevel > 1 )
{
TraceOn ( Trace11 );
}
if ( debugLevel > 2 )
{
TraceOn ( Trace3 | Trace5 | Trace6 | Trace8 );
}
if ( debugLevel > 3 )
{
TraceOn ( Trace4 | Trace7 | Trace9 | Trace12 );
}
/* Temporary testing of single trace flag */
/* TraceOn ( Trace7 ); */
}
/***********************************************************/
/*
* SECTION: Command Line Processing.
*/
static void usageMsg( void )
{
fputs ("Usage: bidiref (-dn)(-unn)(-xyzvh)(-p path)(filename)\n", stdout );
fputs (" Default input is BidiRefTest.txt\n", stdout );
fputs (" Default UBA version is 9.0.\n", stdout );
fputs (" -dn set diagnostic mode: 1 minimum, 2 medium, 3 high, 4 maximum.\n",
stdout );
fputs (" -c continue if test case fails.\n", stdout );
fputs (" -p path\\ read input files from directory specified by path.\n", stdout );
fputs (" -unn set UBA version to n.n. (valid values: -u62, -u63, -u70, -u80, -u90)\n",
stdout );
fputs (" -x set UBA version to 6.3. (= -u63)\n", stdout );
fputs (" -y omit output for vacuous rule application (Trace14 on).\n", stdout );
fputs (" -z run one statically defined test diagnostic.\n", stdout );
fputs (" -v show bidiref program version.\n", stdout );
fputs (" -h show this usage message.\n", stdout );
}
static void versionMsg(void)
{
fputs ( versionString, stdout );
}
/*
* processArguments()
*
* -1 Error return code. Post error message and stop.
* 0 Stop return code. Stop without further processing.
* 1 Continue return code. Continue processing.
*/
static int processArguments( int argc, char *argv[] )
{
char argstring[MAXARGLEN];
char* tmp;
char c;
int numargs = argc;
int foundFile = 0;
/*
* Set up default values for input parameters.
*/
debugLevel = 0;
staticTest = 0;
continueOnTestErr = 0;
SetUBAVersion (UBA90);
strcpy ( datapath, "" );
while ( numargs > 1 )
{
strncpy ( argstring, *++argv, MAXARGLEN );
argstring[MAXARGLEN - 1] = '\0';
numargs--;
tmp = argstring;
c = *tmp++;
if ( c == '-' )
{
c = *tmp;
switch ( c )
{
case 'd' :
tmp++;
if ( *tmp == '1' )
{
debugLevel = 1;
}
else if ( *tmp == '2' )
{
debugLevel = 2;
}
else if ( *tmp == '3' )
{
debugLevel = 3;
}
else if ( *tmp == '4' )
{
debugLevel = 4;
}
else
{
usageMsg();
return -1;
}
break;
case 'u' :
tmp++;
if ( *tmp == '6' )
{
tmp++;
if ( *tmp == '2')
{
SetUBAVersion (UBA62);
}
else if ( *tmp == '3')
{
SetUBAVersion (UBA63);
}
else
{
usageMsg();
return -1;
}
}
else if ( *tmp == '7' )
{
tmp++;
if ( *tmp == '0')
{
SetUBAVersion (UBA70);
}
else
{
usageMsg();
return -1;
}
}
else if ( *tmp == '8' )
{
tmp++;
if ( *tmp == '0')
{
SetUBAVersion (UBA80);
}
else
{
usageMsg();
return -1;
}
}
else if ( *tmp == '9' )
{
tmp++;
if ( *tmp == '0')
{
SetUBAVersion (UBA90);
}
else
{
usageMsg();
return -1;
}
}
else
{
usageMsg();
return -1;
}
break;
case 'p' :
if ( numargs > 1 )
{
strncpy (argstring, *++argv, MAXARGLEN );
/* Truncate if necessary */
argstring[MAXARGLEN - 1] = '\0';
numargs--;
strcpy ( datapath, argstring );
}
else
{
usageMsg();
return -1 ;
}
break;
case 'x' :
SetUBAVersion ( UBA63 );
break;
case 'v' :
versionMsg();
return 0;
/* The -y command line arg is a temporary hack. */
case 'y' :
TraceOn ( Trace14 );
break;
case 'c' :
continueOnTestErr = 1;
break;
case 'z' :
staticTest = 1;
break;
case '?' :
case 'h' :
usageMsg();
return 0;
default:
usageMsg();
return -1;
}
}
else if ( !foundFile )
{
strncpy ( inputFileName, argstring, MAXARGLEN );
foundFile = 1;
}
else
{
usageMsg();
return -1;
}
}
/*
* Default empty parameter1 to input file name as BidiRefTest.txt.
*/
if ( !foundFile )
{
strcpy ( inputFileName, infile );
}
/*
* Detect whether the input for test set data is BidiTest.txt.
* If so, reset the fileFormat to FORMAT_B. For a simple test,
* just check whether "BidiTest" occurs anywhere in the
* inputFileName string, because we aren't actually parsing
* fully-qualified paths here.
*/
tmp = strstr ( inputFileName, "BidiTest" );
if ( tmp != NULL )
{
/*
* TBD: Further checking to ensure name meets
* qualification for FORMAT_B.
*/
SetFileFormat ( FORMAT_B );
}
return ( 1 );
}
/***********************************************************/
main ( int argc, char *argv[] )
{
int rc;
rc = processArguments ( argc, argv );
if ( rc != 1 )
{
if ( rc < 0 )
{
br_ErrPrint ( "Error in processing command line arguments.\n" );
}
return ( BR_INITERR );
}
/*
* Set any individual trace flags based on overall debug levels.
*/
SetInitialTraceFlags();
if ( Trace ( Trace2 ) )
{
if ( staticTest )
{
printf ( "Trace: Starting bidiref, UBA version=%s, with static input.\n",
GetUBAVersionStr() );
}
else
{
printf ( "Trace: Starting bidiref, UBA version=%s, input file=\"%s\"\n",
GetUBAVersionStr(), inputFileName );
}
}
/*
* Initialize property tables from UnicodeData.txt and BidiBrackets.txt.
*/
rc = br_InitTable ( GetUBAVersion(), datapath );
if ( rc != 1 )
{
br_ErrPrint ( "Error in processing property tables.\n" );
return ( BR_INITERR );
}
if ( staticTest )
{
rc = br_RunStaticTest();
}
else
{
rc = br_RunFileTests ( GetUBAVersion(), datapath, inputFileName );
}
return ( rc );
}