diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | common.pri | 1 | ||||
| -rw-r--r-- | glib-2.0.pri | 38 | ||||
| -rw-r--r-- | openscad.pro | 3 | ||||
| -rwxr-xr-x | scripts/check-dependencies.sh | 17 | ||||
| -rwxr-xr-x | scripts/macosx-build-dependencies.sh | 43 | ||||
| -rwxr-xr-x | scripts/uni-build-dependencies.sh | 44 | ||||
| -rwxr-xr-x | scripts/uni-get-dependencies.sh | 15 | ||||
| -rw-r--r-- | src/AboutDialog.html | 1 | ||||
| -rw-r--r-- | src/PlatformUtils.cc | 3 | ||||
| -rw-r--r-- | src/func.cc | 49 | ||||
| -rw-r--r-- | src/value.cc | 18 | ||||
| -rw-r--r-- | testdata/scad/misc/search-tests-unicode.scad | 116 | ||||
| -rw-r--r-- | testdata/scad/misc/string-unicode.scad | 44 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 42 | ||||
| -rw-r--r-- | tests/FindGLIB2.cmake | 28 | ||||
| -rw-r--r-- | tests/regression/echotest/search-tests-unicode-expected.echo | 109 | ||||
| -rw-r--r-- | tests/regression/echotest/string-unicode-expected.echo | 107 | 
19 files changed, 654 insertions, 26 deletions
| @@ -1,5 +1,6 @@  /*.scad  *.dmg +*~  *.tar*  Makefile  objects @@ -95,6 +95,7 @@ Follow the instructions for the platform you're compiling on below.  * [OpenCSG (1.3.2)](http://www.opencsg.org/)  * [GLEW (1.5.4 ->)](http://glew.sourceforge.net/)  * [Eigen (3.0 - 3.2)](http://eigen.tuxfamily.org/) +* [glib2 (2.2.0)](https://developer.gnome.org/glib/)  * [GCC C++ Compiler (4.2 ->)](http://gcc.gnu.org/)  * [Bison (2.4)](http://www.gnu.org/software/bison/)  * [Flex (2.5.35)](http://flex.sourceforge.net/) @@ -11,3 +11,4 @@ include(opencsg.pri)  include(glew.pri)  include(eigen.pri)  include(boost.pri) +include(glib-2.0.pri)
\ No newline at end of file diff --git a/glib-2.0.pri b/glib-2.0.pri new file mode 100644 index 0000000..0fbc4e2 --- /dev/null +++ b/glib-2.0.pri @@ -0,0 +1,38 @@ +# Detect glib-2.0, then use this priority list to determine +# which library to use: +# +# Priority +# 1. GLIB2_INCLUDEPATH / GLIB2_LIBPATH (qmake parameter, not checked it given on commandline) +# 2. OPENSCAD_LIBRARIES (environment variable) +# 3. system's standard include paths from pkg-config + +glib-2.0 { + +# read environment variables +OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES) +GLIB2_DIR = $$(GLIB2DIR) + +!isEmpty(OPENSCAD_LIBRARIES_DIR) { +  isEmpty(GLIB2_INCLUDEPATH) { +    GLIB2_INCLUDEPATH_1 = $$OPENSCAD_LIBRARIES_DIR/include/glib-2.0 +    GLIB2_INCLUDEPATH_2 = $$OPENSCAD_LIBRARIES_DIR/lib/glib-2.0/include +    GLIB2_LIBPATH = $$OPENSCAD_LIBRARIES_DIR/lib +  } +} + +isEmpty(GLIB2_INCLUDEPATH) { +  GLIB2_CFLAGS = $$system("pkg-config --cflags glib-2.0") +} else { +  GLIB2_CFLAGS = -I$$GLIB2_INCLUDEPATH_1 +  GLIB2_CFLAGS += -I$$GLIB2_INCLUDEPATH_2 +} + +isEmpty(GLIB2_LIBPATH) { +  GLIB2_LIBS = $$system("pkg-config --libs glib-2.0") +} else { +  GLIB2_LIBS = -L$$GLIB2_LIBPATH -lglib-2.0 +} + +QMAKE_CXXFLAGS += $$GLIB2_CFLAGS +LIBS += $$GLIB2_LIBS +} diff --git a/openscad.pro b/openscad.pro index b38419e..ec5af20 100644 --- a/openscad.pro +++ b/openscad.pro @@ -8,7 +8,7 @@  #   OPENCSGDIR  #   OPENSCAD_LIBRARIES  # -# Please see the 'Buildling' sections of the OpenSCAD user manual  +# Please see the 'Building' sections of the OpenSCAD user manual   # for updated tips & workarounds.  #  # http://en.wikibooks.org/wiki/OpenSCAD_User_Manual @@ -156,6 +156,7 @@ CONFIG += cgal  CONFIG += opencsg  CONFIG += boost  CONFIG += eigen +CONFIG += glib-2.0  #Uncomment the following line to enable QCodeEdit  #CONFIG += qcodeedit diff --git a/scripts/check-dependencies.sh b/scripts/check-dependencies.sh index b63c677..e587198 100755 --- a/scripts/check-dependencies.sh +++ b/scripts/check-dependencies.sh @@ -66,6 +66,21 @@ cgal_sysver()    cgal_sysver_result=`grep "define  *CGAL_VERSION  *[0-9.]*" $cgalpath | awk '{print $3}'`  } +glib2_sysver() +{ +  #Get architecture triplet - e.g. x86_64-linux-gnu +  glib2archtriplet=`gcc -dumpmachine 2>/dev/null` +  if [ -z "$VAR" ]; then +    glib2archtriplet=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` +  fi +  glib2path=$1/lib/$glib2archtriplet/glib-2.0/include/glibconfig.h +  if [ ! -e $glib2path ]; then return; fi +  glib2major=`grep "define  *GLIB_MAJOR_VERSION  *[0-9.]*" $glib2path | awk '{print $3}'` +  glib2minor=`grep "define  *GLIB_MINOR_VERSION  *[0-9.]*" $glib2path | awk '{print $3}'` +  glib2micro=`grep "define  *GLIB_MICRO_VERSION  *[0-9.]*" $glib2path | awk '{print $3}'` +  glib2_sysver_result="${glib2major}.${glib2minor}.${glib2micro}" +} +  boost_sysver()  {    boostpath=$1/include/boost/version.hpp @@ -530,7 +545,7 @@ checkargs()  main()  { -  deps="qt4 cgal gmp mpfr boost opencsg glew eigen gcc bison flex make" +  deps="qt4 cgal gmp mpfr boost opencsg glew eigen glib2 gcc bison flex make"    #deps="$deps curl git" # not technically necessary for build    #deps="$deps python cmake imagemagick" # only needed for tests    #deps="cgal" diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index eadea9f..45f6818 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -294,6 +294,43 @@ build_glew()    make GLEW_DEST=$DEPLOYDIR CC=$CC CFLAGS.EXTRA="-no-cpp-precomp -dynamic -fno-common -mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" LDFLAGS.EXTRA="-mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" STRIP= install  } +build_gettext() +{ +  version=$1 +  echo "Building gettext $version..." + +  cd "$BASEDIR"/src +  rm -rf "gettext-$version" +  if [ ! -f "glib-$version.tar.xz" ]; then +    curl --insecure -LO "http://ftpmirror.gnu.org/gettext/gettext-$version.tar.gz" +  fi +  tar xzf "gettext-$version.tar.gz" +  cd "gettext-$version" + +  ./configure --prefix="$DEPLOYDIR" +  make -j4 +  make install +} + +build_glib2() +{ +  version=$1 +  echo "Building glib2 $version..." + +  cd "$BASEDIR"/src +  rm -rf "glib-$version" +  maj_min_version="${version%.*}" #Drop micro +  if [ ! -f "glib-$version.tar.xz" ]; then +    curl --insecure -LO "http://ftp.gnome.org/pub/gnome/sources/glib/$maj_min_version/glib-$version.tar.xz" +  fi +  tar xJf "glib-$version.tar.xz" +  cd "glib-$version" + +  ./configure --disable-gtk-doc --disable-man --prefix="$DEPLOYDIR" CFLAGS="-I$DEPLOYDIR/include" LDFLAGS="-L$DEPLOYDIR/lib" +  make -j4 +  make install +} +  build_opencsg()  {    version=$1 @@ -458,6 +495,12 @@ build_boost 1.54.0  # NB! For CGAL, also update the actual download URL in the function  build_cgal 4.3  build_glew 1.10.0 +<<<<<<< HEAD +build_gettext 0.18.3.1 +build_glib2 2.38.2 +======= +build_glib2 2.38.1 +>>>>>>> d7d5bea7363703c76b9787598304bfc838e893ee  build_opencsg 1.3.2  if $OPTION_DEPLOY; then  #  build_sparkle andymatuschak 0ed83cf9f2eeb425d4fdd141c01a29d843970c20 diff --git a/scripts/uni-build-dependencies.sh b/scripts/uni-build-dependencies.sh index e652c47..5b9e129 100755 --- a/scripts/uni-build-dependencies.sh +++ b/scripts/uni-build-dependencies.sh @@ -409,6 +409,48 @@ build_glew()    GLEW_DEST=$DEPLOYDIR $MAKER install  } +build_gettext() +{ +  version=$1 +  echo "Building gettext $version..." + +  cd "$BASEDIR"/src +  rm -rf "gettext-$version" +  if [ ! -f "glib-$version.tar.xz" ]; then +    curl --insecure -LO "http://ftpmirror.gnu.org/gettext/gettext-$version.tar.gz" +  fi +  tar xzf "gettext-$version.tar.gz" +  cd "gettext-$version" + +  ./configure --prefix="$DEPLOYDIR" +  make -j4 +  make install +} + +build_glib2() +{ +  version="$1" +  maj_min_version="${version%.*}" #Drop micro + +  if [ -e $DEPLOYDIR/lib/glib-2.0 ]; then +echo "glib2 already installed. not building" +    return +fi + +echo "Building glib2 $version..." +  cd "$BASEDIR"/src +  rm -rf "glib-$version" +  if [ ! -f "glib-$version.tar.xz" ]; then +curl --insecure -LO "http://ftp.gnome.org/pub/gnome/sources/glib/$maj_min_version/glib-$version.tar.xz" +  fi +tar xJf "glib-$version.tar.xz" +  cd "glib-$version" + +  ./configure --disable-gtk-doc --disable-man --prefix="$DEPLOYDIR" CFLAGS="-I$DEPLOYDIR/include" LDFLAGS="-L$DEPLOYDIR/lib" +  make -j$NUMCPU +  make install +} +  build_opencsg()  {    if [ -e $DEPLOYDIR/lib/libopencsg.so ]; then @@ -603,5 +645,7 @@ build_boost 1.53.0  build_cgal 4.0.2  build_glew 1.9.0  build_opencsg 1.3.2 +build_gettext 0.18.3.1 +build_glib2 2.38.2  echo "OpenSCAD dependencies built and installed to " $BASEDIR diff --git a/scripts/uni-get-dependencies.sh b/scripts/uni-get-dependencies.sh index a0306ef..d2408c0 100755 --- a/scripts/uni-get-dependencies.sh +++ b/scripts/uni-get-dependencies.sh @@ -8,7 +8,7 @@ get_fedora_deps()  {   sudo yum install qt-devel bison flex eigen3-devel python-paramiko \    boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc gcc-c++ pkgconfig \ -  opencsg-devel git libXmu-devel curl imagemagick ImageMagick make \ +  opencsg-devel git libXmu-devel curl imagemagick ImageMagick glib2-devel make \    xorg-x11-server-Xvfb  } @@ -21,7 +21,7 @@ get_altlinux_deps()  {   for i in boost-devel boost-filesystem-devel gcc4.5 gcc4.5-c++ boost-program_options-devel \    boost-thread-devel boost-system-devel boost-regex-devel eigen3 libmpfr libgmp libgmp_cxx-devel qt4-devel libcgal-devel git-core \ -  libglew-devel flex bison curl imagemagick; do sudo apt-get install $i; done +  libglew-devel flex bison curl imagemagick glib2-devel; do sudo apt-get install $i; done  }  get_freebsd_deps() @@ -29,20 +29,21 @@ get_freebsd_deps()   pkg_add -r bison boost-libs cmake git bash eigen3 flex gmake gmp mpfr \    xorg libGLU libXmu libXi xorg-vfbserver glew \    qt4-corelib qt4-gui qt4-moc qt4-opengl qt4-qmake qt4-rcc qt4-uic \ -  opencsg cgal curl imagemagick +  opencsg cgal curl imagemagick glib2-devel  }  get_netbsd_deps()  {   sudo pkgin install bison boost cmake git bash eigen flex gmake gmp mpfr \    qt4 glew cgal opencsg modular-xorg python27 py27-paramiko curl \ -  imagemagick ImageMagick +  imagemagick ImageMagick glib2-devel  }  get_opensuse_deps()  {   sudo zypper install libeigen3-devel mpfr-devel gmp-devel boost-devel \ -  libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl +  libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl \ +  glib2-devel  }  get_mageia_deps() @@ -50,7 +51,7 @@ get_mageia_deps()   sudo urpmi ctags   sudo urpmi task-c-devel task-c++-devel libqt4-devel libgmp-devel \    libmpfr-devel libboost-devel eigen3-devel libglew-devel bison flex \ -  cmake imagemagick python curl git x11-server-xvfb +  cmake imagemagick glib2-devel python curl git x11-server-xvfb  }  get_debian_deps() @@ -59,7 +60,7 @@ get_debian_deps()    libxmu-dev cmake bison flex git-core libboost-all-dev \    libXi-dev libmpfr-dev libboost-dev libglew-dev \    libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev \ -  python-paramiko curl imagemagick; do +  python-paramiko curl imagemagick libglib2.0-dev; do     sudo apt-get -y install $pkg;   done  } diff --git a/src/AboutDialog.html b/src/AboutDialog.html index 99e7c3b..65a54d7 100644 --- a/src/AboutDialog.html +++ b/src/AboutDialog.html @@ -64,6 +64,7 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li  <li><a href="http://www.stroustrup.com/C++.html">C++</a>, <a href="http://gcc.gnu.org/">GCC</a>, <a href="http://clang.llvm.org/">clang</a>  <li><a href="http://www.python.org">python</a>  <li><a href="http://nsis.sourceforge.net/Main_Page">Nullsoft installer</a> +<li><a href="https://developer.gnome.org/glib/">GLib</a>  </lu>  </p> diff --git a/src/PlatformUtils.cc b/src/PlatformUtils.cc index b02b822..8b39f6d 100644 --- a/src/PlatformUtils.cc +++ b/src/PlatformUtils.cc @@ -1,6 +1,8 @@  #include "PlatformUtils.h"  #include "boosty.h" +#include <glib.h> +  bool PlatformUtils::createLibraryPath()  {  	std::string path = PlatformUtils::libraryPath(); @@ -114,6 +116,7 @@ std::string PlatformUtils::info()  	  << "\nOpenCSG version: " << OPENCSG_VERSION_STRING  	  << "\nQt version: " << qtVersion  	  << "\nMingW build: " << mingwstatus +	  << "\nGLib version: "       << GLIB_MAJOR_VERSION << "." << GLIB_MINOR_VERSION << "." << GLIB_MICRO_VERSION  	  << "\nOPENSCADPATH: " << getenv("OPENSCADPATH") << "\n"  	;  	return s.str(); diff --git a/src/func.cc b/src/func.cc index 865a2b4..4587f72 100644 --- a/src/func.cc +++ b/src/func.cc @@ -45,6 +45,8 @@  #include <boost/random/mersenne_twister.hpp>  #include <boost/random/uniform_real.hpp> +/*Unicode support for string lengths and array accesses*/ +#include <glib.h>  #ifdef __WIN32__  #include <process.h> @@ -306,7 +308,11 @@ Value builtin_length(const Context *, const EvalContext *evalctx)  {  	if (evalctx->numArgs() == 1) {  		if (evalctx->getArgValue(0).type() == Value::VECTOR) return Value(int(evalctx->getArgValue(0).toVector().size())); -		if (evalctx->getArgValue(0).type() == Value::STRING) return Value(int(evalctx->getArgValue(0).toString().size())); +		if (evalctx->getArgValue(0).type() == Value::STRING) { +			//Unicode glyph count for the length -- rather than the string (num. of bytes) length. +			std::string text = evalctx->getArgValue(0).toString(); +			return Value(int( g_utf8_strlen( text.c_str(), text.size() ) )); +		}  	}  	return Value();  } @@ -380,10 +386,17 @@ Value builtin_lookup(const Context *, const EvalContext *evalctx)    num_returns_per_match : int;    index_col_num : int; + The search string and searched strings can be unicode strings.   Examples:    Index values return as list:      search("a","abcdabcd"); -        - returns [0,4] +        - returns [0] +    search("Π","Π");  //A unicode string +        - returns [0] +    search("π‘aΠ","aπ‘Ππ‘aπ‘Ππ‘a",0); +        - returns [[1,3,5,7],[0,4,8],[2,6]] +    search("a","abcdabcd",0); //Search up to all matches +        - returns [[0,4]]      search("a","abcdabcd",1);          - returns [0]      search("e","abcdabcd",1); @@ -433,16 +446,25 @@ Value builtin_search(const Context *, const EvalContext *evalctx)  		}  	} else if (findThis.type() == Value::STRING) {  		unsigned int searchTableSize; -		if (searchTable.type() == Value::STRING) searchTableSize = searchTable.toString().size(); -		else searchTableSize = searchTable.toVector().size(); -		for (size_t i = 0; i < findThis.toString().size(); i++) { +		//Unicode glyph count for the length +		unsigned int findThisSize =  g_utf8_strlen( findThis.toString().c_str(), findThis.toString().size() ); +		if (searchTable.type() == Value::STRING) { +			searchTableSize = g_utf8_strlen( searchTable.toString().c_str(), searchTable.toString().size() ); +		} else { +		    searchTableSize = searchTable.toVector().size(); +		} +		for (size_t i = 0; i < findThisSize; i++) {  		  unsigned int matchCount = 0;  			Value::VectorType resultvec;  		  for (size_t j = 0; j < searchTableSize; j++) { -		    if ((searchTable.type() == Value::VECTOR &&  -						 findThis.toString()[i] == searchTable.toVector()[j].toVector()[index_col_num].toString()[0]) || -						(searchTable.type() == Value::STRING &&  -						 findThis.toString()[i] == searchTable.toString()[j])) { +		    gchar* ptr_ft = g_utf8_offset_to_pointer(findThis.toString().c_str(), i); +		    gchar* ptr_st = NULL; +		    if(searchTable.type() == Value::VECTOR) { +		        ptr_st = g_utf8_offset_to_pointer(searchTable.toVector()[j].toVector()[index_col_num].toString().c_str(), 0); +		    } else if(searchTable.type() == Value::STRING){ +		    	ptr_st = g_utf8_offset_to_pointer(searchTable.toString().c_str(), j); +		    } +		    if( (ptr_ft) && (ptr_st) && (g_utf8_get_char(ptr_ft) == g_utf8_get_char(ptr_st)) ) {  		      Value resultValue((double(j)));  		      matchCount++;  		      if (num_returns_per_match == 1) { @@ -454,7 +476,14 @@ Value builtin_search(const Context *, const EvalContext *evalctx)  		      if (num_returns_per_match > 1 && matchCount >= num_returns_per_match) break;  		    }  		  } -		  if (matchCount == 0) PRINTB("  WARNING: search term not found: \"%s\"", findThis.toString()[i]); +		  if (matchCount == 0) { +			  gchar* ptr_ft = g_utf8_offset_to_pointer(findThis.toString().c_str(), i); +			  gchar utf8_of_cp[6] = ""; //A buffer for a single unicode character to be copied into +			  if(ptr_ft) { +			      g_utf8_strncpy( utf8_of_cp, ptr_ft, 1 ); +		      } +			  PRINTB("  WARNING: search term not found: \"%s\"", utf8_of_cp ); +		  }  		  if (num_returns_per_match == 0 || num_returns_per_match > 1) {  				returnvec.push_back(Value(resultvec));  			} diff --git a/src/value.cc b/src/value.cc index 5afb650..c8a88c6 100644 --- a/src/value.cc +++ b/src/value.cc @@ -36,6 +36,8 @@  #include <boost/format.hpp>  #include "boost-utils.h"  #include "boosty.h" +/*Unicode support for string lengths and array accesses*/ +#include <glib.h>  std::ostream &operator<<(std::ostream &stream, const Filename &filename)  { @@ -579,14 +581,28 @@ Value Value::operator-() const    }  */ +/* + * bracket operation [] detecting multi-byte unicode. + * If the string is multi-byte unicode then the index will offset to the character (2 or 4 byte) and not to the byte. + * A 'normal' string with byte chars are a subset of unicode and still work. + */  class bracket_visitor : public boost::static_visitor<Value>  {  public:    Value operator()(const std::string &str, const double &idx) const {      int i = int(idx);      Value v; +    //Check that the index is positive and less than the size in bytes      if ((i >= 0) && (i < (int)str.size())) { -      v = Value(str[int(idx)]); +	  //Ensure character (not byte) index is inside the character/glyph array +	  if( (unsigned) i < g_utf8_strlen( str.c_str(), str.size() ) )	{ +		  gchar utf8_of_cp[6] = ""; //A buffer for a single unicode character to be copied into +		  gchar* ptr = g_utf8_offset_to_pointer(str.c_str(), i); +		  if(ptr) { +		    g_utf8_strncpy(utf8_of_cp, ptr, 1); +		  } +		  v = std::string(utf8_of_cp); +	  }        //      std::cout << "bracket_visitor: " <<  v << "\n";      }      return v; diff --git a/testdata/scad/misc/search-tests-unicode.scad b/testdata/scad/misc/search-tests-unicode.scad new file mode 100644 index 0000000..d863eff --- /dev/null +++ b/testdata/scad/misc/search-tests-unicode.scad @@ -0,0 +1,116 @@ +//Test search with unicode strings + +//Helper function that pretty prints our search test +//Expected result is checked against execution of a search() invocation and OK/FAIL is indicated +module test_search_and_echo( exp_res, search_to_find, search_to_search, search_up_to_num_matches = undef) +{ +   if(undef != search_up_to_num_matches) +   { +      assign( test_res = search(search_to_find, search_to_search, search_up_to_num_matches) ) +      echo(str("Expect ", exp_res, " for search(", search_to_find, ", ", search_to_search, ", ", search_up_to_num_matches, ")=", test_res, ". ", (exp_res == test_res)?"OK":"FAIL"  )); +   } +   else +   { +      assign( test_res = search(search_to_find, search_to_search) ) +      echo(str("Expect ", exp_res, " for search(", search_to_find, ", ", search_to_search, ")=", test_res, ". ", (exp_res == test_res)?"OK":"FAIL"  )); +   } +} + + +//"Normal" text for comparison +echo ("----- Lookup of 1 byte into 1 byte"); +//Hits - up_to_count 1 +test_search_and_echo( [0],   "a","aaaa" ); +test_search_and_echo( [0],   "a","aaaa",1 ); +test_search_and_echo( [0,0], "aa","aaaa" ); +test_search_and_echo( [0,0], "aa","aaaa",1 ); + + +//Hits - up to count 1+ (incl 0 == all) +test_search_and_echo( [[0,1,2,3]] , 	"a","aaaa",0 ); +test_search_and_echo( [[0,1]], 			"a","aaaa",2 ); +test_search_and_echo( [[0,1,2]], 		"a","aaaa",3 ); +test_search_and_echo( [[0,1,2,3]] , 	"a","aaaa",4 ); +test_search_and_echo( [[0,1,2,3],[0,1,2,3]] , "aa","aaaa",0 ); +//Misses +test_search_and_echo( [],		"b","aaaa" ); +test_search_and_echo( [],		"b","aaaa",1 ); +test_search_and_echo( [[]],		"b","aaaa",0 ); +test_search_and_echo( [[]],		"b","aaaa",2 ); + +test_search_and_echo( [],			"bb","aaaa" ); +test_search_and_echo( [],			"bb","aaaa",1 ); +test_search_and_echo( [[],[]],		"bb","aaaa",0 ); +test_search_and_echo( [[],[]],		"bb","aaaa",2 ); +//Miss - empties +test_search_and_echo( [], "","aaaa" ); +test_search_and_echo( [], "","" ); +test_search_and_echo( [], "a","" ); + + +//Unicode tests +echo ("----- Lookup of multi-byte into 1 byte"); +test_search_and_echo( [],		"Π","aaaa" ); +test_search_and_echo( [],		"π‘","aaaa" ); +test_search_and_echo( [[]],		"Π","aaaa",0 ); +test_search_and_echo( [[]],		"π‘","aaaa",0 ); + +test_search_and_echo( [],		"ΠΠ","aaaa" ); +test_search_and_echo( [],		"π‘π‘","aaaa" ); +test_search_and_echo( [[],[]],		"ΠΠ","aaaa",0 ); +test_search_and_echo( [[],[]],		"π‘π‘","aaaa",0 ); + +echo ("----- Lookup of 1-byte into multi-byte"); +test_search_and_echo( [] , "a","ΠΠΠΠ" ); +test_search_and_echo( [] , "a","π‘π‘π‘π‘" ); +test_search_and_echo( [] , "a","ΠΠΠΠ",1 ); + +test_search_and_echo( [[]] , "a","π‘π‘π‘π‘",0 ); +test_search_and_echo( [[]] , "a","π‘π‘π‘π‘",2 ); + +echo ("----- Lookup of 1-byte into mixed multi-byte"); +test_search_and_echo( [0], "a","aΠaΠaΠaΠa" ); +test_search_and_echo( [0], "a","aπ‘aπ‘aπ‘aπ‘a" ); +test_search_and_echo( [0], "a","aπ‘Ππ‘aπ‘Ππ‘a" ); + +test_search_and_echo( [[0,2,4,6,8]], "a","aΠaΠaΠaΠa",0 ); +test_search_and_echo( [[0,2,4,6,8]], "a","aπ‘aπ‘aπ‘aπ‘a", 0 ); +test_search_and_echo( [[0,4,8]]    , "a","aπ‘Ππ‘aπ‘Ππ‘a", 0 ); + +echo ("----- Lookup of 2-byte into 2-byte"); +test_search_and_echo( [0]       , "Π","ΠΠΠΠ" ); +test_search_and_echo( [[0,1,2,3]] , "Π","ΠΠΠΠ",0 ); + +echo ("----- Lookup of 2-byte into 4-byte"); +test_search_and_echo( [] , "Π","π‘π‘π‘π‘" ); + +echo ("----- Lookup of 4-byte into 4-byte"); +test_search_and_echo( [0] , 		  "π‘","π‘π‘π‘π‘" ); +test_search_and_echo( [[0,1,2,3]], "π‘","π‘π‘π‘π‘",0 ); + +echo ("----- Lookup of 4-byte into 2-byte"); +test_search_and_echo( [] , "π‘","ΠΠΠΠ" ); + +echo ("----- Lookup of 2-byte into mixed multi-byte"); +test_search_and_echo( [1] , 	"Π","aΠaΠaΠaΠa",1 ); +test_search_and_echo( [] , 	"Π","aπ‘aπ‘aπ‘aπ‘a", 1 ); +test_search_and_echo( [2] , 	"Π","aπ‘Ππ‘aπ‘Ππ‘a", 1 ); + +test_search_and_echo( [[1,3,5,7]] , 	"Π","aΠaΠaΠaΠa",0 ); +test_search_and_echo( [[]] , 				"Π","aπ‘aπ‘aπ‘aπ‘a", 0 ); +test_search_and_echo( [[2,6]] , 			"Π","aπ‘Ππ‘aπ‘Ππ‘a", 0 ); + +echo ("----- Lookup of 4-byte into mixed multi-byte"); +test_search_and_echo( [] , 			"π‘","aΠaΠaΠaΠa",1 ); +test_search_and_echo( [1] , "π‘","aπ‘aπ‘aπ‘aπ‘a", 1 ); + +test_search_and_echo( [[]] , 			"π‘","aΠaΠaΠaΠa",0 ); +test_search_and_echo( [[1,3,5,7]] , "π‘","aπ‘aπ‘aπ‘aπ‘a", 0 ); +test_search_and_echo( [[1,3,5,7]] , "π‘","aπ‘Ππ‘aπ‘Ππ‘a", 0 ); + +echo ("----- Lookup of mixed multi-byte into mixed multi-byte"); +test_search_and_echo( [[0,2,4,6,8],[1,3,5,7],[]], "aΠπ‘","aΠaΠaΠaΠa",0 ); +test_search_and_echo( [[0,2,4,6,8],[],[1,3,5,7]], "aΠπ‘","aπ‘aπ‘aπ‘aπ‘a", 0 ); +test_search_and_echo( [[0,4,8],[2,6],[1,3,5,7]]    , "aΠπ‘","aπ‘Ππ‘aπ‘Ππ‘a", 0 ); +test_search_and_echo( [[1,3,5,7],[0,4,8],[2,6]]    , "π‘aΠ","aπ‘Ππ‘aπ‘Ππ‘a", 0 ); + diff --git a/testdata/scad/misc/string-unicode.scad b/testdata/scad/misc/string-unicode.scad new file mode 100644 index 0000000..1386d63 --- /dev/null +++ b/testdata/scad/misc/string-unicode.scad @@ -0,0 +1,44 @@ +//Test length reporting +text_1bytes_len = "1234"; +text_2bytes_len = "ΠΠΠΠ"; +text_4bytes_len = "π‘π±ππ"; + +echo( "text_1bytes_len = ", text_1bytes_len, " len = ", len(text_1bytes_len)  ); +echo( "text_2bytes_len = ", text_2bytes_len, " len = ", len(text_2bytes_len)  ); +echo( "text_4bytes_len = ", text_4bytes_len, " len = ", len(text_4bytes_len)  ); + +//Test how well arrays of unicode string are accessed. + +texts_array = [ +"DEADBEEF", +"ΠΠ΅Π½ΠΈΠ²ΡΠΉ ΡΡΠΆΠΈΠΉ ΠΊΠΎΡ", +"ΩΨ³ΩΩ Ψ§ΩΨ²ΩΨ¬Ψ¨ΩΩ Ψ§ΩΩΨ·", +"ζΆζ°ηε§θ²", +"Àâü ΓΓΓ Γ", +"πππππ
πππππππππππ", +"β β β β β 
β β β β β β β β β β ", +"π‘π±ππ", +]; + +text_2bytes = "ΠΠ΅Π½ΠΈΠ²ΡΠΉ ΡΡΠΆΠΈΠΉ ΠΊΠΎΡ"; +text_4bytes = "π‘π±ππ"; + + +//Test all the normal accesses +for (text_array_idx = [0:(len(texts_array)-1)]) +{ +	echo( "[", text_array_idx, "] = ", texts_array[text_array_idx], " of len=", len(texts_array[text_array_idx]), ":"  ); +    for (text_idx = [0:(len(texts_array[text_array_idx])-1)]) +    { +	    echo( "    [", text_idx, ,"]=", texts_array[text_array_idx][text_idx]  ); +    } +} + +//Test one past the last element of (x-byte unicode). This will be one past the length but inside the char length of the string +echo( "Past end of unicode only 2-byte ", text_2bytes[len(text_2bytes)]  ); +echo( "Past end of unicode only 4-byte ", text_4bytes[len(text_4bytes)]  ); + +//Test past the last element of (x-byte unicode). Outside both lengths. +echo( "Past end of both 2-byte ", text_2bytes[ len(text_2bytes) * 2 ]   ); +echo( "Past end of both 4-byte ", text_4bytes[ len(text_4bytes) * 4 ]   ); + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 370c8be..d76f498 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -366,10 +366,10 @@ if (NOT $ENV{CGALDIR} STREQUAL "")  elseif (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")    if (EXISTS "$ENV{OPENSCAD_LIBRARIES}/lib/CGAL")      set(CGAL_DIR "$ENV{OPENSCAD_LIBRARIES}/lib/CGAL") -    set(CMAKE_MODULE_PATH "${CGAL_DIR}") +    set(CMAKE_MODULE_PATH "${CGAL_DIR}" ${CMAKE_MODULE_PATH})    elseif (EXISTS "$ENV{OPENSCAD_LIBRARIES}/include/CGAL")      set(CGAL_DIR "$ENV{OPENSCAD_LIBRARIES}") -    set(CMAKE_MODULE_PATH "${CGAL_DIR}") +    set(CMAKE_MODULE_PATH "${CGAL_DIR}" ${CMAKE_MODULE_PATH})    endif()  endif()  message(STATUS "CGAL_DIR: " ${CGAL_DIR}) @@ -383,12 +383,40 @@ if("${CGAL_MAJOR_VERSION}.${CGAL_MINOR_VERSION}" VERSION_LESS 3.6)    message(FATAL_ERROR "CGAL >= 3.6 required")  endif()  inclusion(CGAL_DIR CGAL_INCLUDE_DIRS) +#Remove bad BOOST libraries from CGAL 3rd party dependencies when they don't exist (such as on 64-bit Ubuntu 13.10). +#Libs of concern are /usr/lib/libboost_thread.so;/usr/lib/libboost_system.so; +#Confirmed bug in CGAL @ https://bugs.launchpad.net/ubuntu/+source/cgal/+bug/1242111 +string(FIND "${CGAL_3RD_PARTY_LIBRARIES}" "/usr/lib/libboost_system.so" FIND_POSITION  ) +if(NOT "-1" STREQUAL ${FIND_POSITION} ) +  if(NOT EXISTS "/usr/lib/libboost_system.so") +    MESSAGE( STATUS "CGAL_3RD_PARTY_LIBRARIES:Removing non-existent /usr/lib/libboost_system.so" ) +    string(REPLACE "/usr/lib/libboost_system.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES}) +  endif() +endif()  +string(FIND "${CGAL_3RD_PARTY_LIBRARIES}" "/usr/lib/libboost_thread.so" FIND_POSITION  ) +if(NOT "-1" STREQUAL ${FIND_POSITION} ) +  if(NOT EXISTS "/usr/lib/libboost_thread.so") +    MESSAGE( STATUS "CGAL_3RD_PARTY_LIBRARIES:Removing non-existent /usr/lib/libboost_thread.so" ) +    string(REPLACE "/usr/lib/libboost_thread.so" "" CGAL_3RD_PARTY_LIBRARIES ${CGAL_3RD_PARTY_LIBRARIES}) +  endif() +endif()   if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*" AND NOT ${CGAL_CXX_FLAGS_INIT} STREQUAL "" )  	string(REPLACE "-frounding-math" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})  	string(REPLACE "--param=ssp-buffer-size=4" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})  endif() +if (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "") +  # Force pkg-config to look _only_ in the local library folder +  # in case OPENSCAD_LIBRARIES is set. +  set(ENV{PKG_CONFIG_PATH} "$ENV{OPENSCAD_LIBRARIES}/lib/pkgconfig") +  set(ENV{PKG_CONFIG_LIBDIR} "$ENV{OPENSCAD_LIBRARIES}/lib/pkgconfig") +endif() + +find_package(GLIB2 2.2.0 REQUIRED) +add_definitions(${GLIB2_DEFINITIONS}) +inclusion(GLIB2_DIR GLIB2_INCLUDE_DIRS) +  # Imagemagick  if (SKIP_IMAGEMAGICK) @@ -560,8 +588,8 @@ set(OFFSCREEN_SOURCES    ../src/OpenCSGRenderer.cc)  add_library(tests-core STATIC ${CORE_SOURCES}) -target_link_libraries(tests-core ${OPENGL_LIBRARIES}) -set(TESTS-CORE-LIBRARIES ${OPENGL_LIBRARIES} ${Boost_LIBRARIES}) +target_link_libraries(tests-core ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} ) +set(TESTS-CORE-LIBRARIES ${OPENGL_LIBRARIES} ${GLIB2_LIBRARIES} ${Boost_LIBRARIES} )  add_library(tests-common STATIC ${COMMON_SOURCES})  target_link_libraries(tests-common tests-core) @@ -581,7 +609,7 @@ set(TESTS-NOCGAL-LIBRARIES ${TESTS-CORE-LIBRARIES})  # modulecachetest  #  add_executable(modulecachetest modulecachetest.cc) -target_link_libraries(modulecachetest tests-nocgal ${TESTS-NOCGAL-LIBRARIES} ${Boost_LIBRARIES}) +target_link_libraries(modulecachetest tests-nocgal ${TESTS-NOCGAL-LIBRARIES})  #  # csgtexttest @@ -601,7 +629,7 @@ target_link_libraries(cgalcachetest tests-cgal ${TESTS-CGAL-LIBRARIES} ${GLEW_LI  #  add_executable(openscad_nogui ../src/openscad.cc)  set_target_properties(openscad_nogui PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -DEIGEN_DONT_ALIGN -DENABLE_CGAL -DENABLE_OPENCSG ${CGAL_CXX_FLAGS_INIT}") -target_link_libraries(openscad_nogui tests-offscreen tests-cgal tests-nocgal ${TESTS-CORE-LIBRARIES} ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${Boost_LIBRARIES} ${OPENCSG_LIBRARY} ${COCOA_LIBRARY} ) +target_link_libraries(openscad_nogui tests-offscreen tests-cgal tests-nocgal ${TESTS-CORE-LIBRARIES} ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${OPENCSG_LIBRARY} ${COCOA_LIBRARY} )  #  # GUI binary tests @@ -781,8 +809,10 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}              ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/dim-all.scad              ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-test.scad              ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-indexing.scad +            ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-unicode.scad              ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/vector-values.scad              ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad +            ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests-unicode.scad              ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/recursion-tests.scad              ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests.scad              ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/value-reassignment-tests2.scad diff --git a/tests/FindGLIB2.cmake b/tests/FindGLIB2.cmake new file mode 100644 index 0000000..9164c39 --- /dev/null +++ b/tests/FindGLIB2.cmake @@ -0,0 +1,28 @@ +find_package(PkgConfig REQUIRED) + +pkg_search_module(GLIB2 REQUIRED glib-2.0) +#message("GLIB2_LIBRARIES ${GLIB2_LIBRARIES}") +message("GLIB2_LIBRARY_DIRS ${GLIB2_LIBRARY_DIRS}") +#message("GLIB2_LDFLAGS ${GLIB2_LDFLAGS}") +#message("GLIB2_LDFLAGS_OTHER ${GLIB2_LDFLAGS_OTHER}") +message("GLIB2_INCLUDE_DIRS ${GLIB2_INCLUDE_DIRS}") +#message("GLIB2_CFLAGS ${GLIB2_CFLAGS}") +#message("GLIB2_CFLAGS_OTHER ${GLIB2_CFLAGS_OTHER}") +message("GLIB2_LIBDIR ${GLIB2_LIBDIR}") + +set(GLIB2_DEFINITIONS ${GLIB2_CFLAGS_OTHER}) +#message("GLIB2_DEFINITIONS ${GLIB2_DEFINITIONS}") + +set(GLIB2_LIBRARY_NAMES ${GLIB2_LIBRARIES}) +set(GLIB2_LIBRARIES "") +foreach(GLIB2_LIB ${GLIB2_LIBRARY_NAMES}) +#  message("lib: ${GLIB2_LIB}") +  set(TMP TMP-NOTFOUND) +  find_library(TMP NAMES ${GLIB2_LIB} +               PATHS ${GLIB2_LIBRARY_DIRS} +               PATHS ${GLIB2_LIBDIR} +               NO_DEFAULT_PATH) +#  message("TMP: ${TMP}") +  list(APPEND GLIB2_LIBRARIES "${TMP}") +endforeach() +message("GLIB2_LIBRARIES: ${GLIB2_LIBRARIES}") diff --git a/tests/regression/echotest/search-tests-unicode-expected.echo b/tests/regression/echotest/search-tests-unicode-expected.echo new file mode 100644 index 0000000..801bc8c --- /dev/null +++ b/tests/regression/echotest/search-tests-unicode-expected.echo @@ -0,0 +1,109 @@ +ECHO: "----- Lookup of 1 byte into 1 byte" +ECHO: "Expect [0] for search(a, aaaa)=[0]. OK" +ECHO: "Expect [0] for search(a, aaaa, 1)=[0]. OK" +ECHO: "Expect [0, 0] for search(aa, aaaa)=[0, 0]. OK" +ECHO: "Expect [0, 0] for search(aa, aaaa, 1)=[0, 0]. OK" +ECHO: "Expect [[0, 1, 2, 3]] for search(a, aaaa, 0)=[[0, 1, 2, 3]]. OK" +ECHO: "Expect [[0, 1]] for search(a, aaaa, 2)=[[0, 1]]. OK" +ECHO: "Expect [[0, 1, 2]] for search(a, aaaa, 3)=[[0, 1, 2]]. OK" +ECHO: "Expect [[0, 1, 2, 3]] for search(a, aaaa, 4)=[[0, 1, 2, 3]]. OK" +ECHO: "Expect [[0, 1, 2, 3], [0, 1, 2, 3]] for search(aa, aaaa, 0)=[[0, 1, 2, 3], [0, 1, 2, 3]]. OK" +  WARNING: search term not found: "b" +ECHO: "Expect [] for search(b, aaaa)=[]. OK" +  WARNING: search term not found: "b" +ECHO: "Expect [] for search(b, aaaa, 1)=[]. OK" +  WARNING: search term not found: "b" +ECHO: "Expect [[]] for search(b, aaaa, 0)=[[]]. OK" +  WARNING: search term not found: "b" +ECHO: "Expect [[]] for search(b, aaaa, 2)=[[]]. OK" +  WARNING: search term not found: "b" +  WARNING: search term not found: "b" +ECHO: "Expect [] for search(bb, aaaa)=[]. OK" +  WARNING: search term not found: "b" +  WARNING: search term not found: "b" +ECHO: "Expect [] for search(bb, aaaa, 1)=[]. OK" +  WARNING: search term not found: "b" +  WARNING: search term not found: "b" +ECHO: "Expect [[], []] for search(bb, aaaa, 0)=[[], []]. OK" +  WARNING: search term not found: "b" +  WARNING: search term not found: "b" +ECHO: "Expect [[], []] for search(bb, aaaa, 2)=[[], []]. OK" +ECHO: "Expect [] for search(, aaaa)=[]. OK" +ECHO: "Expect [] for search(, )=[]. OK" +  WARNING: search term not found: "a" +ECHO: "Expect [] for search(a, )=[]. OK" +ECHO: "----- Lookup of multi-byte into 1 byte" +  WARNING: search term not found: "Π" +ECHO: "Expect [] for search(Π, aaaa)=[]. OK" +  WARNING: search term not found: "π‘" +ECHO: "Expect [] for search(π‘, aaaa)=[]. OK" +  WARNING: search term not found: "Π" +ECHO: "Expect [[]] for search(Π, aaaa, 0)=[[]]. OK" +  WARNING: search term not found: "π‘" +ECHO: "Expect [[]] for search(π‘, aaaa, 0)=[[]]. OK" +  WARNING: search term not found: "Π" +  WARNING: search term not found: "Π" +ECHO: "Expect [] for search(ΠΠ, aaaa)=[]. OK" +  WARNING: search term not found: "π‘" +  WARNING: search term not found: "π‘" +ECHO: "Expect [] for search(π‘π‘, aaaa)=[]. OK" +  WARNING: search term not found: "Π" +  WARNING: search term not found: "Π" +ECHO: "Expect [[], []] for search(ΠΠ, aaaa, 0)=[[], []]. OK" +  WARNING: search term not found: "π‘" +  WARNING: search term not found: "π‘" +ECHO: "Expect [[], []] for search(π‘π‘, aaaa, 0)=[[], []]. OK" +ECHO: "----- Lookup of 1-byte into multi-byte" +  WARNING: search term not found: "a" +ECHO: "Expect [] for search(a, ΠΠΠΠ)=[]. OK" +  WARNING: search term not found: "a" +ECHO: "Expect [] for search(a, π‘π‘π‘π‘)=[]. OK" +  WARNING: search term not found: "a" +ECHO: "Expect [] for search(a, ΠΠΠΠ, 1)=[]. OK" +  WARNING: search term not found: "a" +ECHO: "Expect [[]] for search(a, π‘π‘π‘π‘, 0)=[[]]. OK" +  WARNING: search term not found: "a" +ECHO: "Expect [[]] for search(a, π‘π‘π‘π‘, 2)=[[]]. OK" +ECHO: "----- Lookup of 1-byte into mixed multi-byte" +ECHO: "Expect [0] for search(a, aΠaΠaΠaΠa)=[0]. OK" +ECHO: "Expect [0] for search(a, aπ‘aπ‘aπ‘aπ‘a)=[0]. OK" +ECHO: "Expect [0] for search(a, aπ‘Ππ‘aπ‘Ππ‘a)=[0]. OK" +ECHO: "Expect [[0, 2, 4, 6, 8]] for search(a, aΠaΠaΠaΠa, 0)=[[0, 2, 4, 6, 8]]. OK" +ECHO: "Expect [[0, 2, 4, 6, 8]] for search(a, aπ‘aπ‘aπ‘aπ‘a, 0)=[[0, 2, 4, 6, 8]]. OK" +ECHO: "Expect [[0, 4, 8]] for search(a, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[0, 4, 8]]. OK" +ECHO: "----- Lookup of 2-byte into 2-byte" +ECHO: "Expect [0] for search(Π, ΠΠΠΠ)=[0]. OK" +ECHO: "Expect [[0, 1, 2, 3]] for search(Π, ΠΠΠΠ, 0)=[[0, 1, 2, 3]]. OK" +ECHO: "----- Lookup of 2-byte into 4-byte" +  WARNING: search term not found: "Π" +ECHO: "Expect [] for search(Π, π‘π‘π‘π‘)=[]. OK" +ECHO: "----- Lookup of 4-byte into 4-byte" +ECHO: "Expect [0] for search(π‘, π‘π‘π‘π‘)=[0]. OK" +ECHO: "Expect [[0, 1, 2, 3]] for search(π‘, π‘π‘π‘π‘, 0)=[[0, 1, 2, 3]]. OK" +ECHO: "----- Lookup of 4-byte into 2-byte" +  WARNING: search term not found: "π‘" +ECHO: "Expect [] for search(π‘, ΠΠΠΠ)=[]. OK" +ECHO: "----- Lookup of 2-byte into mixed multi-byte" +ECHO: "Expect [1] for search(Π, aΠaΠaΠaΠa, 1)=[1]. OK" +  WARNING: search term not found: "Π" +ECHO: "Expect [] for search(Π, aπ‘aπ‘aπ‘aπ‘a, 1)=[]. OK" +ECHO: "Expect [2] for search(Π, aπ‘Ππ‘aπ‘Ππ‘a, 1)=[2]. OK" +ECHO: "Expect [[1, 3, 5, 7]] for search(Π, aΠaΠaΠaΠa, 0)=[[1, 3, 5, 7]]. OK" +  WARNING: search term not found: "Π" +ECHO: "Expect [[]] for search(Π, aπ‘aπ‘aπ‘aπ‘a, 0)=[[]]. OK" +ECHO: "Expect [[2, 6]] for search(Π, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[2, 6]]. OK" +ECHO: "----- Lookup of 4-byte into mixed multi-byte" +  WARNING: search term not found: "π‘" +ECHO: "Expect [] for search(π‘, aΠaΠaΠaΠa, 1)=[]. OK" +ECHO: "Expect [1] for search(π‘, aπ‘aπ‘aπ‘aπ‘a, 1)=[1]. OK" +  WARNING: search term not found: "π‘" +ECHO: "Expect [[]] for search(π‘, aΠaΠaΠaΠa, 0)=[[]]. OK" +ECHO: "Expect [[1, 3, 5, 7]] for search(π‘, aπ‘aπ‘aπ‘aπ‘a, 0)=[[1, 3, 5, 7]]. OK" +ECHO: "Expect [[1, 3, 5, 7]] for search(π‘, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[1, 3, 5, 7]]. OK" +ECHO: "----- Lookup of mixed multi-byte into mixed multi-byte" +  WARNING: search term not found: "π‘" +ECHO: "Expect [[0, 2, 4, 6, 8], [1, 3, 5, 7], []] for search(aΠπ‘, aΠaΠaΠaΠa, 0)=[[0, 2, 4, 6, 8], [1, 3, 5, 7], []]. OK" +  WARNING: search term not found: "Π" +ECHO: "Expect [[0, 2, 4, 6, 8], [], [1, 3, 5, 7]] for search(aΠπ‘, aπ‘aπ‘aπ‘aπ‘a, 0)=[[0, 2, 4, 6, 8], [], [1, 3, 5, 7]]. OK" +ECHO: "Expect [[0, 4, 8], [2, 6], [1, 3, 5, 7]] for search(aΠπ‘, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[0, 4, 8], [2, 6], [1, 3, 5, 7]]. OK" +ECHO: "Expect [[1, 3, 5, 7], [0, 4, 8], [2, 6]] for search(π‘aΠ, aπ‘Ππ‘aπ‘Ππ‘a, 0)=[[1, 3, 5, 7], [0, 4, 8], [2, 6]]. OK" diff --git a/tests/regression/echotest/string-unicode-expected.echo b/tests/regression/echotest/string-unicode-expected.echo new file mode 100644 index 0000000..a1cd3be --- /dev/null +++ b/tests/regression/echotest/string-unicode-expected.echo @@ -0,0 +1,107 @@ +ECHO: "text_1bytes_len = ", "1234", " len = ", 4 +ECHO: "text_2bytes_len = ", "ΠΠΠΠ", " len = ", 4 +ECHO: "text_4bytes_len = ", "π‘π±ππ", " len = ", 4 +ECHO: "[", 0, "] = ", "DEADBEEF", " of len=", 8, ":" +ECHO: "    [", 0, "]=", "D" +ECHO: "    [", 1, "]=", "E" +ECHO: "    [", 2, "]=", "A" +ECHO: "    [", 3, "]=", "D" +ECHO: "    [", 4, "]=", "B" +ECHO: "    [", 5, "]=", "E" +ECHO: "    [", 6, "]=", "E" +ECHO: "    [", 7, "]=", "F" +ECHO: "[", 1, "] = ", "ΠΠ΅Π½ΠΈΠ²ΡΠΉ ΡΡΠΆΠΈΠΉ ΠΊΠΎΡ", " of len=", 17, ":" +ECHO: "    [", 0, "]=", "Π" +ECHO: "    [", 1, "]=", "Π΅" +ECHO: "    [", 2, "]=", "Π½" +ECHO: "    [", 3, "]=", "ΠΈ" +ECHO: "    [", 4, "]=", "Π²" +ECHO: "    [", 5, "]=", "Ρ" +ECHO: "    [", 6, "]=", "ΠΉ" +ECHO: "    [", 7, "]=", " " +ECHO: "    [", 8, "]=", "Ρ" +ECHO: "    [", 9, "]=", "Ρ" +ECHO: "    [", 10, "]=", "ΠΆ" +ECHO: "    [", 11, "]=", "ΠΈ" +ECHO: "    [", 12, "]=", "ΠΉ" +ECHO: "    [", 13, "]=", " " +ECHO: "    [", 14, "]=", "ΠΊ" +ECHO: "    [", 15, "]=", "ΠΎ" +ECHO: "    [", 16, "]=", "Ρ" +ECHO: "[", 2, "] = ", "ΩΨ³ΩΩ Ψ§ΩΨ²ΩΨ¬Ψ¨ΩΩ Ψ§ΩΩΨ·", " of len=", 18, ":" +ECHO: "    [", 0, "]=", "Ω" +ECHO: "    [", 1, "]=", "Ψ³" +ECHO: "    [", 2, "]=", "Ω" +ECHO: "    [", 3, "]=", "Ω" +ECHO: "    [", 4, "]=", " " +ECHO: "    [", 5, "]=", "Ψ§" +ECHO: "    [", 6, "]=", "Ω" +ECHO: "    [", 7, "]=", "Ψ²" +ECHO: "    [", 8, "]=", "Ω" +ECHO: "    [", 9, "]=", "Ψ¬" +ECHO: "    [", 10, "]=", "Ψ¨" +ECHO: "    [", 11, "]=", "Ω" +ECHO: "    [", 12, "]=", "Ω" +ECHO: "    [", 13, "]=", " " +ECHO: "    [", 14, "]=", "Ψ§" +ECHO: "    [", 15, "]=", "Ω" +ECHO: "    [", 16, "]=", "Ω" +ECHO: "    [", 17, "]=", "Ψ·" +ECHO: "[", 3, "] = ", "ζΆζ°ηε§θ²", " of len=", 5, ":" +ECHO: "    [", 0, "]=", "ζΆ" +ECHO: "    [", 1, "]=", "ζ°" +ECHO: "    [", 2, "]=", "η" +ECHO: "    [", 3, "]=", "ε§" +ECHO: "    [", 4, "]=", "θ²" +ECHO: "[", 4, "] = ", "Àâü ΓΓΓ Γ", " of len=", 9, ":" +ECHO: "    [", 0, "]=", "Γ€" +ECHO: "    [", 1, "]=", "ΓΆ" +ECHO: "    [", 2, "]=", "ΓΌ" +ECHO: "    [", 3, "]=", " " +ECHO: "    [", 4, "]=", "Γ" +ECHO: "    [", 5, "]=", "Γ" +ECHO: "    [", 6, "]=", "Γ" +ECHO: "    [", 7, "]=", " " +ECHO: "    [", 8, "]=", "Γ" +ECHO: "[", 5, "] = ", "πππππ
πππππππππππ", " of len=", 16, ":" +ECHO: "    [", 0, "]=", "π" +ECHO: "    [", 1, "]=", "π" +ECHO: "    [", 2, "]=", "π" +ECHO: "    [", 3, "]=", "π" +ECHO: "    [", 4, "]=", "π
" +ECHO: "    [", 5, "]=", "π" +ECHO: "    [", 6, "]=", "π" +ECHO: "    [", 7, "]=", "π" +ECHO: "    [", 8, "]=", "π" +ECHO: "    [", 9, "]=", "π" +ECHO: "    [", 10, "]=", "π" +ECHO: "    [", 11, "]=", "π" +ECHO: "    [", 12, "]=", "π" +ECHO: "    [", 13, "]=", "π" +ECHO: "    [", 14, "]=", "π" +ECHO: "    [", 15, "]=", "π" +ECHO: "[", 6, "] = ", "β β β β β 
β β β β β β β β β β ", " of len=", 15, ":" +ECHO: "    [", 0, "]=", "β " +ECHO: "    [", 1, "]=", "β " +ECHO: "    [", 2, "]=", "β " +ECHO: "    [", 3, "]=", "β " +ECHO: "    [", 4, "]=", "β 
" +ECHO: "    [", 5, "]=", "β " +ECHO: "    [", 6, "]=", "β " +ECHO: "    [", 7, "]=", "β " +ECHO: "    [", 8, "]=", "β " +ECHO: "    [", 9, "]=", "β " +ECHO: "    [", 10, "]=", "β " +ECHO: "    [", 11, "]=", "β " +ECHO: "    [", 12, "]=", "β " +ECHO: "    [", 13, "]=", "β " +ECHO: "    [", 14, "]=", "β " +ECHO: "[", 7, "] = ", "π‘π±ππ", " of len=", 4, ":" +ECHO: "    [", 0, "]=", "π‘" +ECHO: "    [", 1, "]=", "π±" +ECHO: "    [", 2, "]=", "π" +ECHO: "    [", 3, "]=", "π" +ECHO: "Past end of unicode only 2-byte ", undef +ECHO: "Past end of unicode only 4-byte ", undef +ECHO: "Past end of both 2-byte ", undef +ECHO: "Past end of both 4-byte ", undef | 
