diff --git a/.cvsignore b/.cvsignore index 38b6258c..5f4ab297 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,15 +1,14 @@ -CVS/ -/contrib/include/ -/defunct/ -/EXTRA/ -/doc/ +contrib/include +defunct +EXTRA +doc /win32/Autoupdater/ -/objects/ -/lib/ -/bin/ -/macros/ -/help/ -/.makelib/ +objects.* +lib.* +bin.* +macros +help +.makelib _grstate .created .unpacked* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ab78dd41..a3336ac4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,49 +8,60 @@ jobs: matrix: os: [windows-latest, ubuntu-latest] steps: - - uses: actions/checkout@v2 - + - uses: actions/checkout@v2 + - uses: ilammy/msvc-dev-cmd@v1 if: runner.os == 'Windows' with: arch: x86 + + - uses: msys2/setup-msys2@v2 + if: runner.os == 'Windows' + with: + release: false + update: true + install: >- + bison + - name: Windows, generating Makefiles if: runner.os == 'Windows' shell: cmd run: | @set PERL=c:/Strawberry/perl/bin/perl - c:/Strawberry/perl/bin/perl makelib.pl --perlpath=c:/Strawberry/perl/bin --busybox=./win32/busybox --wget=./win32/wget --bison=c:/msys64/usr/bin/bison --flex=./bin/flex --verbose vc2019 + c:/Strawberry/perl/bin/perl makelib.pl --perlpath=c:/Strawberry/perl/bin --busybox=./win32/busybox --wget=./win32/wget --bison=c:/msys64/usr/bin/bison --flex=./bin/flex --verbose vc2022 @rem dir c:\tools @rem dir c:\msys64 @rem dir c:\msys64\usr\bin + - name: Windows, compiling if: runner.os == 'Windows' shell: cmd run: | @set PERL=c:/Strawberry/perl/bin/perl - .\win32\gmake-42 contrib - .\win32\gmake-42 + .\win32\gmake-42 release contrib + .\win32\gmake-42 release + - name: Windows, package if: runner.os == 'Windows' uses: actions/upload-artifact@v2 with: name: package-win32 - path: ./bin.vs160/debug/* + path: ./bin.vs170/debug/* - name: Linux, generating Makefiles if: runner.os == 'Linux' shell: bash run: | - ./support/config_withncurses + ./support/config_withncurses - name: Linux, compiling if: runner.os == 'Linux' shell: bash run: | - make + make release - name: Linux, package if: runner.os == 'Linux' uses: actions/upload-artifact@v2 with: name: package-linux path: ./bin.gcc/debug/* - + diff --git a/.gitignore b/.gitignore index 04b37a70..d4e2ff67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,28 +1,42 @@ CVS/ -/contrib/include/ -/win32/Autoupdater/ -/defunct/ -/EXTRA/ -/doc/ -/objects/ -/lib/ -/bin/ -/macros/ -/help/ -/.makelib/ +defunct/ +.makelib/ +contrib/include/ +win32/Autoupdater/ +EXTRA/ +doc/ +bin +bin.*/ +lib.*/ +objects*/ +macros/ +help/ +Makefile GIT_Notes.txt GIT*.bat _grstate .created .unpacked* __libtool__.lnk -Makefile +.#* *.cache *.exe *.dll *.pdb *.obj +*.o *.cm *.bak +*.a +*.lo +*.la +*~ *.err -.#* +*.mbr +*.log +*.old +*.sav +*.bak +*.orig +*.org +*.bat diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..51054403 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "win32/libappupdater"] + path = win32/libappupdater + url = https://github.com/adamyg/libappupdater diff --git a/BUILDNUMBER.in b/BUILDNUMBER.in index d6b24041..2bd5a0a9 100644 --- a/BUILDNUMBER.in +++ b/BUILDNUMBER.in @@ -1 +1 @@ -19 +22 diff --git a/Changes b/Changes index 844941b3..6e0accfd 100644 --- a/Changes +++ b/Changes @@ -1,7 +1,34 @@ -*- encoding: utf-8; -*- +Tue Mar 22 18:46:50 2022 adamy + + * BUILD 21, version: 3.2.2 + + * libw32 merge. + +Mon Jul 12 22:52:00 2021 adamy + + * echo-line winch handling. + + * width-character + + o wcwidth(), set_unique_version() and inq_unicode_version() primitives. + o wxxx() primitives(). + o %S and %W printf formats. + o buffer insertion primitives (insert() and insertf()) return width not characters. + o read() primitive encoding aware. + o wide-character aware cursor movements. + o unicode description table, inline character-value. + o libiconv() dll relative paths. + o 32-bit internal key-codes. + o Alt+Keycode handler (win32 - experimental). + + * utf8 filenames. + Mon Apr 12 20:50:30 2021 adamy + * BUILD 17 release + * duktape 2.6.0 Sat Apr 3 11:50:35 2021 adamy diff --git a/INSTALL b/INSTALL index cd5060a4..7cfea496 100644 --- a/INSTALL +++ b/INSTALL @@ -129,12 +129,34 @@ On UNIX variations (including cygwin), build by following these steps: - a. (optional) set the CFLAGS environment variable according to - your preference. If you are using a GNU compiler, then -O or -O2 (there is - little advantage in using -O2 and it usually builds larger executables) is fine. + a. Optionally the following external packages can be in additional + functionality; auto-detected during 'conf + + enchant-devel Wrapper library for various s + hunspell-devel Spell checker and morphologic + aspell-devel GNU aspell. + + enca-devel Extremely Naive Charset Analy + libguess-devel Speed character set detection + + libexplain-devel System message add-value. + + libarchive-devel Archive access. + libicu-devel Character conversion. + + libbz2-devel bzip compression. + libzstd-devel gz compression. + xz-devel liblzma. + snappy-devel google fast/compressor/decomp + + plus the following, which are generally available. + + ncurses-devel Terminal interface library. + libcurl-devel Network tools. + openssl-devel OpenSSL. b. If you're building with a non-standard compiler or one known, by something - other than "cc" or "gcc" then you can set the environment variable "CC" to that. + other than "cc" or "gcc" then you can set the environment variable "CC" to that. c. Run the `configure' script by typing: @@ -142,15 +164,15 @@ Alternatively select one the available preset configurations - ./configure_withmost - ./configure_withcurses - ./configure_withncurses - ./configure_withncursesw - ./configure_withtermcap - ./configure_withtermlib - ./configure_withtinfo + ./support/configure_withmost + ./support/configure_withcurses + ./support/configure_withncurses + ./support/configure_withncursesw + ./support/configure_withtermcap + ./support/configure_withtermlib + ./support/configure_withtinfo - d. Note any errors. Please get back to me at the address below if you have any + d. Note any errors. Please get back to me via github below if you have any configure problems. e. This should built the entire set of makefiles and one include file in @@ -160,7 +182,8 @@ f. Build the entire tree with: - make + make + or make release g. Note that the default installation paths (compiled into GRIEF, but may be overridden with environment variables or command line) are: @@ -278,5 +301,5 @@ setting up terminal features. *Some* of this information may be obsolete, but most of it will be fine. -$Id: INSTALL,v 1.14 2020/04/22 22:59:18 cvsuser Exp $ +$Id: INSTALL,v 1.15 2021/06/10 06:13:01 cvsuser Exp $ diff --git a/Makefile.in b/Makefile.in index b980a671..244aba42 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,8 +1,8 @@ # -*- mode: mak; -*- -# $Id: Makefile.in,v 1.47 2020/06/18 20:35:15 cvsuser Exp $ +# $Id: Makefile.in,v 1.52 2022/03/22 10:50:24 cvsuser Exp $ # GRIEF - top level makefile. # -# Copyright (c) 1998 - 2020, Adam Young. +# Copyright (c) 1998 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. @@ -36,7 +36,7 @@ PKG_TARNAME = @PACKAGE_TARNAME@ PKG_URL = @PACKAGE_URL@ PKG_VERSION = @PACKAGE_VERSION@ ifeq ("","$(PKG_VERSION)") -PKG_VERSION = 3.2.1 +PKG_VERSION = 3.2.2 endif PKG_VERSION_1 =$(word 1,$(subst ., ,$(PKG_VERSION))) PKG_VERSION_2 =$(word 2,$(subst ., ,$(PKG_VERSION))) @@ -105,18 +105,63 @@ E= A= .a O= .o LP= lib +E= .exe CLEAN= *.bak *~ *.BAK *.swp *.tmp core *.core a.out -XCLEAN= +XCLEAN= $(D_BIN)/*.map # Configuration +ifneq "" "$(filter win32,@build_os@)" +BUSYBOX= @BUSYBOX@ +ifeq ($(BUSYBOX),busybox) +BUSYBOX= $(shell which busybox 2>/dev/null) +endif +ECHO= $(BUSYBOX) echo +else +ECHO= echo +endif + ifeq ("$(BUILD_TYPE)","") #default -BUILD_TYPE= debug -MAKEFLAGS+= BUILD_TYPE=debug + +.PHONY: help clean vclean build package +help clean vclean build package: +ifneq ("$(word 1,$(MAKECMDGOALS))","debug") +ifneq ("$(word 1,$(MAKECMDGOALS))","release") + @$(ECHO) -n -e "\ + |\n\ + | make [release or debug] target \n\ + |\n\ + | Build one or more of the following targets recursively within each sub-directory. \n\ + |\n\ + | Targets: \n\ + |\n\ + | build - build everything. \n\ + | package - build package. \n\ + | clean - delete everything which can be remade. \n\ + | vclean - delete all. \n\ + | help - command line usage. \n\ + " endif -ifneq ("$(BUILD_TYPE)","release") +endif + @echo . + +.PHONY: release +release: + $(MAKE) BUILD_TYPE=release $(filter-out release, $(MAKECMDGOALS)) + +.PHONY: debug +debug: + $(MAKE) BUILD_TYPE=debug $(filter-out debug, $(MAKECMDGOALS)) + +else # BUILD_TYPE + +ifeq ("$(BUILD_TYPE)","debug") RTSUFFIX=d +else +ifneq ("$(BUILD_TYPE)","release") +$(error invalid BUILD_TYPE; debug or release expected) +endif endif # Directories @@ -140,6 +185,7 @@ D_HLPDOC= $(ROOT)/hlpdoc BUILDNUMBER= BUILDNUMBER.in BUILDINFO= include/edbuildinfo.h +PACKAGEINFO= include/edpackageinfo.h # Compilers, programs @@ -167,10 +213,6 @@ INNO= "C:/Program Files (x86)/Inno Setup 5/Compil32" endif endif -BUSYBOX= @BUSYBOX@ -ifeq ($(BUSYBOX),busybox) -BUSYBOX= $(shell which busybox 2>/dev/null) -endif # Common flags @@ -233,7 +275,10 @@ BINS=\ $(D_BIN)/grcpp$(E) \ $(D_BIN)/grmandoc$(E) \ $(D_BIN)/grunch$(E) - +ifneq "" "$(filter mingw32 win32,@build_os@)" +BINS+= $(D_BIN)/grwc$(E) +endif + LIBS= ifneq "" "$(filter mingw32 win32,@build_os@)" LIBS+= $(LW)win32 @@ -248,6 +293,7 @@ LIBS+=\ $(LW)onigrx \ $(LW)tre \ $(LW)chartable \ + $(LW)widechar \ $(LW)charudet \ $(LW)vfs \ $(LW)duktape \ @@ -264,13 +310,32 @@ DIRECTORIES=\ ######################################################################################### # Rules -.PHONY: build release debug directories install -build: directories buildinfo libs bins import +.PHONY: build directories install +build: directories artifacts libs bins import $(MAKE) -C $(D_HLPDOC) $(MAKE) -C $(D_MACSRC) +.PHONY: help +help: + @$(ECHO) -e "\ + |\n\ + | make [release or debug] target \n\ + |\n\ + | Build one or more of the following targets recursively within each sub-directory. \n\ + |\n\ + | Targets: \n\ + |\n\ + | build - build everything. \n\ + | package - build all packages. \n\ + | clean - delete everything which can be remade. \n\ + | help - command line usage. \n\ + " + +.PHONY: release release: $(MAKE) BUILD_TYPE=release $(filter-out release, $(MAKECMDGOALS)) + +.PHONY: debug debug: $(MAKE) BUILD_TYPE=debug $(filter-out debug, $(MAKECMDGOALS)) @@ -284,14 +349,12 @@ endif directories: $(DIRECTORIES) +artifacts: buildinfo + %/.created: -@$(PERL) ./win32/mkdir_p.pl $(@D) @echo "++ do not delete, grief edit managed content ++" > $@ -.PHONY: package -package: import - $(INNO) ./win32/gr-inno-setup.iss - .PHONY: import import: $(IMPORT) @@ -314,19 +377,49 @@ $(D_BIN)/$(PLBRNAME).dll: $(LIBPLBRPATH) @$(CP) -f $(subst /,\,$^) $@ endif +.PHONY: package +package: import packageinfo + $(INNO) ./win32/gr-inno-setup.iss + -$(RM) $(PACKAGEINFO) ######################################################################################### # Applications -buildinfo: $(BUILDINFO) +BUILD_DATE= $(shell date +'%Y%m%d') +ifneq ($(APPVEYOR_BUILD_NUMBER),) +BUILD_NUMBER= $(APPVEYOR_BUILD_NUMBER) +else ifneq ($(GITHUB_RUN_NUMBER),) +BUILD_NUMBER= $(GITHUB_RUN_NUMBER) +else +BUILD_NUMBER= $(shell cat ./$(BUILDNUMBER)) +endif -PKG_BUILD_DATE= $(shell date +'%Y%m%d') -PKG_BUILD_NUMBER= $(shell cat ./$(BUILDNUMBER)) +.PHONY: buildinfo +$(BUILDINFO): Makefile $(BUILDNUMBER) buildinfo +buildinfo: + @echo updating buildinfo.h ... + -@$(PERL) ./buildinfo.pl -o $(BUILDINFO) --prefix="GR_" --package="$(PACKAGE)" --name="$(PKG_NAME)" --version="$(PKG_VERSION)" \ + --date="$(BUILD_DATE)" --build="$(BUILD_NUMBER)" --toolchain="@TOOLCHAINEXT@" --type="$(BUILD_TYPE)" \ + --bindir="$(BINDIR)" --sbindir="$(SBINDIR)" --libexecdir="$(LIBEXECDIR)" --libdir="$(LIBDIR)" --datadir="$(DATADIR)" + +.PHONY: packageinfo +packageinfo: + -@$(PERL) ./buildinfo.pl -o $(PACKAGEINFO) --prefix="GR_" --package="$(PACKAGE)" --name="$(PKG_NAME)" --version="$(PKG_VERSION)" \ + --date="$(BUILD_DATE)" --build="$(BUILD_NUMBER)" --toolchain="@TOOLCHAINEXT@" --type="$(BUILD_TYPE)" + +buildinfo.h: BUILDNUMBER buildinfo.pl + +ifneq ($(APPVEYOR_BUILD_NUMBER),) +BUILDNUMBER: + @echo importing appveyor build number ... + @echo $(APPVEYOR_BUILD_NUMBER)>$@ +endif -$(BUILDINFO): Makefile $(BUILDNUMBER) - -@$(PERL) ./buildinfo.pl -o $@ --prefix="GR_" --package="$(PACKAGE)" --name="$(PKG_NAME)" --version="$(PKG_VERSION)" \ - --date="$(PKG_BUILD_DATE)" --build="$(PKG_BUILD_NUMBER)" --toolchain="@TOOLCHAINEXT@" --type="$(BUILD_TYPE)" \ - --bindir="$(BINDIR)" --sbindir="$(SBINDIR)" --libexecdir="$(LIBEXECDIR)" --libdir="$(LIBDIR)" --datadir="$(DATADIR)" +ifneq ($(GITHUB_RUN_NUMBER),) +BUILDNUMBER: + @echo importing github build number ... + @echo $(GITHUB_RUN_NUMBER)>$@ +endif .PHONY: new_buildnumber new_buildnumber: @@ -358,7 +451,9 @@ $(D_BIN)/grmandoc$(E): $(D_BIN)/.created libs $(D_BIN)/grunch$(E): $(D_BIN)/.created libs $(MAKE) -C $(D_GRUNCH) - + +$(D_BIN)/grwc$(E): $(D_BIN)/.created libs + $(MAKE) -C util ######################################################################################### # Rules @@ -412,6 +507,7 @@ endif $(MAKE) -C libonigrx clean $(MAKE) -C libtre clean $(MAKE) -C libchartable clean + $(MAKE) -C libwidechar clean $(MAKE) -C libcharudet clean $(MAKE) -C libvfs clean $(MAKE) -C libduktape clean @@ -448,6 +544,7 @@ distclean: clean libonigrx/Makefile \ libtre/Makefile \ libchartable/Makefile \ + libwidechar/Makefile \ libcharudet/Makefile \ libvfs/Makefile \ libduktape/Makefile \ @@ -465,3 +562,5 @@ distclean: clean # endif #end + +endif # BUILD_TYPE diff --git a/auto/configure b/auto/configure index ab462a35..56a8b928 100755 --- a/auto/configure +++ b/auto/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 1.72 . +# From configure.in Revision: 1.75 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for GRIEF 3.2.1. # @@ -788,7 +788,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -938,7 +937,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1191,15 +1189,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1337,7 +1326,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1490,7 +1479,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -17235,7 +17223,7 @@ EOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC __attribute__ directives..." >&5 $as_echo "$as_me: checking for $CC __attribute__ directives..." >&6;} cat > conftest.$ac_ext <. +# ==end== # use strict; @@ -104,6 +126,7 @@ #define ${prefix}VERSION_1 ${version1} #define ${prefix}VERSION_2 ${version2} #define ${prefix}VERSION_3 ${version3} +#define ${prefix}VERSION_4 ${buildnumber} #define ${prefix}BUILD_DATE "${builddate}" #define ${prefix}BUILD_NUMBER "${buildnumber}" EOT @@ -114,10 +137,10 @@ if ($buildtype) { print FILE "#define BUILD_TYPE \"${buildtype}\"\n"; - die "makeconfig.pm: build type verb 'release' or 'debug' expected.\n" + die "buildinfo.pm: build type verb 'release' or 'debug' expected.\n" if ($buildtype !~ /release/ && $buildtype !~ /debug/); - - die "makeconfig.pm: build type verbs 'release' and 'debug' are mutually exclusive.\n" + + die "buildinfo.pm: build type verbs 'release' and 'debug' are mutually exclusive.\n" if ($buildtype =~ /release/ && $buildtype =~ /debug/); print FILE "#define BUILD_TYPE_RELEASE 1\n" @@ -176,4 +199,3 @@ #end - diff --git a/contrib/.cvsignore b/contrib/.cvsignore index f3c7a7c5..8d2c87c4 100644 --- a/contrib/.cvsignore +++ b/contrib/.cvsignore @@ -1 +1,4 @@ Makefile +*.err +include + diff --git a/contrib/extags/.cvsignore b/contrib/extags/.cvsignore new file mode 100644 index 00000000..8a4ee951 --- /dev/null +++ b/contrib/extags/.cvsignore @@ -0,0 +1,4 @@ +Makefile +*.err +.unpacked.* + diff --git a/contrib/flex/.cvsignore b/contrib/flex/.cvsignore index 91db0003..934c7f94 100644 --- a/contrib/flex/.cvsignore +++ b/contrib/flex/.cvsignore @@ -2,3 +2,9 @@ flex-2.5.10 .unpacked.* Makefile *.err +parse.c +parse.h +scan.c +skel.c + + diff --git a/contrib/flex/.gitignore b/contrib/flex/.gitignore index f7986f77..3a903dbb 100644 --- a/contrib/flex/.gitignore +++ b/contrib/flex/.gitignore @@ -2,3 +2,9 @@ file-2.510/ .unpacked.* Makefile *.err +parse.c +parse.h +scan.c +skel.c + + diff --git a/contrib/hunspell/.cvsignore b/contrib/hunspell/.cvsignore new file mode 100644 index 00000000..ae9b9137 --- /dev/null +++ b/contrib/hunspell/.cvsignore @@ -0,0 +1,3 @@ +Makefile +*.err +.unpacked.* diff --git a/contrib/libarchive/.cvsignore b/contrib/libarchive/.cvsignore new file mode 100644 index 00000000..8a4ee951 --- /dev/null +++ b/contrib/libarchive/.cvsignore @@ -0,0 +1,4 @@ +Makefile +*.err +.unpacked.* + diff --git a/contrib/libbzip2/.cvsignore b/contrib/libbzip2/.cvsignore new file mode 100644 index 00000000..8a4ee951 --- /dev/null +++ b/contrib/libbzip2/.cvsignore @@ -0,0 +1,4 @@ +Makefile +*.err +.unpacked.* + diff --git a/contrib/libcitrus/.cvsignore b/contrib/libcitrus/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/contrib/libcitrus/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/contrib/libcitrus/libpaths.c b/contrib/libcitrus/libpaths.c index 81a67a7e..662f9a5e 100644 --- a/contrib/libcitrus/libpaths.c +++ b/contrib/libcitrus/libpaths.c @@ -1,8 +1,8 @@ -/* $Id: libpaths.c,v 1.8 2015/03/01 02:56:37 cvsuser Exp $ +/* $Id: libpaths.c,v 1.10 2021/06/14 14:12:57 cvsuser Exp $ * * libcitrus implementation * - * Copyright (c) 2012-2015 Adam Young. + * Copyright (c) 2012-2021 Adam Young. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,6 +53,7 @@ static const char * x_application_dir = APPLICATIONDIR; static const char * getpath(const char *application, const char *dir, char *buffer, const int buflen); static int getexedir(char *buf, int maxlen); +static int getdlldir(char *buf, int maxlen); static void dospath(char *path); @@ -197,8 +198,8 @@ getpath(const char *application, const char *dir, char *buffer, const int buflen { int len, done = FALSE; - // , generally same as INSTALLDIR - if ((len = getexedir(buffer, buflen)) > 0) { + // , generally same as INSTALLDIR + if ((len = getdlldir(buffer, buflen)) > 0) { _snprintf(buffer + len, buflen - len, "/%s", dir); buffer[buflen - 1] = 0; if (0 == _access(buffer, 0)) { @@ -206,6 +207,17 @@ getpath(const char *application, const char *dir, char *buffer, const int buflen } } + // , generally same as INSTALLDIR + if (! done) { + if ((len = getexedir(buffer, buflen)) > 0) { + _snprintf(buffer + len, buflen - len, "/%s", dir); + buffer[buflen - 1] = 0; + if (0 == _access(buffer, 0)) { + done = TRUE; + } + } + } + // if (! done) { if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROGRAM_FILES, NULL, 0, buffer))) { @@ -256,11 +268,11 @@ getpath(const char *application, const char *dir, char *buffer, const int buflen static int getexedir(char *buf, int maxlen) { - if (GetModuleFileName(NULL, buf, maxlen)) { + if (GetModuleFileNameA(NULL, buf, maxlen)) { const int len = strlen(buf); char *cp; - for (cp = buf + len; (cp > buf) && (*cp != '\\'); cp--) + for (cp = buf + len; (cp > buf) && (*cp != '\\'); --cp) /*cont*/; if ('\\' == *cp) { cp[1] = '\0'; // remove program @@ -272,6 +284,35 @@ getexedir(char *buf, int maxlen) } +static int +getdlldir(char *buf, int maxlen) +{ +#if defined(__WATCOMC__) + HMODULE hm = NULL; + + if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) &__citrus_PATH_ICONV, &hm) != 0 && + GetModuleFileNameA(hm, buf, maxlen)) { +#else + EXTERN_C IMAGE_DOS_HEADER __ImageBase; + + if (GetModuleFileNameA((HINSTANCE)&__ImageBase, buf, maxlen)) { +#endif + const int len = strlen(buf); + char *cp; + + for (cp = buf + len; (cp > buf) && (*cp != '\\'); --cp) + /*cont*/; + if ('\\' == *cp) { + cp[1] = '\0'; // remove library + return (cp - buf) + 1; + } + return len; + } + return -1; +} + + static void dospath(char *path) { @@ -290,3 +331,4 @@ dospath(char *path) } *path = 0; } + diff --git a/contrib/libcitrus/src/citrus_csmapper.c b/contrib/libcitrus/src/citrus_csmapper.c index 8cb52f2d..53ec8b2e 100644 --- a/contrib/libcitrus/src/citrus_csmapper.c +++ b/contrib/libcitrus/src/citrus_csmapper.c @@ -316,7 +316,7 @@ open_serial_mapper(struct _citrus_mapper_area *__restrict ma, struct _citrus_mapper * __restrict * __restrict rcm, const char *src, const char *pivot, const char *dst) { - char buf[PATH_MAX]; + char buf[4 * PATH_MAX]; snprintf(buf, sizeof(buf), "%s/%s,%s/%s", src, pivot, pivot, dst); diff --git a/contrib/libcitrus/src/citrus_csmapper.h b/contrib/libcitrus/src/citrus_csmapper.h index 31b06e40..dbf25b08 100644 --- a/contrib/libcitrus/src/citrus_csmapper.h +++ b/contrib/libcitrus/src/citrus_csmapper.h @@ -27,7 +27,7 @@ */ #ifndef _CITRUS_CSMAPPER_H_ -#define _CITRUS_CSMAPPER_H +#define _CITRUS_CSMAPPER_H_ #define _citrus_csmapper _citrus_mapper #define _citrus_csmapper_close _citrus_mapper_close diff --git a/contrib/libcitrus/src/citrus_ctype_template.h b/contrib/libcitrus/src/citrus_ctype_template.h index 4bb1b629..c27a3791 100644 --- a/contrib/libcitrus/src/citrus_ctype_template.h +++ b/contrib/libcitrus/src/citrus_ctype_template.h @@ -238,8 +238,8 @@ _FUNCNAME(mbsrtowcs_priv)(_ENCODING_INFO * __restrict ei, _DIAGASSERT(nresult != 0); _DIAGASSERT(ei != NULL); _DIAGASSERT(psenc != NULL); - _DIAGASSERT(s == NULL); - _DIAGASSERT(*s == NULL); + _DIAGASSERT(s != NULL); + _DIAGASSERT(*s != NULL); /* if pwcs is NULL, ignore n */ if (pwcs == NULL) diff --git a/contrib/libguess/.cvsignore b/contrib/libguess/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/contrib/libguess/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/contrib/libiconv/.cvsignore b/contrib/libiconv/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/contrib/libiconv/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/contrib/libiconv/iconv.h b/contrib/libiconv/iconv.h index e3bbd313..52a395c6 100644 --- a/contrib/libiconv/iconv.h +++ b/contrib/libiconv/iconv.h @@ -1,10 +1,10 @@ #ifndef ICONV_H_INCLUDED #define ICONV_H_INCLUDED -/* $Id: iconv.h,v 1.5 2020/06/18 19:52:45 cvsuser Exp $ +/* $Id: iconv.h,v 1.6 2021/06/13 16:32:03 cvsuser Exp $ * * win32 - libiconv * - * Copyright (c) 2012-2015 Adam Young. + * Copyright (c) 2012-2021 Adam Young. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -62,7 +62,7 @@ LIBICONV_LINKAGE int LIBICONV_ENTRY iconv_close(iconv_t cd); LIBICONV_LINKAGE int LIBICONV_ENTRY iconv_errno(void); LIBICONV_LINKAGE size_t LIBICONV_ENTRY __iconv(iconv_t handle, const char **in, size_t *szin, char **out, - size_t *szout, unsigned flags, size_t *invalids); + size_t *szout, unsigned flags, size_t *invalids); LIBICONV_LINKAGE int LIBICONV_ENTRY __iconv_get_list(char ***rlist, size_t *rsz); @@ -74,6 +74,10 @@ LIBICONV_LINKAGE const char *LIBICONV_ENTRY __iconv_PATH_CSMAPPER(void); LIBICONV_LINKAGE const char *LIBICONV_ENTRY __iconv_PATH_ICONV(void); +#if !defined(__ICONV_F_HIDE_INVALID) +#define __ICONV_F_HIDE_INVALID 0x0001 +#endif + __END_DECLS #endif /*ICONV_H_INCLUDED*/ diff --git a/contrib/libiconv/iconv1.txt b/contrib/libiconv/iconv1.txt new file mode 100644 index 00000000..86465eb7 --- /dev/null +++ b/contrib/libiconv/iconv1.txt @@ -0,0 +1,150 @@ +ICONV(3) NetBSD Library Functions Manual ICONV(3) + +NAME + + iconv_open, iconv_close, iconv -- codeset conversion functions + + +LIBRARY + + Standard C Library (libc, -lc) + + +SYNOPSIS + + #include + + iconv_t + iconv_open(const char *dstname, const char *srcname); + + int + iconv_close(iconv_t cd); + + size_t + iconv(iconv_t cd, char ** restrict src, size_t * restrict srcleft, + char ** restrict dst, size_t * restrict dstleft); + + +DESCRIPTION + + The iconv_open() function opens a converter from the codeset srcname to + the codeset dstname and returns its descriptor. + + The iconv_close() function closes the specified converter cd. + + The iconv() function converts the string in the buffer *src of length + *srcleft bytes and stores the converted string in the buffer *dst of size + *dstleft bytes. After calling iconv(), the values pointed to by src, + srcleft, dst, and dstleft are updated as follows: + + *src Pointer to the byte just after the last character + fetched. + + *srcleft Number of remaining bytes in the source buffer. + + *dst Pointer to the byte just after the last character stored. + + *dstleft Number of remainder bytes in the destination buffer. + + If the string pointed to by *src contains a byte sequence which is not a + valid character in the source codeset, the conversion stops just after + the last successful conversion. If the output buffer is too small to + store the converted character, the conversion also stops in the same way. + In these cases, the values pointed to by src, srcleft, dst, and dstleft + are updated to the state just after the last successful conversion. + + If the string pointed to by *src contains a character which is valid + under the source codeset but can not be converted to the destination + codeset, the character is replaced by an ``invalid character'' which + depends on the destination codeset, e.g., `?', and the conversion is con- + tinued. iconv() returns the number of such ``invalid conversions''. + + If src or *src is NULL and the source and/or destination codesets are + stateful, iconv() places these into their initial state. + + 1. If both dst and *dst are non-NULL, iconv() stores the shift + sequence for the destination switching to the initial state in + the buffer pointed to by *dst. The buffer size is specified + by the value pointed to by dstleft as above. iconv() will + fail if the buffer is too small to store the shift sequence. + + 2. On the other hand, dst or *dst may be NULL. In this case, the + shift sequence for the destination switching to the initial + state is discarded. + + +RETURN VALUES + + Upon successful completion of iconv_open(), it returns a conversion + descriptor. Otherwise, iconv_open() returns (iconv_t)-1 and sets errno + to indicate the error. + + Upon successful completion of iconv_close(), it returns 0. Otherwise, + iconv_close() returns -1 and sets errno to indicate the error. + + Upon successful completion of iconv(), it returns the number of + ``invalid'' conversions. Otherwise, iconv() returns (size_t)-1 and sets + errno to indicate the error. + + +ERRORS + + The iconv_open() function may cause an error in the following cases: + + [EINVAL] There is no converter specified by srcname and + dstname. + + [ENOMEM] Memory is exhausted. + + The iconv_close() function may cause an error in the following case: + + [EBADF] The conversion descriptor specified by cd is invalid. + + The iconv() function may cause an error in the following cases: + + [E2BIG] The output buffer pointed to by *dst is too small to + store the result string. + + [EBADF] The conversion descriptor specified by cd is invalid. + + [EILSEQ] The string pointed to by *src contains a byte sequence + which does not describe a valid character of the + source codeset. + + [EINVAL] The string pointed to by *src terminates with an + incomplete character or shift sequence. + + +SEE ALSO + + iconv(1) + + +STANDARDS + + iconv_open(), iconv_close(), and iconv() conform to IEEE Std 1003.1-2001 + (``POSIX.1''). + + Historically, the definition of iconv has not been consistent across + operating systems. This is due to an unfortunate historical mistake, + documented in this e-mail: + + https://www5.opengroup.org/sophocles2/show_mail.tpl?&source=L&listname=austin-group-l&id=7404. + + The standards page for the header file defined the second argu- + ment of iconv() as char **, but the standards page for the iconv() imple- + mentation defined it as const char **. The standards committee later + chose to change the function definition to follow the header file defini- + tion (without const), even though the version with const is arguably more + correct. NetBSD used initially the const form. It was decided to reject + the committee's regression and become (technically) incompatible. + + This decision was changed in NetBSD 10 and the iconv() prototype was syn- + chronized with the standard. + + +BUGS + + If iconv() is aborted due to the occurrence of some error, the ``invalid + conversion'' count mentioned above is unfortunately lost. + diff --git a/contrib/libiconv/libiconv.c b/contrib/libiconv/libiconv.c index 3fef29e1..b0426fd3 100644 --- a/contrib/libiconv/libiconv.c +++ b/contrib/libiconv/libiconv.c @@ -1,4 +1,4 @@ -/* $Id: libiconv.c,v 1.3 2012/09/03 23:10:15 ayoung Exp $ +/* $Id: libiconv.c,v 1.4 2021/06/13 16:33:45 cvsuser Exp $ * * Copyright (c)2003 Citrus Project, * All rights reserved. @@ -62,6 +62,16 @@ iconv_open(const char *out, const char *in) { int ret; struct _citrus_iconv *handle; + char *s; + + // gnu-iconv compat, remove //IGNORE, //TRANSLIT and other options + if (NULL != (s = strchr(out, '/'))) { + const size_t outlen = s - out; + char *t_out = alloca(outlen + 1); + + memcpy(t_out, out, outlen), t_out[outlen] = 0; + out = t_out; + } ret = _citrus_iconv_open(&handle, _PATH_ICONV, in, out); if (ret) { @@ -89,7 +99,7 @@ iconv_close(iconv_t handle) LIBICONV_LINKAGE size_t LIBICONV_ENTRY iconv(iconv_t handle, const char **__restrict in, size_t *__restrict szin, - char ** __restrict out, size_t * __restrict szout) + char ** __restrict out, size_t * __restrict szout) { int err; size_t ret; @@ -120,7 +130,7 @@ iconv_errno(void) LIBICONV_LINKAGE size_t LIBICONV_ENTRY __iconv(iconv_t handle, const char **in, size_t *szin, char **out, - size_t *szout, unsigned flags, size_t *invalids) + size_t *szout, unsigned flags, size_t *invalids) { int err; size_t ret; diff --git a/contrib/libiconv/makelib.def b/contrib/libiconv/makelib.def index 1d6d9c28..16904324 100644 --- a/contrib/libiconv/makelib.def +++ b/contrib/libiconv/makelib.def @@ -1,10 +1,10 @@ -# $Id: makelib.def,v 1.3 2012/09/21 17:32:53 ayoung Exp $ +# $Id: makelib.def,v 1.4 2021/06/12 15:34:33 cvsuser Exp $ # win32 makelib configuration # inc=../include lbl=LIBICONV lib=libiconv.lib def=HAVE_LIBICONV -def=HAVE_ICONVL_H -def=HAVE_LIBICONVL_DLL="libiconv.1.0.dll" +def=HAVE_ICONV_CITRUS_H +def=HAVE_LIBICONV_CITRUS_DLL="libiconv.1.0.dll" diff --git a/contrib/libintl/.cvsignore b/contrib/libintl/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/contrib/libintl/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/contrib/liblzma/.cvsignore b/contrib/liblzma/.cvsignore index e171ef07..8a4ee951 100644 --- a/contrib/liblzma/.cvsignore +++ b/contrib/liblzma/.cvsignore @@ -1 +1,4 @@ -xz-5.2.*/ +Makefile +*.err +.unpacked.* + diff --git a/contrib/liblzma/Makefile.in b/contrib/liblzma/Makefile.in index 09464fc7..3ffd04e1 100644 --- a/contrib/liblzma/Makefile.in +++ b/contrib/liblzma/Makefile.in @@ -1,5 +1,5 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.8 2020/06/18 20:35:16 cvsuser Exp $ +# $Id: Makefile.in,v 1.9 2022/03/22 04:10:50 cvsuser Exp $ # liblzma makefile and grxz # # @@ -234,6 +234,8 @@ TSKS= $(LZMAUTIL) LZMA=no ifeq ("@TOOLCHAIN@","owc20") else ifeq ("@TOOLCHAIN@","owc19") +else ifeq ("@TOOLCHAIN@","vs170") +LZMA=yes else ifeq ("@TOOLCHAIN@","vs160") LZMA=yes else ifeq ("@TOOLCHAIN@","vs150") diff --git a/contrib/libmagic/.cvsignore b/contrib/libmagic/.cvsignore new file mode 100644 index 00000000..8c6968cf --- /dev/null +++ b/contrib/libmagic/.cvsignore @@ -0,0 +1,6 @@ +Makefile +*.err +.unpacked.* +magic +magic.mgc + diff --git a/contrib/libmagic/.gitignore b/contrib/libmagic/.gitignore index bfdcbd35..8ca4f0e8 100644 --- a/contrib/libmagic/.gitignore +++ b/contrib/libmagic/.gitignore @@ -1,4 +1,5 @@ file-511/ file-5.29/ +.unpacked.* magic -magic.mgc \ No newline at end of file +magic.mgc diff --git a/contrib/libmagic/config.h b/contrib/libmagic/config.h index a29f7409..3ec815d3 100644 --- a/contrib/libmagic/config.h +++ b/contrib/libmagic/config.h @@ -103,6 +103,7 @@ /* Define to 1 if you have the `getline' function. */ //#define HAVE_GETLINE +#undef HAVE_GETLINE /* Define to 1 if you have the header file. */ #define HAVE_GETOPT_H @@ -132,28 +133,26 @@ /* Define to 1 if you have the header file. */ #if !defined(HAVE_LIMITS_H) && (defined(_MSC_VER) || defined(__WATCOMC__)) -#define HAVE_LIMITS_H +#define HAVE_LIMITS_H 1 #endif /* Define to 1 if you have the header file. */ -#if defined(__WATCOMC__) -#undef HAVE_LOCALE_H -#endif + //#undef HAVE_LOCALE_H /* Define to 1 if you have the `localtime_r' function. */ //#undef HAVE_LOCALTIME_R /* Define to 1 if mbrtowc and mbstate_t are properly declared. */ #if !defined(HAVE_MBRTOWC) && (defined(_MSC_VER) || defined(__WATCOMC__)) -#define HAVE_MBRTOWC +#define HAVE_MBRTOWC 1 #endif /* Define to 1 if declares mbstate_t. */ -#define HAVE_MBSTATE_T +#define HAVE_MBSTATE_T 1 /* Define to 1 if you have the header file. */ #if !defined(HAVE_MEMORY_H) && (defined(_MSC_VER) || defined(__WATCOMC__)) -#define HAVE_MEMORY_H +#define HAVE_MEMORY_H 1 #endif /* Define to 1 if you have the `mkostemp' function. */ @@ -183,16 +182,16 @@ //#undef HAVE_SIG_T /* Define to 1 if you have the header file. */ -#define HAVE_STDDEF_H +#define HAVE_STDDEF_H 1 /* Define to 1 if you have the header file. */ #if !defined(HAVE_STDINT_H) && (defined(_MSC_VER) || defined(__WATCOMC__)) -#define HAVE_STDINT_H +#define HAVE_STDINT_H 1 #endif /* Define to 1 if you have the header file. */ #if !defined(HAVE_STDLIB_H) && (defined(_MSC_VER) || defined(__WATCOMC__)) -#define HAVE_STDLIB_H +#define HAVE_STDLIB_H 1 #endif /* Define to 1 if you have the `strcasestr' function. */ @@ -200,7 +199,7 @@ /* Define to 1 if you have the `strerror' function. */ #if !defined(HAVE_STRERROR) && (defined(_MSC_VER) || defined(__WATCOMC__)) -#define HAVE_STRERROR +#define HAVE_STRERROR 1 #endif /* Define to 1 if you have the header file. */ @@ -208,7 +207,7 @@ /* Define to 1 if you have the header file. */ #if !defined(HAVE_STRING_H) && (defined(_MSC_VER) || defined(__WATCOMC__)) -#define HAVE_STRING_H +#define HAVE_STRING_H 1 #endif /* Define to 1 if you have the `strlcat' function. */ @@ -227,7 +226,7 @@ //#define HAVE_STRTOUL /* HAVE_STRUCT_OPTION */ -#define HAVE_STRUCT_OPTION +#define HAVE_STRUCT_OPTION 1 /* Define to 1 if `st_rdev' is a member of `struct stat'. */ //#undef HAVE_STRUCT_STAT_ST_RDEV @@ -275,7 +274,7 @@ /* Define to 1 if you have the header file. */ #if !defined(HAVE_UNISTD_H) && (defined(_MSC_VER) || defined(__WATCOMC__)) -#define HAVE_UNISTD_H +#define HAVE_UNISTD_H 1 #endif /* Define to 1 if you have the `uselocale' function. */ diff --git a/contrib/libregex/.cvsignore b/contrib/libregex/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/contrib/libregex/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/contrib/libz/.cvsignore b/contrib/libz/.cvsignore new file mode 100644 index 00000000..8a4ee951 --- /dev/null +++ b/contrib/libz/.cvsignore @@ -0,0 +1,4 @@ +Makefile +*.err +.unpacked.* + diff --git a/contrib/libz/.gitignore b/contrib/libz/.gitignore index d9cd289c..350c24e0 100644 --- a/contrib/libz/.gitignore +++ b/contrib/libz/.gitignore @@ -1 +1 @@ -zlib-1.2.*/ \ No newline at end of file +zlib-1.2.*/ diff --git a/contrib/makedepend/.cvsignore b/contrib/makedepend/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/contrib/makedepend/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/contrib/makedepend/Makefile.in b/contrib/makedepend/Makefile.in index 96308936..c410bb4a 100644 --- a/contrib/makedepend/Makefile.in +++ b/contrib/makedepend/Makefile.in @@ -1,5 +1,5 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.8 2020/06/18 20:35:16 cvsuser Exp $ +# $Id: Makefile.in,v 1.9 2022/03/21 17:12:44 cvsuser Exp $ # makedepend makefile # # @@ -45,6 +45,7 @@ D_BIN= $(ROOT)/bin@TOOLCHAINEXT@/$(BUILD_TYPE) D_OBJ= $(ROOT)/objects@TOOLCHAINEXT@/$(BUILD_TYPE)/makedepend D_LIB= $(ROOT)/lib@TOOLCHAINEXT@/$(BUILD_TYPE) + # Common flags XFLAGS= @@ -79,12 +80,13 @@ RMDFLAGS= -rf ######################################################################################### # Targets -MKDEPENDUTIL= $(D_BIN)/makedepend$(E) - MKDEPENDSRC= ./makedepend-1.0.5 VPATH= $(MKDEPENDSRC) -UTILOBJS=\ +BINS=\ + $(D_BIN)/makedepend$(E) + +MAKEDEPENDOBJS=\ $(D_OBJ)/main$(O) \ $(D_OBJ)/cppsetup$(O) \ $(D_OBJ)/ifparser$(O) \ @@ -92,24 +94,27 @@ UTILOBJS=\ $(D_OBJ)/parse$(O) \ $(D_OBJ)/pr$(O) -OBJS= $(UTILOBJS) -TSKS= $(MKDEPENDUTIL) +OBJS= $(MAKEDEPENDOBJS) + ######################################################################################### # Rules .PHONY: build release debug -build: object $(TSKS) +build: object $(BINS) release: $(MAKE) BUILD_TYPE=release $(filter-out release, $(MAKECMDGOALS)) + debug: $(MAKE) BUILD_TYPE=debug $(filter-out debug, $(MAKECMDGOALS)) .PHONY: object object: $(D_OBJ)/.created -$(MKDEPENDUTIL): $(UTILOBJS) - $(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) + +$(D_BIN)/makedepend$(E): MAPFILE=$(basename $@).map +$(D_BIN)/makedepend$(E): $(MAKEDEPENDOBJS) + $(CC) $(LDFLAGS) -o $@ $(MAKEDEPENDOBJS) $(LDLIBS) @LDMAPFILE@ %/.created: -@mkdir $(@D) @@ -124,4 +129,3 @@ $(D_OBJ)/%$(O): %.c #end - diff --git a/gm/.cvsignore b/gm/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/gm/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/gm/Makefile.in b/gm/Makefile.in index 8f8047a5..ff4f8994 100644 --- a/gm/Makefile.in +++ b/gm/Makefile.in @@ -1,9 +1,9 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.22 2020/06/18 20:35:16 cvsuser Exp $ +# $Id: Makefile.in,v 1.23 2022/03/22 08:04:52 cvsuser Exp $ # GRIEF Macro Compiler makefile. # # -# Copyright (c) 1998 - 2020, Adam Young. +# Copyright (c) 1998 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. @@ -44,6 +44,8 @@ XCLEAN= CC= @CC@ RM= @RM@ +PERL= @PERL@ +LIBTOOL= @LIBTOOL@ # Configuration @@ -84,7 +86,7 @@ else CFLAGS+= $(CDEBUG) $(CWARN) $(CINCLUDE) $(CEXTRA) $(XFLAGS) LDFLAGS= $(LDDEBUG) @LDFLAGS@ endif -LDLIBS= -L$(D_LIB) @LIBS@ -lsplay -lmisc -lllist -lmisc @LIBMALLOC@ @EXTRALIBS@ +LDLIBS= -L$(D_LIB) @LDLIBS@ -lsplay -lllist -lmisc @LIBS@ @LIBYACC@ @LIBM@ @LIBMALLOC@ @EXTRALIBS@ YFLAGS= -d ARFLAGS= rcv @@ -117,7 +119,7 @@ debug: $(D_BIN)/$(TARGET): MAPFILE=$(basename $@).map $(D_BIN)/$(TARGET): $(D_OBJ)/.created $(OBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) @LDMAPFILE@ + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) @LDMAPFILE@ $(D_OBJ)/.created: -@mkdir $(D_OBJ) diff --git a/gr/Makefile.in b/gr/Makefile.in index 29fee939..1bd0324e 100644 --- a/gr/Makefile.in +++ b/gr/Makefile.in @@ -1,5 +1,5 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.79 2021/04/18 16:16:57 cvsuser Exp $ +# $Id: Makefile.in,v 1.80 2021/07/05 15:01:26 cvsuser Exp $ # GRIEF editor makefile. # # @@ -190,7 +190,7 @@ LDFLAGS+= -rdynamic endif endif -LDLIBS= -L$(D_LIB) -lbsddb -lbsdfetch -lbsdio -lchartable -lvfs -lsplay -lllist -lmisc -lonigrx -ltre +LDLIBS= -L$(D_LIB) -lbsddb -lbsdfetch -lbsdio -lwidechar -lchartable -lvfs -lsplay -lllist -lmisc -lonigrx -ltre LDLIBS+= @LDLIBS@ @LIBS@ LDLIBS+= @LIBENCA@ @LIBSPELL@ @LIBICU@ @LIBICONV@ @LIBCURL@ @LIBOPENSSL@ @LIBARCHIVE@ @LIBMAGIC@ LDLIBS+= @LIBM@ @EXTRALIBS@ diff --git a/gr/anchor.c b/gr/anchor.c index e4d5ea4d..c4606126 100644 --- a/gr/anchor.c +++ b/gr/anchor.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_anchor_c,"$Id: anchor.c,v 1.45 2020/04/21 00:01:54 cvsuser Exp $") +__CIDENT_RCSID(gr_anchor_c,"$Id: anchor.c,v 1.46 2021/06/10 06:13:01 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: anchor.c,v 1.45 2020/04/21 00:01:54 cvsuser Exp $ +/* $Id: anchor.c,v 1.46 2021/06/10 06:13:01 cvsuser Exp $ * Anchor primitives. * * @@ -638,7 +638,7 @@ do_raise_anchor(void) /* int () */ inq_marked, raise_anchor, drop_anchor */ void -do_mark(void) /* int ([int type = NULL]) */ +do_mark(void) /* int ([int type = NULL]) */ { if (curbp) { @@ -787,13 +787,13 @@ greatest_line(LINENO start_line, LINENO end_line) } while (line <= end_line) { - const LINE_t *lp = linep(line); - + const LINE_t *lp = vm_lock_line(line); if (lp) { const int col = line_column2(lp, line, (int) llength(lp)); if (col > maxcol) { maxcol = col; } + vm_unlock(line); } ++line; } @@ -874,4 +874,5 @@ do_swap_anchor(void) /* int () */ acc_assign_int(ret); } -/*end*/ \ No newline at end of file +/*end*/ + diff --git a/gr/basic.c b/gr/basic.c index 330353fb..b12c13ec 100644 --- a/gr/basic.c +++ b/gr/basic.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_basic_c,"$Id: basic.c,v 1.29 2015/02/11 23:25:12 cvsuser Exp $") +__CIDENT_RCSID(gr_basic_c,"$Id: basic.c,v 1.31 2021/10/18 13:14:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: basic.c,v 1.29 2015/02/11 23:25:12 cvsuser Exp $ +/* $Id: basic.c,v 1.31 2021/10/18 13:14:57 cvsuser Exp $ * Basic cursor movement. * * @@ -800,11 +800,9 @@ do_move_abs(void) /* int ([int line = -1], [int col = -1], [int bu if (bp && bp != curbp) { BUFFER_t *ocurbp = curbp; - curbp = bp; - set_hooked(); + set_curbp(bp); move2((LINENO) line, (LINENO) col, (clip ? MOVE_CLIP : 0)); - curbp = ocurbp; - set_hooked(); + set_curbp(ocurbp); return; } } @@ -889,12 +887,13 @@ move_next_char(int n, int flags_notused) */ LINENO dot = 0, count = 0; - lp = vm_lock_line(line); - dot = (col > 1 ? line_offset2(lp, line, col, LOFFSET_NORMAL) : 0); - if (dot < (LINENO)llength(lp)) { - count = line_sizeregion(lp, col, dot, n, NULL, &col); + if (NULL != (lp = vm_lock_line2(line))) { + dot = (col > 1 ? line_offset_const(lp, line, col, LOFFSET_NORMAL) : 0); + if (dot < (LINENO)llength(lp)) { + count = line_sizeregion(lp, col, dot, n, NULL, &col); + } + vm_unlock(line); } - vm_unlock(line); if ((n -= count) <= 0) { goto done; } @@ -909,28 +908,28 @@ done:; trace_ilog("\tdone (line:%d, col:%d)\n", (int)line, (int)col); * binary/8bit */ const int nl = (BFTST(curbp, BF_BINARY) ? 0 : 1); - int offset, length; - LINE_t *lp; + int dot, length; + const LINE_t *lp; while (n > 0 && line < bottomline) { - lp = vm_lock_line(line); - offset = (col > 1 ? line_offset2(lp, line, col, LOFFSET_NORMAL) : 0); - length = llength(lp); - - if (offset + n <= length) { /* EOL, move to next line */ - if (offset + n == length) { - vm_unlock(line); - ++line; - col = 1; - } else { /* otherwise, position within current line */ - col = line_column2(lp, line, offset + n); - vm_unlock(line); + if (NULL != (lp = vm_lock_line2(line))) { + dot = (col > 1 ? line_offset_const(lp, line, col, LOFFSET_NORMAL) : 0); + length = llength(lp); + + if ((dot + n) <= length) { /* EOL, move to next line */ + if ((dot + n) == length) { + vm_unlock(line); + ++line; + col = 1; + } else { /* otherwise, position within current line */ + col = line_column2(lp, line, dot + n); + vm_unlock(line); + } + break; /* done */ } - break; /* done */ + n -= (length - dot) + nl; /* remove line, plus optional nl */ + vm_unlock(line); } - n -= (length - offset) + nl; /* remove line, plus optional nl */ - - vm_unlock(line); ++line, col = 1; } } @@ -958,13 +957,13 @@ move_prev_char(int n) */ const LINECHAR *cp, *start, *end; int count, column; - LINE_t *lp; while (n > 0 && line >= 1) { /* MCHAR */ /* * setup line references */ - lp = vm_lock_line(line); + const LINE_t *lp = vm_lock_line(line); + cp = start = ltext(lp); end = start + llength(lp); ED_TRACE_LINE2(lp) @@ -1056,7 +1055,7 @@ done:; trace_ilog("==> line:%d, col:%d\n", line, col); line = 1; /* top of buffer */ break; } - dot = llength(linep(line)); /* EOL */ + dot = llength(linep0(line)); /* EOL */ n -= nl; } } @@ -1130,25 +1129,75 @@ mov_gotoline(int n) static void -mov_char(const int n, const int direction) +mov_char(const int cnt, const int direction) { const LINENO cline = *cur_line, ccol = *cur_col; int ncol; - assert(n > 0); + assert(cnt > 0); assert(0 == direction || 1 == direction); if (direction) { /* right */ - if ((ncol = ccol + n) < ccol) { + if ((ccol + cnt) >= LINEMAX) { ncol = LINEMAX; + + } else { + ncol = ccol + cnt; + + if (! BFTST(curbp, BF_BINARY)) { /* MCHAR */ + const LINE_t *lp = vm_lock_line2(cline); + if (lp) { /* TODO: LI_MBSWIDE */ + int pos = 1, width, length; + const LINECHAR *cp = ltext(lp), + *end = cp + llength(lp); + int32_t ch = 0; + + while (pos < ncol && cp < end) { + width = character_decode(pos, cp, end, &length, &ch, NULL); + if ((pos + width) > ncol) { + assert(width > 1); + ncol = pos + width; /* align to next wide-character */ + break; + } + pos += width; + cp += length; + } + vm_unlock(cline); + } + } } + } else { /* left */ - if (n >= ccol) { + if (cnt >= ccol) { ncol = 1; + } else { - ncol = ccol - n; + ncol = ccol - cnt; + + if (! BFTST(curbp, BF_BINARY)) { /* MCHAR */ + const LINE_t *lp = vm_lock_line2(cline); + if (lp) { /* TODO: LI_MBSWIDE */ + int pos = 1, width, length; + const LINECHAR *cp = ltext(lp), + *end = cp + llength(lp); + int32_t ch = 0; + + while (pos < ncol && cp < end) { + width = character_decode(pos, cp, end, &length, &ch, NULL); + if ((pos + width) > ncol) { + assert(width > 1); + ncol = pos; /* align to prev wide-character */ + break; + } + pos += width; + cp += length; + } + vm_unlock(cline); + } + } } } + move(cline, ncol, MOVE_OBEY); } @@ -1157,11 +1206,12 @@ static void mov_line(const int n, const int direction) { const LINENO cline = *cur_line, ccol = *cur_col; - int nline; + int nline, ncol = ccol; assert(n > 0); assert(0 == direction || 1 == direction); + /* reposition line */ if (direction) { /* down */ if ((nline = cline + n) < cline) { nline = LINEMAX; @@ -1173,7 +1223,31 @@ mov_line(const int n, const int direction) nline = cline - n; } } - move(nline, ccol, MOVE_OBEY); + + /* realign column, if within a wide-character */ + if (! BFTST(curbp, BF_BINARY)) { /* MCHAR */ + const LINE_t *lp = vm_lock_line2(nline); + if (lp) { /* TODO: LI_MBSWIDE */ + int pos = 1, width, length; + const LINECHAR *cp = ltext(lp), + *end = cp + llength(lp); + int32_t ch = 0; + + while (pos < ccol && cp < end) { + width = character_decode(pos, cp, end, &length, &ch, NULL); + if ((pos + width) > ccol) { + assert(width > 1); + ncol = pos; /* align wide-character */ + break; + } + pos += width; + cp += length; + } + vm_unlock(nline); + } + } + + move(nline, ncol, MOVE_OBEY); } @@ -1294,4 +1368,5 @@ move(LINENO nline, LINENO ncol, int flags) trace_ilog("\t= [line:%d, col:%d] : %d\n", (int)nline, (int)ncol, ret); return ret; } + /*end*/ diff --git a/gr/buffer.c b/gr/buffer.c index 0fb7373e..7aa07873 100644 --- a/gr/buffer.c +++ b/gr/buffer.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_buffer_c,"$Id: buffer.c,v 1.48 2020/04/21 00:01:55 cvsuser Exp $") +__CIDENT_RCSID(gr_buffer_c,"$Id: buffer.c,v 1.50 2021/10/18 13:16:15 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: buffer.c,v 1.48 2020/04/21 00:01:55 cvsuser Exp $ +/* $Id: buffer.c,v 1.50 2021/10/18 13:16:15 cvsuser Exp $ * Buffer managment. * * @@ -309,9 +309,9 @@ buf_anycb(void) for (bp = buf_first(); bp; bp = buf_next(bp)) { if (buf_isdirty(bp)) { if (BFTST(bp, BF_AUTOWRITE)) { /* unconditonal write */ - curbp = bp; + set_curbp(bp); if (file_write(NULL, 0 /*TODO - WRITE_NOTRIGGER*/) < 0) { - curbp = saved_curbp; + set_curbp(saved_curbp); return TRUE; } } else { @@ -319,7 +319,7 @@ buf_anycb(void) } } } - curbp = saved_curbp; + set_curbp(saved_curbp); if (0 == mods) { return FALSE; @@ -350,15 +350,15 @@ buf_anycb(void) for (bp = buf_first(); bp; bp = buf_next(bp)) { if (buf_isdirty(bp)) { - curbp = bp; + set_curbp(bp); if (file_write(NULL, 0 /*XXX - WRITE_NOTRIGGER*/) < 0) { - curbp = saved_curbp; + set_curbp(saved_curbp); return TRUE; } } } - curbp = saved_curbp; + set_curbp(saved_curbp); return FALSE; } @@ -746,7 +746,7 @@ buf_kill(int bufnum) } } if (NULL == curbp) { - curbp = buf_first(); + curbp = buf_first(); } assert(curbp != bp); set_hooked(); @@ -943,8 +943,7 @@ buf_line_length(const BUFFER_t *bp, /*__CBOOL*/ int marked) woldline = curwp->w_old_line; } - curbp = (BUFFER_t *)bp; - set_hooked(); + set_curbp((BUFFER_t *)bp); if (! marked || FALSE == anchor_get(NULL, NULL, &a)) { a.start_line = 1; a.end_line = curbp->b_numlines; /* NEWLINE */ @@ -952,7 +951,7 @@ buf_line_length(const BUFFER_t *bp, /*__CBOOL*/ int marked) for (line = a.start_line; line <= a.end_line; ++line) { if ((col = line_column_eol(line)) > maxcol) { - maxlinep = vm_lock_line(line); + maxlinep = vm_lock_line2(line); maxcol = col; } } @@ -962,8 +961,7 @@ buf_line_length(const BUFFER_t *bp, /*__CBOOL*/ int marked) curbp->b_maxlength = maxcol; } - curbp = saved_curbp; - set_hooked(); + set_curbp(saved_curbp); /* Make sure buffer is repositioned where it was. */ if (curwp) { @@ -990,9 +988,7 @@ buf_change_window(WINDOW_t *wp) set_buffer_parms(curbp, curwp); curwp->w_status |= WFHARD; wp->w_status |= WFHARD; - curwp = wp; - curbp = curwp->w_bufp; - set_hooked(); + set_curwpbp(wp, wp->w_bufp); } diff --git a/gr/builtin.c b/gr/builtin.c index 778f4843..037d1232 100644 --- a/gr/builtin.c +++ b/gr/builtin.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_builtin_c,"$Id: builtin.c,v 1.59 2020/06/03 14:12:36 cvsuser Exp $") +__CIDENT_RCSID(gr_builtin_c,"$Id: builtin.c,v 1.63 2021/10/18 13:21:23 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: builtin.c,v 1.59 2020/06/03 14:12:36 cvsuser Exp $ +/* $Id: builtin.c,v 1.63 2021/10/18 13:21:23 cvsuser Exp $ * Builtin expresssion evaluation. * * @@ -60,7 +60,7 @@ static void execute_builtin(const BUILTIN *bp, const LIST *lp); static void __CINLINE arg_error(const BUILTIN *bp, enum ARGERRORS msg, struct SAVED *saved_str, struct SAVED *ssp, int arg); static void __CINLINE arg_free(struct SAVED *saved_str, struct SAVED *ssp); -static int arg_expand(const BUILTIN *bp, int varargs, int largc, +static int arg_expand(const BUILTIN *bp, int varargs, int largc, LISTV **largv, LISTV **lap, struct SAVED **lsaved, struct SAVED **ssp); static int execute_expr2(const argtype_t arg, const LIST *argp, LISTV *lap); @@ -108,7 +108,7 @@ iscsym(int c) /*TODO: compat_iscsym()*/ /* * execute_str --- - * Take a string, possiblity entered via the the command prompt, taking the + * Take a string, possiblity entered via the the command prompt, taking the * form , parse and then execute the specified macro. * * Arguments can be either int, float otherwise treated as a string. @@ -526,7 +526,7 @@ execute_xmacro(register const LIST *lp, const LIST *lp_argv) ++mptr->m_hits; #endif - if (bp) bp->b_macro = mptr; /* pop chain */ + if (bp) bp->b_macro = mptr; /* pop chain */ mptr->m_ftime = FALSE; /* first time */ x_msglevel = omsglevel; /* restore message level */ @@ -648,7 +648,7 @@ execute_builtin(const BUILTIN *bp, const LIST *lp) case F_NULL: break; case EEXECUTE: /* ... */ - goto execute; + goto execute; case EERROR: /* * One last chance -- @@ -676,7 +676,7 @@ execute_builtin(const BUILTIN *bp, const LIST *lp) } /* - * Move onto the next argument descriptor. + * Move onto the next argument descriptor. * Note: Don't move if an indefinite list and last descriptor; as it repeats. */ if (! varargs || argtypes[1] /*not-last*/) { @@ -738,7 +738,7 @@ execute_builtin(const BUILTIN *bp, const LIST *lp) } else { assert(0 == argtype && 0 == *argtypes); - assert(op == *lp); + assert((NULL == lp && op == F_HALT) || op == *lp); if (F_HALT != op) { /* unexpected argments */ arg_error(bp, ERR_TOOMANY, lsaved, ssp, 0); @@ -866,12 +866,12 @@ arg_expand(const BUILTIN *bp, int varargs, int largc, LISTV **largv, LISTV **lap const size_t lapi = (size_t)(*lap - *largv); const size_t sspi = (size_t)(*ssp - *lsaved); - struct SAVED *nlsaved = NULL; + struct SAVED *nlsaved = NULL; LISTV *nlargv; int nvarargs; /* - * Varargs available ? + * Varargs available ? */ assert(varargs >= -1); if (! varargs) { @@ -956,8 +956,8 @@ static const int state_tbl[][12] = { /*ls-i*/ {-1, -1, F_INT, -1, F_STR, F_LIT, F_LIST, -1, -1, F_RSTR, F_RLIST, -1 }, /*lsf-*/ {-1, -1, -1, F_FLOAT, F_STR, F_LIT, F_LIST, -1, -1, F_RSTR, F_RLIST, -1 }, /*lsfi*/ {-1, -1, F_INT, F_FLOAT, F_STR, F_LIT, F_LIST, -1, F_NULL, F_RSTR, F_RLIST, -1 }, - }; - + }; + static const int state2_tbl[][11] = { /* * Symbol type conversions. @@ -1081,6 +1081,31 @@ check_hooked(void) #endif //!NDEBUG +void +set_curbp(BUFFER_t *bp) +{ + curbp = bp; + set_hooked(); +} + + +void +set_curwp(WINDOW_t *wp) +{ + curwp = wp; + set_hooked(); +} + + +void +set_curwpbp(WINDOW_t *wp, BUFFER_t *bp) +{ + curwp = wp; + curbp = bp; + set_hooked(); +} + + void set_hooked(void) { @@ -1114,7 +1139,7 @@ set_hooked(void) if (curbp != currentbp) { trace_ilog("set_hooked(line:%d,col:%d,num:%d,fname:\"%s\")\n", \ - *cur_line, *cur_col, (curbp ? curbp->b_bufnum : -1), (curbp ? curbp->b_fname : "")); + *cur_line, *cur_col, (curbp ? curbp->b_bufnum : -1), (curbp ? c_string(curbp->b_fname) : "")); currentbp = curbp; } diff --git a/gr/builtin.h b/gr/builtin.h index 415aa516..8df17588 100644 --- a/gr/builtin.h +++ b/gr/builtin.h @@ -1,11 +1,11 @@ #ifndef GR_BUILTIN_H_INCLUDED #define GR_BUILTIN_H_INCLUDED #include -__CIDENT_RCSID(gr_builtin_h,"$Id: builtin.h,v 1.25 2020/04/21 00:01:55 cvsuser Exp $") +__CIDENT_RCSID(gr_builtin_h,"$Id: builtin.h,v 1.26 2021/10/18 13:20:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: builtin.h,v 1.25 2020/04/21 00:01:55 cvsuser Exp $ +/* $Id: builtin.h,v 1.26 2021/10/18 13:20:42 cvsuser Exp $ * Builtin primitive table. * * @@ -34,6 +34,7 @@ extern void execute_event_ctrlc(void); extern void execute_event_usr1(void); extern void execute_event_usr2(void); extern const char * execute_name(void); + extern void set_hooked(void); extern LINENO *cur_line, *cur_col; @@ -77,4 +78,4 @@ extern void *x_returns; __CEND_DECLS -#endif /*GR_BUILTIN_H_INCLUDED*/ \ No newline at end of file +#endif /*GR_BUILTIN_H_INCLUDED*/ diff --git a/gr/cmain.c b/gr/cmain.c index 2c33bc99..3942dbb7 100644 --- a/gr/cmain.c +++ b/gr/cmain.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_cmain_c,"$Id: cmain.c,v 1.36 2020/05/03 21:09:41 cvsuser Exp $") +__CIDENT_RCSID(gr_cmain_c,"$Id: cmain.c,v 1.41 2021/10/24 16:46:45 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: cmain.c,v 1.36 2020/05/03 21:09:41 cvsuser Exp $ +/* $Id: cmain.c,v 1.41 2021/10/24 16:46:45 cvsuser Exp $ * Main body, startup and command-line processing. * * @@ -145,6 +145,9 @@ static struct argoption options[] = { { "encoding", arg_required, NULL, 317, "Default file encoding", "" }, + { "ucsver", arg_required, NULL, 320, "Unicode version; wcwidth support", + "" }, + { "nograph", arg_none, NULL, 5, "Disable use of graphic characters" }, { "nounicode", arg_none, NULL, 307, "Disable use of UNICODE graphic characters" }, @@ -327,6 +330,8 @@ int x_bftype_default = BFTYP_UNDEFINED; /* Default file encoding. */ const char * x_encoding_default = NULL; +const char * x_unicode_version = NULL; + uint32_t xf_test = 0; /* BITMAP enables test code --- internal use only --- */ int x_mflag = FALSE; /* TRUE whilst processing -m strings to avoid messages. */ @@ -354,12 +359,14 @@ static const char * m_strings[MAX_M+1]; /* Array of pointer to -m string BUFFER_t * curbp = NULL; /* Current buffer. */ WINDOW_t * curwp = NULL; /* Current window. */ -static void path_cat(const char *path, const char *sub, char *buf); +static int path_cat(const char *path, const char *sub, char *buf); static char * path_cook(const char *name); static void argv_init(int *argcp, char **argv); static int argv_process(int doerr, int argc, const char **argv); +static void unicode_init(void); + static void env_setup(void); static __CINLINE int env_iswhite(const char ch); static int env_define(const char *cp); @@ -450,12 +457,16 @@ cmain(int argc, char **argv) // textdomain(PACKAGE); #endif #endif -#if defined(_MSC_VER) +#if defined(HAVE__TZSET) _tzset(); #else tzset(); /* localtime requirement */ #endif +#if defined(_WIN32) + w32_utf8filenames_enable(); +#endif + if (argc < 0) cpp_linkage(""); x_umask = (mode_t)fileio_umask(0); /* our umask */ @@ -475,6 +486,7 @@ cmain(int argc, char **argv) search_init(); /* regular expression engine */ mchar_info_init(); mchar_guess_init(); + mchar_iconv_init(); playback_init(); bookmark_init(); position_init(); @@ -508,6 +520,7 @@ cmain(int argc, char **argv) if (xf_spell) { spell_init(); } + unicode_init(); vtready(); if (xf_mouse) { if (mouse_init("")) { /* mouse interface */ @@ -572,8 +585,8 @@ cmain(int argc, char **argv) firstbp = curbp; } } - buf_show(curbp = firstbp, curwp); - set_hooked(); + buf_show(firstbp, curwp); + set_curbp(firstbp); } else { /* load default quietly */ const char *grfile = ggetenv("GRFILE"); @@ -635,7 +648,7 @@ panic(const char *fmt, ...) } -static void +static int path_cat(const char *path, const char *sub, char *buf) { char t_path[1024] = {0}, t_realpath[1024] = {0}; @@ -650,10 +663,13 @@ path_cat(const char *path, const char *sub, char *buf) } if (NULL == sub || - 0 == fileio_access(path, 0)) { /* push if it exists */ + 0 == sys_access(path, 0)) { /* push if it exists */ strcat(buf, path); strcat(buf, sys_pathdelimiter()); + return 1; } + + return 0; } @@ -1268,6 +1284,10 @@ argv_process(int doerr, int argc, const char **argv) x_encoding_default = args.val; break; + case 320: /* --ucsver= */ + x_unicode_version = args.val; + break; + case 308: /* --term= */ gputenv2("TERM", args.val); break; @@ -1280,7 +1300,7 @@ argv_process(int doerr, int argc, const char **argv) gputenv2("GRHELP", args.val); break; - case 319: /* --grprofile= */ + case 319: /* --grprofile= */ gputenv2("GRPROFILE", args.val); break; @@ -1338,6 +1358,16 @@ argv_process(int doerr, int argc, const char **argv) } +static void +unicode_init(void) +{ + if (NULL == x_unicode_version) + x_unicode_version = ggetenv("UNICODE_VERSION"); + if (x_unicode_version) + ucs_width_set(x_unicode_version); +} + + static void env_setup(void) { @@ -1368,7 +1398,9 @@ env_setup(void) sprintf(buf, "GRPATH="); if (binpath[0]) { /* rel to binary image */ - path_cat(binpath, "../macros", buf); + if (0 == path_cat(binpath, "../macros", buf)) { + path_cat(binpath, "../../macros", buf); + } #if defined(__MINGW32__) path_cat(binpath, "../lib/grief/macros", buf); #endif @@ -1388,7 +1420,9 @@ env_setup(void) sprintf(buf, "GRHELP="); if (binpath[0]) { /* rel to binary image */ - path_cat(binpath, "../help", buf); + if (0 == path_cat(binpath, "../help", buf)) { + path_cat(binpath, "../../help", buf); + } #if defined(__MINGW32__) path_cat(binpath, "../lib/grief/help", buf); #endif @@ -1641,7 +1675,6 @@ editor_setup(void) } k_init(bp); - curbp = bp; /* current ones. */ bp->b_nwnd = 1; /* displayed. */ bp->b_keyboard = NULL; @@ -1654,17 +1687,13 @@ editor_setup(void) wp->w_type = W_TILED; wp->w_tab = 0; /* TABLINE */ window_append(wp); - curwp = wp; - - cur_line = &bp->b_line; - cur_col = &bp->b_col; wp->w_w = (uint16_t)(ttcols() - 2); /* 0..78 */ wp->w_h = (uint16_t)(ttrows() - 3); wp->w_status = WFHARD; window_title(wp, "*scratch*", ""); - set_hooked(); + set_curwpbp(wp, bp); } @@ -1778,4 +1807,4 @@ usage(int what) #undef HINDENT } -/*end*/ \ No newline at end of file +/*end*/ diff --git a/gr/cmap.c b/gr/cmap.c index 1bef71c3..0f0001f0 100644 --- a/gr/cmap.c +++ b/gr/cmap.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_cmap_c,"$Id: cmap.c,v 1.32 2021/04/14 14:09:54 cvsuser Exp $") +__CIDENT_RCSID(gr_cmap_c,"$Id: cmap.c,v 1.34 2021/07/18 23:03:18 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: cmap.c,v 1.32 2021/04/14 14:09:54 cvsuser Exp $ +/* $Id: cmap.c,v 1.34 2021/07/18 23:03:18 cvsuser Exp $ * Character map management/primitives. * * @@ -260,7 +260,7 @@ cmap_build(cmap_t *cmap) cmapchr_str(mc, (const char *)(cp - 2)); } /* printable non-ascii/C1 characters */ - } else if (isutf8 || (is8bit && i < 0xff)) { + } else if (isutf8 || (is8bit && i <= 0xff)) { *cp++ = (unsigned char)i; *cp++ = 0; cmapchr_str(mc, (const char *)(cp - 2)); @@ -1250,4 +1250,5 @@ do_set_char_map(void) /* int (int mapid|string name, list definition) } } #endif + /*eof*/ diff --git a/gr/debug.c b/gr/debug.c index 5b13fce1..b1a6e2e6 100644 --- a/gr/debug.c +++ b/gr/debug.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_debug_c,"$Id: debug.c,v 1.35 2020/04/21 00:01:55 cvsuser Exp $") +__CIDENT_RCSID(gr_debug_c,"$Id: debug.c,v 1.36 2021/07/04 08:39:16 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: debug.c,v 1.35 2020/04/21 00:01:55 cvsuser Exp $ +/* $Id: debug.c,v 1.36 2021/07/04 08:39:16 cvsuser Exp $ * internal debug/diagnositics. * * @@ -230,7 +230,7 @@ trace_lines(void) for (bp = buf_first(); bp; bp = buf_next((BUFFER_t *)bp)) { register const LINE_t *lp; - trace_log("Buffer %s:\n", bp->b_fname); + trace_log("Buffer %s:\n", c_string(bp->b_fname)); TAILQ_FOREACH(lp, &bp->b_lineq, l_node) { sxprintf(buf, sizeof(buf), "\tLine %3u: old=%u, used=%2d, size=%2d, fl=0x%x, chunk=%p\n", (unsigned)++lineno, (unsigned)lp->l_oldlineno, (int)lp->l_used, (int)lp->l_size, @@ -459,7 +459,7 @@ trace_refs(void) const BUILTIN *bp, *endbp = builtin + builtin_count; for (bp = builtin; bp < endbp; ++bp) { - trace_log("%5u %5u %s\n", bp->b_reference, bp->b_replacement, bp->b_name); + trace_log("%5u %5u %s\n", bp->b_reference, bp->b_replacement, c_string(bp->b_name)); #if defined(DO_PROFILE) #endif } @@ -606,4 +606,4 @@ trace_string(const char *str) trace_log("\""); } -/*end*/ \ No newline at end of file +/*end*/ diff --git a/gr/dialog.c b/gr/dialog.c index 252d54aa..2b8031f4 100644 --- a/gr/dialog.c +++ b/gr/dialog.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_dialog_c,"$Id: dialog.c,v 1.29 2019/01/26 22:27:08 cvsuser Exp $") +__CIDENT_RCSID(gr_dialog_c,"$Id: dialog.c,v 1.30 2021/07/18 23:03:18 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: dialog.c,v 1.29 2019/01/26 22:27:08 cvsuser Exp $ +/* $Id: dialog.c,v 1.30 2021/07/18 23:03:18 cvsuser Exp $ * Dialog manager. * * @@ -237,7 +237,7 @@ dialog_shutdown(void) *<> Macro: dialog_create - Build a dialog resource. - int + int dialog_create(list decl) Macro Description: @@ -296,7 +296,7 @@ dialog_shutdown(void) ! DLGA_TOOLTIP String Tooltip topic. ! DLGA_X Int Horizontal position. - ! DLGA_Y Int Vertical position. + ! DLGA_Y Int Vertical position. ! DLGA_COLS Int Width in columns. ! DLGA_ROWS Int Height in rows. @@ -328,14 +328,14 @@ dialog_shutdown(void) ! DLGA_TEXT_ONLY n/a ! DLGA_GUI_ONLY n/a ! DLGA_ACCELERATOR String - ! DLGA_HOTKEY Integer + ! DLGA_HOTKEY Integer ! DLGA_GREYED n/a ! DLGA_ACTIVE n/a - ! DLGA_SENSITIVE Integer - ! DLGA_PADX Integer - ! DLGA_PADY Integer + ! DLGA_SENSITIVE Integer + ! DLGA_PADX Integer + ! DLGA_PADY Integer - ! DLGA_ORIENTATION Integer + ! DLGA_ORIENTATION Integer ! DLGA_HIDDEN n/a ! DLGA_VISIBLE n/a ! DLGA_KEYDOWN Boolean @@ -345,9 +345,9 @@ dialog_shutdown(void) ! DLCA_USERDATA Int ! DLGA_EDEDITABLE Boolean - ! DLGA_EDMAXLENGTH Integer + ! DLGA_EDMAXLENGTH Integer ! DLGA_EDVISIBLITY Boolean - ! DLGA_EDPOSITION Integer + ! DLGA_EDPOSITION Integer ! DLGA_EDPLACEHOLDER String ! DLGA_LBCOUNT Integer @@ -358,20 +358,20 @@ dialog_shutdown(void) ! DLGA_LBDUPLICATES Integer ! DLGA_LBCLEAR n/a - ! DLGA_LBCURSOR Integer - ! DLGA_LBACTIVE Integer - ! DLGA_LBDISPLAYTEXT Integer - ! DLGA_LBDISPLAYTEXTLEN Integer - ! DLGA_LBTEXT Integer - ! DLGA_LBTEXTLEN Integer + ! DLGA_LBCURSOR Integer + ! DLGA_LBACTIVE Integer + ! DLGA_LBDISPLAYTEXT Integer + ! DLGA_LBDISPLAYTEXTLEN Integer + ! DLGA_LBTEXT Integer + ! DLGA_LBTEXTLEN Integer ! DLGA_LBPAGEMODE Boolean ! DLGA_LBINDEXMODE Boolean - + ! DLGA_CBEDITABLE Boolean - ! DLGA_CBRELAXMODE Integer - ! DLGA_CBAUTOCOMPLETEMODE Integer - ! DLGA_CBPOPUPMODE Integer - ! DLGA_CBPOPUPSTATE Integer + ! DLGA_CBRELAXMODE Integer + ! DLGA_CBAUTOCOMPLETEMODE Integer + ! DLGA_CBPOPUPMODE Integer + ! DLGA_CBPOPUPSTATE Integer ! DLGA_GAUGEMIN Int|Str ! DLGA_GAUGEMAX Int|Str @@ -683,7 +683,7 @@ do_dialog_run(void) /* int (int dialog, [string args]) */ current dialog is referenced. Macro Returns: - The 'dialog_delete()' primitive return non-zero on success, + The 'dialog_delete()' primitive return non-zero on success, otherwise zero on error. Macro Portability: @@ -732,7 +732,7 @@ do_dialog_delete(void) /* int (int dialog) */ The 'dialog_exit()' primitive exits the current dialog. Macro Parameters: - retval - Integer return value, returned to the + retval - Integer return value, returned to the original caller. dialog - Optional dialog instance handle, if omitted the @@ -834,7 +834,7 @@ inq_dialog(void) /* int () */ mutliple elements. Macro Returns: - The 'widget_set()' primitive returns the assigned value, + The 'widget_set()' primitive returns the assigned value, otherwise NULL on error. Macro Portability: @@ -939,7 +939,7 @@ do_widget_set(void) /* ([int dialog], [int name|string name], declar multiple elements. Macro Returns: - The 'widget_get()' primitive returns the assigned value, + The 'widget_get()' primitive returns the assigned value, otherwise NULL on error. Macro Portability: diff --git a/gr/dialog_tty.c b/gr/dialog_tty.c index 1d811ce2..177ca3ca 100644 --- a/gr/dialog_tty.c +++ b/gr/dialog_tty.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_dialog_tty_c,"$Id: dialog_tty.c,v 1.26 2020/04/21 00:01:55 cvsuser Exp $") +__CIDENT_RCSID(gr_dialog_tty_c,"$Id: dialog_tty.c,v 1.27 2021/10/18 13:14:34 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: dialog_tty.c,v 1.26 2020/04/21 00:01:55 cvsuser Exp $ +/* $Id: dialog_tty.c,v 1.27 2021/10/18 13:14:34 cvsuser Exp $ * Dialog manager, TTY interface. * * @@ -391,9 +391,7 @@ dlg_close(DIALOG_t *d) d->d_ucontrol = NULL; c->cx_current = NULL; - curbp = c->cx_obp; /* restore */ - curwp = c->cx_owp; - set_hooked(); + set_curwpbp(c->cx_owp, c->cx_obp); /* restore */ ttyframe_close(&c->cx_popup, TRUE); ttyframe_close(&c->cx_base, TRUE); @@ -431,8 +429,7 @@ ttyframe_create(TTYFrame_t *frame, int clear, const char *title, int x, int y, i chk_free(cp); } - curwp = NULL; curbp = bp; - set_hooked(); + set_curwpbp(NULL, bp); bp->b_termtype = LTERM_UNIX; /* UNIX style line feeds */ bp->b_imode = TRUE; /* localised insert-mode */ @@ -454,8 +451,7 @@ ttyframe_create(TTYFrame_t *frame, int clear, const char *title, int x, int y, i * Create the window, */ if (-1 == window_create(W_POPUP, "", x, y, cols, rows)) { - curwp = owp; curbp = obp; - set_hooked(); + set_curwpbp(owp, obp); buf_kill(bp->b_bufnum); return FALSE; } @@ -467,8 +463,7 @@ ttyframe_create(TTYFrame_t *frame, int clear, const char *title, int x, int y, i WFSET(wp, WF_DIALOG); attach_buffer(wp, bp); wp->w_ctrl_state = 0; /* disable scrollbars etc */ - curwp = owp; curbp = obp; - set_hooked(); + set_curwpbp(owp, obp); frame->f_wp = wp; frame->f_bp = bp; return TRUE; @@ -480,9 +475,7 @@ ttyframe_focus(const TTYFrame_t *frame) { if (frame && frame->f_wp && frame->f_bp) { if (curwp != frame->f_wp || curbp != frame->f_bp) { - curwp = frame->f_wp; - curbp = frame->f_bp; - set_hooked(); + set_curwpbp(frame->f_wp, frame->f_bp); } return TRUE; } @@ -534,9 +527,7 @@ dlg_controller(DIALOG_t *d, unsigned op, int p1, ...) ttyframe_focus(&c->cx_base); dlg_update(d); - curbp = savbp; - curwp = savwp; - set_hooked(); + set_curwpbp(savwp, savbp); } break; diff --git a/gr/display.c b/gr/display.c index a1b47102..295c35ee 100644 --- a/gr/display.c +++ b/gr/display.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_display_c,"$Id: display.c,v 1.76 2020/04/13 14:29:18 cvsuser Exp $") +__CIDENT_RCSID(gr_display_c,"$Id: display.c,v 1.81 2021/10/18 13:22:21 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: display.c,v 1.76 2020/04/13 14:29:18 cvsuser Exp $ +/* $Id: display.c,v 1.81 2021/10/18 13:22:21 cvsuser Exp $ * High level display interface. * * @@ -1037,16 +1037,29 @@ vtmove(int row, int col) * col - Cursor position on completion. * * Returns: - * Resulting cursor location. + * Resulting cursor location, accounting for wide-characters, + * otherwise -1 if off screen. */ int vtpute(vbyte_t ch, int col) { - if (vscreen) - if (col >= 0 && col < ttcols()) { + if (vscreen) { + WChar_t wch = VBYTE_CHAR_GET(ch); + const int width = (wch > 0xff ? Wcwidth(wch) : 1); + + if (col >= 0 && (col + width) <= ttcols()) { vcell_set(vscreen[ttrows() - 1] + col, ch); + if (width >= 1) { + ++col; + if (width > 1) { + vcell_set(vscreen[ttrows() - 1] + col, CH_PADDING); + ++col; + } + } + return col; } - return col + 1; + } + return -1; //off-screen } @@ -2428,10 +2441,9 @@ winputch(WINDOW_t *wp, const vbyte_t ch, const vbyte_t attr, int rclip) } } else { /* MCHAR??? */ - int wcwidth = mchar_ucs_width(ch, 1); - + int wcwidth = Wcwidth(ch); while (wcwidth-- > 0) { - winputm('?' | attr); /* ? or ?? */ + winputm('?' | attr); /* ? or ?? */ } } @@ -2589,8 +2601,9 @@ draw_window(WINDOW_t *wp, int top, LINENO line, int end, const int bottom, int a const int iscurrent = (curwp == wp ? TRUE : FALSE); const int ledge = win_ledge(wp); const int redge = win_redge(wp); - const int syntax = (BFTST(wp->w_bufp, BF_SYNTAX) && wp->w_bufp->b_syntax); - + const int syntax = (bp && BFTST(bp, BF_SYNTAX) && bp->b_syntax && //MCHAR??? + bp->b_type != BFTYP_UTF16 && bp->b_type != BFTYP_UTF32); + /* syntax parser not wchar safe/FIXME */ const vbyte_t nattr = normalcolor(wp); const vbyte_t lattr = (syntax ? VBYTE_ATTR(ATTR_COLUMN_LINENO) : nattr); const vbyte_t sattr = (syntax ? VBYTE_ATTR(ATTR_COLUMN_STATUS) : nattr); @@ -2609,7 +2622,7 @@ draw_window(WINDOW_t *wp, int top, LINENO line, int end, const int bottom, int a wp->w_disp_anchor = NULL; anchor.type = MK_NONE; - if (wp->w_bufp) { + if (bp) { if (iscurrent || WFTST(wp, WF_SHOWANCHOR)) { if (anchor_get(wp, NULL, &anchor)) { wp->w_disp_anchor = &anchor; /* active anchor */ @@ -2691,12 +2704,11 @@ draw_window(WINDOW_t *wp, int top, LINENO line, int end, const int bottom, int a * Body */ saved_wp = curwp; /* requirement of lower level functionality (draw_line). */ - curwp = wp; saved_bp = curbp; - curbp = bp; + set_curwpbp(wp, bp); for (; top <= end; ++top, ++line) { - LINE_t *lp = vm_lock_line(line); + const LINE_t *lp = vm_lock_line2(line); if (VTDRAW_DIRTY & actions) { /* skip clean/blank lines */ if (NULL == lp || 0 == lisdirty(lp)) { @@ -2863,9 +2875,7 @@ draw_window(WINDOW_t *wp, int top, LINENO line, int end, const int bottom, int a } wp->w_disp_anchor = NULL; - curwp = saved_wp; /* restore state */ - curbp = saved_bp; - set_hooked(); + set_curwpbp(saved_wp, saved_bp); /* restore state */ } @@ -2905,9 +2915,10 @@ draw_title(const WINDOW_t *wp, const int top, const int line) const unsigned char *title = (unsigned char *)(!top ? wp->w_message : (bp && BF2TST(bp, BF2_TITLE_FULL) && bp->b_fname[0] ? bp->b_fname : wp->w_title)); + const unsigned char *titleend = (title ? title + strlen((const char *)title) : 0); const char *suffix = NULL; const vbyte_t col = framecolor(wp); - int titlelen = (title && *title ? (int)strlen((const char *) title) : 0); + int titlelen = (title && *title ? (int)utf8_width(title, titleend) : 0); /*MCHAR*/ int left = 0; int right = 0; char numbuf[20]; @@ -2915,7 +2926,7 @@ draw_title(const WINDOW_t *wp, const int top, const int line) /* read-only/modified suffix */ if (titlelen > 0) { - if (bp) { /* MCHAR??? */ + if (bp) { if (BFTST(bp, BF_RDONLY)) { if ((DC_ROSUFFIX & x_display_ctrl) || BF2TST(bp, BF2_SUFFIX_RO)) { suffix = " (ro)"; @@ -2998,15 +3009,31 @@ draw_title(const WINDOW_t *wp, const int top, const int line) int title_col = col; if (WFTST(wp, WF_SELECTED) || (wp->w_status & WFTOP)) { - title_col = titlecolor(wp); /* 'selected' window */ + title_col = titlecolor(wp); /* 'selected' window */ } ch = col | ' '; vtputb(ch); ((WINDOW_t *)wp)->w_disp_cmap = x_base_cmap; - while (*title && titlelen-- > 0) { - vtputb(*title++ | title_col); + +// while (*title && titlelen-- > 0) { +// vtputb(*title++ | title_col); +// } + while (*title && titlelen > 0) { /* MCHAR */ + const unsigned char *cend; + int cwidth; + int32_t wch; + + if ((cend = charset_utf8_decode_safe(title, titleend, &wch)) > title && + (cwidth = Wcwidth(wch)) >= 0) { + vtputb(wch | title_col); + titlelen -= cwidth; + title = cend; + continue; //next + } + break; //error } + if (titlelen > 0 && suffix) { while (*suffix && titlelen-- > 0) { vtputb(*suffix++ | title_col); @@ -3390,7 +3417,7 @@ draw_line(const vbyte_t nattr, const vbyte_t wattr, wch = 0; if ((wcp = mchar_decode_safe(iconv, ocp, end, &wch)) > ocp && - (wwidth = mchar_ucs_width(wch, 1)) >= 0) { + (wwidth = Wcwidth(wch)) >= 0) { /* * apply cursor rules and increment buffers */ @@ -4122,4 +4149,5 @@ do_screen_dump(void) /* int ([string filename], [string encoding]) */ acc_assign_int(0); fclose(fp); } + /*end*/ diff --git a/gr/echo.c b/gr/echo.c index 29751683..56d94cb7 100644 --- a/gr/echo.c +++ b/gr/echo.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_echo_c,"$Id: echo.c,v 1.63 2015/02/19 00:16:51 ayoung Exp $") +__CIDENT_RCSID(gr_echo_c,"$Id: echo.c,v 1.72 2021/08/01 14:34:04 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: echo.c,v 1.63 2015/02/19 00:16:51 ayoung Exp $ +/* $Id: echo.c,v 1.72 2021/08/01 14:34:04 cvsuser Exp $ * Command/echo line implementation/interface. * * @@ -40,6 +40,7 @@ __CIDENT_RCSID(gr_echo_c,"$Id: echo.c,v 1.63 2015/02/19 00:16:51 ayoung Exp $") #include "kill.h" #include "m_time.h" #include "macros.h" /* macro_lookup */ +#include "mchar.h" #include "main.h" #include "map.h" #include "playback.h" @@ -68,7 +69,9 @@ struct _estate { int vf_status; int vf_values[4]; int position; - char buffer[200]; +#define buffer_end(__state) \ + (__state->buffer + (_countof(__state->buffer) - 1 /*nul*/)) + WChar_t buffer[200]; MAGIC_t magic2; }; @@ -78,31 +81,33 @@ static int ereplyask(const char *prompt, const char *defstr, char * static int elineedit(const char *prompt, const char *defstr, char *buf, int nbuf, int one); static void eprompt(int force, int buflen); static void edisplay(void); -static int eposition(const char *buf, int bpos, int left); + +static int eposition(const WChar_t *buf, int bpos, int bleft); static int emaxcols(void); static int eputc(int col, int c, vbyte_t attr); -static int eputs(int col, vbyte_t *buf, int len, vbyte_t attr); - -static int estrlen(const char *str, int hilite); -static int eprintable(const vbyte_t ch, vbyte_t *buf); - -static void ef_format(const char *fmt, char *cp, struct _estate *s); -static char * ef_space(char *cp); -static char * ef_integer(char *cp, int ivalue, int width); -static char * ef_buffer(char *cp, const char *buf); -static char * ef_ovmode(char *cp, const struct _estate *s); -static char * ef_charvalue(char *cp, struct _estate *s); -static char * ef_virtual(char *cp, struct _estate *s); -static char * ef_imode(char *cp, const struct _estate *s); -static char * ef_line(char *cp, const struct _estate *s); -static char * ef_numlines(char *cp, const struct _estate *s); -static char * ef_filemode(char *cp, const struct _estate *s); -static char * ef_col(char *cp, const struct _estate *s); -static char * ef_percent(char *cp, const struct _estate *s); -static char * ef_time(char *cp, const struct _estate *s, int hour24); -static char * ef_date(char *cp, const struct _estate *s, int format); -static char * ef_version(char *cp, const struct _estate *s); +static int eputs(int col, const vbyte_t *buf, int len, vbyte_t attr); + +static int eprintlen(const WChar_t *str); +static int eprintable(const vbyte_t ch, vbyte_t *buf, int *buflen); + +static void ef_format(const char *fmt, struct _estate *s); +static WChar_t * ef_space(WChar_t *cp, const struct _estate *s); +static WChar_t * ef_buffer(WChar_t *cp, const char *buf, const struct _estate *s); +static WChar_t * ef_utf8(WChar_t *cp, const char *buf, const struct _estate *s); +static WChar_t * ef_integer(WChar_t *cp, int ivalue, int width, const struct _estate *s); +static WChar_t * ef_ovmode(WChar_t *cp, const struct _estate *s); +static WChar_t * ef_charvalue(WChar_t *cp, struct _estate *s); +static WChar_t * ef_virtual(WChar_t *cp, struct _estate *s); +static WChar_t * ef_imode(WChar_t *cp, const struct _estate *s); +static WChar_t * ef_line(WChar_t *cp, const struct _estate *s); +static WChar_t * ef_numlines(WChar_t *cp, const struct _estate *s); +static WChar_t * ef_filemode(WChar_t *cp, const struct _estate *s); +static WChar_t * ef_col(WChar_t *cp, const struct _estate *s); +static WChar_t * ef_percent(WChar_t *cp, const struct _estate *s); +static WChar_t * ef_time(WChar_t *cp, int hour24, const struct _estate *s); +static WChar_t * ef_date(WChar_t *cp, int format, const struct _estate *s); +static WChar_t * ef_version(WChar_t *cp, const struct _estate *s); int xf_echoflags = /* echo line status */ E_CHARVALUE | E_VIRTUAL | E_LINE | E_COL | E_CURSOR | E_REMEMBER | E_TIME; @@ -122,16 +127,19 @@ static struct _estate lc_state; /* current echo_line state */ static vbyte_t echo_color = ATTR_MESSAGE; static vbyte_t echo_standout = 0; -static unsigned char echo_line[EBUFSIZ*2]; /* echo line buffer */ -static unsigned char echo_attr[EBUFSIZ+2]; /* character attributes 0=normal,1=standout */ +#define ECHOLINESZ (MAX_CMDLINE + EBUFSIZ) + +static WChar_t wecho_line[ECHOLINESZ]; /* echo line buffer */ +static unsigned char echo_attr[ECHOLINESZ]; /* character attributes 0=normal,1=standout */ -static int echo_prompt; /* length of prompt, in characters */ +static int echo_prompt_len; /* length of prompt in characters */ +static int echo_prompt_width; /* display width of prompt, in characters */ static int echo_default; /* length of default abs() +active,-inactive */ static int echo_offset; /* displayed offset within echo line when prompt > vtcols */ -static char * echo_cmdline; /* pointer to string just typed in by user (see inq_cmd_line) */ +static const char * echo_cmdline; /* pointer to string just typed in by user (see inq_cmd_line) */ static char last_msg[MSG_SIZE]; /* last message printed. */ @@ -160,8 +168,8 @@ eyorn(const char *msg) echo_color = ATTR_QUESTION; while (1) { ewprintf("%s [yn]? ", msg); - s = (KEY)io_get_key(0); - if ((s & RANGE_MASK) == RANGE_ASCII) { + s = (KEY) io_get_key(0); + if (IS_CHARACTER(s)) { if (strchr("yYnN\033", s)) { /* Y[es], N[o] or ESC */ break; } @@ -427,7 +435,7 @@ equestion(const char *prompt, char *buf, int nbuf) */ static int ereplyask(const char *prompt, const char *defstr, - char *buf, int nbuf, int attr, int standout, int one) + char *buf, int bufsiz, int attr, int standout, int one) { const int saved_flags = trace_flags(); const int omsglevel = x_msglevel; @@ -443,40 +451,44 @@ ereplyask(const char *prompt, const char *defstr, echo_color = attr; echo_standout = standout; eprint(prompt, (defstr ? defstr : "")); - if ('\001' == *prompt) { - ++prompt; /* consume hilite marker \001 */ - } - - trace_log("ereplyask: <%s>(%d:%d)\n", prompt, nbuf, one); if (nflags && 0 == (nflags & DB_PROMPT)) { nflags = 0; /* disable debug prompt */ } /* trigger start */ - if (!one) { - static const char _prompt_begin[] = "_prompt_begin"; + { const char *t_prompt = prompt; - if (macro_lookup(_prompt_begin)) { - char ebuf[EBUFSIZ + 20]; + if ('\001' == *prompt) { /* hilite marker \001 */ + ++t_prompt; + } - sxprintf(ebuf, sizeof(ebuf), "%s \"%s\"", _prompt_begin, prompt); - trace_flagsset(nflags); - execute_str(ebuf); - /* - * TODO, BRIEF compat --- - * The new default response should be returned as a - * string if changed, otherwise return an integer/null - * to indicate no change. - */ - trace_flagsset(saved_flags); - } else { - trace_log("ereplyask: _prompt_begin not found\n"); + trace_log("ereplyask: <%s>(%d:%d)\n", t_prompt, bufsiz, one); + + if (! one) { + static const char _prompt_begin[] = "_prompt_begin"; + + if (macro_lookup(_prompt_begin)) { + char ebuf[EBUFSIZ + 20]; + + sxprintf(ebuf, sizeof(ebuf), "%s \"%s\"", _prompt_begin, t_prompt); + trace_flagsset(nflags); + execute_str(ebuf); + /* + * TODO, BRIEF compat --- + * The new default response should be returned as a + * string if changed, otherwise return an integer/null + * to indicate no change. + */ + trace_flagsset(saved_flags); + } else { + trace_log("ereplyask: _prompt_begin not found\n"); + } } } /* line-editor implementation */ - ret = elineedit(prompt, defstr, buf, nbuf, one); + ret = elineedit(prompt, defstr, buf, bufsiz, one); /* completion */ echo_standout = t_echo_standout; @@ -566,7 +578,7 @@ ereplyask(const char *prompt, const char *defstr, * * Ctrl+V, Ctrl+Y (*) Paste from clipboard. * - * TODO: + * TODO (plus key mapping): * * Ctrl+C, Ctrl+W (*) Cut to clipboard. * @@ -587,38 +599,44 @@ ereplyask(const char *prompt, const char *defstr, * otherwise TRUE with result contained within 'buf'. */ static int -elineedit(const char *prompt, const char *defstr, char *buf, int bufsiz, int one) +elineedit(const char *prompt, const char *defstr, char *result, int bufsiz, int one) { - char ndefstr[MAX_CMDLINE] = {0}; - int left = 0, bpos = 0, imode = TRUE; - int first_key = TRUE; - KEY c; + WChar_t buf[EBUFSIZ]; + char ndefstr[EBUFSIZ]; + int bleft = 0, bpos = 0, imode = TRUE; + int first_key = TRUE; + KEY c = 0; + + assert(bufsiz >= 2 /*&& bufsiz <= EBUFSIZ*/); + if (bufsiz > _countof(buf)) bufsiz = _countof(buf); - assert(bufsiz >= 2); + memset(buf, 0, sizeof(buf)); + memset(ndefstr, 0, sizeof(ndefstr)); - memset(buf, 0, bufsiz); /* zap reply */ if (NULL == defstr) defstr = ""; - strxcpy(buf, defstr, bufsiz); - --bufsiz; /* remove terminator */ + Wcsfromutf8(defstr, buf, bufsiz); last_msg[0] = '\0'; x_prompting = TRUE; ecursor(imode); ttcolornormal(); + trace_log("elineedit:\n"); + while (1) { /* update prompt/cursor */ + assert(bpos >= 0 && bpos <= bufsiz); if (! first_key) { if (0 == bpos) { - echo_offset = left = 0; /* home */ + echo_offset = bleft = 0; /* home */ } - eprompt(FALSE, (int)strlen(buf)); - left = eposition(buf, bpos, left); + eprompt(FALSE, (int) Wcslen(buf)); + bleft = eposition(buf, bpos, bleft); } /* next key */ ttflush(); - c = (KEY)io_get_key(0); + c = (KEY) io_get_key(0); if (one) { /* @@ -628,7 +646,7 @@ elineedit(const char *prompt, const char *defstr, char *buf, int bufsiz, int one */ if (KEY_ESC != c) { buf[0] = (c > 0x7f ? 0 : (char)c); - buf[1] = '\0'; + buf[1] = '\0'; goto done; } goto cancel; @@ -639,13 +657,12 @@ elineedit(const char *prompt, const char *defstr, char *buf, int bufsiz, int one * First key and it is a special one, * then user has accepted the default prompt unmark. */ - case KEY_TAB: case CTRL_H: - case KEY_HOME: case KEY_END: - case KEY_WLEFT: case KEY_WRIGHT: - case KEY_LEFT: case KEY_RIGHT: - case 0x7f: case KEY_DEL: - strxcpy(buf, defstr, bufsiz + 1); - bpos = (int)strlen(buf); + case KEY_TAB: case CTRL_H: + case KEY_HOME: case KEY_END: + case KEY_WLEFT: case KEY_WRIGHT: + case KEY_LEFT: case KEY_RIGHT: + case KEY_DELETE: case KEY_DEL: + bpos = Wcsfromutf8(defstr, buf, bufsiz); break; /* @@ -695,51 +712,64 @@ cancel:; ecursor(buf_imode(curbp)); case KEY_UP: case WHEEL_UP: case WHEEL_DOWN: -badkey:; { const char *sacc; - char *oecho_cmdline = echo_cmdline; +badkey:; { const char *oecho_cmdline = echo_cmdline; + const int t_bufsiz = Wcslen(buf) * 4; + const char *sacc; + char *t_buf = NULL; + + trace_log("elineedit: badkey\n"); + if (t_bufsiz) { + if (NULL == (t_buf = malloc(t_bufsiz))) { + goto cancel; + } + Wcstoutf8(buf, t_buf, t_bufsiz); + } key_cache_key(x_push_ref, c, FALSE); trigger(REG_INVALID); /* old interface, use of _bad_key() preferred */ + + echo_cmdline = (t_buf ? t_buf : ""); x_prompting = FALSE; - echo_cmdline = buf; - execute_str("_bad_key"); /* XXX - should pass the keycode */ + execute_str("_bad_key"); /* pass the keycode?? */ echo_cmdline = oecho_cmdline; x_prompting = TRUE; + free(t_buf); if (NULL == (sacc = acc_get_sval())) { goto cancel; } strxcpy(ndefstr, sacc, sizeof(ndefstr)); - strxcpy(buf, sacc, bufsiz + 1); + Wcsfromutf8(sacc, buf, bufsiz); + eprint(prompt, ndefstr); defstr = ndefstr; first_key = TRUE; } - continue; + break; case KEY_WLEFT: /* , cursor movement */ case KEY_WLEFT2: - while (isspace(buf[bpos]) && bpos > 0) { + while (bpos > 0 && isspace(buf[bpos])) { --bpos; } - while (!isspace(buf[bpos]) && bpos > 0) { + while (bpos > 0 && !isspace(buf[bpos])) { --bpos; } break; case KEY_WRIGHT: /* , cursor movement */ case KEY_WRIGHT2: - while (isspace(buf[bpos]) && buf[bpos]) { + while (bpos < bufsiz && isspace(buf[bpos]) && buf[bpos]) { ++bpos; } - while (!isspace(buf[bpos]) && buf[bpos]) { + while (bpos < bufsiz && !isspace(buf[bpos]) && buf[bpos]) { ++bpos; } break; case KEY_RIGHT: /* , cursor movement */ - if (buf[bpos]) { + if (bpos < bufsiz && buf[bpos]) { ++bpos; } break; @@ -756,7 +786,7 @@ badkey:; { const char *sacc; break; case KEY_END: /* , cursor movement */ - bpos = (int)strlen(buf); + bpos = (int)Wcslen(buf); break; case ALT_I: /* , toggle insert/overstrike mode */ @@ -776,11 +806,11 @@ badkey:; { const char *sacc; case KEY_DEL: /* , delete character under the cursor */ case 0x7F: case CTRL_D: { - char *bcursor = buf + bpos; - size_t rlen = strlen(bcursor); + WChar_t *bcursor = buf + bpos; + size_t rlen = Wcslen(bcursor); if (rlen) { - if (--rlen) memmove(bcursor, bcursor + 1, rlen); + if (--rlen) Wmemmove(bcursor, bcursor + 1, rlen); bcursor[rlen] = 0; } } @@ -794,79 +824,123 @@ badkey:; { const char *sacc; case ALT_D: /* , delete line/buffer */ case CTRL_X: case CTRL_U: - bpos = 0; buf[0] = '\0'; + bpos = 0; break; case KEY_INS: /* , insert scrap into prompt */ case KEY_PASTE: case CTRL_V: case CTRL_Y: { - const char *cpp; - int scount = 0; - char *bcursor; - - k_seek(); - if ((scount = k_read(&cpp)) <= 0) { - ttbeep(); - continue; + WChar_t t_buf[sizeof(buf)] = {0}; + const char *scrap_buffer = NULL; + int scrap_size = 0; + + if (bpos >= (bufsiz - 1)) { + ttbeep(); /* end-of-buffer */ + break; } - while (estrlen(buf, FALSE) <= bufsiz && --scount) { - if (bpos > bufsiz) { - ttbeep(); - break; + k_seek(); /* MCHAR/???, utf8 assumption */ + while (0 == (scrap_size = k_read(&scrap_buffer))) { + continue; /* first non-empty line */ + } + + if (scrap_size < 0 /*eof*/) { + ttbeep(); /* nothing available */ + + } else { + const int blen = Wcslen(buf); + const int trailing = (bpos < blen ? blen - bpos : 0); + const int remaining = bufsiz - (bpos + (imode ? trailing : 0)); + + assert(bpos <= blen); + if (remaining > imode) { /* space available, inc nul */ + int copied; + + memcpy(t_buf, buf, sizeof(buf)); + if ((copied = Wcsfromutf8(scrap_buffer, buf + bpos, remaining)) > 0) { + assert((bpos + copied) < bufsiz); + if (trailing) { + const int binsert = bpos + copied; + if (imode) { /* append original */ + assert((binsert + trailing) < bufsiz); + Wmemcpy(buf + binsert, t_buf + bpos, trailing + 1 /*nul*/); + } else { /* replace null with previous value */ + if (binsert < blen) { + buf[binsert] = t_buf[binsert]; + } + } + } + assert(Wcslen(buf) < (size_t)bufsiz); + } + scrap_size -= copied; } - bcursor = buf + bpos; - if (0 == *bcursor) { - bcursor[1] = '\0'; - } else if (imode) { - memmove(bcursor + 1, bcursor, bufsiz - bpos); + + if (scrap_size) { + ttbeep(); /* overflow */ } - *bcursor = *cpp++; - ++bpos; } } break; case 0: case KEY_VOID: - continue; + break; + + case KEY_WINCH: /* resize event */ + vtwinch(ttcols(), ttrows()); + vtupdate(); + elinecol(LC_DONTENABLE); + break; case ALT_Q: /* , quote the next input character */ case CTRL_Q: - c = (KEY)io_get_raw(0); + c = (KEY) io_get_raw(0); if (0 == c || c >= KEY_VOID) { - continue; + break; } /*FALLTHRU*/ - default: { - if ((c & RANGE_MASK) != RANGE_ASCII) { - goto badkey; - } + default: + if (0 == IS_CHARACTER(c)) { + goto badkey; /* invalid key */ - if (0 == (c & 0xff) || bpos > bufsiz || - estrlen(buf, FALSE) > bufsiz) { - ttbeep(); + } else if (bpos >= (bufsiz - 1)) { + ttbeep(); /* end-of-buffer */ - } else { - char *bcursor = buf + bpos; - - if (0 == *bcursor) { - bcursor[1] = '\0'; - } else if (imode) { - memmove(bcursor + 1, bcursor, bufsiz - bpos); + } else { + const int blen = Wcslen(buf); + const int trailing = (bpos < blen ? blen - bpos : 0); + const int remaining = bufsiz - (bpos + (imode ? trailing : 0)); + + assert(bpos <= blen); /* space available, minus nul */ + if (remaining > imode) { + WChar_t *binsert = buf + bpos++; + if (*binsert) { + assert(trailing); + if (imode) { /* insert, otherwise replace */ + assert((binsert + trailing) < (buf + bufsiz)); + Wmemmove(binsert + 1, binsert, trailing + 1 /*nul*/); + } + } else { + binsert[1] = '\0'; /* end-of-string */ } - *bcursor = (char) c; - ++bpos; + *binsert = c; + assert(Wcslen(buf) < (size_t)bufsiz); + + } else { + ttbeep(); /* overflow */ } } break; } } + done:; - assert(0 == buf[bufsiz]); + assert(Wcslen(buf) < (size_t)bufsiz); + Wcstoutf8(buf, result, bufsiz); + assert((int)strlen(result) < bufsiz); x_prompting = FALSE; ecursor(buf_imode(curbp)); return TRUE; @@ -888,7 +962,7 @@ eprompt(int force, int buflen) { const int odisabled = lc_disabled; const int ooffset = echo_offset; - const int length = echo_prompt + /* total length */ + const int length = echo_prompt_width + /* total length */ (buflen >= 0 ? buflen : echo_default); /* disable line/col? */ @@ -902,7 +976,7 @@ eprompt(int force, int buflen) echo_offset = 0; /* home */ } else { /* >3/4 shall be prompt */ - echo_offset = echo_prompt - (ttcols() * 3) / 4; + echo_offset = echo_prompt_width - (ttcols() * 3) / 4; if (echo_offset < 0) { echo_offset = 0; } @@ -927,64 +1001,66 @@ eprompt(int force, int buflen) * Parameters: * buf - Address of user buffer. * bpos - Current buffer position (cursor). - * left - Storage of working variable contained the 'left' margin. + * bleft - Storage of working variable contained the 'left' margin. * * Return: - * New 'left' value. + * Resultng 'left' value. */ static int -eposition(const char *buf, int bpos, int left) +eposition(const WChar_t *buf, int bpos, int bleft) { const vbyte_t attr = VBYTE_ATTR(echo_color); - int col = echo_prompt - echo_offset; /* user buffer base column */ + int col = echo_prompt_width - echo_offset; /* user buffer base column */ int cursor = -1; /* cursor position */ - int pos = 0; - int partial = 0; - int len, i; + int i, pos = 0; - /* figure out where the cursor is going to land */ + /* + * Size output buffer ... + */ for (i = 0; i < bpos && buf[i];) { - pos += eprintable(buf[i++], NULL); + pos += eprintable(buf[i++], NULL, NULL); } - /* if cursor off the screen then we need to reframe the users input */ - if (bpos < left) { - while (i > 0 && left > bpos) { - pos -= eprintable(buf[--i], NULL); - --left; + /* + * if cursor off screen, reframe + */ + if (bpos < bleft) { + while (i > 0 && bleft > bpos) { + pos -= eprintable(buf[--i], NULL, NULL); + --bleft; } - } else if (col + pos - left >= lc_column) { + } else if (col + pos - bleft >= lc_column) { pos = lc_column; - - --i; - while (pos > col && i >= 0) { - pos -= eprintable(buf[i--], NULL); - } - ++i; - if (pos < col) { - partial = col - pos; + while (pos >= col && i >= 0) { + const int width = eprintable(buf[i--], NULL, NULL); + if ((pos - width) <= col) { + ++i; + break; + } + pos -= width; } - ++i; - left = i; + bleft = i; } - /* redraw the line, pad with trailing spaces */ - buf += left; - for (i = left; col < lc_column; ++i) { + /* + * Redraw prompt, pad with trailing spaces. + */ + buf += bleft; + for (i = bleft; col < lc_column; ++i) { const int ch = (*buf ? *buf++ : ' '); - vbyte_t vbuf[10] = {0}; + vbyte_t vbuf[16] = {0}; + int vlen = _countof(vbuf); - if (i == bpos) { /* cursor located */ - cursor = col; - } - len = eprintable(ch, vbuf); - col = eputs(col, vbuf + partial, len - partial, attr); - partial = 0; + if (i == bpos) cursor = col; /* cursor located */ + + eprintable(ch, vbuf, &vlen); + col = eputs(col, vbuf, vlen, attr); } + vtupdate_bottom(cursor); - return left; + return bleft; } @@ -1003,28 +1079,35 @@ edisplay(void) const vbyte_t normal = VBYTE_ATTR(echo_color); const vbyte_t standout = VBYTE_ATTR(echo_standout); const vbyte_t completion = VBYTE_ATTR(ATTR_PROMPT_COMPLETE); - unsigned char *cp, *ap, *ep; /* buffer working pointers */ - int cursor, col = 0; + const WChar_t *cp, *ep; /* buffer working pointers */ + const unsigned char *ap; + int offset = echo_offset, cursor, col = 0; - trace_log("edisplay: prompt[%d]:<", echo_prompt); + trace_log("edisplay: prompt[%d,%d]:<", offset, echo_prompt_width); - ep = echo_line + echo_prompt; /* display prompt, hilite if required */ - for (cp = echo_line + echo_offset, ap = echo_attr + echo_offset; *cp; ++cp, ++ap) { + for (cp = wecho_line, ep = cp + echo_prompt_len, + ap = echo_attr; *cp; ++cp, ++ap) { + const int32_t wch = *cp; + + if (offset > 0) { /* consume off-screen */ + --offset; + continue; + } if (lc_column && col >= lc_column) { break; /* trim */ } - trace_log("%c", *cp); + trace_log("%c", wch); - if (cp < ep && *ap && standout) { - col = eputc(col, *cp, standout); /* prompt */ + if (standout && col < echo_prompt_width && *ap) { + col = eputc(col, wch, standout); /* prompt */ } else if (echo_default > 0 && cp >= ep) { - col = eputc(col, *cp, completion); /* default/completion */ + col = eputc(col, wch, completion); /* default/completion */ } else { - col = eputc(col, *cp, normal); /* user text */ + col = eputc(col, wch, normal); /* user text */ } } @@ -1041,32 +1124,6 @@ edisplay(void) } -/* Function: estrlen - * Determine the display length of the specified buffer 'str'. - * - * Parameters: - * str - Buffer. - * hilite - TRUE or FALSE, process hilite markers. - * - * Returns: - * Length of the buffer in bytes. - */ -static int -estrlen(const char *str, int hilite) -{ - int ch, len = 0; - - if (str) { - while (0 != (ch = *str++)) { - if (! hilite || '^' != ch) { - len += eprintable((ch >= ' ' ? ch : (ch | 0x80)), NULL); - } - } - } - return len; -} - - /* Function: inq_message * inq_message primitive. * @@ -1102,7 +1159,10 @@ estrlen(const char *str, int hilite) void inq_message(void) { - acc_assign_str((char *)echo_line, -1); + char t_echo_line[ECHOLINESZ] = {0}; + + Wcstoutf8(wecho_line, t_echo_line, sizeof(t_echo_line)); + acc_assign_str((const char *)t_echo_line, -1); } @@ -1170,8 +1230,7 @@ inq_prompt(void) none Macro Returns: - The 'inq_cmd_line' returns a string containing the current - prompt. + The 'inq_cmd_line' returns a string containing the current prompt. Macro Portability: n/a @@ -1184,8 +1243,12 @@ inq_cmd_line(void) { if (echo_cmdline) { acc_assign_str((const char *)echo_cmdline, -1); + } else { - acc_assign_str((const char *)(echo_line + echo_prompt), -1); + char t_cmd_line[EBUFSIZ] = {0}; + + Wcstoutf8(wecho_line + echo_prompt_len, t_cmd_line, sizeof(t_cmd_line)); + acc_assign_str((const char *)t_cmd_line, -1); } } @@ -1213,8 +1276,7 @@ inq_cmd_line(void) none Macro Returns: - The 'inq_line_col()' primitive returns the current echo line - status. + The 'inq_line_col()' primitive returns the current echo line status. Macro Portability: n/a @@ -1225,7 +1287,10 @@ inq_cmd_line(void) void inq_line_col(void) { - acc_assign_str(lc_state.buffer, -1); + char t_line_col[_countof(lc_state.buffer) * 4] = {0}; + + Wcstoutf8(lc_state.buffer, t_line_col, sizeof(t_line_col)); + acc_assign_str(t_line_col, -1); } @@ -1284,7 +1349,6 @@ ewprintx(const char *fmt, ...) void eeprintf(const char *fmt, ...) { -// const vbyte_t t_echo_color = echo_color; char iobuf[EBUFSIZ]; va_list ap; @@ -1298,7 +1362,6 @@ eeprintf(const char *fmt, ...) void eeprintx(const char *fmt, ...) { -// const vbyte_t t_echo_color = echo_color; const int xerrno = errno; char iobuf[EBUFSIZ]; va_list ap; @@ -1413,40 +1476,37 @@ eprint(const char *prompt, const char *defstr) } } - /* save prompt */ - echo_prompt = estrlen(prompt, hilite); + /* + * import prompt, default and display + */ + echo_prompt_len = Wcsfromutf8(prompt, wecho_line, _countof(wecho_line)); memset(echo_attr, 0, sizeof(echo_attr)); - if (hilite) { - const unsigned char *p = (const unsigned char *)prompt; - unsigned char *echo = echo_line, - *end = echo + (sizeof(echo_line) - 1); - unsigned char *attr = echo_attr; - unsigned char ch; - - while (echo < end && 0 != (ch = *p++)) { - if ('^' == ch) { /* hilite next character */ - *attr = 1; - } else { - *echo++ = ch; - ++attr; + if (hilite) { + WChar_t *cp = wecho_line, *out = cp, + *end = cp + (_countof(wecho_line) - 1), wch; + unsigned char *ap = echo_attr; + + while (cp < end && 0 != (wch = *cp++)) { + if ('^' == wch && *cp) { /* hilite next character */ + --echo_prompt_len; + *ap = 1; + continue; } + *out++ = wch; + ++ap; } - *echo = 0; - } else { - strxcpy((char *)echo_line, prompt, sizeof(echo_line)); + *out = 0; } - /* save default (if any) */ + echo_prompt_width = eprintlen(wecho_line); /* display width */ + if (!defstr || !*defstr) { echo_default = 0; /* no default */ - } else { - strxcat((char *)echo_line, defstr, sizeof(echo_line)); - echo_default = (int)strlen(defstr); + echo_default = Wcsfromutf8(defstr, wecho_line + echo_prompt_len, _countof(wecho_line) - echo_prompt_len); } - /* display */ eprompt(TRUE, -1); } @@ -1473,9 +1533,8 @@ emaxcols(void) /* Function: eputc - * Write to the virtual display, using the existing attribute. The - * specified character is converted to it printable form prior to being - * displayed. + * Write to the virtual display, using the existing attribute. + * The specified character is converted to it printable form prior to being displayed. * * Parameter: * pp - Cursor. @@ -1488,12 +1547,14 @@ emaxcols(void) static int eputc(int col, int c, vbyte_t attr) { - vbyte_t vbuf[10] = {0}; + vbyte_t vbuf[16] = {0}; + int vlen = _countof(vbuf); if ('\r' == c || '\n' == c) { return col; } - return eputs(col, vbuf, eprintable(c, vbuf), attr); + eprintable(c, vbuf, &vlen); + return eputs(col, vbuf, vlen, attr); } @@ -1510,7 +1571,7 @@ eputc(int col, int c, vbyte_t attr) * Resulting cursor position. */ static int -eputs(int col, vbyte_t *buf, int len, vbyte_t attr) +eputs(int col, const vbyte_t *buf, int len, vbyte_t attr) { assert(col >= 0); assert(col < ttcols()); @@ -1518,13 +1579,12 @@ eputs(int col, vbyte_t *buf, int len, vbyte_t attr) assert(lc_column <= ttcols()); if (col >= 0) { - while (len-- > 0) { - if (col < lc_column) { - if (vtpute((vbyte_t)(*buf++ | attr), col) < 0) { - break; /* error, abort */ - } - ++col; + while (len-- > 0 && col < lc_column) { + const int ncol = vtpute((vbyte_t)(*buf++ | attr), col); + if (-1 == ncol) { + break; /* off-screen */ } + col = ncol; } } return col; @@ -1628,11 +1688,11 @@ elinecol(int flags) state.buffer[0] = '\0'; if (xf_echofmt && (E_FORMAT & xf_echoflags)) { - ef_format(xf_echofmt, state.buffer, &state); + ef_format(xf_echofmt, &state); } else { const int echoflags = xf_echoflags; - char *cp = state.buffer; + WChar_t *cp = state.buffer; if (curwp && W_TILED == curwp->w_type) { if (echoflags & E_CHARVALUE) { @@ -1644,15 +1704,15 @@ elinecol(int flags) } if (echoflags & E_LINE) { /* line */ - cp = ef_line(ef_space(cp), &state); + cp = ef_line(ef_space(cp, &state), &state); } if (echoflags & E_COL) { /* column */ - cp = ef_col(ef_space(cp), &state); + cp = ef_col(ef_space(cp, &state), &state); } if (echoflags & E_PERCENT) { /* cursor percentage within file */ - cp = ef_percent(ef_space(cp), &state); + cp = ef_percent(ef_space(cp, &state), &state); } if (echoflags & E_CURSOR) { @@ -1660,48 +1720,52 @@ elinecol(int flags) } if ((echoflags & E_REMEMBER) && x_rem_string[0] != ' ') { - cp = ef_buffer(cp, x_rem_string); /* RE/PA */ - cp = ef_space(cp); + cp = ef_buffer(cp, x_rem_string, &state); /* RE/PA */ + cp = ef_space(cp, &state); } if (echoflags & (E_TIME|E_TIME24)) { /* current time */ - cp = ef_time(ef_space(cp), &state, (E_TIME24 & echoflags) ? TRUE : FALSE); + cp = ef_time(ef_space(cp, &state), (E_TIME24 & echoflags) ? TRUE : FALSE, &state); } } assert(ESTATE_MAGIC == state.magic); assert(ESTATE_MAGIC == state.magic2); - lc_length = (int)strlen(state.buffer); /* line length */ + lc_length = (int)Wcslen(state.buffer); /* line length */ assert(lc_length < (int) sizeof(state.buffer)); /* update */ lc_column = emaxcols() - lc_length; /* left column */ if ((LC_FORCE & flags) || lc_state.position != lc_column || - 0 != strcmp(lc_state.buffer, state.buffer)) { + 0 != Wcscmp(lc_state.buffer, state.buffer)) { const vbyte_t attr = VBYTE_ATTR(ATTR_ECHOLINE); - const char *cp; + const WChar_t *cp; int col = 0; /* erase characters longer needed */ if (0 == lc_state.position || lc_state.position >= lc_column) { col = lc_column; } else { col += lc_state.position; - while (col < lc_column) { - vtpute(' ' | attr, col++); + while (col >= 0 && col < lc_column) { + const int ncol = vtpute(' ' | attr, col); + if (-1 == ncol) { + break; /* off-screen */ + } + col = ncol; } } - for (cp = state.buffer; *cp; ++cp) { /* now draw in the line/col string */ - vtpute(*cp | attr, col++); + for (cp = state.buffer; *cp; ++cp) { + col = vtpute(*cp | attr, col); /* now draw in the line/col string */ } if (! ttlastsafe()) { /* clear last character */ - vtpute(' ' | VBYTE_ATTR(ATTR_NORMAL), col++); + col = vtpute(' ' | VBYTE_ATTR(ATTR_NORMAL), col); } vtupdate_bottom(-1); /* updated */ - strcpy(lc_state.buffer, state.buffer); + Wcscpy(lc_state.buffer, state.buffer); lc_state.position = lc_column; } } @@ -1787,7 +1851,7 @@ elinecol(int flags) The virtual character status is represented by one of the following otherwise blank if a normal character. - X - Virtual space, for example logical space created as + X - Virtual space, for example logical space created as the result of tab expansion. $ - End of line. @@ -2191,7 +2255,7 @@ inq_echo_format(void) /* string () */ /* Function: infof_truncated - * Print a message contained a filenamet, truncating the filename + * Print a message contained a filename, truncating the filename * if too long for the echo line. * * The format argument must be a sprintf() style string containing @@ -2326,6 +2390,29 @@ errorfx(const char *fmt, ...) } +/* Function: eprintlen + * Determine the display length of the specified buffer 'str'. + * + * Parameters: + * str - Buffer. + * + * Returns: + * Length of the buffer in bytes. + */ +static int +eprintlen(const WChar_t *str) +{ + WChar_t ch; + int len = 0; + if (str) { + while (0 != (ch = *str++)) { + len += eprintable(ch, NULL, NULL); + } + } + return len; +} + + /* Function: eprintable * Converts a character to a printable format taking into account whether * the terminal can support printable 8-bit chars, etc. @@ -2333,17 +2420,18 @@ errorfx(const char *fmt, ...) * Parameters: * ch - Character value. * buf - Destination buffer. + * buflen - Length, in bytes, of the output buffer. * * Returns: - * length of the printed version. + * Display width. */ static int -eprintable(const vbyte_t c, vbyte_t *buf) +eprintable(const vbyte_t c, vbyte_t *buf, int *buflen) { const vbyte_t attr = VBYTE_ATTR_GET(c); vbyte_t ch = VBYTE_CHAR_GET(c); - char cp[32]; /* MCHAR */ - int len = 0; + char t_buffer[32]; + int idx, len = 0; if (ch <= 0xff) { /* @@ -2354,20 +2442,19 @@ eprintable(const vbyte_t c, vbyte_t *buf) len = mc->mc_length; if (buf) { const unsigned char *mccp = (unsigned char *) mc->mc_str; - int idx; - - if (NULL == cp) { + if (NULL == mccp) { if ((ch = mc->mc_chr) > 0 && ch < 0x80) { *buf++ = ch | attr; } else { goto ischaracter; } } else { - assert(len <= 10); + assert(len < *buflen); for (idx = 0; idx < len; ++idx) { *buf++ = mccp[idx] | attr; } } + *buflen = len; } return len; } @@ -2376,14 +2463,24 @@ eprintable(const vbyte_t c, vbyte_t *buf) * extended character values */ ischaracter:; - len = sxprintf(cp, sizeof(cp), "u%04x", ch); + if (vtisunicode() || vtisutf8()) { + const int width = Wcwidth(ch); + if (width >= 0) { + if (buf) { + buf[0] = (ch & VBYTE_CHAR_MASK) | attr; + buf[1] = 0; + *buflen = 1; + } + return width; + } + } + len = sxprintf(t_buffer, sizeof(t_buffer), "u%04x", ch); if (buf) { - int idx; - - assert(len <= 10); + assert(len < *buflen); for (idx = 0; idx < len; ++idx) { - *buf++ = cp[idx] | attr; + *buf++ = t_buffer[idx] | attr; } + *buflen = len; } return len; } @@ -2414,14 +2511,15 @@ eredraw(void) * Parameters: * fmt - Echo line format specification. * cp - Buffer pointer. - * state - State information, buffer and time/date. + * status - Edit state information, buffer and time/date. * * Returns: * nothing */ static void -ef_format(const char *fmt, char *cp, struct _estate *state) +ef_format(const char *fmt, struct _estate *s) { + WChar_t *cp = s->buffer; if (fmt) { char ch; @@ -2474,7 +2572,7 @@ ef_format(const char *fmt, char *cp, struct _estate *state) case 1: /* Number as decimal */ break; default: /* Title */ - cp = ef_buffer(cp, curbp->b_title); + cp = ef_utf8(cp, curbp->b_title, s); break; } } @@ -2502,90 +2600,90 @@ ef_format(const char *fmt, char *cp, struct _estate *state) case 'n': /* File name with directory */ if (curbp) { - cp = ef_buffer(cp, curbp->b_fname); + cp = ef_utf8(cp, curbp->b_fname, s); } break; case 'N': /* File name without the directory */ if (curbp && curbp->b_fname) { - cp = ef_buffer(cp, sys_basename(curbp->b_fname)); + cp = ef_utf8(cp, sys_basename(curbp->b_fname), s); } break; case 'p': /* Percent string */ - cp = ef_percent(cp, state); + cp = ef_percent(cp, s); break; case 'c': /* Column number */ switch (modifier) { case 1: /* xxx */ - cp = ef_integer(cp, state->bf_col, 0); + cp = ef_integer(cp, s->bf_col, 0, s); break; default: /* Col: xxx */ - cp = ef_col(cp, state); + cp = ef_col(cp, s); } break; case 'm': /* Mode string (i.e. --rw-rw-rw) */ - cp = ef_filemode(cp, state); + cp = ef_filemode(cp, s); break; case 'o': /* Overwrite mode, " OV" otherwise "" */ - cp = ef_ovmode(cp, state); + cp = ef_ovmode(cp, s); break; case 'O': /* Overwrite/insert flag - like %o, but shows OV/RE */ - cp = ef_imode(cp, state); + cp = ef_imode(cp, s); break; case 'C': /* Character value */ - cp = ef_charvalue(cp, state); + cp = ef_charvalue(cp, s); break; case 'V': /* Virtual character indicator */ - cp = ef_virtual(cp, state); + cp = ef_virtual(cp, s); break; case 'r': /* Remember flag */ if (x_rem_string[0] != ' ') { - cp = ef_buffer(cp, x_rem_string); - cp = ef_space(cp); + cp = ef_buffer(cp, x_rem_string, s); + cp = ef_space(cp, s); } break; case 'l': /* Line number */ switch (modifier) { case 1: /* xxx */ - cp = ef_integer(cp, state->bf_line, 0); + cp = ef_integer(cp, s->bf_line, 0, s); break; default: /* Line: xxx */ - cp = ef_line(cp, state); + cp = ef_line(cp, s); } break; case 'L': /* Number of lines in the file */ - cp = ef_numlines(cp, state); + cp = ef_numlines(cp, s); break; case 't': /* Time (12 or 24 hour) */ - cp = ef_time(cp, state, modifier ? TRUE : FALSE); + cp = ef_time(cp, modifier ? TRUE : FALSE, s); break; case 'd': /* Date, optional format */ - cp = ef_date(cp, state, modifier); + cp = ef_date(cp, modifier, s); break; case 'v': /* Version */ - cp = ef_version(cp, state); + cp = ef_version(cp, s); break; case 'Y': /* Year */ switch (modifier) { case 1: /* YY */ - cp = ef_integer(cp, state->tm_year%100, 2); + cp = ef_integer(cp, s->tm_year%100, 2, s); break; default: /* YYYY */ - cp = ef_integer(cp, state->tm_year, 4); + cp = ef_integer(cp, s->tm_year, 4, s); break; } break; @@ -2593,16 +2691,16 @@ ef_format(const char *fmt, char *cp, struct _estate *state) case 'M': /* Month of the year */ switch (modifier) { case 3: /* Abbrev */ - cp = ef_buffer(cp, tm_month_abbrev(state->tm_month - 1)); + cp = ef_buffer(cp, tm_month_abbrev(s->tm_month - 1), s); break; case 2: /* Name */ - cp = ef_buffer(cp, tm_month_name(state->tm_month - 1)); + cp = ef_buffer(cp, tm_month_name(s->tm_month - 1), s); break; case 1: /* M[M] */ - cp = ef_integer(cp, state->tm_month, 0); + cp = ef_integer(cp, s->tm_month, 0, s); break; default: /* MM */ - cp = ef_integer(cp, state->tm_month, 2); + cp = ef_integer(cp, s->tm_month, 2, s); break; } break; @@ -2610,16 +2708,16 @@ ef_format(const char *fmt, char *cp, struct _estate *state) case 'D': /* Day of the month */ switch (modifier) { case 3: /* Abbrev */ - cp = ef_buffer(cp, tm_day_abbrev(state->tm_day - 1)); + cp = ef_buffer(cp, tm_day_abbrev(s->tm_day - 1), s); break; case 2: /* Name */ - cp = ef_buffer(cp, tm_day_abbrev(state->tm_day - 1)); + cp = ef_buffer(cp, tm_day_abbrev(s->tm_day - 1), s); break; case 1: /* D[D] */ - cp = ef_integer(cp, state->tm_day, 0); + cp = ef_integer(cp, s->tm_day, 0, s); break; default: /* DD */ - cp = ef_integer(cp, state->tm_day, 2); + cp = ef_integer(cp, s->tm_day, 2, s); break; } break; @@ -2640,77 +2738,107 @@ ef_format(const char *fmt, char *cp, struct _estate *state) * * Parameters: * cp - Echo-line buffer cursor. + * s - Edit state. * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_space(char *cp) +static WChar_t * +ef_space(WChar_t *cp, const struct _estate *s) { - *cp++ = ' '; - *cp = 0; + const WChar_t *end = buffer_end(s); + if (cp < end) { + *cp++ = ' '; + *cp = 0; + } return cp; } -/* Function: ef_integer - * Insert an integer attribute into the echo_line buffer. +/* Function: ef_buffer + * Insert the specfied buffer 'buf' into the echo_line buffer. * * Parameters: * cp - Echo-line buffer cursor. - * ivalue - Integer value. - * width - Optional field width. + * buf - Buffer to be inserted. + * s - Edit state. * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_integer(char *cp, int ivalue, int width) +static WChar_t * +ef_buffer(WChar_t *cp, const char *buf, const struct _estate *s) { - if (width > 0) { - sprintf(cp, "%0*d", width, ivalue); - } else if (width < 0) { - sprintf(cp, "%*d", width * -1, ivalue); - } else { - sprintf(cp, "%d", ivalue); + const WChar_t *end = buffer_end(s); + if (buf && cp < end) { + WChar_t c; + while (cp < end && 0 != (c = *buf++)) { + *cp++ = c; + } + *cp = 0; } - return cp + strlen(cp); + return cp; } -/* Function: ef_buffer - * Insert the specfied buffer 'buf' into the echo_line buffer. +/* Function: ef_utf8 + * Insert the specfied utf8 encoded buffer 'buf' into the echo_line buffer. * * Parameters: * cp - Echo-line buffer cursor. * buf - Buffer to be inserted. + * s - Edit state. + * + * Returns: + * resulting buffer cursor. + */ +static WChar_t * +ef_utf8(WChar_t *cp, const char *buf, const struct _estate *s) +{ + return cp + (buf ? Wcsfromutf8(buf, cp, buffer_end(s) - cp) : 0); +} + + +/* Function: ef_integer + * Insert an integer attribute into the echo_line buffer. + * + * Parameters: + * cp - Echo-line buffer cursor. + * ivalue - Integer value. + * width - Optional field width. + * s - Edit state. * * Returns: * resulting buffer cursor */ -static char * -ef_buffer(char *cp, const char *buf) +static WChar_t * +ef_integer(WChar_t *cp, int ivalue, int width, const struct _estate *s) { - if (buf) { - while ((*cp = *buf++) != '\0') { - ++cp; - } + char t_buffer[32]; + if (width > 0) { + sprintf(t_buffer, "%0*d", width, ivalue); + } else if (width < 0) { + sprintf(t_buffer, "%*d", width * -1, ivalue); + } else { + sprintf(t_buffer, "%d", ivalue); } - return cp; + return ef_buffer(cp, t_buffer, s); } + /* Function: ef_ovmode * Insert the ovmode into the echo_line buffer. * * Parameters: * cp - Echo-line buffer cursor. + * s - Edit state. * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_ovmode(char *cp, const struct _estate *s) +static WChar_t * +ef_ovmode(WChar_t *cp, const struct _estate *s) { __CUNUSED(s) if (0 == x_pt.pt_icursor[0]) { /* visual cursor not available */ @@ -2730,17 +2858,20 @@ ef_ovmode(char *cp, const struct _estate *s) * * Parameters: * cp - Character value. + * s - Edit state. * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_charvalue(char *cp, struct _estate *s) +static WChar_t * +ef_charvalue(WChar_t *cp, struct _estate *s) { int vstatus, charvalue; + char t_buffer[32]; __CUNUSED(s) + t_buffer[0] = 0; if (-999 == (vstatus = s->vf_status)) { /* loaded? */ s->vf_status = vstatus = line_current_status(s->vf_values, 4); } @@ -2748,42 +2879,44 @@ ef_charvalue(char *cp, struct _estate *s) if (0 == (BUFFERVSTATUS_ILLEGAL & vstatus)) { if ((BUFFERVSTATUS_EOL|BUFFERVSTATUS_XEOL|BUFFERVSTATUS_PEOL) & vstatus) { - return cp + sprintf(cp, " EOL "); /* */ + strcpy(t_buffer, " EOL "); /* */ } else if (BUFFERVSTATUS_EOF == vstatus) { - return cp + sprintf(cp, " EOF "); /* */ + strcpy(t_buffer, " EOF "); /* */ } else if (charvalue <= 0) { - return cp + sprintf(cp, " NUL "); + strcpy(t_buffer, " NUL "); /* control */ } else if (charvalue <= 0x1f) { - return cp + sprintf(cp, " ^%c ", 'A' + (charvalue - 1)); + sprintf(t_buffer, " ^%c ", 'A' + (charvalue - 1)); /* ascii */ } else if (charvalue <= 0x7f && isprint(charvalue)) { - return cp + sprintf(cp, " [%c] ", charvalue); + sprintf(t_buffer, " [%c] ", charvalue); } } - if (0 == charvalue) { /* others */ - strcpy(cp, "u0000 "); - } else { - unsigned i; + if (0 == t_buffer[0]) { + if (0 == charvalue) { /* others */ + strcpy(t_buffer, "u0000 "); - for (i = 0; i < 4 && (charvalue = s->vf_values[i]) > 0; ++i) { - if (charvalue <= 0xff) { - sprintf(cp, "%c0x%02x ", (i ? '+' : ' '), charvalue); + } else { + unsigned i; + for (i = 0; i < 4 && (charvalue = s->vf_values[i]) > 0; ++i) { + if (charvalue <= 0xff) { + sprintf(t_buffer, "%c0x%02x ", (i ? '+' : ' '), charvalue); - } else if (charvalue <= 0xffff) { - sprintf(cp, "%cu%04x ", (i ? '+' : ' '), charvalue); + } else if (charvalue <= 0xffff) { + sprintf(t_buffer, "%cu%04x ", (i ? '+' : ' '), charvalue); - } else { - sprintf(cp, "%cU%06x ", (i ? '+' : ' '), charvalue); + } else { + sprintf(t_buffer, "%cU%06x ", (i ? '+' : ' '), charvalue); + } } - cp += strlen(cp); } } - return cp + strlen(cp); + + return ef_buffer(cp, t_buffer, s); } @@ -2792,12 +2925,13 @@ ef_charvalue(char *cp, struct _estate *s) * * Parameters: * cp - Echo-line buffer cursor. + * s - Edit state. * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_virtual(char *cp, struct _estate *s) +static WChar_t * +ef_virtual(WChar_t *cp, struct _estate *s) { int status; @@ -2823,12 +2957,13 @@ ef_virtual(char *cp, struct _estate *s) * * Parameters: * cp - Echo-line buffer cursor. + * s - Edit state. * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_imode(char *cp, const struct _estate *s) +static WChar_t * +ef_imode(WChar_t *cp, const struct _estate *s) { __CUNUSED(s) if (buf_imode(curbp)) { @@ -2848,19 +2983,20 @@ ef_imode(char *cp, const struct _estate *s) * * Parameters: * cp - Echo-line buffer cursor. - * s - Edit status. + * s - Edit state. * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_numlines(char *cp, const struct _estate *s) +static WChar_t * +ef_numlines(WChar_t *cp, const struct _estate *s) { const int numlines = (int)(curbp ? curbp->b_numlines : 1); + char t_buffer[32]; __CUNUSED(s) - sprintf(cp, numlines > 9999 ? "%u" : "%-4u", numlines); - return cp + strlen(cp); + sprintf(t_buffer, numlines > 9999 ? "%u" : "%-4u", numlines); + return ef_buffer(cp, t_buffer, s); } @@ -2869,21 +3005,20 @@ ef_numlines(char *cp, const struct _estate *s) * * Parameters: * cp - Echo-line buffer cursor. - * s - Edit status. + * s - Edit state. * * Returns: * resulting buffer cursor */ -static char * -ef_filemode(char *cp, const struct _estate *s) +static WChar_t * +ef_filemode(WChar_t *cp, const struct _estate *s) { int mode = (curbp ? curbp->b_mode : 0); - char buffer[16]; + char t_buffer[16]; __CUNUSED(s) - file_modedesc((mode_t)mode, NULL, 0, buffer, sizeof(buffer)); - strcpy(cp, (const char *)buffer); - return cp + strlen(cp); + file_modedesc((mode_t)mode, NULL, 0, t_buffer, sizeof(t_buffer)); + return ef_buffer(cp, t_buffer, s); } @@ -2892,16 +3027,17 @@ ef_filemode(char *cp, const struct _estate *s) * * Parameters: * cp - Echo-line buffer cursor. - * s - Edit status. + * s - Edit state. * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_line(char *cp, const struct _estate *s) +static WChar_t * +ef_line(WChar_t *cp, const struct _estate *s) { - sprintf(cp, s->bf_line > 9999 ? "Line:%-5u" : "Line: %-4u", s->bf_line); - return cp + strlen(cp); + char t_buffer[32]; + sprintf(t_buffer, s->bf_line > 9999 ? "Line:%-5u" : "Line: %-4u", s->bf_line); + return ef_buffer(cp, t_buffer, s); } @@ -2910,16 +3046,17 @@ ef_line(char *cp, const struct _estate *s) * * Parameters: * cp - Echo-line buffer cursor. - * s - Edit status. + * s - Edit state. * * Returns: * resulting buffer cursor */ -static char * -ef_col(char *cp, const struct _estate *s) +static WChar_t * +ef_col(WChar_t *cp, const struct _estate *s) { - sprintf(cp, s->bf_col > 99 ? "Col:%-3u" : "Col: %-2u", s->bf_col); - return cp + strlen(cp); + char t_buffer[32]; + sprintf(t_buffer, s->bf_col > 99 ? "Col:%-3u" : "Col: %-2u", s->bf_col); + return ef_buffer(cp, t_buffer, s); } @@ -2928,26 +3065,24 @@ ef_col(char *cp, const struct _estate *s) * * Parameters: * cp - Echo-line buffer cursor. - * s - Edit status. + * s - Edit state. * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_percent(char *cp, const struct _estate *s) +static WChar_t * +ef_percent(WChar_t *cp, const struct _estate *s) { + char t_buffer[32]; accint_t perc; perc = ((accint_t)s->bf_line * 100) / (accint_t)(curbp && curbp->b_numlines > 0 ? curbp->b_numlines : 1); - if (perc > 100) { - perc = 100; - } if (perc >= 100) { - strcpy(cp, "END"); + strcpy(t_buffer, "END"); } else { - sprintf(cp, "%2lu%%", perc); + sprintf(t_buffer, "%2lu%%", perc); } - return cp + strlen(cp); + return ef_buffer(cp, t_buffer, s); } @@ -2956,23 +3091,24 @@ ef_percent(char *cp, const struct _estate *s) * * Parameters: * cp - Echo-line buffer cursor. - * s - Edit status. - * + * s - Edit state. + * * Returns: - * resulting buffer cursor + * resulting buffer cursor. */ -static char * -ef_time(char *cp, const struct _estate *s, int hour24) +static WChar_t * +ef_time(WChar_t *cp, int hour24, const struct _estate *s) { - if (hour24) { - sprintf(cp, "%02d:%02d", s->tm_hour, s->tm_min); + char t_buffer[32]; + if (hour24) { + sprintf(t_buffer, "%02d:%02d", s->tm_hour, s->tm_min); } else { - sprintf(cp, "%d:%02d%cm", + sprintf(t_buffer, "%d:%02d%cm", (s->tm_hour > 12 ? s->tm_hour - 12 : (s->tm_hour == 0 ? 12 : s->tm_hour)), s->tm_min, s->tm_hour >= 12 ? 'p' : 'a'); } - return cp + strlen(cp); + return ef_buffer(cp, t_buffer, s); } @@ -2981,15 +3117,15 @@ ef_time(char *cp, const struct _estate *s, int hour24) * * Parameters: * cp - Echo-line buffer cursor. - * s - Edit status. + * s - Edit state. * * Returns: * resulting buffer cursor */ -static char * -ef_date(char *cp, const struct _estate *s, int format) +static WChar_t * +ef_date(WChar_t *cp, int format, const struct _estate *s) { - char t_month[16]; + char t_buffer[32], t_month[16]; char delim = '-'; /* 30.. delimiter as '/' */ @@ -3010,32 +3146,32 @@ ef_date(char *cp, const struct _estate *s, int format) switch (format) { case 7: /* mm-dd */ - sprintf(cp, "%s%c%02d", t_month, delim, s->tm_day); + sprintf(t_buffer, "%s%c%02d", t_month, delim, s->tm_day); break; case 6: /* dd-mm[m] */ - sprintf(cp, "%02d%c%s", s->tm_day, delim, t_month); + sprintf(t_buffer, "%02d%c%s", s->tm_day, delim, t_month); break; case 5: /* mm[m]-dd-yy */ - sprintf(cp, "%s%c%02d%c%02d", t_month, delim, s->tm_day, delim, s->tm_year%100); + sprintf(t_buffer, "%s%c%02d%c%02d", t_month, delim, s->tm_day, delim, s->tm_year%100); break; case 4: /* dd-mm[m]-yy */ - sprintf(cp, "%02d%c%s%c%02d", s->tm_day, delim, t_month, delim, s->tm_year%100); + sprintf(t_buffer, "%02d%c%s%c%02d", s->tm_day, delim, t_month, delim, s->tm_year%100); break; case 3: /* mm[m]-dd-yyyy */ - sprintf(cp, "%s%c%02d%c%04d", t_month, delim, s->tm_day, delim, s->tm_year); + sprintf(t_buffer, "%s%c%02d%c%04d", t_month, delim, s->tm_day, delim, s->tm_year); break; case 2: /* dd-mm[m]-yyyy */ - sprintf(cp, "%02d%c%s%c%04d", s->tm_day, delim, t_month, delim, s->tm_year); + sprintf(t_buffer, "%02d%c%s%c%04d", s->tm_day, delim, t_month, delim, s->tm_year); break; case 1: /* yy-mm[m]-dd */ - sprintf(cp, "%02d%c%s%c%02d", s->tm_year%100, delim, t_month, delim, s->tm_day); + sprintf(t_buffer, "%02d%c%s%c%02d", s->tm_year%100, delim, t_month, delim, s->tm_day); break; case 0: /* yyyy-mm[m]-dd */ default: - sprintf(cp, "%04d%c%s%c%02d", s->tm_year, delim, t_month, delim, s->tm_day); + sprintf(t_buffer, "%04d%c%s%c%02d", s->tm_year, delim, t_month, delim, s->tm_day); break; } - return cp + strlen(cp); + return ef_buffer(cp, t_buffer, s); } @@ -3044,16 +3180,16 @@ ef_date(char *cp, const struct _estate *s, int format) * * Parameters: * cp - Echo-line buffer cursor. - * s - Edit status. + * s - Edit state. * * Returns: * resulting buffer cursor */ -static char * -ef_version(char *cp, const struct _estate *s) +static WChar_t * +ef_version(WChar_t *cp, const struct _estate *s) { __CUNUSED(s) - sprintf(cp, "%s", x_version); - return cp + strlen(cp); + return ef_buffer(cp, x_version, s); } + /*end*/ diff --git a/gr/file.c b/gr/file.c index 95020678..27490dbd 100644 --- a/gr/file.c +++ b/gr/file.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_file_c,"$Id: file.c,v 1.86 2021/04/18 17:12:41 cvsuser Exp $") +__CIDENT_RCSID(gr_file_c,"$Id: file.c,v 1.90 2021/10/18 13:19:59 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: file.c,v 1.86 2021/04/18 17:12:41 cvsuser Exp $ +/* $Id: file.c,v 1.90 2021/10/18 13:19:59 cvsuser Exp $ * File-buffer primitives and support. * * @@ -89,7 +89,7 @@ static int buf_trimline(BUFFER_t *bp, const LINECHAR *text, LINENO static int file_copy(const char *src, const char *dst, mode_t perms, uid_t owner, gid_t group); static int file_cmp_char(const int c1, const int c2); -static void file_canonicalize2(const char *fname, char *buf); +static void file_canonicalize2(const char *filename, char *path, int length); static size_t varlen(const char *dp, const char *dpend); static char * varend(char *dp, char *dpend, const int what); @@ -189,7 +189,7 @@ do_output_file(void) /* ([string filename]) */ /* file image not exist */ if (!BFTST(curbp, BF_SYSBUF) && - fileio_access(fname, 0) >= 0) { + sys_access(fname, 0) >= 0) { errorf("Output file '%s' already exists.", fname); chk_free(fname); return; @@ -674,7 +674,7 @@ static int buf_insert(BUFFER_t *bp, const char *fname, int inserting, const int32_t flags, const char *encoding) { const int startup = ((EDIT_STARTUP & flags) ? TRUE : FALSE); - BUFFER_t *saved_bp = curbp; + BUFFER_t *ocurbp = curbp; int fd, readonly = 0; #if (TODO_POPEN) @@ -750,8 +750,7 @@ buf_insert(BUFFER_t *bp, const char *fname, int inserting, const int32_t flags, BFSET(bp, BF_SYSBUF); } - curbp = bp; - set_hooked(); + set_curbp(bp); numlines = buf_readin(bp, fd, fname, sb.st_size, flags, encoding); vfs_close(fd); fd = -1; @@ -778,8 +777,7 @@ buf_insert(BUFFER_t *bp, const char *fname, int inserting, const int32_t flags, wp->w_status |= WFHARD; } - curbp = saved_bp; - set_hooked(); + set_curbp(ocurbp); return (numlines >= 0 ? 0 : -1); } } @@ -833,7 +831,7 @@ buf_diskchanged(BUFFER_t *bp) struct stat sb; if (bp->b_fname[0] && bp->b_mtime) { /* was read in */ - if (stat(bp->b_fname, &sb) >= 0) { + if (sys_stat(bp->b_fname, &sb) >= 0) { if (sb.st_mtime > bp->b_mtime) { if ((size_t)sb.st_size != bp->b_rsize) { return 2; /* size change */ @@ -961,7 +959,7 @@ file_write(const char *fname, const int32_t flags) BFCLR(curbp, BF_CHANGED); BFCLR(curbp, BF_BACKUP); curbp->b_nummod = 0; - if (stat(curbp->b_fname, &sb) >= 0) { + if (sys_stat(curbp->b_fname, &sb) >= 0) { curbp->b_mtime = sb.st_mtime; /* on disk time-stamp */ curbp->b_rsize = sb.st_size; } @@ -1833,7 +1831,7 @@ buf_writeout(BUFFER_t *bp, const char *fname, int undo, int append /*const char __CUNUSED(undo) oflags = OPEN_W_BINARY | O_WRONLY | O_CREAT; - if (stat(fname, &sb) >= 0) { + if (sys_stat(fname, &sb) >= 0) { bp->b_mode = sb.st_mode; /* update permissions */ } else { oflags |= O_EXCL; @@ -1853,7 +1851,7 @@ buf_writeout(BUFFER_t *bp, const char *fname, int undo, int append /*const char return FALSE; } - curbp = bp; + set_curbp(bp); termlen = file_terminator_get(bp, termbuf, sizeof(termbuf), NULL); infof("Writing ..."); @@ -1931,7 +1929,7 @@ buf_writeout(BUFFER_t *bp, const char *fname, int undo, int append /*const char errorf("Error closing file: File system may be full."); } } - curbp = saved_bp; + set_curbp(saved_bp); return TRUE; error:; @@ -1954,7 +1952,7 @@ error:; } else { vfs_fclose(fp); } - curbp = saved_bp; + set_curbp(saved_bp); return FALSE; } @@ -2193,7 +2191,7 @@ do_edit_file(int version) /* int ([int mode], [string | list file ...]) */ char path[MAX_PATH]; if (NULL == get_xarg(fileidx, "Edit file: ", path, sizeof(path))) { - if (xf_readonly || -1 == fileio_access(curbp->b_fname, W_OK)) { + if (xf_readonly || -1 == sys_access(curbp->b_fname, W_OK)) { BFSET(curbp, BF_RDONLY); } else { BFCLR(curbp, BF_RDONLY); @@ -2718,8 +2716,7 @@ file_load(const char *fname, const int32_t flags, const char *encoding) if (0 == (EDIT_AGAIN & flags) && BFTST(bp, BF_READ)) { trace_log("=> already(2)\n"); - curbp = bp; /* already read */ - set_hooked(); + set_curbp(bp); /* already read */ ret = 2; } else { @@ -2769,9 +2766,7 @@ file_load(const char *fname, const int32_t flags, const char *encoding) buf_type_default(bp); } } - - curbp = bp; - set_hooked(); + set_curbp(bp); lrenumber(bp); if (!noundo) { @@ -3061,7 +3056,7 @@ buf_rollbackups(BUFFER_t *bp, const char *path, int remove_flag) trace_log("\tVERSION=%d\n", bversion); if (bversion <= 1) { if (remove_flag) { - fileio_unlink(path); + sys_unlink(path); } return; } @@ -3088,14 +3083,14 @@ buf_rollbackups(BUFFER_t *bp, const char *path, int remove_flag) } /* $BACKUP// */ sprintf(nname + dirlen, "%c%d%c%s", PATH_SEPERATOR, bversion + 1, PATH_SEPERATOR, filename); - fileio_unlink(nname); + sys_unlink(nname); - if (0 == fileio_access(oname, F_OK)) { + if (0 == sys_access(oname, F_OK)) { if (rename(oname, nname) < 0) { char *tcp = strrchr(nname, PATH_SEPERATOR); *tcp = 0; - (void) fileio_mkdir(nname, 0777 & ~x_umask); + sys_mkdir(nname, 0777 & ~x_umask); *tcp = PATH_SEPERATOR; if (-1 == rename(oname, nname)) { eeprintx("unable to rename '%s' to '%s'", oname, nname); @@ -3213,16 +3208,16 @@ buf_backup(BUFFER_t *bp) #if defined(HAVE_LINK) #if defined(HAVE_LSTAT) /* Let's look at the *real* entry and see if it is a symbolic link. */ - r = lstat(fname, &sb); + r = sys_lstat(fname, &sb); if (r == 0 && (sb.st_mode & S_IFLNK)) { - stat(fname, &sb); + sys_stat(fname, &sb); sb.st_nlink = 1 + 1; /* force backup via copy method */ } else if (r < 0) { sb.st_nlink = 1 + 1; } #else - r = stat(fname, &sb) + r = sys_stat(fname, &sb) if (r < 0) { sb.st_nlink = 1 + 1; } @@ -3419,11 +3414,11 @@ file_copy( if ((ifd = fileio_open(src, OPEN_R_BINARY | O_RDONLY, 0)) < 0) { fileio_close(ofd); - fileio_unlink(dst); + sys_unlink(dst); return TRUE; } - (void) fileio_chmod(dst, perms); /* FIXME: return */ + (void) sys_chmod(dst, perms); /* FIXME: return */ #ifdef HAVE_CHOWN if (-1 == chown(dst, owner, group)) ewprintf("warning: unable to chown(%s)", dst); @@ -4140,18 +4135,21 @@ file_cwdd(int drv, char *cwdd, unsigned length) char * file_canonicalize(const char *filename, char *path, int length) { - if (path && filename != path && length >= MAX_PATH) { - file_canonicalize2(filename, path); /* normal case, correctly sized buffer */ + assert(filename); + + if (path && length >= MAX_PATH) { /* explicit buffer */ + file_canonicalize2(filename, path, length); return path; } else { - char t_path[MAX_PATH]; + char t_path[MAX_PATH] = {0}; - file_canonicalize2(filename, t_path); - if (path && length > 0) { /* local result */ + file_canonicalize2(filename, t_path, sizeof(t_path)); + if (path && length > 0) { /* local result; may truncate/FIXME */ strxcpy(path, (const char *)t_path, length); return path; } + return chk_salloc(t_path); /* dynamic */ } /*NOTREACHED*/ @@ -4159,22 +4157,15 @@ file_canonicalize(const char *filename, char *path, int length) static void -file_canonicalize2(const char *filename, char *path) +file_canonicalize2(const char *filename, char *path, int length) { - char t_filename[MAX_PATH]; - int unc = FALSE, len; - char *p, *s; - - strxcpy(t_filename, filename, sizeof(t_filename)); - filename = t_filename; /* working copy */ - #if defined(_VMS) if (strchr(filename, PATH_SEPERATOR) != NULL) { - filename = sys_fname_unix_to_vms(filename, path, sizeof(t_filename)); + filename = sys_fname_unix_to_vms(filename, path, length); } if (filename != path) { - strxcpy(path, (const char *)filename, sizeof(t_filename)); + strxcpy(path, (const char *)filename, length); } if (strchr(path, ':') == NULL) { @@ -4183,9 +4174,18 @@ file_canonicalize2(const char *filename, char *path) #else /*!VMS*/ + const int filenamelen = strlen(filename) + 1 /*nul*/; + char *t_filename = alloca(filenamelen); + int unc = FALSE, len; + char *p, *s; + + assert(length >= MAX_PATH); + + memcpy(t_filename, filename, filenamelen); /* copy, allow emplace */ #if defined(DOSISH) /* normalize */ file_slashes(t_filename); #endif + filename = t_filename; /* preserve UNC paths (//servername/...) */ if (PATH_SEPERATOR == filename[0] && PATH_SEPERATOR == filename[1]) { @@ -4196,10 +4196,11 @@ file_canonicalize2(const char *filename, char *path) } if (*cursor && cursor > filename + 2) { /* trailing separator */ - while (filename < cursor) { + while (length && filename < cursor) { *path++ = *filename++; + --length; } - strcpy(path, filename); + strxcpy(path, filename, length); unc = TRUE; } } @@ -4218,8 +4219,10 @@ file_canonicalize2(const char *filename, char *path) drv = cwd[0]; cwd += 2; } + } else { cwd = file_cwd(NULL, 0); + if (isalpha(*((unsigned char *)cwd)) && ':' == cwd[1]) { drv = cwd[0]; cwd += 2; @@ -4227,28 +4230,36 @@ file_canonicalize2(const char *filename, char *path) } else if (PATH_SEPERATOR == cwd[0] && PATH_SEPERATOR == cwd[1]) { *path++ = *cwd++; *path++ = *cwd++; - while (*cwd && PATH_SEPERATOR != *cwd) { + length -= 2; + + while (length && *cwd && PATH_SEPERATOR != *cwd) { *path++ = *cwd++; /* preserve UNC */ + --length; } unc = TRUE; } } + if (drv > 0) { /* assign and preserve drive */ *path++ = drv; *path++ = ':'; + length -= 2; } #endif /*DOSISH*/ if (PATH_SEPERATOR == *filename) { /* absolute */ - strcpy(path, filename); + strxcpy(path, filename, length); + } else { if (NULL == cwd) cwd = file_cwd(NULL, 0); if (PATH_SEPERATOR == cwd[0] && 0 == cwd[1]) { /* / */ - sprintf(path, "%c%s", PATH_SEPERATOR, filename); + len = snprintf(path, length, "%c%s", PATH_SEPERATOR, filename); } else { /* */ - sprintf(path, "%s%c%s", cwd, PATH_SEPERATOR, filename); + len = snprintf(path, length, "%s%c%s", cwd, PATH_SEPERATOR, filename); } + if (len < 0 || len >= length) + path[length - 1] = 0; /* overflow/FIXME */ } } @@ -4294,6 +4305,7 @@ file_canonicalize2(const char *filename, char *path) if ((len = (int)strlen(path)) < 2) { return; } + assert(len < length); if (PATH_SEPERATOR == path[len - 1]) { /* XXX/ -> XXX */ path[len - 1] = 0; @@ -4354,4 +4366,5 @@ file_canonicalize2(const char *filename, char *path) } #endif /*! _VMS*/ } + /*end*/ diff --git a/gr/getkey.c b/gr/getkey.c index 303e5a2a..021967cd 100644 --- a/gr/getkey.c +++ b/gr/getkey.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_getkey_c,"$Id: getkey.c,v 1.44 2015/02/11 23:25:13 cvsuser Exp $") +__CIDENT_RCSID(gr_getkey_c,"$Id: getkey.c,v 1.46 2021/10/15 08:58:07 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: getkey.c,v 1.44 2015/02/11 23:25:13 cvsuser Exp $ +/* $Id: getkey.c,v 1.46 2021/10/15 08:58:07 cvsuser Exp $ * Low level input, both keyboard and mouse. * * @@ -299,8 +299,8 @@ io_wait(int state, struct IOEvent *evt, accint_t utmo) assert(EVT_NONE != evt->type); return 0; } - Sleep(250); - } while ((tmo -= 250) > 0); + Sleep(50); + } while ((tmo -= 50) > 0); return event; } #endif /*CYGWIN*/ @@ -1544,5 +1544,3 @@ io_device_pollfds(int *count) #endif /*HAVE_POLL*/ /*end*/ - - diff --git a/gr/keyboard.c b/gr/keyboard.c index 9d46e968..16e146ec 100644 --- a/gr/keyboard.c +++ b/gr/keyboard.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_keyboard_c,"$Id: keyboard.c,v 1.62 2020/05/03 18:25:44 cvsuser Exp $") +__CIDENT_RCSID(gr_keyboard_c,"$Id: keyboard.c,v 1.66 2021/07/18 23:03:19 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: keyboard.c,v 1.62 2020/05/03 18:25:44 cvsuser Exp $ +/* $Id: keyboard.c,v 1.66 2021/07/18 23:03:19 cvsuser Exp $ * Manipulate key maps and bindings. * * @@ -79,6 +79,8 @@ typedef struct _keyboard { int kt_pushed; /* push state. */ } keyboard_t; +#define IS_UNICODE(x) (IS_CHARACTER(x) && x > 0xff) + #define HIST_DEPTH 16 /* AUTOCONF - configuration item. */ #define HIST_NAME 64 /* AUTOCONF */ @@ -125,27 +127,27 @@ static char * historyget(int idx); * internal codes labels */ static const char * keypad_names[] = { - "Ins", /* 0 */ - "End", /* 1 */ - "Down", /* 2 */ - "PgDn", /* 3 */ - "Left", /* 4 */ - "5", /* 5 */ - "Right", /* 6 */ - "Home", /* 7 */ - "Up", /* 8 */ - "PgUp", /* 9 */ - "Del", /* 10 Delete */ - "Plus", /* 11 + */ - "Minus", /* 12 - */ - "Star", /* 13 * */ - "Divide", /* 14 / */ - "Equals", /* 15 = */ - "Enter", /* 16 */ - "Pause", /* 17 */ - "PrtSc", /* 18 */ - "Scroll", /* 19 */ - "NumLock" /* 20 */ + "Ins", /* KEYPAD_0 - 0 */ + "End", /* KEYPAD_1 - 1 */ + "Down", /* KEYPAD_2 - 2 */ + "PgDn", /* KEYPAD_3 - 3 */ + "Left", /* KEYPAD_4 - 4 */ + "5", /* KEYPAD_5 - 5 */ + "Right", /* KEYPAD_6 - 6 */ + "Home", /* KEYPAD_7 - 7 */ + "Up", /* KEYPAD_8 - 8 */ + "PgUp", /* KEYPAD_9 - 9 */ + "Del", /* KEYPAD_DEL - 10 Delete */ + "Plus", /* KEYPAD_PLUS - 11 + */ + "Minus", /* KEYPAD_MINUS - 12 - */ + "Star", /* KEYPAD_STAR - 13 * */ + "Divide", /* KEYPAD_DIV - 14 / */ + "Equals", /* KEYPAD_EQUAL - 15 = */ + "Enter", /* KEYPAD_ENTER - 16 */ + "Pause", /* KEYPAD_PAUSE - 17 */ + "PrtSc", /* KEYPAD_PRTSC - 18 */ + "Scroll", /* KEYPAD_SCROLL - 19 */ + "NumLock" /* KEYPAD_NUMLOCK - 20 */ }; struct map { @@ -209,6 +211,7 @@ static const struct map keystring_tbl[] = { { 4, "OPEN", RANGE_MISC, KEY_OPEN }, { 4, "SAVE", RANGE_MISC, KEY_SAVE }, { 4, "MENU", RANGE_MISC, KEY_MENU }, + { 5, "BREAK", RANGE_MISC, KEY_BREAK }, { 0, NULL, 0, 0} }; @@ -224,88 +227,128 @@ static const struct map keystring_tbl[] = { */ static const struct w32key { WORD vk; /* windows virtual key code */ - int mods; /* modifiers */ -#define MOD_ALL -1 -#define MOD_ENHANCED -2 + int32_t mods; /* modifiers */ +#define VKMOD_ANY -1 +#define VKMOD_ENHANCED -2 +#define VKMOD_NONENHANCED -3 +#define VKMOD_NONSHIFT -4 const char * desc; /* description */ KEY code; /* interval key value */ } w32Keys[] = { - { VK_BACK, 0, "Back", KEY_BACKSPACE }, - { VK_TAB, 0, "TAB", KEY_TAB }, - { VK_BACK, MOD_SHIFT, "S-Back", SHIFT_BACKSPACE }, - { VK_TAB, MOD_SHIFT, "S-TAB", BACK_TAB }, - { VK_BACK, MOD_CTRL, "C-Back", CTRL_BACKSPACE }, - { VK_TAB, MOD_CTRL, "C-TAB", CTRL_TAB }, - { VK_BACK, MOD_META, "A-Back", ALT_BACKSPACE }, - { VK_TAB, MOD_META, "A-TAB", ALT_TAB }, - { VK_ESCAPE, MOD_ALL, "ESC", KEY_ESC }, - { VK_RETURN, MOD_ALL, "Return", KEY_ENTER }, - { VK_RETURN, MOD_ENHANCED, "Return", KEYPAD_ENTER }, - { VK_PAUSE, MOD_ALL, "Pause", KEYPAD_PAUSE }, - { VK_PRIOR, MOD_ALL, "PRIOR", KEY_PAGEUP }, - { VK_NEXT, MOD_ALL, "NEXT", KEY_PAGEDOWN }, - { VK_END, MOD_ALL, "END", KEY_END }, - { VK_HOME, MOD_ALL, "HOME", KEY_HOME }, - { VK_LEFT, MOD_ALL, "LEFT", KEY_LEFT }, - { VK_UP, MOD_ALL, "UP", KEY_UP }, - { VK_RIGHT, MOD_ALL, "RIGHT", KEY_RIGHT }, - { VK_DOWN, MOD_ALL, "DOWN", KEY_DOWN }, - { VK_INSERT, MOD_ALL, "INSERT", KEY_INS }, - { VK_DELETE, MOD_ALL, "DELETE", KEY_DEL }, - { VK_HELP, MOD_ALL, "HELP", KEY_HELP }, - - /* - * XXX - others? - - { VK_POUND/0x9C MOD_ALL, "POUND", KEY_POUND }, - - */ - - /* VK_NUMPAD1 thru VK_NUMPAD0 are ignored allowing user selection via the NumLock */ - - { VK_SUBTRACT, MOD_ALL, "-", KEYPAD_MINUS }, - { VK_MULTIPLY, MOD_ALL, "*", KEYPAD_STAR }, - { VK_ADD, MOD_ALL, "+", KEYPAD_PLUS }, - { VK_DIVIDE, MOD_ALL, "/", KEYPAD_DIV }, + // Only reportsd as an up event, down redirected to event handler. +// { VK_CANCEL, MOD_CTRL, "Ctrl-Break", KEY_BREAK }, + +// { VK_KANA, "IME Kana mode", 0 }, +// { VK_HANGUL, "IME Hangul mode", 0 }, +// { VK_IME_ON, "IME On", 0 }, +// { VK_JUNJA, "IME Junja mode", 0 }, +// { VK_FINAL, "IME final mode", 0 }, +// { VK_HANJA, "IME Hanja mode", 0 }, +// { VK_KANJI, "IME Kanji mode", 0 }, +// { VK_IME_OFF, "IME Off", 0 }, +// { VK_CONVERT, "IME convert", 0 }, +// { VK_NONCONVERT, "IME nonconvert", 0 }, +// { VK_ACCEPT, "IME accept", 0 }, +// { VK_MODECHANGE, "IME mode change", 0 }, + + { VK_BACK, 0, "Back", KEY_BACKSPACE }, + { VK_TAB, 0, "Tab", KEY_TAB }, + { VK_BACK, MOD_SHIFT, "Shift-Back", SHIFT_BACKSPACE }, + { VK_TAB, MOD_SHIFT, "Shift-Tab", BACK_TAB }, + { VK_BACK, MOD_CTRL, "Ctrl-Back", CTRL_BACKSPACE }, + { VK_TAB, MOD_CTRL, "Ctrl-Tab", CTRL_TAB }, + { VK_BACK, MOD_META, "Alt-Back", ALT_BACKSPACE }, + { VK_TAB, MOD_META, "Alt-Tab", ALT_TAB }, + { VK_ESCAPE, VKMOD_ANY, "Esc", KEY_ESC }, + { VK_RETURN, VKMOD_ANY, "Return", KEY_ENTER }, + { VK_RETURN, VKMOD_ENHANCED, "Return", KEYPAD_ENTER }, + { VK_PAUSE, VKMOD_ANY, "Pause", KEYPAD_PAUSE }, + { VK_PRIOR, VKMOD_ANY, "Prior", KEY_PAGEUP }, + { VK_NEXT, VKMOD_ANY, "Next", KEY_PAGEDOWN }, + { VK_END, VKMOD_ANY, "End", KEY_END }, + { VK_HOME, VKMOD_ANY, "Home", KEY_HOME }, + { VK_LEFT, VKMOD_ANY, "Left", KEY_LEFT }, + { VK_UP, VKMOD_ANY, "Uo", KEY_UP }, + { VK_RIGHT, VKMOD_ANY, "Right", KEY_RIGHT }, + { VK_DOWN, VKMOD_ANY, "Down", KEY_DOWN }, + { VK_INSERT, VKMOD_ANY, "Insert", KEY_INS }, + { VK_DELETE, VKMOD_ANY, "Delete", KEY_DEL }, + { VK_HELP, VKMOD_ANY, "Help", KEY_HELP }, + + /* VK_NUMPAD1 thru VK_NUMPAD0 are ignored allowing user selection via the NumLock */ + +// { VK_PRIOR, VKMOD_NONENHANCED, "Keypad-PgUp", KEYPAD_PAGEUP }, +// { VK_NEXT, VKMOD_NONENHANCED, "Keypad-PgDn", KEYPAD_PAGEDOWN }, +// { VK_END, VKMOD_NONENHANCED, "Keypad-End", KEYPAD_END }, +// { VK_HOME, VKMOD_NONENHANCED, "Keypad-Home", KEYPAD_HOME }, +// { VK_LEFT, VKMOD_NONENHANCED, "Keypad-Left", KEYPAD_LEFT }, +// { VK_CLEAR, VKMOD_NONENHANCED, "Keypad-5", KEYPAD_5 }, +// { VK_UP, VKMOD_NONENHANCED, "Keypad-Up", KEYPAD_UP }, +// { VK_RIGHT, VKMOD_NONENHANCED, "Keypad-Right", KEYPAD_RIGHT }, +// { VK_DOWN, VKMOD_NONENHANCED, "Keypad-Down", KEYPAD_DOWN }, +// { VK_INSERT, VKMOD_NONENHANCED, "Keypad-Ins", KEYPAD_INS }, +// { VK_DELETE, VKMOD_NONENHANCED, "Keypad-Delete", KEYPAD_DEL }, + { VK_SUBTRACT, VKMOD_ANY, "Keypad-Minus", KEYPAD_MINUS }, + { VK_MULTIPLY, VKMOD_ANY, "Keypad-Star", KEYPAD_STAR }, + { VK_ADD, VKMOD_ANY, "Keypad-Plus", KEYPAD_PLUS }, + { VK_DIVIDE, VKMOD_ANY, "Keypad-Divide", KEYPAD_DIV }, /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ - { 0x30, MOD_CTRL, "0", CTRL_0 }, - { 0x31, MOD_CTRL, "1", CTRL_1 }, - { 0x32, MOD_CTRL, "2", CTRL_2 }, - { 0x33, MOD_CTRL, "3", CTRL_3 }, - { 0x34, MOD_CTRL, "4", CTRL_4 }, - { 0x35, MOD_CTRL, "5", CTRL_5 }, - { 0x36, MOD_CTRL, "6", CTRL_6 }, - { 0x37, MOD_CTRL, "7", CTRL_7 }, - { 0x38, MOD_CTRL, "8", CTRL_8 }, - { 0x39, MOD_CTRL, "9", CTRL_9 }, - - { VK_F1, MOD_ALL, "F1", F(1) }, - { VK_F2, MOD_ALL, "F2", F(2) }, - { VK_F3, MOD_ALL, "F3", F(3) }, - { VK_F4, MOD_ALL, "F4", F(4) }, - { VK_F5, MOD_ALL, "F5", F(5) }, - { VK_F6, MOD_ALL, "F6", F(6) }, - { VK_F7, MOD_ALL, "F7", F(7) }, - { VK_F8, MOD_ALL, "F8", F(8) }, - { VK_F9, MOD_ALL, "F9", F(9) }, - { VK_F10, MOD_ALL, "F10", F(10) }, - { VK_F11, MOD_ALL, "F11", F(11) }, - { VK_F12, MOD_ALL, "F12", F(12) }, - { VK_F13, MOD_ALL, "F13", F(13) }, - { VK_F14, MOD_ALL, "F14", F(14) }, - { VK_F15, MOD_ALL, "F15", F(15) }, - { VK_F16, MOD_ALL, "F16", F(16) }, - { VK_F17, MOD_ALL, "F17", F(17) }, - { VK_F18, MOD_ALL, "F18", F(18) }, - { VK_F19, MOD_ALL, "F19", F(19) }, - { VK_F20, MOD_ALL, "F20", F(20) }, - - { VK_NUMLOCK, MOD_ALL, "Numlock", KEYPAD_NUMLOCK }, - { VK_SCROLL, MOD_ALL, "Scroll", KEYPAD_SCROLL } + { 0x30, MOD_CTRL, "0", CTRL_0 }, + { 0x31, MOD_CTRL, "1", CTRL_1 }, + { 0x32, MOD_CTRL, "2", CTRL_2 }, + { 0x33, MOD_CTRL, "3", CTRL_3 }, + { 0x34, MOD_CTRL, "4", CTRL_4 }, + { 0x35, MOD_CTRL, "5", CTRL_5 }, + { 0x36, MOD_CTRL, "6", CTRL_6 }, + { 0x37, MOD_CTRL, "7", CTRL_7 }, + { 0x38, MOD_CTRL, "8", CTRL_8 }, + { 0x39, MOD_CTRL, "9", CTRL_9 }, + + /* VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A) */ + + { VK_F1, VKMOD_ANY, "F1", F(1) }, + { VK_F2, VKMOD_ANY, "F2", F(2) }, + { VK_F3, VKMOD_ANY, "F3", F(3) }, + { VK_F4, VKMOD_ANY, "F4", F(4) }, + { VK_F5, VKMOD_ANY, "F5", F(5) }, + { VK_F6, VKMOD_ANY, "F6", F(6) }, + { VK_F7, VKMOD_ANY, "F7", F(7) }, + { VK_F8, VKMOD_ANY, "F8", F(8) }, + { VK_F9, VKMOD_ANY, "F9", F(9) }, + { VK_F10, VKMOD_ANY, "F10", F(10) }, + { VK_F11, VKMOD_ANY, "F11", F(11) }, + { VK_F12, VKMOD_ANY, "F12", F(12) }, + { VK_F13, VKMOD_ANY, "F13", F(13) }, + { VK_F14, VKMOD_ANY, "F14", F(14) }, + { VK_F15, VKMOD_ANY, "F15", F(15) }, + { VK_F16, VKMOD_ANY, "F16", F(16) }, + { VK_F17, VKMOD_ANY, "F17", F(17) }, + { VK_F18, VKMOD_ANY, "F18", F(18) }, + { VK_F19, VKMOD_ANY, "F19", F(19) }, + { VK_F20, VKMOD_ANY, "F20", F(20) }, + + { VK_NUMLOCK, VKMOD_ANY, "Numlock", KEYPAD_NUMLOCK }, + { VK_SCROLL, VKMOD_ANY, "Scroll", KEYPAD_SCROLL }, + +// { VK_OEM_1, // ';:' for US +// { VK_OEM_PLUS, VKMOD_NONSHIFT, "+" '+' }, +// { VK_OEM_COMMA, VKMOD_NONSHIFT, "," ',' }, +// { VK_OEM_MINUS, VKMOD_NONSHIFT, "-" '-' }, +// { VK_OEM_PERIOD, VKMOD_NONSHIFT, "." '.' }, +// { VK_OEM_2, // '/?' for US +// { VK_OEM_3, VKMOD_NONSHIFT, "~", '~' }, +// { VK_OEM_4, // '[{' for US +// { VK_OEM_5, // '\|' for US +// { VK_OEM_6, // ']}' for US +// { VK_OEM_7, // ''"' for US + + { VK_OEM_NEC_EQUAL, VKMOD_ANY, "Keypad-Equal", KEYPAD_EQUAL }, + { VK_ICO_HELP, VKMOD_ANY, "Help", KEY_HELP }, + }; #endif /*WIN32 || __CYGWIN__*/ @@ -324,6 +367,30 @@ key_init(void) { unsigned i; + assert((KEY_MASK & (RANGE_MASK | MOD_MASK)) == 0); + assert((RANGE_MASK & (KEY_MASK | MOD_MASK)) == 0); + assert((MOD_MASK & (KEY_MASK | RANGE_MASK)) == 0); + + assert((RANGE_CHARACTER & ~RANGE_MASK) == 0); + assert((RANGE_KEYPAD & ~RANGE_MASK) == 0 && (RANGE_KEYPAD & RANGE_MASK)); + assert((RANGE_MISC & ~RANGE_MASK) == 0 && (RANGE_MISC & RANGE_MASK)); + assert((RANGE_MULTIKEY & ~RANGE_MASK) == 0 && (RANGE_MULTIKEY & RANGE_MASK)); + assert((RANGE_PRIVATE & ~RANGE_MASK) == 0 && (RANGE_PRIVATE & RANGE_MASK)); + assert((RANGE_BUTTON & ~RANGE_MASK) == 0 && (RANGE_BUTTON & RANGE_MASK)); + assert((RANGE_MASK & ~RANGE_MASK) == 0 && (RANGE_MASK & RANGE_MASK)); + assert((RANGE_MAX & ~RANGE_MASK) == 0 && (RANGE_MAX & RANGE_MASK)); + + assert((MOD_SHIFT & ~MOD_MASK) == 0 && (MOD_SHIFT & MOD_MASK)); + assert((MOD_CTRL & ~MOD_MASK) == 0 && (MOD_CTRL & MOD_MASK)); + assert((MOD_META & ~MOD_MASK) == 0 && (MOD_META & MOD_MASK)); + assert((MOD_APP & ~MOD_MASK) == 0 && (MOD_APP & MOD_MASK)); + + assert(IS_CHARACTER(' ')); + assert(IS_CHARACTER(0x1ff)); + assert(IS_FUNCTION(F(1))); + assert(IS_BUTTON(BUTTON1_DOWN)); + assert(IS_BUTTON(BUTTON_DRAG)); + TAILQ_INIT(&x_kbdlist); x_kbdstack = ll_init(); x_kseqtree = spinit(); @@ -388,7 +455,7 @@ key_shutdown(void) /* Function: key_typeables - * Initialise typeable key assignments + * Enable all typeable key assignments as "self_insert". * * Parameters: * none @@ -401,9 +468,10 @@ key_typeables(void) { unsigned i; - for (i = 0; i < 256; ++i) { /* 0 .. 25, extended ASCII */ + for (i = 0; i <= 0xff; ++i) { /* 0 .. 25, extended ASCII */ key_macro_add(i, NULL); } + key_macro_add(KEY_UNICODE, NULL); /* >= 256 x <= KEY_UNICODE */ } @@ -477,7 +545,7 @@ key_define_key_seq(int key, const char *str) */ sp = spblk(sizeof(keyseq_t) + len); ks = (keyseq_t *) sp->data; - ks->ks_code = (KEY)key_code; + ks->ks_code = (KEY) key_code; memcpy(ks->ks_buf, str, len + 1); sp->key = ks->ks_buf; spenq(sp, x_kseqtree); @@ -579,12 +647,9 @@ keyboard_free(keyboard_t *kp) /* Function: keyboard_find * Keyboard lookup, searchings both the pushed stack or the popped stack. * - * If inc_ref is TRUE, then we are creating a new reference to it. - * Otherwise we're just going to look at it - * * Parameters: * id - Keyboard identifier. - * incref - Reference count increment. + * incref - Reference count increment on success. * * Results: * Keyboard object, otherwise NULL. @@ -761,19 +826,23 @@ key_macro_find(int key) if (curbp->b_keyboard) { /* buffer specific */ sep = stype_lookup(curbp->b_keyboard->kt_macros, (stypekey_t) key); + if (NULL == sep && IS_UNICODE(key)) { + sep = stype_lookup(curbp->b_keyboard->kt_macros, (stypekey_t) KEY_UNICODE); + } } if (NULL == sep) { /* keyboard */ sep = stype_lookup(x_kbdcur->kt_macros, (stypekey_t) key); + if (NULL == sep && IS_UNICODE(key)) { + sep = stype_lookup(x_kbdcur->kt_macros, (stypekey_t) KEY_UNICODE); + } } if (NULL == sep) { cp = "nothing"; - } else { cp = key_macro_value((const object_t *)sep->se_ptr); } - return cp; } @@ -938,7 +1007,7 @@ key_name2code(const char *string, int *lenp) /* function key, F */ if ('F' == *cp && isdigit(cp[1])) { key = atoi(++cp) - 1; - flags |= RANGE_FN; + flags |= RANGE_FUNCTION; while (isdigit(*cp)) { ++cp; } @@ -1121,7 +1190,7 @@ key_name2code(const char *string, int *lenp) supported. #xxx - Substitutes the '#' lead sequence of digits with - the represent value. For example '#!23' result in + the represent value. For example '#123' result in the key code 123. ^x - The '^' characters treats the following character @@ -1141,77 +1210,79 @@ key_name2code(const char *string, int *lenp) For examples review current supplied macro code. (start table,format=simple) - |Key |Description |Keypad|Shift|Ctrl |Alt |Meta | - |ASCII |ASCII key | | x | x | x | x | + |Key |Description |Keypad|Shift|Ctrl |Alt |Meta | + |ASCII |ASCII key | | x | x | x | x | - |F1..F12 |Function keys | | x | x | x | x | + |F1..F12 |Function keys | | x | x | x | x | - |PgDn |Page Down | | | | | | - |PgUp |Page Up | | | | | | + |PgDn |Page Down | | | | | | + |PgUp |Page Up | | | | | | - |Left |Cursor Left | x | x | x | x | | - |Right |Cursor Right | x | x | x | x | | - |Up |Cursor Up | x | x | x | x | | - |Down |Cursor Down | x | x | x | x | | + |Left |Cursor Left | x | x | x | x | | + |Right |Cursor Right | x | x | x | x | | + |Up |Cursor Up | x | x | x | x | | + |Down |Cursor Down | x | x | x | x | | - |Tab | | | | | | | - |Back-Tab |Shifted Tab | | | | | | - |Backspace | | | | | | | - |Back | | | | | | | - |Del |Delete | | | | | | + |Tab | | | | | | | + |Back-Tab |Shifted Tab | | | | | | + |Backspace | | | | | | | + |Back | | | | | | | + |Del |Delete | | | | | | - |Enter |Enter/Return Key | x | | | | | - |Esc |Escape key | | | | | | - |Space |Space ( ) | | | | | | + |Enter |Enter/Return Key | x | | | | | + |Esc |Escape key | | | | | | + |Space |Space ( ) | | | | | | - |Home |Cursor Home | x | | | | | - |End |Cursor End | x | | | | | + |Home |Cursor Home | x | | | | | + |End |Cursor End | x | | | | | - |Ins |Insert | x | | | | | - |Plus |plus (+) | x | | | | | - |Minus |minus (-) | x | | | | | - |Star |star (*) | x | | | | | + |Ins |Insert | x | | | | | + |Plus |Plus (+) | x | | | | | + |Minus |Minus (-) | x | | | | | + |Star |Multiply (*) | x | | | | | + |Divide |Div (/) | x | | | | | + |Equals |Equal (=) | x | | | | | - |Cancel |Cancel Key | | | | | | - |Command |Command Key | | | | | | - |Copy |Copy Key | | | | | | - |Cut |Cut Key | | | | | | - |Exit |Exit Key | | | | | | - |Help |Help Key | | | | | | - |Menu |Menu Key | | | | | | - |Next |Next Key | | | | | | - |Open |Open key | | | | | | - |Paste |Paste key | | | | | | - |Prev |Prev Key | | | | | | - |Prtsc |Print-Screen Key | | | | | | - |Redo |Redo Key | | | | | | - |Replace |Replace | | | | | | - |Save |Save | | | | | | - |Scroll |Scroll | | | | | | - |Search |Search | | | | | | - |Undo |Undo | | | | | | + |Cancel |Cancel Key | | | | | | + |Command |Command Key | | | | | | + |Copy |Copy Key | | | | | | + |Cut |Cut Key | | | | | | + |Exit |Exit Key | | | | | | + |Help |Help Key | | | | | | + |Menu |Menu Key | | | | | | + |Next |Next Key | | | | | | + |Open |Open key | | | | | | + |Paste |Paste key | | | | | | + |Prev |Prev Key | | | | | | + |Prtsc |Print-Screen Key | | | | | | + |Redo |Redo Key | | | | | | + |Replace |Replace | | | | | | + |Save |Save | | | | | | + |Scroll |Scroll | | | | | | + |Search |Search | | | | | | + |Undo |Undo | | | | | | - |Keypad-# |Keypad 0..9 | | x | x | x | x | + |Keypad-# |Keypad 0..9 | | x | x | x | x | - |Grey-# |Aliases for keypad | | | | | | + |Grey-# |Aliases for keypad | | | | | | - |Button# |Button number # | | | | | | + |Button# |Button number # | | | | | | - |Button#-Up | | | | | | | + |Button#-Up | | | | | | | - |Button#-Double | | | | | | | + |Button#-Double | | | | | | | - |Button#-Motion | | | | | | | + |Button#-Motion | | | | | | | - |Button#-Down | | | | | | | + |Button#-Down | | | | | | | - |Private# |Private keys | | | | | | + |Private# |Private keys | | | | | | - |Mouse |Special Mouse Event | | | | | | + |Mouse |Special Mouse Event | | | | | | - |Wheel-Up |Mousewheel up movement | | | | | | + |Wheel-Up |Mousewheel up movement| | | | | | - |wheel-Down |Mousewheel down | | | | | | + |wheel-Down |Mousewheel down | | | | | | movement (end table) @@ -1444,8 +1515,7 @@ key_cache_mouse(ref_t *pp, int code, int front, int x, int y, int win, int where KEY buffer[(sizeof(KEY) + sizeof(struct IOMouse))/2] = {0}, *msg = buffer; - assert(code > 0 && code < KEY_VOID); - + assert(code > 0 && code <= (MOD_MASK|RANGE_MASK|KEY_MASK) && code != KEY_VOID); *msg++ = (KEY)code; if (RANGE_BUTTON == (RANGE_MASK & code)) { @@ -1495,7 +1565,7 @@ key_cache_pop(ref_t *pp, struct IOEvent *evt) assert(used >= (int)sizeof(KEY)); code = (int) *msg; - assert(code > 0 && code < KEY_VOID); + assert(code > 0 && code <= (MOD_MASK|RANGE_MASK|KEY_MASK) && code != KEY_VOID); evt->type = EVT_KEYDOWN; if (RANGE_BUTTON == (RANGE_MASK & code)) { @@ -1546,24 +1616,23 @@ key_cache_test(ref_t *pp) key_to_int(string key, int raw) Macro Description: - The 'key_to_int()' primitive converts a mnemonic key string - to an integer. + The 'key_to_int()' primitive converts a mnemonic key string to an integer. - The following scheme is utilised for encoding internal - key-codes, allowing for simple conversion of ASCII character - code to the internal codes and vice-versa. + The following scheme is utilised for encoding internal key-codes, + allowing for simple conversion of ASCII character code to the internal + codes and vice-versa. Firstly key-codes are divided into several ranges. (start table) [Key Code [Range [Description ] - ! RANGE_ASCII 0x0000..0x0ff ASCII range. - ! RANGE_FN 0x0100..0x1ff Support for up to 255 function keys. - ! RANGE_KEYPAD 0x0200..0x2ff Up to 255 keypad keys. - ! RANGE_MISC 0x0300..0x3ff Miscellaneous. - ! RANGE_MULTIKEY 0x0400..0x7ff Multi-key stroke. - ! RANGE_PRIVATE 0x0800..0x8ff Private key definitions for users. - ! RANGE_BUTTON 0x0900..0x9ff Mouse buttons and movement. + ! RANGE_CHARACTER 0x0 ... 1fffff Character ASCII/Unicode range. + ! RANGE_FUNCTION 0x02000... Function keys. + ! RANGE_KEYPAD 0x03000... Keypad keys. + ! RANGE_MISC 0x04000... Miscellaneous. + ! RANGE_MULTIKEY 0x05000... Multi-key stroke. + ! RANGE_PRIVATE 0x06000... Private key definitions for users. + ! RANGE_BUTTON 0x07000... Mouse buttons and movement. (end table) These ranges can be OR'ed with one or more of the following @@ -1572,9 +1641,9 @@ key_cache_test(ref_t *pp) (start table) [Modifier [Code [Description ] - ! MOD_SHIFT 0x1000 Shift'ed. - ! MOD_CTRL 0x2000 Ctrl. - ! MOD_META 0x4000 Meta or Alt. + ! MOD_SHIFT 0x00200000 Shift'ed. + ! MOD_CTRL 0x00400000 Control. + ! MOD_META 0x00800000 Meta or Alt. (end table) To further simplify key handling, the follow special key @@ -1582,44 +1651,46 @@ key_cache_test(ref_t *pp) (start table) [Key Code [Description ] - ! CTRL_1 .. CTRL_10 - ! ALT_1 .. ALT_10 - ! CTRL_A .. CTRL_Z - ! ALT_Z .. ALT_Z + ! CTRL_1 .. CTRL_10 Control 1 thru 10. + ! ALT_1 .. ALT_10 Alt 1 thru 10. + ! CTRL_A .. CTRL_Z Control A thru Z. + ! ALT_Z .. ALT_Z Alt A thru Z. ! KEY_BACKSPACE Backspace. - ! KEY_CANCEL - ! KEY_CLOSE + ! KEY_BREAK Break. + ! KEY_CANCEL Cancel key. + ! KEY_CLOSE Close key. ! KEY_COMMAND - ! KEY_COPY - ! KEY_COPY_CMD - ! KEY_CUT + ! KEY_COPY Copy to clipboard. + ! KEY_COPY_CMD + ! KEY_CUT Cut to clipboard. ! KEY_CUT_CMD - ! KEY_DEL - ! KEY_END + ! KEY_DEL Delete, rubout. + ! KEY_DOWN Move down, down arrow. + ! KEY_END End key. ! KEY_ENTER Enter key. ! KEY_ESC Escape. ! KEY_EXIT - ! KEY_HELP - ! KEY_HOME - ! KEY_INS - ! KEY_LEFT - ! KEY_MENU + ! KEY_HELP Help, usage. + ! KEY_HOME Home key. + ! KEY_INS Insert. + ! KEY_LEFT Move left, left arrow. + ! KEY_MENU Menu key. ! KEY_NEWLINE New line. - ! KEY_NEXT - ! KEY_OPEN - ! KEY_PAGEDOWN - ! KEY_PAGEUP - ! KEY_PASTE - ! KEY_PREV - ! KEY_REDO + ! KEY_NEXT Next. + ! KEY_OPEN Open key. + ! KEY_PAGEDOWN Page down. + ! KEY_PAGEUP Page up. + ! KEY_PASTE Paste clipboard. + ! KEY_PREV Prior, previous. + ! KEY_REDO Redo, again. ! KEY_REPLACE - ! KEY_RIGHT + ! KEY_RIGHT Move right, right arrow. ! KEY_SAVE - ! KEY_SEARCH + ! KEY_SEARCH Search. ! KEY_TAB Tab. - ! KEY_UNDO - ! KEY_UNDO_CMD - ! KEY_UP + ! KEY_UNDO Undo key. + ! KEY_UNDO_CMD Undo key. + ! KEY_UP Move up, up arrow. ! KEY_WDOWN ! KEY_WDOWN2 ! KEY_WLEFT @@ -1764,7 +1835,7 @@ key_code2name(int key) /* * parse the user definable 'kbd_labels' list, if defined. */ - if (! IS_ASCII(key) && + if (! IS_CHARACTER(key) && NULL != (sp = sym_global_lookup("kbd_labels")) && F_LIST == sp->s_type) { /* * iterate table, abort on error. @@ -1806,9 +1877,9 @@ key_code2name(int key) } } - /* normal ASCII case */ + /* normal character case */ do_normal: - if (IS_ASCII(key)) { + if (IS_CHARACTER(key)) { key_to_char(buf, key); assert(strlen(buf) < sizeof(buf)); return buf; @@ -1831,145 +1902,128 @@ key_code2name(int key) case MOUSE_KEY: desc ="Mouse"; break; - case BACK_TAB: desc = "Back-Tab"; break; - case CTRL_TAB: desc = "Ctrl-Tab"; break; - case ALT_TAB: desc = "Alt-Tab"; break; - case SHIFT_BACKSPACE: desc = "Shift-Backspace"; break; - case CTRL_BACKSPACE: desc = "Ctrl-Backspace"; break; - case ALT_BACKSPACE: desc = "Alt-Backspace"; break; - case KEY_UNDO_CMD: case KEY_UNDO: desc = "Undo"; break; - case KEY_COPY_CMD: case KEY_COPY: desc = "Copy"; break; - case KEY_CUT_CMD: case KEY_CUT: desc = "Cut"; break; - case KEY_PASTE: desc = "Paste"; break; - case KEY_HELP: desc = "Help"; break; - case KEY_REDO: desc = "Redo"; break; - case KEY_SEARCH: desc = "Search"; break; - case KEY_REPLACE: desc = "Replace"; break; - case KEY_CANCEL: desc = "Cancel"; break; - case KEY_COMMAND: desc = "Command"; break; - case KEY_EXIT: desc = "Exit"; break; - case KEY_NEXT: desc = "Next"; break; - case KEY_PREV: desc = "Prev"; break; - case KEY_OPEN: desc = "Open"; break; - case KEY_SAVE: desc = "Save"; break; - case KEY_MENU: desc = "Menu"; break; - + case KEY_BREAK: + desc = "Break"; + break; case WHEEL_UP: desc = "Wheel-Up"; break; - case WHEEL_DOWN: desc = "Wheel-Down"; break; - default: - goto DEFAULT; + sprintf(bp, "#%u", key); + break; } - strcpy(bp, desc); + if (desc) strcpy(bp, desc); } break; - case RANGE_ASCII: { - const char *desc = NULL, - key8 = (char) (key & KEY_MASK); + case RANGE_CHARACTER: { + if ((key & KEY_MASK) > 0xff) { + sprintf(bp, "#%u", key); + } else { + const char *desc = NULL, + key8 = (char) (key & KEY_MASK); - switch (key8) { - case KEY_ENTER: - desc = "Enter"; - break; - case KEY_ESC: - desc = "Esc"; - break; - case KEY_BACKSPACE: - desc = "Backspace"; - break; - case KEY_TAB: - desc = "Tab"; - break; - case ' ': - if (key & (MOD_META|MOD_CTRL|MOD_SHIFT)) { - desc = "Space"; + switch (key8) { + case KEY_ENTER: + desc = "Enter"; + break; + case KEY_ESC: + desc = "Esc"; + break; + case KEY_BACKSPACE: + desc = "Backspace"; + break; + case KEY_TAB: + desc = "Tab"; + break; + case ' ': + if (key & (MOD_META|MOD_CTRL|MOD_SHIFT)) { + desc = "Space"; + } + break; + default: + break; } - break; - default: - break; - } - if (desc) { - strcpy(bp, desc); - bp += strlen(desc); - } else { - *bp++ = key8; - *bp = '\0'; + if (desc) { + strcpy(bp, desc); + bp += strlen(desc); + } else { + *bp++ = key8; + *bp = '\0'; + } } } break; @@ -1978,7 +2032,7 @@ key_code2name(int key) sprintf(bp, "Private-%d", key & KEY_MASK); break; - case RANGE_FN: + case RANGE_FUNCTION: sprintf(bp, "F%d", (key & KEY_MASK) + 1); break; @@ -1999,9 +2053,6 @@ key_code2name(int key) break; case RANGE_MULTIKEY: - case RANGE_MULTIKEY + 0x100: - case RANGE_MULTIKEY + 0x200: - case RANGE_MULTIKEY + 0x300: if (NULL == x_multitbl || (key >= RANGE_MULTIKEY + x_multiseq)) { strcpy(bp, "undefined"); /* out side range */ @@ -2038,8 +2089,7 @@ key_code2name(int key) /*FALLTHRU*/ default: -DEFAULT: - sprintf(bp, "#%d", key); + sprintf(bp, "#%u", key); break; } strcat(buf, ">"); @@ -2049,9 +2099,7 @@ key_code2name(int key) /* Function: key_to_char - * Function to convert a single 8-bit character into the - * canonic notation. - * + * Convert a single 8-bit character into the canonic notation. */ static char * key_to_char(char *buf, int key) @@ -2109,31 +2157,36 @@ key_to_char(char *buf, int key) /* Function: key_execute - * Function called to execute the macro associated - * with an internal key code. + * Execute the macro associated with an internal key code. */ void -key_execute(int c) +key_execute(int key) { sentry_t *sep = NULL; const char *cp; - if (KEY_WINCH == c) { + assert(key >= 0); + if (KEY_WINCH == key) { trace_log("\nKEY_EXEC(WINCH) 0x%x\n", KEY_WINCH); return; /* WINCH event; ignore */ } if (curbp && curbp->b_keyboard) { /* buffer specific */ - sep = stype_lookup(curbp->b_keyboard->kt_macros, c); + sep = stype_lookup(curbp->b_keyboard->kt_macros, key); + if (NULL == sep && IS_UNICODE(key)) { + sep = stype_lookup(curbp->b_keyboard->kt_macros, (stypekey_t) KEY_UNICODE); + } } if (NULL == sep) { /* current keyboard */ - sep = stype_lookup(x_kbdcur->kt_macros, c); + sep = stype_lookup(x_kbdcur->kt_macros, key); + if (NULL == sep && IS_UNICODE(key)) { + sep = stype_lookup(x_kbdcur->kt_macros, (stypekey_t) KEY_UNICODE); + } } if (NULL == sep) { cp = ""; - } else { cp = key_macro_value((const object_t *)sep->se_ptr); } @@ -2142,13 +2195,12 @@ key_execute(int c) * execute/ */ u_chain(); - x_character = (int32_t) c; /* save internal key-code */ + x_character = (int32_t) key; /* save internal key-code */ playback_macro(cp); /* record key-stroke */ /* * history/ - * Commands with names beginning with an - * underscore (_) are ignored. + * Commands with names beginning with an underscore (_) are ignored. */ assert(x_histhead >= 0); assert(x_histhead < HIST_DEPTH); @@ -2176,7 +2228,7 @@ key_execute(int c) } trace_log("\nKEY_EXEC(%s) 0x%x/%d (%02d) => %s\n", - key_code2name(c), (unsigned)c, (int)x_character, x_histhead, cp); + key_code2name(key), (unsigned)key, (int)x_character, x_histhead, cp); if (0 == *cp) { trigger(REG_UNASSIGNED /*REG_INVALID*/); @@ -2567,15 +2619,15 @@ cygwin_to_int(const char *buf) * Parameters: * dwCtrlKeyState - Control key status. * wVirtKeyCode - Virtual key code. - * AsciiChar - Ascii character code, if any. + * CharCode - Character code, if any. * * Results: * nothing */ int -key_mapwin32(unsigned dwCtrlKeyState, unsigned wVirtKeyCode, unsigned AsciiChar) +key_mapwin32(unsigned dwCtrlKeyState, unsigned wVirtKeyCode, unsigned CharCode) { - const struct w32key *key = w32Keys + VSIZEOF(w32Keys); + const struct w32key *key = w32Keys + _countof(w32Keys); int mod = 0, ch = -1; /* modifiers */ @@ -2594,27 +2646,31 @@ key_mapwin32(unsigned dwCtrlKeyState, unsigned wVirtKeyCode, unsigned AsciiChar) } /* virtual keys */ - while (--key >= w32Keys) + while (--key >= w32Keys) { if (key->vk == wVirtKeyCode && - ((key->mods == MOD_ALL) || - (key->mods == MOD_ENHANCED && (dwCtrlKeyState & (ENHANCED_KEY))) || + ((key->mods == VKMOD_ANY) || + (key->mods == VKMOD_ENHANCED && 0 != (dwCtrlKeyState & (ENHANCED_KEY))) || + (key->mods == VKMOD_NONENHANCED && 0 == (dwCtrlKeyState & (ENHANCED_KEY))) || + (key->mods == VKMOD_NONSHIFT && 0 == (dwCtrlKeyState & (SHIFT_PRESSED))) || (key->mods >= 0 && key->mods == mod) )) { if ((ch = key->code) >= 0) { - if (key->mods == MOD_ALL) { + if (key->mods == VKMOD_ANY) { ch |= mod; /* apply modifiers */ } } break; } + } /* ascii */ - if (-1 == ch && (AsciiChar & 0xff)) { - ch = (AsciiChar & 0xff); /* ASCII value */ + assert((CharCode & ~KEY_MASK) == 0); + if (-1 == ch && (CharCode & KEY_MASK)) { + ch = (CharCode & KEY_MASK); /* UNICODE value */ if (MOD_META == mod || (MOD_META|MOD_SHIFT) == mod) { /* - * Special handling for ALT-ASCII .. other modifiers SHIFT and CONTROL - * are already applied to the ASCII value. + * Special handling for ALT-ASCII .. + * other modifiers SHIFT and CONTROL are already applied to the ASCII value. */ if (ch >= 'a' && ch <= 'z') { ch = toupper(ch); @@ -2623,9 +2679,9 @@ key_mapwin32(unsigned dwCtrlKeyState, unsigned wVirtKeyCode, unsigned AsciiChar) } } - trace_log("W32KEY %c%c%c = %d (%s=%s)\n", + trace_log("W32KEY %c%c%c = %d/0x%x (%s=%s)\n", (mod & MOD_META ? 'M' : '.'), (mod & MOD_CTRL ? 'C' : '.'), (mod & MOD_SHIFT ? 'S' : '.'), - ch, (ch == -1 ? "n/a" : (key >= w32Keys ? key->desc : "ASCII")), key_code2name(ch)); + ch, ch, (ch == -1 ? "n/a" : (key >= w32Keys ? key->desc : "ASCII")), key_code2name(ch)); return (ch); } #endif /*WIN32 || __CYGWIN__*/ diff --git a/gr/keywd.c b/gr/keywd.c index 92252e34..3d229f9c 100644 --- a/gr/keywd.c +++ b/gr/keywd.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_keywd_c,"$Id: keywd.c,v 1.94 2020/06/18 14:40:37 cvsuser Exp $") +__CIDENT_RCSID(gr_keywd_c,"$Id: keywd.c,v 1.100 2021/07/03 10:44:33 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: keywd.c,v 1.94 2020/06/18 14:40:37 cvsuser Exp $ +/* $Id: keywd.c,v 1.100 2021/07/03 10:44:33 cvsuser Exp $ * Keyword table. * * @@ -119,9 +119,10 @@ const int cm_version = CM_VERSION; #define VERSION_203 #define VERSION_204 #define VERSION_205 /* 01/04/2020, register(), __lexicalblock(), isclose() and cast_xxx() */ +#define VERSION_206 /* 06/21, UTF8 */ -// #define VERSION_206 /* array's, staged/experimental */ -// #define VERSION_207 /* not implemented/alpha */ +// #define VERSION_207 /* array's, staged/experimental */ +// #define VERSION_208 /* not implemented/alpha */ /* * Keyword table, assumed to be in alphabetic order. @@ -332,7 +333,7 @@ BUILTIN builtin[] = { {"below_eq", MACRO(do_com_op), ARG_INT, 0, MOP_BELOW_EQ, /* arith */ 2, {ARG_NUM | ARG_STRING, ARG_NUM | ARG_STRING}}, -#if defined(VERSION_207) +#if defined(VERSION_208) {"bless", MACRO(do_bless), ARG_INT, 0, 0, /* macro */ 2, {ARG_INT, ARG_OPT | ARG_STRING}}, #endif @@ -461,10 +462,7 @@ BUILTIN builtin[] = { 1, {ARG_OPT | ARG_INT}}, {"create_nested_buffer", MACRO(do_create_buffer), ARG_INT, 0, TRUE, /* buffer */ - 4, {ARG_STRING, - ARG_OPT | ARG_STRING, - ARG_OPT | ARG_INT, - ARG_OPT | ARG_INT}}, + 4, {ARG_STRING, ARG_OPT | ARG_STRING, ARG_OPT | ARG_INT, ARG_OPT | ARG_INT}}, {"create_syntax", MACRO(do_create_syntax), ARG_INT, 0, 0, /* syntax */ 1, {ARG_STRING}}, @@ -926,7 +924,7 @@ BUILTIN builtin[] = { {"get_region", MACRO(do_get_region), ARG_STRING, 0, 0, /* scrap */ 1, {ARG_OPT | ARG_INT}}, -#if defined(VERSION_206) +#if defined(VERSION_207) {"get_system_resources", MACRO(do_get_system_resources), ARG_STRING, 0, 0, /* env */ 1, {ARG_OPT | ARG_INT}}, #endif @@ -1297,7 +1295,7 @@ BUILTIN builtin[] = { {"inq_prompt", MACRO(inq_prompt), ARG_INT, 0, 0, /* screen */ 0, {0}}, -#if defined(VERSION_206) +#if defined(VERSION_207) {"inq_remember_buffer", MACRO(inq_remember_buffer), ARG_STRING, 0, 0, /* kbd */ 1, {ARG_OPT | ARG_INT}}, #endif @@ -1343,9 +1341,14 @@ BUILTIN builtin[] = { ARG_OPT | ARG_LVAL | ARG_INT, ARG_OPT | ARG_LVAL | ARG_INT}}, - {"inq_username", MACRO(inq_username), ARG_STRING, 0, 0, /* env */ +#if defined(VERSION_206) + {"inq_unicode_version", MACRO(inq_unicode_version), ARG_STRING, 0, 0, /* display */ 0, {0}}, +#endif + {"inq_username", MACRO(inq_username), ARG_STRING, 0, 0, /* env */ + 0, {0}}, + {"inq_vfs_mounts", MACRO(inq_vfs_mounts), ARG_LIST, 0, 0, /* file */ 0, {0}}, @@ -1422,7 +1425,7 @@ BUILTIN builtin[] = { {"int_to_key", MACRO(do_int_to_key), ARG_STRING, 0, 0, /* kbd */ 1, {ARG_INT}}, -#if defined(VERSION_206) +#if defined(VERSION_207) #if defined(DO_ARRAY) {"is_array", MACRO(do_is_type), ARG_INT, 0, F_ARRAY, /* var */ 1, {ARG_LVAL | ARG_ANY}}, @@ -1476,7 +1479,7 @@ BUILTIN builtin[] = { {"isfinite", MACRO(do_isfinite), ARG_INT, 0, 0, /* float, arith */ 1, {ARG_FLOAT}}, -#if defined(VERSION_206) +#if defined(VERSION_207) {"isgold", MACRO(do_isgold), ARG_INT, 0, 0, /* string */ 2, {ARG_INT | ARG_STRING, ARG_OPT | ARG_INT}}, #endif @@ -1548,7 +1551,7 @@ BUILTIN builtin[] = { {"length_of_list", MACRO(do_length_of_list), ARG_INT, 0, 0, /* list */ 1, {ARG_LIST}}, -#if defined(VERSION_206) +#if defined(VERSION_207) {"link", MACRO(do_link), ARG_INT, 0, 0, /* file */ 3, {ARG_STR, ARG_STR, ARG_OPT | ARG_INT}}, #endif @@ -2061,6 +2064,11 @@ BUILTIN builtin[] = { ARG_OPT | ARG_INT, ARG_OPT | ARG_INT}}, +#if defined(VERSION_206) + {"set_unicode_version", MACRO(do_set_unicode_version), ARG_INT, 0, 0, /* display */ + 1, {ARG_STRING}}, +#endif + {"set_window", MACRO(do_set_window), ARG_INT, 0, 0, /* window */ 1, {ARG_INT}}, @@ -2117,7 +2125,7 @@ BUILTIN builtin[] = { {"spell_distance", MACRO(do_spell_distance), ARG_UNDEF, 0, 0, /* spell */ 2, {ARG_STRING, ARG_STRING}}, -#if defined(VERSION_206) +#if defined(VERSION_207) {"spell_dictionary", MACRO(do_spell_dictionary), ARG_UNDEF, 0, 0, /* spell */ -3, {ARG_INT, ARG_OPT|ARG_INT, ARG_STRING|ARG_LIST}}, #endif @@ -2334,7 +2342,7 @@ BUILTIN builtin[] = { {"undo", MACRO(do_undo), ARG_INT, 0, -1, /* buffer, kbd */ 3, {ARG_OPT | ARG_INT, ARG_OPT | ARG_INT, ARG_OPT | ARG_INT}}, -#if defined(VERSION_206) +#if defined(VERSION_207) {"unlink", MACRO(do_unlink), ARG_INT, 0, 0, /* file */ 2, {ARG_STR, ARG_OPT | ARG_INT}}, #endif @@ -2388,6 +2396,17 @@ BUILTIN builtin[] = { {"watch", MACRO(do_unimp), ARG_VOID, 0, 0, /* debug */ 0, {0}}, +#if defined(VERSION_206) + {"wcharacterat", MACRO(do_wcharacterat), ARG_INT, 0, 0, /* string */ + 2, {ARG_STRING, ARG_INT}}, + + {"wcwidth", MACRO(do_wcwidth), ARG_INT, 0, 0, /* string */ + 2, {ARG_INT | ARG_STRING, ARG_OPT | ARG_INT}}, + + {"wfirstof", MACRO(do_wfirstof), ARG_INT, 0, 0, /* string */ + 3, {ARG_STRING, ARG_STRING, ARG_OPT | ARG_LVAL | ARG_INT}}, +#endif + {"while", MACRO(do_while), ARG_VOID, 0, 0, /* macro */ 2, {ARG_COND, ARG_OPT | ARG_REST}}, @@ -2401,15 +2420,63 @@ BUILTIN builtin[] = { ARG_OPT | ARG_INT, ARG_OPT | ARG_INT}}, +#if defined(VERSION_206) + {"windex", MACRO(do_windex), ARG_INT, 0, 0, /* string */ + 2, {ARG_STRING, ARG_INT | ARG_STRING}}, +#endif + {"window_color", MACRO(do_window_color), ARG_INT, 0, 0, /* window, screen */ 2, {ARG_OPT | ARG_INT, ARG_OPT | ARG_INT}}, +#if defined(VERSION_206) + {"wlastof", MACRO(do_wlastof), ARG_INT, 0, 0, /* string */ + 3, {ARG_STRING, ARG_STRING, ARG_OPT | ARG_LVAL | ARG_INT }}, + + {"wlower", MACRO(do_wlower), ARG_STRING, 0, 0, /* string */ + 1, {ARG_INT | ARG_STRING}}, + + {"wrindex", MACRO(do_wrindex), ARG_INT, 0, 0, /* string */ + 2, {ARG_STRING, ARG_INT | ARG_STRING}}, +#endif + {"write_block", MACRO(do_write_block), ARG_INT, 0, 0, /* file, scrap */ 4, {ARG_OPT | ARG_STRING, ARG_OPT | ARG_INT, ARG_OPT | ARG_INT, ARG_OPT | ARG_INT}}, {"write_buffer", MACRO(do_write_buffer), ARG_INT, 0, 0, /* file, buffer */ 2, {ARG_OPT | ARG_STRING, ARG_OPT | ARG_INT}}, + {"write_buffer", MACRO(do_write_buffer), ARG_INT, 0, 0, /* file, buffer */ + 2, {ARG_OPT | ARG_STRING, ARG_OPT | ARG_INT}}, + +#if defined(VERSION_206) + {"wstrcasecmp", MACRO(do_wstrcasecmp), ARG_INT, 0, 0, /* string */ + 3, {ARG_STRING, ARG_STRING, ARG_OPT | ARG_INT}}, + + {"wstrcmp", MACRO(do_wstrcmp), ARG_INT, 0, 0, /* string */ + 3, {ARG_STRING, ARG_STRING, ARG_OPT | ARG_INT}}, + + {"wstrlen", MACRO(do_wstrlen), ARG_INT, 0, 0, /* string */ + 2, {ARG_STRING | ARG_LIST, ARG_OPT | ARG_INT}}, + + {"wstrnlen", MACRO(do_wstrnlen), ARG_INT, 0, 0, /* string */ + 3, {ARG_STRING | ARG_LIST, ARG_INT, ARG_OPT | ARG_INT}}, + + {"wstrpbrk", MACRO(do_wstrpbrk), ARG_INT, 0, 0, /* string */ + 2, {ARG_STRING, ARG_STRING}}, + + {"wstrrstr", MACRO(do_wstrrstr), ARG_INT, 0, 0, /* string */ + 2, {ARG_STRING, ARG_STRING}}, + + {"wstrstr", MACRO(do_wstrstr), ARG_INT, 0, 0, /* string */ + 2, {ARG_STRING, ARG_STRING}}, + + {"wsubstr", MACRO(do_wsubstr), ARG_STRING, 0, 0, /* string */ + 3, {ARG_STRING, ARG_INT, ARG_OPT | ARG_INT}}, + + {"wupper", MACRO(do_wupper), ARG_STRING, 0, 0, /* string */ + 1, {ARG_INT | ARG_STRING}}, +#endif + {"|", MACRO(do_com_op), ARG_UNDEF, 0, MOP_BOR, /* arith */ 2, {ARG_INT, ARG_INT}}, @@ -2480,7 +2547,7 @@ builtin_init(void) #if !defined(__NOFUNCTIONS__) if (i && b_sort(bp - 1, bp) > 0) { - trace_log("\t'%s' and '%s' are not ordered\n", bp[-1].b_name, bp->b_name); + trace_log("\t'%s' and '%s' are not ordered\n", bp[-1].b_name, c_string(bp->b_name)); } #endif } diff --git a/gr/kill.c b/gr/kill.c index 6528583d..bc614d8b 100644 --- a/gr/kill.c +++ b/gr/kill.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_kill_c,"$Id: kill.c,v 1.22 2020/04/21 00:01:55 cvsuser Exp $") +__CIDENT_RCSID(gr_kill_c,"$Id: kill.c,v 1.23 2021/10/18 13:17:45 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: kill.c,v 1.22 2020/04/21 00:01:55 cvsuser Exp $ +/* $Id: kill.c,v 1.23 2021/10/18 13:17:45 cvsuser Exp $ * Scrap buffer. * * @@ -34,8 +34,8 @@ __CIDENT_RCSID(gr_kill_c,"$Id: kill.c,v 1.22 2020/04/21 00:01:55 cvsuser Exp $") #include "undo.h" -#define K_START BUFFER_t *savedbp = curbp; curbp = scrbp; set_hooked() -#define K_END curbp = savedbp; set_hooked() +#define K_START BUFFER_t *savedbp = curbp; set_curbp(scrbp) +#define K_END set_curbp(savedbp) static BUFFER_t * scrap_bp = NULL; /* system scrap buffer */ diff --git a/gr/line.c b/gr/line.c index 2bd9003e..8238f190 100644 --- a/gr/line.c +++ b/gr/line.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_line_c,"$Id: line.c,v 1.44 2020/06/05 15:40:35 cvsuser Exp $") +__CIDENT_RCSID(gr_line_c,"$Id: line.c,v 1.46 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: line.c,v 1.44 2020/06/05 15:40:35 cvsuser Exp $ +/* $Id: line.c,v 1.46 2021/07/05 15:01:27 cvsuser Exp $ * Line management. * * @@ -24,7 +24,6 @@ __CIDENT_RCSID(gr_line_c,"$Id: line.c,v 1.44 2020/06/05 15:40:35 cvsuser Exp $") #include #include "../libvfs/vfs.h" -#include "../libchartable/libchartable.h" #include "accum.h" /* acc_...() */ #include "anchor.h" /* anchor_...() */ @@ -416,7 +415,7 @@ lchange(int flag, LINENO count) if (count < 1) count = 1; for (cline = line, eline = line + count; cline < eline; ++cline) { - if (NULL != (lp = linep(cline))) { + if (NULL != (lp = vm_lock_line(cline))) { const LINENO length = llength(lp); if (bp->b_maxlinep == lp) { /* length change? */ @@ -432,6 +431,8 @@ lchange(int flag, LINENO count) bp->b_maxlinep = (LINE_t *)lp; } } + + vm_unlock(cline); } } } @@ -627,7 +628,7 @@ linsertc(int ch) const int isutf8 = buf_isutf8(bp); /* legacy/dialog buffer encoding */ if (isutf8 && MCHAR_ISUTF8(ch)) { - linsert((const char *)buffer, mchar_ucs_encode(ch, buffer), FALSE); + linsert((const char *)buffer, Wctoutf8(ch, buffer, sizeof(buffer)), FALSE); } else { /* NORMAL */ *((unsigned char *)buffer) = (unsigned char) ch; @@ -708,10 +709,10 @@ lnewline(void) return; } llinepad(); - if (NULL != (lp = vm_lock_line(cline))) { + if (NULL != (lp = vm_lock_line2(cline))) { assert(cline == *cur_line); assert(ccol == *cur_col); - newlinedot(lp, line_offset2(lp, cline, ccol, LOFFSET_NORMAL_MATCH)); + newlinedot(lp, line_offset_const(lp, cline, ccol, LOFFSET_NORMAL_MATCH)); vm_unlock(cline); } } @@ -798,10 +799,12 @@ linsert(const char *buffer, LINENO length, int nl) assert(nl || length > 0); llinepad(); - lp = vm_lock_line(cline); - assert(lp != x_static_line); + lp = vm_lock_line2(cline); + assert(lp); + if (NULL == lp) + goto false_exit; - dot = line_offset2(lp, cline, ccol, LOFFSET_FILL_VSPACE); + dot = line_offset_fill(lp, cline, ccol, LOFFSET_FILL_VSPACE); if (length) { if (FALSE == lexpand(lp, dot, length)) { goto false_exit; @@ -860,8 +863,8 @@ lwrite(const char *buffer, LINENO length, int characters) int replace = FALSE; LINE_t *lp; - lp = vm_lock_line(cline); - dot = line_offset2(lp, cline, ccol, LOFFSET_FILL_SPACE); + lp = vm_lock_line2(cline); + dot = line_offset_fill(lp, cline, ccol, LOFFSET_FILL_SPACE); count = line_sizeregion(lp, ccol, dot, characters, &olength, NULL); if (olength < length) { if ((dot + length) <= (LINENO)llength(lp)) { @@ -891,6 +894,7 @@ lwrite(const char *buffer, LINENO length, int characters) } } } + *cur_col += characters; /* XXX - issues when line is filled */ vm_unlock(cline); } @@ -910,7 +914,7 @@ ldeletec(int cnt) while (cnt > 0) { const LINENO cline = *cur_line, ccol = *cur_col; const LINENO numlines = curbp->b_numlines; - LINENO count, length, dot; + LINENO count = 1, length, dot; LINE_t *lp; ED_TRACE(("\tline:%d,col:%d,numlines:%d,cnt:%d\n", cline, ccol, numlines, cnt)) @@ -920,14 +924,15 @@ ldeletec(int cnt) break; } - lp = vm_lock_line(cline); - dot = line_offset2(lp, cline, ccol, LOFFSET_NORMAL_MATCH); - if (0 == (count = line_sizeregion(lp, ccol, dot, cnt, &length, NULL))) { - count = length = 1; /* */ + if (NULL != (lp = vm_lock_line2(cline))) { + dot = line_offset_const(lp, cline, ccol, LOFFSET_NORMAL_MATCH); + if (0 == (count = line_sizeregion(lp, ccol, dot, cnt, &length, NULL))) { + count = length = 1; /* */ + } + ldeletedot(length, dot); + vm_unlock(cline); } - ldeletedot(length, dot); - vm_unlock(cline); - cnt -= count; + cnt -= count; /* MCHAR/characters */ } ED_TRACE(("==> cnt:%d\n", cnt)) } @@ -1029,19 +1034,20 @@ lreplacedot(const char *buffer, int ins, int del, int dot, int *edot) /* * simple case/ - * insert-size < delete-size and no new-lines + * insert-size < delete-size and no new-lines. */ - lp = vm_lock_line(cline); - if (ledit(lp, 0)) { - lchange(WFEDIT, 0); - u_replace((const char *)(ltext(lp) + dot), del, ins); - if (diff) { - line_move(lp, dot + ins, dot + del, llength(lp) - dot - del); - lp->l_used -= diff; + if (NULL != (lp = vm_lock_line2(cline))) { + if (ledit(lp, 0)) { + lchange(WFEDIT, 0); + u_replace((const char *)(ltext(lp) + dot), del, ins); + if (diff) { + line_move(lp, dot + ins, dot + del, llength(lp) - dot - del); + lp->l_used -= diff; + } + line_set(lp, dot, buffer, ins, *cur_attr, 1); } - line_set(lp, dot, buffer, ins, *cur_attr, 1); + vm_unlock(cline); } - vm_unlock(cline); if (edot) { *edot = dot + ins; } @@ -1072,8 +1078,7 @@ ldeletedot(LINENO cnt, int dot) ED_TRACE(("ldeletedot(line:%d, col:%d, dot:%d, cnt:%d)\n", *cur_line, *cur_col, dot, cnt)) assert(cnt > 0); - if (NULL == (lp = vm_lock_line(cline))) { - vm_unlock(cline); + if (NULL == (lp = vm_lock_line2(cline))) { return; } @@ -1505,4 +1510,5 @@ line_set(LINE_t *lp, LINENO dst, const char *src, LINENO len, LINEATTR attr, LIN } } } + /*end*/ diff --git a/gr/lisp.c b/gr/lisp.c index 2f237a8b..a6787190 100644 --- a/gr/lisp.c +++ b/gr/lisp.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_lisp_c,"$Id: lisp.c,v 1.44 2020/06/18 14:40:37 cvsuser Exp $") +__CIDENT_RCSID(gr_lisp_c,"$Id: lisp.c,v 1.45 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: lisp.c,v 1.44 2020/06/18 14:40:37 cvsuser Exp $ +/* $Id: lisp.c,v 1.45 2021/07/05 15:01:27 cvsuser Exp $ * List primitives. * * @@ -652,7 +652,7 @@ atom_assign_sym(const LIST *lp, SYMBOL *sp) case F_NULL: return 1; -// case F_STR: +// case F_STR: // case F_ID: // case F_SYM: // case F_REG: diff --git a/gr/lock.c b/gr/lock.c index 19dc609a..048bfc6e 100644 --- a/gr/lock.c +++ b/gr/lock.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_lock_c,"$Id: lock.c,v 1.30 2020/06/03 16:22:15 cvsuser Exp $") +__CIDENT_RCSID(gr_lock_c,"$Id: lock.c,v 1.31 2021/06/02 13:25:28 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: lock.c,v 1.30 2020/06/03 16:22:15 cvsuser Exp $ +/* $Id: lock.c,v 1.31 2021/06/02 13:25:28 cvsuser Exp $ * File locking support. When two users edit the same file at the same time, they are likely @@ -263,11 +263,7 @@ info_get(const char *lfile, Info_t *i) memset((char *)i, 0, sizeof (*i)); /* zap */ /* is symbolic link? */ -#if defined(unix) || defined(__APPLE__) - if (lstat(lfile, &st) == -1) -#else if (sys_lstat(lfile, &st) == -1) -#endif { if (errno == ENOENT) { return 1; /* doesnt exist */ @@ -285,17 +281,10 @@ info_get(const char *lfile, Info_t *i) // n >= (int)sizeof(buf)-1) { // return -1; // } -#if defined(unix) || defined(__APPLE__) - if ((n = readlink(lfile, buf, sizeof (buf)-1)) == -1 || - n >= (int)sizeof(buf)-1) { - return -1; - } -#else if ((n = sys_readlink(lfile, buf, sizeof (buf)-1)) == -1 || n >= (int)sizeof(buf)-1) { return -1; } -#endif buf[n] = '\0'; /* user */ @@ -366,11 +355,7 @@ info_get(const char *lfile, Info_t *i) static int lck_create(const Info_t *i, const char *buf) { -#if defined(unix) || defined(__APPLE__) - return symlink(buf, i->i_file); -#else return sys_symlink(buf, i->i_file); -#endif } @@ -387,11 +372,7 @@ static int lck_remove(const Info_t *i) { if (i->i_file) { -#if defined(unix) || defined(__APPLE__) - return unlink(i->i_file); -#else return sys_unlink(i->i_file); -#endif } return -1; } diff --git a/gr/m_backup.c b/gr/m_backup.c index 1d16cec0..89bb145f 100644 --- a/gr/m_backup.c +++ b/gr/m_backup.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_backup_c,"$Id: m_backup.c,v 1.18 2014/10/22 02:33:00 ayoung Exp $") +__CIDENT_RCSID(gr_m_backup_c,"$Id: m_backup.c,v 1.19 2021/06/02 13:40:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_backup.c,v 1.18 2014/10/22 02:33:00 ayoung Exp $ +/* $Id: m_backup.c,v 1.19 2021/06/02 13:40:03 cvsuser Exp $ * File backup option/configuration primitives. * * @@ -25,6 +25,7 @@ __CIDENT_RCSID(gr_m_backup_c,"$Id: m_backup.c,v 1.18 2014/10/22 02:33:00 ayoung #include "m_backup.h" /* public interface */ +#include "system.h" #include "accum.h" /* acc_...() */ #include "buffer.h" /* buf_...() */ #include "debug.h" /* trace_...() */ @@ -202,7 +203,7 @@ bkcfg_ask(const char *fname) if (! xf_backups) { ret = FALSE; } else { - if (stat(fname, &sb) >= 0) { + if (sys_stat(fname, &sb) >= 0) { if (x_backup_dont && sb.st_size >= x_backup_dont) { ret = FALSE; } else if (x_backup_ask && sb.st_size >= x_backup_ask) { diff --git a/gr/m_buf.c b/gr/m_buf.c index 842dad0d..1f67d435 100644 --- a/gr/m_buf.c +++ b/gr/m_buf.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_buf_c,"$Id: m_buf.c,v 1.55 2020/06/03 16:18:30 cvsuser Exp $") +__CIDENT_RCSID(gr_m_buf_c,"$Id: m_buf.c,v 1.56 2021/10/18 13:12:49 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_buf.c,v 1.55 2020/06/03 16:18:30 cvsuser Exp $ +/* $Id: m_buf.c,v 1.56 2021/10/18 13:12:49 cvsuser Exp $ * Buffer primitives. * * @@ -1994,8 +1994,7 @@ do_set_buffer(void) /* int (int bufnum) */ curbp->b_col = curwp->w_col; curbp->b_top = curwp->w_top_line; } - curbp = bp; - set_hooked(); + set_curbp(bp); } @@ -2124,8 +2123,7 @@ do_create_edge(void) /* int ([int direction]) */ if (wp) { if (WD_RIGHT == i || WD_DOWN == i) { - curwp = wp; - set_hooked(); + set_curwp(wp); } ret = 1; } else { diff --git a/gr/m_display.c b/gr/m_display.c index 4f03cde7..f29b1708 100644 --- a/gr/m_display.c +++ b/gr/m_display.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_display_c,"$Id: m_display.c,v 1.27 2020/06/05 15:51:34 cvsuser Exp $") +__CIDENT_RCSID(gr_m_display_c,"$Id: m_display.c,v 1.29 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_display.c,v 1.27 2020/06/05 15:51:34 cvsuser Exp $ +/* $Id: m_display.c,v 1.29 2021/07/05 15:01:27 cvsuser Exp $ * Display primitives. * * @@ -503,7 +503,7 @@ flag_override(const char *name, int length, int *value) trace_ilog(value ? "\t %*s=%d\n" : "\t %*s\n", namelength, name, (value ? *value : -1)); for (i = 0; i < (unsigned)(sizeof(doflagnames)/sizeof(doflagnames[0])); ++i) - if (namelength == (size_t)doflagnames[i].f_length && + if (namelength == doflagnames[i].f_length && 0 == str_nicmp(doflagnames[i].f_name, name, namelength)) { return doflagnames[i].f_value; } @@ -864,4 +864,5 @@ do_view_screen(void) /* int () */ } acc_assign_int(ret); } + /*end*/ diff --git a/gr/m_errno.c b/gr/m_errno.c index 8439d62e..c02da1b4 100644 --- a/gr/m_errno.c +++ b/gr/m_errno.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_errno_c,"$Id: m_errno.c,v 1.26 2014/10/22 02:33:02 ayoung Exp $") +__CIDENT_RCSID(gr_m_errno_c,"$Id: m_errno.c,v 1.27 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_errno.c,v 1.26 2014/10/22 02:33:02 ayoung Exp $ +/* $Id: m_errno.c,v 1.27 2021/07/05 15:01:27 cvsuser Exp $ * errno symbol primitives. * * @@ -845,7 +845,7 @@ do_perror(void) /* ([int errno], string format, ...) */ { int msglen = -1, errlen; const int xerrno = get_xinteger(1, (int) *x_errno_ptr); - const char *msg = print_formatted(2, &msglen); + const char *msg = print_formatted(2, &msglen, NULL); char err[80]; errlen = sxprintf(err, sizeof(err), ": %s (%d)", str_error(xerrno), xerrno); diff --git a/gr/m_file.c b/gr/m_file.c index cf9fdab3..b8d839b6 100644 --- a/gr/m_file.c +++ b/gr/m_file.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_file_c,"$Id: m_file.c,v 1.41 2021/04/16 11:45:43 cvsuser Exp $") +__CIDENT_RCSID(gr_m_file_c,"$Id: m_file.c,v 1.43 2021/06/19 09:42:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_file.c,v 1.41 2021/04/16 11:45:43 cvsuser Exp $ +/* $Id: m_file.c,v 1.43 2021/06/19 09:42:03 cvsuser Exp $ * File primitives. * * @@ -326,7 +326,7 @@ do_searchpath(void) /* int (string searchpath, string file, [string strxcat(path, extension, sizeof(path)); } - if (0 == stat(path, &sb)) { + if (0 == sys_stat(path, &sb)) { const char *result = path; if (expand) { @@ -1468,7 +1468,7 @@ do_mkdir(void) /* (string pathname, int mode = 0755) */ if (ret && EEXIST != ret) { struct stat sb; - if (0 == stat(pathname, &sb) && S_ISDIR(sb.st_mode)) { + if (0 == sys_stat(pathname, &sb) && S_ISDIR(sb.st_mode)) { ret = 0; /* ignore, false error */ } } @@ -2781,11 +2781,7 @@ do_readlink(void) /* string (string path, [string &link]) */ //TODO // path = file_tilder(path, t_path, sizeof(t_path)); // if (vfs_readlink(name, link, sizeof(link)-1) == -1) -#if defined(unix) || defined(__APPLE__) - if ((ret = readlink(name, linkpath, sizeof(linkpath)-1)) <= -1) { -#else if ((ret = sys_readlink(name, linkpath, sizeof(linkpath)-1)) <= -1) { -#endif acc_assign_int(errno == ENOSYS ? 0 : -1); } else { @@ -2939,12 +2935,7 @@ do_symlink(void) /* int (string, string) */ int ret = -1; if (path1 && path2) { -#if defined(unix) || defined(__APPLE__) - if ((ret = symlink(path1, path2)) <= -1) -#else - if ((ret = sys_symlink(path1, path2)) <= -1) -#endif - { + if ((ret = sys_symlink(path1, path2)) <= -1) { system_call(ret); } } else { @@ -3418,5 +3409,5 @@ do_mktemp(void) /* string (string path) */ acc_assign_str("", -1); } } -/*end*/ +/*end*/ diff --git a/gr/m_line.c b/gr/m_line.c index cffa6ed2..e0cbda6b 100644 --- a/gr/m_line.c +++ b/gr/m_line.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_line_c,"$Id: m_line.c,v 1.19 2020/04/21 00:01:56 cvsuser Exp $") +__CIDENT_RCSID(gr_m_line_c,"$Id: m_line.c,v 1.20 2021/06/10 06:13:02 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_line.c,v 1.19 2020/04/21 00:01:56 cvsuser Exp $ +/* $Id: m_line.c,v 1.20 2021/06/10 06:13:02 cvsuser Exp $ * Line primitives. * * @@ -188,6 +188,7 @@ do_find_marker(void) /* int ([int marker = L_MARKED]) */ const lineflags_t marker = get_xinteger(1, L_MARKED); const LINENO numlines = curbp->b_numlines; LINENO line; + LINE_t *lp; int ret = 0; if (0 == (L_USER_MASK & marker) || 1 != flagcount(marker)) { @@ -196,16 +197,16 @@ do_find_marker(void) /* int ([int marker = L_MARKED]) */ } for (line = *cur_line + 1; line <= numlines; ++line) { /*NEWLINE*/ - LINE_t *lp = vm_lock_line(line); - - if (marker & lp->l_uflags) { - lp->l_uflags &= ~marker; /* clear */ + if (NULL != (lp = vm_lock_line2(line))) { + if (marker & lp->l_uflags) { + lp->l_uflags &= ~marker; /* clear */ + vm_unlock(line); + *cur_line = line; + ret = 1; + break; + } vm_unlock(line); - *cur_line = line; - ret = 1; - break; } - vm_unlock(line); } acc_assign_int(ret); @@ -362,11 +363,12 @@ do_set_line_flags(void) /* int ([int bufnum], [int start], [int end], [i } for (line = start; line < end; ++line) { - LINE_t *lp = vm_lock_line(line); - - lp->l_uflags &= and_mask; - lp->l_uflags |= or_value; - vm_unlock(line); + LINE_t *lp = vm_lock_line2(line); + if (lp) { + lp->l_uflags &= and_mask; + lp->l_uflags |= or_value; + vm_unlock(line); + } ++ret; } } @@ -473,7 +475,7 @@ do_find_line_flags(void) /* int ([int bufnum], [int lineno], LINENO line; for (line = (uint32_t) start; line; --line) { - LINE_t *lp = vm_lock_line(line); + const LINE_t *lp = vm_lock_line(line); if (((mode & LF_MATCH_EQ) && (((lp->l_uflags & and_mask) | or_value) == value)) || ((mode & LF_MATCH_ANY) && ((lp->l_uflags & and_mask) != 0))) { diff --git a/gr/m_mchar.c b/gr/m_mchar.c index b8198610..a6d4a7e2 100644 --- a/gr/m_mchar.c +++ b/gr/m_mchar.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_mchar_c,"$Id: m_mchar.c,v 1.11 2014/10/22 02:33:05 ayoung Exp $") +__CIDENT_RCSID(gr_m_mchar_c,"$Id: m_mchar.c,v 1.15 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_mchar.c,v 1.11 2014/10/22 02:33:05 ayoung Exp $ +/* $Id: m_mchar.c,v 1.15 2021/07/05 15:01:27 cvsuser Exp $ * Multibyte/locale primitives. * * @@ -22,6 +22,8 @@ __CIDENT_RCSID(gr_m_mchar_c,"$Id: m_mchar.c,v 1.11 2014/10/22 02:33:05 ayoung Ex #include #include "m_mchar.h" +#include "../libchartable/libchartable.h" +#include "../libwidechar/widechar.h" #include "accum.h" /* acc_...() */ #include "buffer.h" /* buf_...() */ @@ -89,12 +91,12 @@ __CIDENT_RCSID(gr_m_mchar_c,"$Id: m_mchar.c,v 1.11 2014/10/22 02:33:05 ayoung Ex ! SCSU BFTYP_SCSU ! UTF-7 BFTYP_UTF7 65002 - ! UTF-4 BFTYP_UCS4 - ! UTF-4be BFTYP_UCS4 - ! UTF-4le BFTYP_UCS4 - ! UTF-2 BFTYP_UCS2 + ! UTF-2 BFTYP_UCS2 BFTYP_UTF16 aliases ! UTF-2be BFTYP_UCS2 ! UTF-2le BFTYP_UCS2 + ! UTF-4 BFTYP_UCS4 BFTYP_UTF32 aliases + ! UTF-4be BFTYP_UCS4 + ! UTF-4le BFTYP_UCS4 ! cp437 BFTYP_SBCS 437 OEM/US, ASCII ! cp737 BFTYP_SBCS 737 Greek, ISO-8859-7 @@ -301,4 +303,43 @@ inq_encodings(void) /* list ([int flags]) */ { //TODO } + + +void +do_wcwidth(void) /* int (string str | int character), [int default]] */ +{ + int width = -1; + + if (isa_integer(1)) { + if ((width = ucs_width(get_xinteger(1, 0))) < 0) { + width = get_xinteger(2, -1); + } + + } else if (isa_string(1)) { + width = utf8_swidth(get_str(1)); + } + + acc_assign_int((accint_t) width); +} + + +void +do_set_unicode_version(void) +{ + int version = -1; + + if (isa_string(1)) { + version = ucs_width_set(get_str(1)); + } + + acc_assign_int((accint_t) version); +} + + +void +inq_unicode_version(void) +{ + acc_assign_str(ucs_width_version(), -1); +} + /*end*/ diff --git a/gr/m_mchar.h b/gr/m_mchar.h index 070c11bc..5214f23f 100644 --- a/gr/m_mchar.h +++ b/gr/m_mchar.h @@ -1,11 +1,11 @@ #ifndef GR_M_MCHAR_H_INCLUDED #define GR_M_MCHAR_H_INCLUDED #include -__CIDENT_RCSID(gr_m_mchar_h,"$Id: m_mchar.h,v 1.7 2014/10/22 02:33:05 ayoung Exp $") +__CIDENT_RCSID(gr_m_mchar_h,"$Id: m_mchar.h,v 1.9 2021/06/13 16:01:34 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_mchar.h,v 1.7 2014/10/22 02:33:05 ayoung Exp $ +/* $Id: m_mchar.h,v 1.9 2021/06/13 16:01:34 cvsuser Exp $ * Multiple-byte/local primitives. * * @@ -29,6 +29,10 @@ extern void do_set_encoding(void); extern void inq_encoding(void); extern void inq_encodings(void); +extern void do_wcwidth(void); +extern void do_set_unicode_version(void); +extern void inq_unicode_version(void); + __CEND_DECLS #endif /*GR_M_MCHAR_H_INCLUDED*/ diff --git a/gr/m_msg.c b/gr/m_msg.c index eb660d3c..965767d8 100644 --- a/gr/m_msg.c +++ b/gr/m_msg.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_msg_c,"$Id: m_msg.c,v 1.30 2014/10/27 23:27:55 ayoung Exp $") +__CIDENT_RCSID(gr_m_msg_c,"$Id: m_msg.c,v 1.31 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_msg.c,v 1.30 2014/10/27 23:27:55 ayoung Exp $ +/* $Id: m_msg.c,v 1.31 2021/07/05 15:01:27 cvsuser Exp $ * Message and formatting primitives. * * @@ -435,7 +435,7 @@ void do_message(void) /* (string format, ...) */ { int len = -1; - const char *cp = print_formatted(0, &len); + const char *cp = print_formatted(0, &len, NULL); if (cp && len) { infos(cp); @@ -523,7 +523,7 @@ void do_error(void) /* int (string format, ...) */ { int len = -1; - const char *cp = print_formatted(0, &len); + const char *cp = print_formatted(0, &len, NULL); if (cp && len) { errorf("%s", cp); @@ -630,7 +630,7 @@ do_print(void) /* int () */ void do_printf(void) /* (string format, ...) */ { - const char *cp = print_formatted(0, NULL); + const char *cp = print_formatted(0, NULL, NULL); if (NULL == cp) { acc_assign_int(-1); @@ -714,7 +714,7 @@ do_printf(void) /* (string format, ...) */ void do_dprintf(void) /* (string format, ...) */ { - const char *cp = print_formatted(0, NULL); + const char *cp = print_formatted(0, NULL, NULL); if (NULL == cp) { acc_assign_int(-1); @@ -787,13 +787,13 @@ do_sprintf(void) /* int (string buffer, string format, ...) */ { SYMBOL *sp = get_symbol(1); const char *cp; - int len = 0; + int len = 0, width = 0; - cp = print_formatted(1, &len); + cp = print_formatted(1, &len, &width); if (cp) { sym_assign_str(sp, cp); } - acc_assign_int(len); + acc_assign_int(width); } @@ -857,9 +857,10 @@ void do_format(void) /* (string format, ...) */ { const char *cp; + int len = 0; - cp = print_formatted(0, NULL); - acc_assign_str(cp, -1); + cp = print_formatted(0, &len, NULL); + acc_assign_str(cp, len); } diff --git a/gr/m_pty.c b/gr/m_pty.c index 5a4b4ad0..698420fd 100644 --- a/gr/m_pty.c +++ b/gr/m_pty.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_pty_c,"$Id: m_pty.c,v 1.23 2020/04/21 00:01:56 cvsuser Exp $") +__CIDENT_RCSID(gr_m_pty_c,"$Id: m_pty.c,v 1.25 2021/10/18 13:12:13 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_pty.c,v 1.23 2020/04/21 00:01:56 cvsuser Exp $ +/* $Id: m_pty.c,v 1.25 2021/10/18 13:12:13 cvsuser Exp $ * * * This file is part of the GRIEF Editor. @@ -904,9 +904,8 @@ p_push(BUFFER_t *bp, const char *str) DISPLAY_t *dp = bp->b_display; const char *start = NULL; - curbp = bp; + set_curbp(bp); BFSET(curbp, BF_NO_UNDO); - set_hooked(); if ((*cur_line = dp->d_curline) < 1) { *cur_line = 1; @@ -1029,11 +1028,10 @@ p_push(BUFFER_t *bp, const char *str) if (curwp && curwp->w_bufp == curbp) { set_buffer_parms(bp, curwp); } - curbp = saved_bp; + set_curbp(saved_bp); if (! saved_no_undo) { BFCLR(curbp, BF_NO_UNDO); } - set_hooked(); } @@ -1379,7 +1377,7 @@ p_escape_decode(DISPLAY_t *dp) */ if (NULL != (lp = linepx(curbp, cline))) { if ((length = llength(lp)) > 0) { - dot = line_offset2(lp, cline, ccol, LOFFSET_FIRSTBYTE); + dot = line_offset_const(lp, cline, ccol, LOFFSET_FIRSTBYTE); dellen = p_sgrlength(ltext(lp) + dot, ltext(lp) + length, 'm'); } vm_unlock(cline); @@ -1584,7 +1582,7 @@ void pty_poll(void) { static int entry = 0; - BUFFER_t *saved_curbp = curbp; + BUFFER_t *ocurbp = curbp; int updated; char buf[1024+1]; @@ -1631,8 +1629,7 @@ pty_poll(void) * Update screen if necessary and make sure that the current buffer is restored * so that cursor goes at right place and in case we exit this loop */ - curbp = saved_curbp; - set_hooked(); + set_curbp(ocurbp); if (updated) { vtupdate(); } diff --git a/gr/m_spell.c b/gr/m_spell.c index b872b4ae..67bd701f 100644 --- a/gr/m_spell.c +++ b/gr/m_spell.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_spell_c,"$Id: m_spell.c,v 1.42 2020/04/21 00:01:56 cvsuser Exp $") +__CIDENT_RCSID(gr_m_spell_c,"$Id: m_spell.c,v 1.43 2021/06/10 06:13:02 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_spell.c,v 1.42 2020/04/21 00:01:56 cvsuser Exp $ +/* $Id: m_spell.c,v 1.43 2021/06/10 06:13:02 cvsuser Exp $ * Spell primitives. * * Enchant - AbiWord spell-checker generic interface @@ -22,7 +22,6 @@ __CIDENT_RCSID(gr_m_spell_c,"$Id: m_spell.c,v 1.42 2020/04/21 00:01:56 cvsuser E * http://linguscomponent.openoffice.org * OpenOffice original - based on pspell now aspell * - * * Copyright (c) 1998 - 2018, Adam Young. * This file is part of the GRIEF Editor. * @@ -346,7 +345,7 @@ spell_check_buffer(LINENO start, LINENO end, int tokenize, int suggest, int uniq for (line = start; line < end; ++line) { LINE_t *clp; - if (NULL != (clp = vm_lock_line(line))) { + if (NULL != (clp = vm_lock_line2(line))) { const LINECHAR *text; int length; @@ -354,8 +353,8 @@ spell_check_buffer(LINENO start, LINENO end, int tokenize, int suggest, int uniq lst = spell_check_string(bp, (const char *)text, length, tokenize, suggest, line, (unique ? &wordtbl : NULL), lst, &len); } + vm_unlock(line); } - vm_unlock(line); } stbl_clear(&wordtbl); if (lst) { @@ -1316,5 +1315,5 @@ do_spell_distance(void) /* int (string a, string b) */ ret = EditDistance(s1, s2); acc_assign_int(ret); } -/*end*/ +/*end*/ diff --git a/gr/m_string.c b/gr/m_string.c index e657c546..d396237a 100644 --- a/gr/m_string.c +++ b/gr/m_string.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_string_c,"$Id: m_string.c,v 1.40 2020/04/21 00:01:56 cvsuser Exp $") +__CIDENT_RCSID(gr_m_string_c,"$Id: m_string.c,v 1.45 2021/07/12 15:55:01 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_string.c,v 1.40 2020/04/21 00:01:56 cvsuser Exp $ +/* $Id: m_string.c,v 1.45 2021/07/12 15:55:01 cvsuser Exp $ * String primitives. * * @@ -27,6 +27,8 @@ __CIDENT_RCSID(gr_m_string_c,"$Id: m_string.c,v 1.40 2020/04/21 00:01:56 cvsuser #include #include #include /* HUGE_VAL */ +#include "../libchartable/libchartable.h" +#include "../libchartable/utf8.h" #include /* str_...()/sxprintf() */ #include @@ -50,7 +52,7 @@ static const char * x_strcasestr(const char *haystack, const char *needle); /* Function: do_strxlen - * Work-horse strlen() and strnlen() primitives. + * Workhorse strlen() and strnlen() primitives. * * Parameters: * step - List step increment. @@ -108,6 +110,56 @@ do_strxlen(int step) } +static accint_t +do_wstrxlen(int step) +{ + accint_t len, longest = 0; + const LIST *lp; + int s; + + if (isa_string(1)) { + return utf8len(get_str(1)); + } + + if (step <= 0) { + step = 1; /* default */ + } + + for (lp = get_list(1); lp && F_HALT != *lp;) { + switch (*lp) { + case F_STR: + case F_LIT: + len = (int)utf8len(LGET_PTR2(const char, lp)); + break; + case F_ID: { + const int id = LGET_ID(lp); + const char *name = builtin[id].b_name; + + assert(id >= 0 || (unsigned)id < builtin_count); + len = (int)utf8len(name); + } + break; + case F_RSTR: + len = (int)utf8len(r_ptr(LGET_PTR2(const ref_t, lp))); + break; + default: + len = 0; + break; + } + + if (len > longest) { + longest = len; + } + + for (s = 0; s < step && lp; ++s) { + lp = atom_next(lp); + } + } + + return longest; +} + + /* Function: do_strlen * strlen primitive - return length of string argument or length of * longest string in a list. @@ -155,6 +207,13 @@ do_strlen(void) /* (string|list arg, [int step = 1]) */ } +void +do_wstrlen(void) /* (string|list arg, [int step = 1]) */ +{ + acc_assign_int(do_wstrxlen(get_xinteger(2, 1))); +} + + /* Function: do_strnlen * strnlen primitive - return length of string argument or length of * longest string in a list, limited to maxlen. @@ -210,6 +269,16 @@ do_strnlen(void) /* (string str, int maxlen, [int step = 1]) */ } +void +do_wstrnlen(void) /* (string str, int maxlen, [int step = 1]) */ +{ + const accint_t len = do_wstrxlen(get_xinteger(3, 1)); + const accint_t maxlen = get_xinteger(2, 1); + + acc_assign_int(len > maxlen ? maxlen : len); +} + + /* Function: do_atoi * atoi primitive - string to integer * @@ -269,7 +338,6 @@ do_atoi(void) /* int (string str, [int svalue = TRUE]) */ } - /* Function: do_itoa * itoa primitive - integer to string. * @@ -725,6 +793,37 @@ do_index(void) /* int (string str, int ch|string s) */ } +void +do_windex(void) /* int (string str, int ch|string s) */ +{ + const char *str = get_str(1); + const char *cp; + int val = 0; + + if (isa_integer(2)) { /* extension */ + const int ch = get_xinteger(2, 0); + + if (ch > 0) { + if (NULL != (cp = utf8chr(str, ch))) { + val = (cp - str) + 1; + } + } + + } else { + const char *cp2 = get_xstr(2); + + if (NULL == cp2 || 0 == *cp2) { + val = get_strlen(1) + 1; /* EOS */ + + } else if (NULL != (cp = utf8str(str, cp2))) { + val = (cp - str) + 1; /* character position */ + } + } + + acc_assign_int(val); +} + + /* Function: do_firstof * firstof primitive - first index of character. * @@ -767,23 +866,50 @@ do_index(void) /* int (string str, int ch|string s) */ lastof, index, rindex */ void -do_firstof(void) /* int (string str, string chars [,int &result]) */ +do_firstof(void) /* int (string str, string chars [, int &result]) */ { - const char *start = get_str(1), *str = start, - *end = str + get_strlen(1); - const char *chars = get_xstr(2); - const char *cp; - int val = 0; + const char *str = get_str(1), + *characters = get_xstr(2), *pbrk; + SYMBOL *sp = get_symbol(3); + accint_t position = 0; - while (str < end) { - if (NULL != (cp = strchr(chars, *str++))) { - val = str - start; /* starting from offset 1 */ - break; + if (NULL != (pbrk = strpbrk(str, characters))) { + position = (accint_t)((pbrk - str) + 1); + } + + if (sp) sym_assign_int(sp, (pbrk ? *pbrk : 0)); + acc_assign_int(position); +} + + +void +do_wfirstof(void) /* int (string str, string chars [,int &result]) */ +{ + const char *str = get_str(1), + *characters = get_xstr(2); + utf8_int32_t wch, wch2; + SYMBOL *sp = get_symbol(3); + + if (characters && *characters) { + accint_t cursor; + + for (cursor = 1; *str; ++cursor) { + const char *c = characters; + + str = (const char *)utf8codepoint(str, &wch); + while (*c) { + c = (const char *)utf8codepoint(c, &wch2); + if (wch == wch2) { + if (sp) sym_assign_int(sp, wch); + acc_assign_int(cursor); + return; + } + } } } - sym_assign_int(get_symbol(3), (val > 0 ? str[-1] : 0)); - acc_assign_int(val); + if (sp) sym_assign_int(sp, 0); + acc_assign_int(0); } @@ -852,6 +978,37 @@ do_rindex(void) /* int (string str, int ch|string s) */ } +void +do_wrindex(void) /* int (string str, int ch|string s) */ +{ + const char *str = get_str(1); + const char *cp; + int val = 0; + + if (isa_integer(2)) { /* extension 21/04/06 */ + int ch = get_xinteger(2, 0); + + if (ch > 0) { + if ((cp = utf8rchr(str, ch)) != NULL) { + val = (cp - str) + 1; + } + } + + } else { + const char *str2 = get_str(2); + int len = get_strlen(2); + + for (cp = str + get_strlen(1) - 1; cp >= str; --cp) + if (0 == utf8ncmp(cp, str2, len)) { + val = (cp - str) + 1; + break; + } + } + + acc_assign_int(val); +} + + /* Function: do_lastof * lastof primitive - last index of character. * @@ -899,6 +1056,7 @@ do_lastof(void) /* int (string str, string chars [,int &result]) const char *start = get_str(1), *end = start + get_strlen(1), *str = end; const char *chars = get_xstr(2); + SYMBOL *sp = get_symbol(3); const char *cp; int val = 0; @@ -909,11 +1067,43 @@ do_lastof(void) /* int (string str, string chars [,int &result]) } } - sym_assign_int(get_symbol(3), (val > 0 ? *str : 0)); + if (sp) sym_assign_int(sp, (val > 0 ? *str : 0)); acc_assign_int(val); } +void +do_wlastof(void) /* int (string str, string chars [,int &result]) */ +{ + const char *str = get_str(1), + *characters = get_xstr(2); + SYMBOL *sp = get_symbol(3); + int position = 0, character = 0; + utf8_int32_t wch, wch2; + + if (characters && *characters) { + accint_t cursor; + + for (cursor = 1; *str; ++cursor) { + const char *c = characters; + + str = (const char *)utf8codepoint(str, &wch); + while (*c) { + c = (const char *)utf8codepoint(c, &wch2); + if (wch == wch2) { + character = wch; + position = cursor; + /*continue*/ + } + } + } + } + + if (sp) sym_assign_int(sp, character); + acc_assign_int(position); +} + + /* Function: do_substr * substr primitive - retrieve a substr. * @@ -968,6 +1158,7 @@ do_substr(void) /* string (string str, [int offset], [int length } else if (offset > slen) { offset = slen; } + cp = str + offset; slen -= offset; @@ -982,6 +1173,57 @@ do_substr(void) /* string (string str, [int offset], [int length } +void +do_wsubstr(void) /* string (string str, [int offset], [int length]) */ +{ /* MCHAR */ + const char *str = get_str(1); + const int slen = get_strlen(1); + int offset = get_xinteger(2, 1); /* non-optional?? */ + const char *cp, *cp2, *end = str + slen; + int length; + + if (--offset < 0) { /* index-1/TODO */ + offset = 0; + } else if (offset > slen) { + offset = slen; + } + + cp = str; + while (*cp && offset > 0) { + const char *cend; + int32_t wch; + + if ((cend = charset_utf8_decode_safe(cp, end, &wch)) > cp) { + cp = cend; + --offset; + continue; //next + } + break; //error + } + + if (isa_undef(3)) { + length = slen; + } else if ((length = get_xinteger(3, 0)) < 0) { + length = 0; + } + + cp2 = cp; + while (*cp2 && length > 0) { + const char *cend; + int32_t wch; + + if ((cend = charset_utf8_decode_safe(cp2, end, &wch)) > cp2) { + cp2 = cend; + --length; + continue; //next + } + break; //error + } + + acc_assign_str(cp, cp2 - cp); +} + + /* Function: acc_ltrim * Left trim the accumerlator. * @@ -1151,7 +1393,7 @@ do_compress(void) /* (string str, [int trim = FALSE], Macro: trim - Chomp characters from a string. string - trim(string str, [string chars = " \t\r\n"]) + trim(string str, [string chars = " \\t\\r\\n"]) Macro Description: The 'trim()' primitive removes leading and trailing characters @@ -1204,7 +1446,7 @@ do_trim(void) /* (string str, [string chars = NULL]) */ Macro: rtrim - Chomp characters from the end of a string. string - rtrim(string str, string chars = " \t\r\n") + rtrim(string str, string chars = \\t \\r \\n ) Macro Description: The 'rtrim()' primitive removes trailing (or right) characters @@ -1249,7 +1491,7 @@ do_rtrim(void) /* (string str, [string chars = NULL]) */ Macro: ltrim - Chomp characters from the front of a string. string - ltrim(string str, [string chars = NULL]) + ltrim(string str, [string chars = " \\t\\r\\n"]) Macro Description: The 'ltrim()' primitive removes leading (or left) characters @@ -1318,7 +1560,7 @@ do_upper(void) /* (string str|int character, [TODO int capitali if (isa_integer(1)) { /* 24/04/06 */ int ch = get_xinteger(1, 0); - if (ch >= 'a' && ch <= 'z') { /* ASCII/MCHAR??? */ + if (ch >= 'a' && ch <= 'z') { /* MCHAR??? */ ch = toupper(ch); } acc_assign_int(ch); @@ -1331,7 +1573,7 @@ do_upper(void) /* (string str|int character, [TODO int capitali for (; *cp; ++cp) { const int ch = *cp; - if (ch >= 'a' && ch <= 'z') { /* ASCII/MCHAR??? */ + if (ch >= 'a' && ch <= 'z') { /* MCHAR??? */ *cp = (unsigned char)toupper(ch); } } @@ -1339,6 +1581,20 @@ do_upper(void) /* (string str|int character, [TODO int capitali } +void +do_wupper(void) /* (string str|int character, [TODO int capitalize) */ +{ + if (isa_integer(1)) { + int ch = get_xinteger(1, 0); + acc_assign_int(utf8uprcodepoint(ch)); + + } else { + acc_assign_str(get_str(1), get_strlen(1)); + utf8upr(acc_get_sbuf()); + } +} + + /* Function: do_lower * lower primitive - convert specified character or string to lower-case. * @@ -1379,7 +1635,7 @@ do_lower(void) /* string|int (string str|int character) */ if (isa_integer(1)) { /* 24/04/06 */ int ch = get_xinteger(1, 0); - if (ch >= 'A' && ch <= 'Z') { /* ASCII/MCHAR??? */ + if (ch >= 'A' && ch <= 'Z') { /* MCHAR??? */ ch = tolower(ch); } acc_assign_int(ch); @@ -1393,7 +1649,7 @@ do_lower(void) /* string|int (string str|int character) */ for (; *cp; ++cp) { const int ch = *cp; - if (ch >= 'A' && ch <= 'Z') { /* ASCII/MCHAR??? */ + if (ch >= 'A' && ch <= 'Z') { /* MCHAR??? */ *cp = (unsigned char)tolower(ch); } } @@ -1401,6 +1657,32 @@ do_lower(void) /* string|int (string str|int character) */ } +/* + Various functions provided will do case insensitive compares, or transform utf8 strings from one case to another. + Given the vastness of unicode, and the authors lack of understanding beyond latin codepoints on whether case means anything, + the following categories are the only ones that will be checked in case insensitive code: + + ASCII + Latin-1 Supplement + Latin Extended-A + Latin Extended-B + Greek and Coptic + Cyrillic + */ +void +do_wlower(void) /* string|int (string str|int character) */ +{ + if (isa_integer(1)) { + int ch = get_xinteger(1, 0); + acc_assign_int(utf8lwrcodepoint(ch)); + + } else { + acc_assign_str(get_str(1), get_strlen(1)); + utf8lwr(acc_get_sbuf()); + } +} + + /* Function: isa * Workhorse for isxxx primitive set. * @@ -1612,7 +1894,7 @@ do_isgold(void) /* int (string str|int character) */ const int ch = get_xinteger(1, 0); if (ch > 0) { - if (ch & (RANGE_FN|RANGE_KEYPAD|RANGE_MISC|RANGE_MULTIKEY| + if (ch & (RANGE_FUNCTION|RANGE_KEYPAD|RANGE_MISC|RANGE_MULTIKEY| RANGE_PRIVATE|RANGE_BUTTON|RANGE_MASK)) { ret = 1; } @@ -2582,6 +2864,22 @@ do_strcmp(void) /* int (string s1, string s2 [, int length]) */ } +void +do_wstrcmp(void) /* int (string s1, string s2 [, int length]) */ +{ + const char *s1 = get_str(1); + const char *s2 = get_str(2); + int len = get_xinteger(3, -1); + + if (len > 0) { + acc_assign_int(utf8ncmp(s1, s2, len)); + + } else { + acc_assign_int(utf8cmp(s1, s2)); + } +} + + /* Function: do_strcasecmp * strcasecmp primitive. * @@ -2635,6 +2933,22 @@ do_strcasecmp(void) /* (string s1, string s2 [, int length]) */ } +void +do_wstrcasecmp(void) /* (string s1, string s2 [, int length]) */ +{ + const char *s1 = get_str(1); + const char *s2 = get_str(2); + int len = get_xinteger(3, -1); + + if (len > 0) { + acc_assign_int(utf8ncasecmp(s1, s2, len)); + + } else { + acc_assign_int(utf8casecmp(s1, s2)); + } +} + + /* Function: do_strverscmp * strverscmp primitive. * @@ -2728,7 +3042,7 @@ do_strpop(void) /* (string str, [int length = 1], [int encoding] if (rp && (used = r_used(rp)) > 0) { /* - * decode character value + * decode character value, MCHAR/??? */ if (length >= used) { length = used; /* trim to symbol length */ @@ -2800,6 +3114,33 @@ do_strpbrk(void) /* int (string str, string characters) */ } +void +do_wstrpbrk(void) /* int (string str, string characters) */ +{ + const char *str = get_str(1), + *characters = get_xstr(2); + utf8_int32_t wch, wch2; + + if (characters && *characters) { /* firstof() */ + accint_t cursor; + + for (cursor = 1; *str; ++cursor) { + const char *c = characters; + + str = (const char *)utf8codepoint(str, &wch); + while (*c) { + c = (const char *)utf8codepoint(c, &wch2); + if (wch == wch2) { + acc_assign_int(cursor); + return; + } + } + } + } + + acc_assign_int(0); +} + /* Function: do_strstr * strstr primitive. @@ -2852,6 +3193,40 @@ do_strstr(void) /* int (string haystack, string needle) */ } +void +do_wstrstr(void) /* int (string haystack, string needle) */ +{ + const char *haystack = get_xstr(1); + const char *needle = get_xstr(2); + accint_t position = 0; + + if (haystack && needle) { + if (0 == *needle) { /* empty needle */ + position = 1; + + } else { /* non-empty needle */ + utf8_int32_t t_wch; + accint_t cursor; + + for (cursor = 1; *haystack; ++cursor) { + const char *h = haystack, *n = needle; + + while (*h == *n && *h && *n) { + ++h, ++n; + } + + if (0 == *n) { /* eon, match? */ + position = cursor; + break; + } + + haystack = (const char *)utf8codepoint(haystack, &t_wch); + } + } + } + acc_assign_int(position); +} + /* Function: do_strrstr * strrstr primitive. @@ -2894,14 +3269,48 @@ do_strrstr(void) /* int (string haystack, string needle) */ accint_t position = 0; if (haystack && needle) { - const char *str; + if (*needle) { + const char *str; + /* initial search */ + if (NULL != (str = strstr(haystack, needle))) { + position = (accint_t)((str - haystack) + 1); - if (NULL != (str = strstr(haystack, needle))) { - position = (accint_t)((str - haystack) + 1); + /* continue search */ + while (NULL != (str = strstr(str + 1, needle))) { + position = (accint_t)((str - haystack) + 1); + } + } + } + } + acc_assign_int(position); +} - /* FIXME - hack implementation */ - while (NULL != (str = strstr(str + 1, needle))) { - position = (accint_t)((str - haystack) + 1); + +void +do_wstrrstr(void) /* int (string haystack, string needle) */ +{ + const char *haystack = get_xstr(1); + const char *needle = get_xstr(2); + accint_t position = 0; + + if (haystack && needle) { + if (*needle) { /* non-empty needle */ + utf8_int32_t t_wch; + accint_t cursor; + + for (cursor = 1; *haystack; ++cursor) { + const char *h = haystack, *n = needle; + + while (*h == *n && *h && *n) { + ++h, ++n; + } + + if (0 == *n) { /* eon, match? */ + position = cursor; + /*continue search*/ + } + + haystack = (const char *)utf8codepoint(haystack, &t_wch); } } } @@ -3022,20 +3431,42 @@ x_strcasestr(const char *haystack, const char *needle) A Grief extension. */ void -do_characterat(void) /* int (string str, int index) */ +do_characterat(void) /* int (string str, int index, [int encoding]) */ { const char *str = get_str(1); int length = get_strlen(1); accint_t position = get_xinteger(2, -1); +/*- int encoding = (int) get_xinteger(3, -1); -*/ accint_t val = -1; if (position > 0 && position <= length) { - val = str[position - 1]; /* TODO/MCHAR??? */ + val = str[position - 1]; } acc_assign_int(val); } +void +do_wcharacterat(void) +{ + const char *str = get_str(1); + accint_t position = get_xinteger(2, -1); + + if (str && position > 0) { + utf8_int32_t wch = 0; + const char *next; + /* MCHAR */ + for (; (next = utf8codepoint(str, &wch)) > str && wch; str = next) { + if (--position == 0) { + acc_assign_int(wch); + return; + } + } + } + acc_assign_int(-1); +} + + /* Function: string_mul * Function to replicate a string 'n' times. * @@ -3061,4 +3492,5 @@ string_mul(const char *str, int len, int multiple) acc_assign_strlen(i); } + /*end*/ diff --git a/gr/m_string.h b/gr/m_string.h index c38ee34c..2f7d87c4 100644 --- a/gr/m_string.h +++ b/gr/m_string.h @@ -1,11 +1,11 @@ #ifndef GR_M_STRING_H_INCLUDED #define GR_M_STRING_H_INCLUDED #include -__CIDENT_RCSID(gr_m_string_h,"$Id: m_string.h,v 1.14 2015/07/08 21:08:15 cvsuser Exp $") +__CIDENT_RCSID(gr_m_string_h,"$Id: m_string.h,v 1.15 2021/06/10 06:13:02 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_string.h,v 1.14 2015/07/08 21:08:15 cvsuser Exp $ +/* $Id: m_string.h,v 1.15 2021/06/10 06:13:02 cvsuser Exp $ * String primitives. * * @@ -70,8 +70,25 @@ extern void do_substr(void); extern void do_trim(void); extern void do_upper(void); +extern void do_wcharacterat(void); +extern void do_wfirstof(void); +extern void do_windex(void); +extern void do_wlastof(void); +extern void do_wlower(void); +extern void do_wrindex(void); +extern void do_wstrcasecmp(void); +extern void do_wstrcmp(void); +extern void do_wstrlen(void); +extern void do_wstrnlen(void); +extern void do_wstrpbrk(void); +extern void do_wstrrstr(void); +extern void do_wstrstr(void); +extern void do_wsubstr(void); +extern void do_wupper(void); + extern void string_mul(const char *str, int len, int multipler); __CEND_DECLS #endif /*GR_M_STRING_H_INCLUDED*/ + diff --git a/gr/m_terminal.c b/gr/m_terminal.c index 9e7c7f1c..c166a0d5 100644 --- a/gr/m_terminal.c +++ b/gr/m_terminal.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_terminal_c,"$Id: m_terminal.c,v 1.17 2020/04/21 00:01:56 cvsuser Exp $") +__CIDENT_RCSID(gr_m_terminal_c,"$Id: m_terminal.c,v 1.18 2021/06/22 15:52:44 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_terminal.c,v 1.17 2020/04/21 00:01:56 cvsuser Exp $ +/* $Id: m_terminal.c,v 1.18 2021/06/22 15:52:44 cvsuser Exp $ * Terminal screen and keyboard primitives. * * @@ -173,8 +173,7 @@ static struct pt_map pt_features[] = { { TF_VT_DAVERSION, PT_MKINT(x_pt.pt_vtdaversion), "vt_daversion" }, { TF_ENCODING, PT_MKSTR(x_pt.pt_encoding), "encoding" }, - { TF_UNICODE_VERSION, PT_MKINT(x_pt.pt_unicode_version), "unicode_version" }, - { TF_UNICODE_WIDTH, PT_MKINT(x_pt.pt_unicode_width), "unicode_width" }, + { TF_UNICODE_VERSION, PT_MKSTR(x_pt.pt_unicode_version), "unicode_version" }, { -2, 0, NULL, 0, "" } }; @@ -538,9 +537,8 @@ do_set_term_characters(void) /* int ([int ident string desc], [string|int] va ! TF_ENCODING encoding String Terminal character encoding. - ! TF_UNICODE_VERSION unicode_version Integer UNICODE interface version. - - ! TF_UNICODE_WIDTH unicode_width Integer UNICODE character width. + ! TF_UNICODE_VERSION unicode_version String UNICODE interface version, for + example "6.0.1". (end table) TF_ATTRIBUTE: diff --git a/gr/m_window.c b/gr/m_window.c index 7d8151a2..d7886f14 100644 --- a/gr/m_window.c +++ b/gr/m_window.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_m_window_c,"$Id: m_window.c,v 1.25 2020/06/03 16:22:53 cvsuser Exp $") +__CIDENT_RCSID(gr_m_window_c,"$Id: m_window.c,v 1.28 2021/10/18 13:09:48 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: m_window.c,v 1.25 2020/06/03 16:22:53 cvsuser Exp $ +/* $Id: m_window.c,v 1.28 2021/10/18 13:09:48 cvsuser Exp $ * Window primitives. * * @@ -19,6 +19,8 @@ __CIDENT_RCSID(gr_m_window_c,"$Id: m_window.c,v 1.25 2020/06/03 16:22:53 cvsuser */ #include +#include "../libchartable/libchartable.h" +#include "../libwidechar/widechar.h" #include /* str_...()/sxprintf() */ #include "m_window.h" /* public interface */ @@ -1288,8 +1290,8 @@ do_change_window_pos(void) /* ([int x], [int y], [int w], [int h], [int win x = vtcols - 1; } - w1 = (wp->w_message ? strlen(wp->w_message) : 0) + 4; - w2 = (wp->w_title ? strlen(wp->w_title) : 0) + 4; + w1 = (wp->w_message ? utf8_swidth(wp->w_message) : 0) + 4; /*MCHAR*/ + w2 = (wp->w_title ? utf8_swidth(wp->w_title) : 0) + 4; if (w < w1) w = w1; if (w < w2) w = w2; @@ -1456,8 +1458,7 @@ do_set_window(void) /* ([int winnum]) */ curwp->w_status |= WFHARD; } wp->w_status |= WFHARD; - curwp = wp; - set_hooked(); + set_curwp(wp); ret = 1; } acc_assign_int(ret); @@ -1577,8 +1578,7 @@ do_delete_window(void) /* void ([int winnum]) */ return; if (wp == curwp) { - curwp = &x_window_null; - set_hooked(); + set_curwp(&x_window_null); } ismenu = (W_MENU == wp->w_type); diff --git a/gr/mac1.c b/gr/mac1.c index 504d706d..c58e018f 100644 --- a/gr/mac1.c +++ b/gr/mac1.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_mac1_c,"$Id: mac1.c,v 1.70 2020/04/21 00:01:57 cvsuser Exp $") +__CIDENT_RCSID(gr_mac1_c,"$Id: mac1.c,v 1.75 2021/10/18 13:07:25 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: mac1.c,v 1.70 2020/04/21 00:01:57 cvsuser Exp $ +/* $Id: mac1.c,v 1.75 2021/10/18 13:07:25 cvsuser Exp $ * Basic primitives. * * @@ -369,12 +369,13 @@ do_delete_to_eol(void) /* void () */ LINE_t *lp; int dot, n; - lp = linep(cline); - dot = line_offset2(lp, cline, ccol, LOFFSET_NORMAL); - if ((n = llength(lp) - dot) > 0) { - ldelete(n); + if (NULL != (lp = vm_lock_line2(cline))) { + dot = line_offset_const(lp, cline, ccol, LOFFSET_NORMAL); + if ((n = llength(lp) - dot) > 0) { + ldelete(n); + } + vm_unlock(cline); } - vm_unlock(cline); } @@ -417,10 +418,11 @@ do_delete_line(void) /* void () */ u_dot(); *cur_col = 1; - lp = linep(cline); - ldelete(llength(lp) + 1); /* MCHAR, line plus EOL */ + if (NULL != (lp = vm_lock_line2(cline))) { + ldelete(llength(lp) + 1); /* MCHAR, line plus EOL */ + vm_unlock(cline); + } *cur_col = ccol; - vm_unlock(cline); } @@ -1758,15 +1760,15 @@ do_redraw(void) /* ([int winch]) */ Macro: insert - Insert string into current buffer. int - insert(string str, [int num = 1]) + insert(string|int val, [int num = 1]) Macro Description: - The 'insert()' primitive inserts the specified string 'str' - into the current buffer. The string shall be inserted 'num' - times, which if omitted defaults to 1. + The 'insert_process()' primitive inserts the specified string or + integer character value 'val' into the current buffer. The value + shall be inserted 'num' times, which if omitted defaults to 1. Macro Parameters: - str - String value to be inserted. + val - String or integer character value to be inserted. num - Option integer number stating the repeat count, if specified then the string is inserted the given number of @@ -1787,16 +1789,16 @@ do_redraw(void) /* ([int winch]) */ Macro: insert_process - Send string to a attached process. int - insert_process(string str, [int num = 1]) + insert_process(string|int val, [int num = 1]) Macro Description: - The 'insert_process()' primitive inserts the specified string - 'str' into the process attached to the current buffer. The - string shall be inserted 'num' times, which if omitted - defaults to 1. + The 'insert_process()' primitive inserts the specified string or + integer character value 'val' into the process attached to the + current buffer. The value shall be inserted 'num' times, which + if omitted defaults to 1. Macro Parameters: - str - String value to be inserted. + val - String or integer character value to be inserted. num - Option integer number stating the repeat count, if specified then the string is inserted the given number @@ -1813,7 +1815,7 @@ do_redraw(void) /* ([int winch]) */ insert, insertf, insert_buffer, insert_process */ void -do_insert(int proc) /* int (string str, [int num]) */ +do_insert(int proc) /* int (string str | int character, [int num]) */ { const char *cp; accint_t num; @@ -1842,6 +1844,7 @@ do_insert(int proc) /* int (string str, [int num]) */ /* * Otherwise insert the specified string + * MCHAR/??? utf8->iconv */ cp = get_str(1); len = (int)strlen(cp); @@ -1912,17 +1915,18 @@ void do_insertf(void) /* int (string fmt, ...) */ { const char *cp; - int len = 0; + int len = 0, width = 0; if (margc > 1) { - cp = print_formatted(0, &len); /* sprintf style output */ + cp = print_formatted(0, &len, &width); /* sprintf style output */ } else { cp = get_str(1); + len = width = get_strlen(1); } if (cp) { linserts(cp, len); } - acc_assign_int(len); + acc_assign_int(width); } @@ -1989,7 +1993,7 @@ do_insert_buffer(void) /* int (int bufnum, string | expr ....) */ { BUFFER_t *bp; const char *cp; - int len = 0; + int len = 0, width = 0; if (NULL == (bp = buf_lookup(get_xinteger(1, -1)))) { ewprintf("insert_buffer: no such buffer"); @@ -1998,23 +2002,22 @@ do_insert_buffer(void) /* int (int bufnum, string | expr ....) */ } if (margc > 2) { - cp = print_formatted(1, &len); /* sprintf style output */ + cp = print_formatted(1, &len, &width); /* sprintf style output */ } else { cp = get_str(2); /* just quote string */ + len = width = get_strlen(2); } if (cp) { - BUFFER_t *saved_bp = curbp; + BUFFER_t *ocurbp = curbp; if (bp != curbp) { - curbp = bp; - set_hooked(); + set_curbp(bp); } linserts(cp, len); - curbp = saved_bp; - set_hooked(); + set_curbp(ocurbp); } - acc_assign_int(len); + acc_assign_int(width); } @@ -2503,7 +2506,7 @@ void do_read(void) /* string ([int number], [int &status]) */ { const LINENO cline = *cur_line, ccol = *cur_col; - int status = 0; /* extension, status being -1=eof,1=eol,0=partial */ + int status = 1; /* extension, status being -1=eof,1=eol,0=partial */ LINE_t *lp; if (NULL == (lp = vm_lock_linex(curbp, cline))) { @@ -2514,12 +2517,9 @@ do_read(void) /* string ([int number], [int &status]) */ } else { int dot, len, copy; - dot = line_offset2(lp, cline, ccol, LOFFSET_NORMAL); + dot = line_offset_const(lp, cline, ccol, LOFFSET_NORMAL); len = llength(lp) - dot; - trace_ilog("read(line:%d,col:%d,dot:%d,length:%d) : %d\n", \ - (int)cline, (int)ccol, dot, llength(lp), len); - if (isa_undef(1)) { copy = len; /* EOL */ @@ -2530,15 +2530,51 @@ do_read(void) /* string ([int number], [int &status]) */ copy = (value1 > len ? len : value1); } + trace_ilog("read(line:%d,col:%d,dot:%d,length:%d) : %d of %d\n", \ + (int)cline, (int)ccol, dot, llength(lp), copy, len); + + // MCHAR/???, iconv->utf8 if (copy <= 0) { acc_assign_str("\n", 1); /* empty line */ - } else if (copy < len) { /* sub-line */ - acc_assign_str((const char *) ltext(lp) + dot, copy); - status = 0; + } else { + const LINECHAR *start = ltext(lp) + dot; + + if (! BFTST(curbp, BF_BINARY)) { /* MCHAR */ + const LINECHAR *cp = start, + *end = ltext(lp) + llength(lp); + + if (copy >= len) { + cp = end; + } else { + LINENO pos = ccol; + int32_t ch; + + while (copy > 0 && cp < end) { + int length, width = + character_decode(pos, cp, end, &length, &ch, NULL); + if (width > 0) --copy; + pos += width; + cp += length; + } + } + + if (cp >= end) { /* EOL + \n */ + acc_assign_str2((const char *) start, len, "\n", 1); + } else { /* partial */ + acc_assign_str((const char *) start, cp - start); + status = 0; + } + + } else { + if (copy >= len) { /* EOL + \n */ + acc_assign_str2((const char *) start, copy, "\n", 1); - } else { /* copied to EOL, must add \n */ - acc_assign_str2((const char *) ltext(lp) + dot, copy, "\n", 1); + } else { /* partial */ + acc_assign_str((const char *) start, copy); + status = 0; + } + } } vm_unlock(cline); @@ -2670,4 +2706,4 @@ do_input_mode(void) /* int (int char, int flag) */ acc_assign_int((accint_t)sys_enable_char(ch, value)); } -/*end*/ \ No newline at end of file +/*end*/ diff --git a/gr/main.h b/gr/main.h index d8274001..74046f4c 100644 --- a/gr/main.h +++ b/gr/main.h @@ -1,11 +1,11 @@ #ifndef GR_MAIN_H_INCLUDED #define GR_MAIN_H_INCLUDED #include -__CIDENT_RCSID(gr_main_h,"$Id: main.h,v 1.28 2020/05/03 21:10:56 cvsuser Exp $") +__CIDENT_RCSID(gr_main_h,"$Id: main.h,v 1.29 2021/10/17 12:12:23 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: main.h,v 1.28 2020/05/03 21:10:56 cvsuser Exp $ +/* $Id: main.h,v 1.29 2021/10/17 12:12:23 cvsuser Exp $ * Globals and main process primitives. * * @@ -119,6 +119,10 @@ extern uint32_t xf_test; /* TRUE enables test code --- in extern BUFFER_t * curbp; /* Current buffer */ extern WINDOW_t * curwp; /* Current window */ +extern void set_curbp(BUFFER_t *bp); +extern void set_curwp(WINDOW_t *wp); +extern void set_curwpbp(WINDOW_t *wp, BUFFER_t *bp); + extern void panic(const char *msg, ...) __ATTRIBUTE_FORMAT__((printf, 1, 2)); extern void gr_exit(int); @@ -132,4 +136,4 @@ extern void do_suspend(void); __CEND_DECLS -#endif /*GR_MAIN_H_INCLUDED*/ \ No newline at end of file +#endif /*GR_MAIN_H_INCLUDED*/ diff --git a/gr/map.c b/gr/map.c index df536780..d0496738 100644 --- a/gr/map.c +++ b/gr/map.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_map_c,"$Id: map.c,v 1.32 2015/02/11 23:25:13 cvsuser Exp $") +__CIDENT_RCSID(gr_map_c,"$Id: map.c,v 1.34 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: map.c,v 1.32 2015/02/11 23:25:13 cvsuser Exp $ +/* $Id: map.c,v 1.34 2021/07/05 15:01:27 cvsuser Exp $ * High-level character mapping functionality. * * @@ -86,7 +86,7 @@ character_decode(int pos, const LINECHAR *cp, const LINECHAR *end, int *lenp, in if ((wcp = iconv->ic_decode(iconv, cp, end, &ch, &wraw)) > cp) { length = wcp - cp; if (ch > 0xff) { /* wide character, FIXME - iconv() specific?? */ - width = vtcharwidth(ch, mchar_ucs_width(ch, 1)); + width = vtcharwidth(ch, Wcwidth(ch)); *lenp = length; if (rawp) *rawp = wraw; *chp = ch; @@ -187,13 +187,25 @@ esccombined2: while (escend < end) { /* find escape-sequence */ } +const LINE_t * +linep0(LINENO line) +{ + LINE_t *lp; + + if (NULL == curbp || NULL == (lp = linepx(curbp, line))) { + return x_static_line; /* XXX/FIXME- replace with linep2 */ + } + return lp; +} + + LINE_t * -linep(LINENO line) +linep2(LINENO line) { LINE_t *lp; if (NULL == curbp || NULL == (lp = linepx(curbp, line))) { - return x_static_line; /* XXX - yuk, buffer specific or NULL? */ + return NULL; } return lp; } @@ -339,13 +351,13 @@ line_sizeregion(const LINE_t *lp, int col, int dot, int characters, LINENO *leng while (count < characters && cp < end) { int32_t t_ch; - int t_length,t_width = + int t_length, t_width = character_decode(col, cp, end, &t_length, &t_ch, NULL); #if defined(DO_TRACE_CHARACTER) trace_character(t_ch, t_width, cp, t_length); #endif - cp += t_length; + cp += t_length; length += t_length; col += t_width; @@ -436,12 +448,12 @@ line_current_offset(int fill) int line_offset(const int line, const int col, int fill) { - int offset = 0; + int dot = 0; LINE_t *lp; if (curbp) { if (NULL != (lp = vm_lock_linex(curbp, line))) { - offset = line_offset2(lp, line, col, fill); + dot = line_offset_fill(lp, line, col, fill); vm_unlock(line); } else { curbp->b_vline = line; @@ -452,11 +464,11 @@ line_offset(const int line, const int col, int fill) curbp->b_vwidth = 0; } } - return offset; + return dot; } -/* Function: line_offset2 +/* Function: line_offset_fill * Convert the specified 'column' position into an physical byte offset from the start * of the current line. * @@ -474,7 +486,7 @@ line_offset(const int line, const int col, int fill) * No fill, returning complete character include leading colorization. * * LOFFSET_LASTBYTE - - * No fill, return offset last byte within the character including are + * No fill, return offset last byte within the character including any * combined characters. * * LOFFSET_NORMAL - @@ -494,26 +506,21 @@ line_offset(const int line, const int col, int fill) * Line Offset. */ int -line_offset2(LINE_t *lp, const int line, const int col, int fill) +line_offset_fill(LINE_t *lp, const int line, const int col, int fill) { -// const int isuc = buf_isuc(curbp); // UNICCODE const int isutf8 = buf_isutf8(curbp); /* buffer encoding */ - int used, length = 0, width = 0; - const LINECHAR *cp, *start, *end; - int vstatus = 0, pos = 1, offset = 0; + const LINECHAR *start = ltext(lp), + *cp = start, *end = cp + llength(lp); + int length = 0, width = 0; + int pos = 1, offset = 0; + int vstatus = 0; int32_t ch = 0; - start = ltext(lp); - used = llength(lp); - - cp = start; - end = start + used; - - ED_ITRACE(("line_offset(line:%d, col:%d, fill:%d, used:%d)\n", line, col, fill, used)) - assert(col >= 1); assert(fill >= LOFFSET_LASTBYTE && fill <= LOFFSET_FILL_SPACE); + ED_ITRACE(("line_offset(line:%d, col:%d, fill:%d, used:%d)\n", line, col, fill, llength(lp))) + if (col <= 0) { offset = 0; goto done; @@ -570,6 +577,7 @@ line_offset2(LINE_t *lp, const int line, const int col, int fill) if (t_width || t_ch <= 0xff || t_length <= 0) { break; /* not combining character */ } + #if defined(DO_TRACE_CHARACTER) trace_character(t_ch, t_width, cp, t_length); #endif @@ -671,6 +679,7 @@ line_offset2(LINE_t *lp, const int line, const int col, int fill) if (t_ch != t_raw) { vstatus |= BUFFERVSTATUS_ILLEGAL; } + if (0 == combined) { curbp->b_vwidth = t_width; } @@ -766,6 +775,14 @@ done:; } +int +line_offset_const(const LINE_t *lp, const int line, const int col, int fill) +{ + assert(fill >= LOFFSET_LASTBYTE && fill <= LOFFSET_NORMAL_MATCH); + return line_offset_fill((LINE_t *)lp, line, col, fill); +} + + static __CINLINE int istab(const LINECHAR ch) { @@ -916,9 +933,9 @@ int line_column_eol(int line) { int column = 0; - LINE_t *lp; + const LINE_t *lp; - if (NULL != (lp = vm_lock_line(line))) { + if (NULL != (lp = vm_lock_line2(line))) { column = line_column2(lp, line, llength(lp)); vm_unlock(line); } @@ -930,9 +947,9 @@ int line_column(const int line, int offset) { int column = 0; - LINE_t *lp; + const LINE_t *lp; - if (NULL != (lp = vm_lock_line(line))) { + if (NULL != (lp = vm_lock_line2(line))) { column = line_column2(lp, line, offset); vm_unlock(line); } @@ -1007,8 +1024,8 @@ line_tab_backfill(void) ED_TRACE2(("tab_backfill(line:%d,col:%d)\n", cline, ccol)) - lp = vm_lock_line(cline); - if (! ledit(lp, 0)) { + lp = vm_lock_line2(cline); + if (NULL == lp || !ledit(lp, 0)) { vm_unlock(cline); return; } @@ -1070,4 +1087,5 @@ line_tab_backfill(void) vm_unlock(cline); } + /*end*/ diff --git a/gr/map.h b/gr/map.h index 341e76b4..df018621 100644 --- a/gr/map.h +++ b/gr/map.h @@ -1,11 +1,11 @@ #ifndef GR_MAP_H_INCLUDED #define GR_MAP_H_INCLUDED #include -__CIDENT_RCSID(gr_map_h,"$Id: map.h,v 1.14 2014/10/22 02:33:13 ayoung Exp $") +__CIDENT_RCSID(gr_map_h,"$Id: map.h,v 1.15 2021/06/10 06:13:02 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: map.h,v 1.14 2014/10/22 02:33:13 ayoung Exp $ +/* $Id: map.h,v 1.15 2021/06/10 06:13:02 cvsuser Exp $ * Character/line mapping ulitlies. * * @@ -25,7 +25,8 @@ __CPRAGMA_ONCE __CBEGIN_DECLS -#define vm_lock_line(__ln) linep(__ln) +#define vm_lock_line(__ln) linep0(__ln) +#define vm_lock_line2(__ln) linep2(__ln) #define vm_lock_linex(__bp,__ln) \ linepx(__bp, __ln) #define vm_unlock(__ln) @@ -42,14 +43,15 @@ enum { LOFFSET_LASTBYTE =-2, /* last byte, including ESC/combined */ LOFFSET_FIRSTBYTE =-1, /* first byte */ LOFFSET_NORMAL =0, /* first normal character roffset */ - LOFFSET_NORMAL_MATCH =1, /* first normal and match cursor on completion */ + LOFFSET_NORMAL_MATCH =1, /* first normal and match/update cursor on completion */ LOFFSET_FILL_VSPACE =2, /* fill virtual-space and EOL */ LOFFSET_FILL_SPACE =3 /* fill virtual-space, tabs and EOL */ }; extern int character_decode(int pos, const LINECHAR *cp, const LINECHAR *end, int *lengthp, int32_t *chp, int32_t *rawp); -extern LINE_t * linep(LINENO line); +extern const LINE_t * linep0(LINENO line); +extern LINE_t * linep2(LINENO line); extern LINE_t * linepx(BUFFER_t *bp, LINENO line); extern void linep_flush(BUFFER_t *bp); @@ -59,7 +61,8 @@ extern int line_current_status(int *value, int count); extern int line_current_offset(int fill); extern int line_offset(const int line, const int col, int fill); -extern int line_offset2(LINE_t *lp, const int line, const int col, int fill); +extern int line_offset_const(const LINE_t *lp, const int line, const int col, int fill); +extern int line_offset_fill(LINE_t *lp, const int line, const int col, int fill); extern int line_current_column(int offset); extern int line_column_eol(int line); diff --git a/gr/mchar.h b/gr/mchar.h index a53e54a9..6e4dfa11 100644 --- a/gr/mchar.h +++ b/gr/mchar.h @@ -1,11 +1,11 @@ #ifndef GR_MCHAR_H_INCLUDED #define GR_MCHAR_H_INCLUDED #include -__CIDENT_RCSID(gr_mchar_h,"$Id: mchar.h,v 1.15 2014/10/22 02:33:13 ayoung Exp $") +__CIDENT_RCSID(gr_mchar_h,"$Id: mchar.h,v 1.17 2021/07/05 15:01:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: mchar.h,v 1.15 2014/10/22 02:33:13 ayoung Exp $ +/* $Id: mchar.h,v 1.17 2021/07/05 15:01:27 cvsuser Exp $ * Multibyte character support. * * @@ -23,6 +23,9 @@ __CPRAGMA_ONCE #include +#include "../libchartable/libchartable.h" +#include "../libwidechar/widechar.h" + __CBEGIN_DECLS #define MCHAR_MAX_ENCODING 48 @@ -163,7 +166,8 @@ extern char * mchar_guess_default(void); extern const mcharcharsetinfo_t * mchar_info(mcharcharsetinfo_t *info, const char *name, int namelen); - + +extern void mchar_iconv_init(void); extern mchar_iconv_t * mchar_iconv_open(const char *encoding); extern void mchar_iconv_close(mchar_iconv_t *iconv); #define mchar_encoding(__ic) \ @@ -179,9 +183,6 @@ extern void mchar_iconv_close(mchar_iconv_t *iconv); #define mchar_length(__ic, __ch) \ ((* (__ic)->ic_length)(__ic, __ch)) -extern int mchar_ucs_width(int32_t ch, int bad); -extern int mchar_ucs_encode(int32_t ch, char *buffer); - extern mchar_istream_t * mchar_stream_open(mchar_iconv_t *ic, int handle, const char *filename, const char *mode); extern void mchar_stream_push(mchar_istream_t *is, const char *buffer, size_t buflen); extern size_t mchar_stream_read(mchar_istream_t *is, char *buffer, size_t buflen, size_t *inbytes); diff --git a/gr/mchar_guess.c b/gr/mchar_guess.c index 59dd1e99..a6c152fc 100644 --- a/gr/mchar_guess.c +++ b/gr/mchar_guess.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_mchar_guess_c,"$Id: mchar_guess.c,v 1.27 2020/06/05 23:13:47 cvsuser Exp $") +__CIDENT_RCSID(gr_mchar_guess_c,"$Id: mchar_guess.c,v 1.29 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: mchar_guess.c,v 1.27 2020/06/05 23:13:47 cvsuser Exp $ +/* $Id: mchar_guess.c,v 1.29 2021/07/05 15:01:27 cvsuser Exp $ * Character-set conversion/file type guess logic. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2021, Adam Young. * This file is part of the GRIEF Editor. * * The GRIEF Editor is free software: you can redistribute it @@ -191,10 +191,10 @@ static const struct guessdecoder { * guess - Guesser (libguess). * enca - Extremely Naive Charset Analyser (libenca). * - * Note, order is some-what important as the MBCS checks can result in + * Note, order is some-what important as the MBCS checks can result in * false positives, as such are generally last in line. * - * Module usage has evolved over time, with a number being pure + * Module usage has evolved over time, with a number being pure * experimental alternatives. */ { NAME("mark"), guess_marker, GUESS_FDEFAULT }, @@ -1065,8 +1065,8 @@ guess_guess(guessinfo_t *guess, const void *buffer, unsigned length) * European languages, and a few Unicode variants, independently * on language. * - * Currently it supports Belarusian, Bulgarian, Croatian, Czech, - * Estonian, Hungarian, Latvian, Lithuanian, Polish, Russian, + * Currently it supports Belarusian, Bulgarian, Croatian, Czech, + * Estonian, Hungarian, Latvian, Lithuanian, Polish, Russian, * Slovak, Slovene, Ukrainian, Chinese, and some multibyte * encodings independently on language. * @@ -1076,8 +1076,8 @@ guess_guess(guessinfo_t *guess, const void *buffer, unsigned length) * length - Length of the buffer. * * Warning: - * libenca is licensed under the GPLv2; the user *must* explicitly - * build a local non-standard version and agree to *never* to + * libenca is licensed under the GPLv2; the user *must* explicitly + * build a local non-standard version and agree to *never* to * release. * * References: @@ -1737,8 +1737,9 @@ guess_utf8(guessinfo_t *guess, const void *buffer, unsigned length) guessterm_t linebreak = {0}; register const unsigned char *cursor = buffer; const unsigned char *end = cursor + (length - 1); - int nonascii = 0, isutf8 = 0; - int32_t raw, ch = 0; + unsigned nonascii = 0, noutf8 = 0; + int isutf8 = 0; + int32_t ch = 0; if (BFTYP_UNKNOWN == bomtype || BFTYP_UTF8 == bomtype) { @@ -1749,24 +1750,31 @@ guess_utf8(guessinfo_t *guess, const void *buffer, unsigned length) while (cursor < end && isutf8 >= 0) { if ((ch = *cursor++) >= 0x80) { - if (NULL == (cursor = charset_utf8_decode(cursor - 1, end, &ch, &raw)) || ch != raw) { + /* + * utf8, allowing illegal and overlong only rejecting illformed. + */ + cursor = charset_utf8_decode(cursor - 1, end, &ch); + if (ch <= 0) { trace_ilog("\t\t==> bad UTF8\n"); - isutf8 = -1; - break; + if (++noutf8 > (length/1)) { /* non utf8 >1% */ + isutf8 = -1; + break; + } + continue; } isutf8 = 1; } if (ch <= 0xff) { /* - * [0x0A], [0x0D], [0x20 - 0x7F], [0x85], [0xA0 - 0xFF] - */ + * [CR/LF], [BS], [FF], [0x20 - 0x7F], [0x85], [0xA0 - 0xFF] + */ if (0 == (x_charflags[ch] & (A|X|I))) { trace_ilog("\t\t==> non ASCII (%d/0x%02x)\n", ch, ch); - if (++nonascii > 2) { - isutf8 = -1; /* neither ASCII nor Latin1 */ + if (++nonascii > 2) { /* neither ASCII nor Latin1 */ + isutf8 = -1; } - } else { + } else { linetally(&linebreak, ch); } } @@ -1935,7 +1943,7 @@ guess_gb18030(guessinfo_t *guess, const void *buffer, unsigned length) const unsigned char *cursor = (const unsigned char *)buffer, *end = cursor + length; int isgb = 0; - + while (cursor < end && isgb >= 0) { const unsigned char c1 = *cursor++; @@ -2203,4 +2211,5 @@ guess_ebcdic(guessinfo_t *guess, const void *buffer, unsigned length) #endif return 0; } + /*end*/ diff --git a/gr/mchar_iconv.c b/gr/mchar_iconv.c index e3c9d335..d06a7c99 100644 --- a/gr/mchar_iconv.c +++ b/gr/mchar_iconv.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_mchar_iconv_c,"$Id: mchar_iconv.c,v 1.22 2018/10/01 20:59:48 cvsuser Exp $") +__CIDENT_RCSID(gr_mchar_iconv_c,"$Id: mchar_iconv.c,v 1.24 2021/06/19 09:41:55 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: mchar_iconv.c,v 1.22 2018/10/01 20:59:48 cvsuser Exp $ +/* $Id: mchar_iconv.c,v 1.24 2021/06/19 09:41:55 cvsuser Exp $ * Character-set conversion/mapping interface and adapters. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2021, Adam Young. * This file is part of the GRIEF Editor. * * The GRIEF Editor is free software: you can redistribute it @@ -124,8 +124,6 @@ static mchar_istream_t * icnv_stream_open(struct mchar_iconv *ic, int fd, static void icnv_stream_close(mchar_iconv_t *ic, mchar_istream_t *is); #endif -extern void charset_iconv_init(void); /* FIXME/XXX */ - static mchar_iconv_t x_iconv_internal[] = { { 0, "binary", 1, uchar_decode, @@ -166,6 +164,21 @@ static mchar_iconv_t x_iconv_internal[] = { }; +/* Function: mchar_iconv_init + * Run-time initialisation + * + */ +void +mchar_iconv_init(void) +{ +#if defined(_WIN32) && defined(WIN32_DYNAMIC_ICONV) +#if defined(HAVE_LIBICONV_CITRUS_DLL) + w32_iconv_dllname(HAVE_LIBICONV_CITRUS_DLL); +#endif +#endif +} + + /* Function: mchar_iconv_open * Open a conversion session, allowing conversion between an external encoding and Unicode. * @@ -459,7 +472,7 @@ static const void * utf8_decode(mchar_iconv_t *ic, const void *src, const void *cpend, int32_t *cooked, int32_t *raw) { __CUNUSED(ic) - return charset_utf8_decode(src, cpend, cooked, raw); + return charset_utf8_decode_cook(src, cpend, cooked, raw); } @@ -934,10 +947,10 @@ icnv_open(const char *encoding) mchar_iconv_t *ic; if (encoding) strxcpy(toencoding, encoding, sizeof(toencoding)); - strxcat(toencoding, " //TRANSLIT", sizeof(toencoding)); + strxcat(toencoding, "//TRANSLIT", sizeof(toencoding)); if (NULL == (ic = chk_alloc(sizeof(mchar_iconv_t) + encodinglen)) || - ICONV_NULL == (ihandle = my_iconv_open("utf-8 //IGNORE", encoding)) || + ICONV_NULL == (ihandle = my_iconv_open("utf-8//TRANSLIT", encoding)) || /*IGNORE or TRANSLIT?*/ ICONV_NULL == (ohandle = my_iconv_open(toencoding, "utf-8"))) { if (ic) { if (ICONV_NULL != ihandle) { diff --git a/gr/mchar_info.c b/gr/mchar_info.c index 23679bec..6e14af18 100644 --- a/gr/mchar_info.c +++ b/gr/mchar_info.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_mchar_info_c,"$Id: mchar_info.c,v 1.19 2018/10/01 20:59:48 cvsuser Exp $") +__CIDENT_RCSID(gr_mchar_info_c,"$Id: mchar_info.c,v 1.20 2021/06/13 16:28:51 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: mchar_info.c,v 1.19 2018/10/01 20:59:48 cvsuser Exp $ +/* $Id: mchar_info.c,v 1.20 2021/06/13 16:28:51 cvsuser Exp $ * Locale/multibyte character information. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2021, Adam Young. * This file is part of the GRIEF Editor. * * The GRIEF Editor is free software: you can redistribute it @@ -253,7 +253,7 @@ mchar_info_init(void) * GRPATH/charset.alias */ charset_alias_init(); - mchar_alias_load(CHARSET_MODE_INI, "crcharset.list"); + mchar_alias_load(CHARSET_MODE_INI, "grcharset.list"); mchar_alias_load(CHARSET_MODE_X11, "charset.alias"); return 0; } @@ -607,5 +607,5 @@ charset_map(const char *name, int namelen) } return NULL; } -/*end*/ +/*end*/ diff --git a/gr/mchar_util.c b/gr/mchar_util.c index 7b8acc66..7ef22223 100644 --- a/gr/mchar_util.c +++ b/gr/mchar_util.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_mchar_util_c,"$Id: mchar_util.c,v 1.17 2018/10/01 20:59:48 cvsuser Exp $") +__CIDENT_RCSID(gr_mchar_util_c,"$Id: mchar_util.c,v 1.19 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: mchar_util.c,v 1.17 2018/10/01 20:59:48 cvsuser Exp $ +/* $Id: mchar_util.c,v 1.19 2021/07/05 15:01:27 cvsuser Exp $ * Locale/multibyte character utility functionality. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2021, Adam Young. * This file is part of the GRIEF Editor. * * The GRIEF Editor is free software: you can redistribute it @@ -31,32 +31,6 @@ __CIDENT_RCSID(gr_mchar_util_c,"$Id: mchar_util.c,v 1.17 2018/10/01 20:59:48 cvs #include #include "mchar.h" /* mchar_...() */ -#include "../libchartable/libchartable.h" - - -/* Function: mchar_ucs_width - * Retrieve the character width of the specified Unicode character. - * - * Parameters: - * ch - Character value. - * - * bad - Method of evaluating invalid character values. - * - * Returns: - * Character width. - */ -int -mchar_ucs_width(int32_t ch, int bad) -{ - return charset_width_ucs(ch, bad); -} - - -int -mchar_ucs_encode(int32_t ch, char *buffer) -{ - return charset_utf8_encode(ch, buffer); -} /* Function: mchar_locale_utf8 @@ -161,9 +135,5 @@ sys_unicode_locale(int isterminal) { return mchar_locale_utf8(sys_get_locale(isterminal)); } -/*end*/ - - - - +/*end*/ diff --git a/gr/playback.c b/gr/playback.c index 75ea245d..5a55163a 100644 --- a/gr/playback.c +++ b/gr/playback.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_playback_c,"$Id: playback.c,v 1.32 2019/01/26 22:27:08 cvsuser Exp $") +__CIDENT_RCSID(gr_playback_c,"$Id: playback.c,v 1.33 2021/10/17 12:12:06 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: playback.c,v 1.32 2019/01/26 22:27:08 cvsuser Exp $ +/* $Id: playback.c,v 1.33 2021/10/17 12:12:06 cvsuser Exp $ * * * This file is part of the GRIEF Editor. @@ -744,7 +744,7 @@ playback_grab(int popit) void playback_macro(const char *cp) { - BUFFER_t *bp, *saved_bp = curbp; + BUFFER_t *bp, *ocurbp = curbp; if (!x_playback_recording || x_rem_string[0] == 'P') { return; @@ -765,8 +765,7 @@ playback_macro(const char *cp) return; } - curbp = bp; - set_hooked(); + set_curbp(bp); BFSET(curbp, BF_NO_UNDO); if ('s' == *cp && 0 == strcmp(cp, "self_insert")) { @@ -838,7 +837,6 @@ playback_macro(const char *cp) } rem_doing_self_insert = FALSE; } - curbp = saved_bp; - set_hooked(); + set_curbp(ocurbp); } /*end*/ diff --git a/gr/position.c b/gr/position.c index 7eefe6a3..1346fefd 100644 --- a/gr/position.c +++ b/gr/position.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_position_c,"$Id: position.c,v 1.6 2014/10/22 02:33:14 ayoung Exp $") +__CIDENT_RCSID(gr_position_c,"$Id: position.c,v 1.8 2021/10/17 12:10:13 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: position.c,v 1.6 2014/10/22 02:33:14 ayoung Exp $ +/* $Id: position.c,v 1.8 2021/10/17 12:10:13 cvsuser Exp $ * Buffer position/status. * * @@ -128,8 +128,7 @@ position_restore(int what) move_abs(pos->p_cur_line, pos->p_cur_col); if (1 == what) { /* position restore, but not buffer */ - curbp = saved_bp; - set_hooked(); + set_curbp(saved_bp); } else { attach_buffer(curwp, curbp); } @@ -170,7 +169,7 @@ position_dump(void) trace_log("\t[%2d] %d%d %d/%d ", idx, pos->p_winnum, pos->p_bufnum, pos->p_cur_line, pos->p_cur_col); if (bp) { - trace_log(" active \"%s ...\"\n", bp->b_title ? bp->b_title : "n.s."); + trace_log(" active \"%s ...\"\n", bp->b_title ? c_string(bp->b_title) : "n.s."); } else { trace_log(" closed \"%s ...\"\n", pos->p_name); } diff --git a/gr/prntf.c b/gr/prntf.c index 4daef3ee..8a57160d 100644 --- a/gr/prntf.c +++ b/gr/prntf.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_prntf_c,"$Id: prntf.c,v 1.13 2017/01/19 17:09:30 cvsuser Exp $") +__CIDENT_RCSID(gr_prntf_c,"$Id: prntf.c,v 1.16 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: prntf.c,v 1.13 2017/01/19 17:09:30 cvsuser Exp $ +/* $Id: prntf.c,v 1.16 2021/07/05 15:01:27 cvsuser Exp $ * Print formatter. * * @@ -20,6 +20,8 @@ __CIDENT_RCSID(gr_prntf_c,"$Id: prntf.c,v 1.13 2017/01/19 17:09:30 cvsuser Exp $ #include #include +#include "../libchartable/libchartable.h" +#include "../libwidechar/widechar.h" #include /* str_...()/sxprintf() */ #include "prntf.h" @@ -57,6 +59,7 @@ typedef struct { int width; int precision; + int wadjust; /* wchar adjust */ char * obp; #define ORESET(_x) (_x)->obp = buf_ptr @@ -71,7 +74,9 @@ typedef struct { static int get_value(const char **fmt, int *arg); static void prtl(io_t *io, const LIST *lp, unsigned level); -static void outs(io_t *io, const char *s); +static void outs(io_t *io, const char *s, int slen); +static void wouts(io_t *io, const char *s, int slen); +static void Wouts(io_t *io, const char *s, int slen); static void outb(io_t *io, accuint_t ul, const char *p); static void outl(io_t *io, int radix, accint_t lval); static void outf(io_t *io, const char *format, accfloat_t dval); @@ -94,22 +99,26 @@ static int buf_size; * * Parameters: * offset - Format offset within the argument list. - * - * len - Address of buffer populated with resulting length. + * length - Address of buffer populated with resulting length. + * width - Character width. * * Returns: * Address of internal formatted text buffer, reused on each call. * */ const char * -print_formatted(int offset, int *len) +print_formatted(int offset, int *length, int *width) { + static const char xBSTR[] = ""; + static const char xNULL[] = ""; + const char *fmt; int arg = offset + 2; - io_t io, *iop = &io; + io_t io = {0}, *iop = &io; accint_t lval; const char *sval; char type; + int slen; if (NULL == buf_ptr) { /* prime buffer */ buf_size = PRINTF_SIZE; @@ -223,11 +232,13 @@ literal:; OCHECK(iop, 1); switch (type) { case 's': /* string */ - sval = ""; /* undefined */ - + slen = 0; if (isa_string(arg)) { - if (NULL == (sval = get_str(arg))) { - sval = ""; + if (NULL != (sval = get_str(arg))) { + slen = get_strlen(arg); + } else { + sval = xNULL; + slen = sizeof(xNULL)-1; } } else if (isa_list(arg)) { /* 04/04/10 */ prtl(iop, get_list(arg), 0); @@ -239,9 +250,53 @@ literal:; OCHECK(iop, 1); outl(iop, 10, (accint_t)get_accfloat(arg)); sval = NULL; } else if (isa_null(arg)) { /* 04/04/10 */ - sval = ""; + sval = xNULL; + slen = sizeof(xNULL)-1; + } else { + sval = xBSTR; + slen = sizeof(xBSTR)-1; } - if (sval) outs(iop, sval); + if (sval) outs(iop, sval, slen); + ++arg; + break; + + case 'S': /* wide/utf8 - characters */ + slen = 0; + if (isa_string(arg)) { + if (NULL != (sval = get_str(arg))) { + slen = get_strlen(arg); + } else { + sval = xNULL; + slen = sizeof(xNULL)-1; + } + } else if (isa_null(arg)) { + sval = xNULL; + slen = sizeof(xNULL)-1; + } else { + sval = xBSTR; + slen = sizeof(xBSTR)-1; + } + if (sval) wouts(iop, sval, slen); + ++arg; + break; + + case 'W': /* wide/utf8 - display width */ + slen = 0; + if (isa_string(arg)) { + if (NULL != (sval = get_str(arg))) { + slen = get_strlen(arg); + } else { + sval = xNULL; + slen = sizeof(xNULL)-1; + } + } else if (isa_null(arg)) { + sval = xNULL; + slen = sizeof(xNULL)-1; + } else { + sval = xBSTR; + slen = sizeof(xBSTR)-1; + } + if (sval) Wouts(iop, sval, slen); ++arg; break; @@ -296,7 +351,7 @@ literal:; OCHECK(iop, 1); */ lval = get_xaccint(arg++, 0); if (NULL == (sval = get_xstr(arg++))) { - sval = ""; + sval = xBSTR; } outb(iop, (accuint_t) lval, sval); break; @@ -352,8 +407,11 @@ literal:; OCHECK(iop, 1); } } -end_format:; - if (len) *len = OLENGTH(iop); +end_format:; + { const int olength = OLENGTH(iop); + if (length) *length = olength; + if (width) *width = olength - iop->wadjust; + } OPUTC(iop, '\0'); return buf_ptr; } @@ -480,16 +538,14 @@ prtl(io_t *io, const LIST *lp, unsigned level) } +/* string output */ static void -outs(io_t *io, const char *s) +outs(io_t *io, const char *s, int slen) { - int slen; - /* - * The precision specifies the maximum number of characters to be - * printed. Characters in excess of precision are not printed. + * Precision specifies the maximum number of characters to be printed. + * Characters in excess of precision are not printed. */ - slen = strlen(s); /* retrieve string length */ if (io->precision > 0) { if (io->precision < slen) { slen = io->precision; /* trim */ @@ -499,6 +555,102 @@ outs(io_t *io, const char *s) } +/* long/wide string output - length limited */ +static void +wouts(io_t *io, const char *s, int slen) +{ + const char *cursor = s, *end = cursor + slen; + int precision = (io->precision > 0 ? io->precision : INT_MAX); + int padding = 0, length = 0, buflen = 0; + + /* + * Precision specifies the maximum number of characters to be printed. + * Characters in excess of precision are not printed. + * + * Width defines the upper display width, padding if required. + */ + while (cursor < end && precision > 0) { + const char *cend; /* MCHAR */ + int32_t wch; + + if ((cend = charset_utf8_decode_safe(cursor, end, &wch)) > cursor) { + --precision; + buflen += (cend - cursor); + cursor = cend; + ++length; + continue; + } + break; //done + } + + if (io->width > length) { + padding = io->width - length; + } + + OCHECK(io, padding + buflen); + if ((io->flags & F_LEFTJUST) == 0) + while (padding-- > 0) { + OPUTC(io, ' '); + } + io->wadjust = buflen - length; /* wchar/char delta */ + OPUTS(io, s, buflen); + if (io->flags & F_LEFTJUST) + while (padding-- > 0) { + OPUTC(io, ' '); + } +} + + +/* long/wide string output - display width limited */ +static void +Wouts(io_t *io, const char *s, int slen) +{ + const char *cursor = s, *end = cursor + slen; + int precision = (io->precision > 0 ? io->precision : INT_MAX); + int padding = 0, width = 0, buflen = 0; + + /* + * Precision specifies the maximum number of characters to be printed. + * Characters in excess of precision are not printed. + * + * Width defines the upper display width, padding if required. + */ + while (cursor < end && precision > 0) { + const char *cend; /* MCHAR */ + int32_t wch; + int wc; + + if ((cend = charset_utf8_decode_safe(cursor, end, &wch)) > cursor && + (wc = Wcwidth(wch)) >= 0) { + if (wc <= precision) { + precision -= wc; + buflen += (cend - cursor); + cursor = cend; + width += wc; + continue; + } + } + break; //done + } + + if (io->width > width) { + padding = io->width - width; + } + + OCHECK(io, padding + buflen); + if ((io->flags & F_LEFTJUST) == 0) + while (padding-- > 0) { + OPUTC(io, ' '); + } + io->wadjust = buflen - width; /* wchar/char delta */ + OPUTS(io, s, buflen); + if (io->flags & F_LEFTJUST) + while (padding-- > 0) { + OPUTC(io, ' '); + } +} + + static void outb(io_t *io, accuint_t ul, const char *p) { @@ -722,8 +874,9 @@ outf(io_t *io, const char *format, accfloat_t fval) } +/* string write */ static void -outr(io_t *io, const char *s, int len) +outr(io_t *io, const char *s, int length) { int padding = 0; @@ -740,17 +893,18 @@ outr(io_t *io, const char *s, int len) * is not given, all characters of the value are printed (subject to the precision * specification). */ + assert(length >= 0); if (io->width > 0) { - padding = io->width - len; /* width specifies output columns */ + padding = io->width - length; /* width specifies output columns */ + assert(padding >= 0); } - OCHECK(io, padding + len); + OCHECK(io, padding + length); if ((io->flags & F_LEFTJUST) == 0) while (padding-- > 0) { OPUTC(io, ' '); } - - OPUTS(io, s, len); + OPUTS(io, s, length); if (io->flags & F_LEFTJUST) while (padding-- > 0) { OPUTC(io, ' '); @@ -773,4 +927,5 @@ uitoa(accuint_t value, char *buffer, int base) *s = '\0'; /* NUL terminate the string */ str_rev(buffer); } -/*end*/ \ No newline at end of file + +/*end*/ diff --git a/gr/prntf.h b/gr/prntf.h index 1b07eee1..0d23d3d4 100644 --- a/gr/prntf.h +++ b/gr/prntf.h @@ -1,11 +1,11 @@ #ifndef GR_PRNTF_H_INCLUDED #define GR_PRNTF_H_INCLUDED #include -__CIDENT_RCSID(gr_prntf_h,"$Id: prntf.h,v 1.5 2014/10/22 02:33:14 ayoung Exp $") +__CIDENT_RCSID(gr_prntf_h,"$Id: prntf.h,v 1.6 2021/07/05 15:01:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: prntf.h,v 1.5 2014/10/22 02:33:14 ayoung Exp $ +/* $Id: prntf.h,v 1.6 2021/07/05 15:01:27 cvsuser Exp $ * Print formatter. * * @@ -25,7 +25,7 @@ __CPRAGMA_ONCE __CBEGIN_DECLS -extern const char * print_formatted(int offset, int *len); +extern const char * print_formatted(int offset, int *len, int *width); __CEND_DECLS diff --git a/gr/pty_win32.c b/gr/pty_win32.c index d7d7d086..a1d1e2c3 100644 --- a/gr/pty_win32.c +++ b/gr/pty_win32.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_pty_win32_c,"$Id: pty_win32.c,v 1.21 2018/11/18 00:20:21 cvsuser Exp $") +__CIDENT_RCSID(gr_pty_win32_c,"$Id: pty_win32.c,v 1.22 2022/03/21 15:39:39 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: pty_win32.c,v 1.21 2018/11/18 00:20:21 cvsuser Exp $ +/* $Id: pty_win32.c,v 1.22 2022/03/21 15:39:39 cvsuser Exp $ * * * This file is part of the GRIEF Editor. @@ -154,7 +154,7 @@ dpcreate(DISPLAY_t *dp, const char *shell, const char *cwd) // assert(sizeof(HANDLE) == sizeof(dp->d_handle_in)); in = _open_osfhandle((long) hInputWrite, _O_NOINHERIT); - if ((pid = w32_spawn(&args, in, -1, &out)) <= 0) { + if ((pid = w32_spawnA(&args, in, -1, &out)) <= 0) { CloseHandle((HANDLE) hInputRead); fileio_close(in); diff --git a/gr/regdfa.c b/gr/regdfa.c index 15dca387..288e912b 100644 --- a/gr/regdfa.c +++ b/gr/regdfa.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_regdfa_c,"$Id: regdfa.c,v 1.32 2020/04/21 00:01:57 cvsuser Exp $") +__CIDENT_RCSID(gr_regdfa_c,"$Id: regdfa.c,v 1.33 2021/06/18 14:41:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: regdfa.c,v 1.32 2020/04/21 00:01:57 cvsuser Exp $ +/* $Id: regdfa.c,v 1.33 2021/06/18 14:41:57 cvsuser Exp $ * DFA regular expression engine. * Streamlined engine for use by the syntax hiliting code. * @@ -2004,4 +2004,5 @@ regdfa_pmatch(struct regdfa *regex, const char *str, int sol, const char **start } return -1; } + /*end*/ diff --git a/gr/region.c b/gr/region.c index 3ce1ba33..b6f4d0ec 100644 --- a/gr/region.c +++ b/gr/region.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_region_c,"$Id: region.c,v 1.28 2014/10/22 02:33:16 ayoung Exp $") +__CIDENT_RCSID(gr_region_c,"$Id: region.c,v 1.30 2021/10/17 12:09:43 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: region.c,v 1.28 2014/10/22 02:33:16 ayoung Exp $ +/* $Id: region.c,v 1.30 2021/10/17 12:09:43 cvsuser Exp $ * Region primitives. * * @@ -299,14 +299,14 @@ region_process(const REGION_t *r, region_process_t *rdata) static int textstart(const LINE_t *lp, int line, int col) { - return line_offset2((LINE_t *)lp, line, (col > 1 ? col : 1), LOFFSET_FIRSTBYTE); + return line_offset_const(lp, line, (col > 1 ? col : 1), LOFFSET_FIRSTBYTE); } static int textend(const LINE_t *lp, int line, int col) { - return line_offset2((LINE_t *)lp, line, (col > 1 ? col : 1), LOFFSET_LASTBYTE); + return line_offset_const(lp, line, (col > 1 ? col : 1), LOFFSET_LASTBYTE); } @@ -474,8 +474,7 @@ do_transfer(void) /* int (int bufnum, int sline, int scolumn, int REGION_t r; saved_scrap = k_set(curbp); /* destination */ - curbp = bp; /* source */ - set_hooked(); + set_curbp(bp); /* source */ if (isa_undef(4) && isa_undef(5)) { /* line mode */ a.type = MK_LINE; @@ -506,8 +505,7 @@ do_transfer(void) /* int (int bufnum, int sline, int scolumn, int } k_set(saved_scrap); /* restore default scrap */ - curbp = saved_bp; - set_hooked(); + set_curbp(saved_bp); } acc_assign_int(ret); diff --git a/gr/search.c b/gr/search.c index 15a7230e..c9666152 100644 --- a/gr/search.c +++ b/gr/search.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_search_c,"$Id: search.c,v 1.55 2021/04/05 08:22:53 cvsuser Exp $") +__CIDENT_RCSID(gr_search_c,"$Id: search.c,v 1.57 2021/10/17 12:09:17 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: search.c,v 1.55 2021/04/05 08:22:53 cvsuser Exp $ +/* $Id: search.c,v 1.57 2021/10/17 12:09:17 cvsuser Exp $ * Search interface. * * TODO: @@ -917,8 +917,7 @@ do_re_search(void) /* int ([int flags], [string pattern], [declare if (bp != curbp) { saved_bp = curbp; - curbp = bp; - set_hooked(); + set_curbp(bp); } if (SF_CAPTURES & flags) { /* captures, globalise state */ @@ -946,8 +945,7 @@ do_re_search(void) /* int ([int flags], [string pattern], [declare } if (saved_bp) { - curbp = saved_bp; - set_hooked(); + set_curbp(saved_bp); } } acc_assign_int(result); @@ -1359,13 +1357,11 @@ do_re_translate(void) /* ([int flags], string pattern, [string replace if (bp != curbp) { saved_bp = curbp; - curbp = bp; - set_hooked(); + set_curbp(bp); } translate_buf(dir, global, flags, -2, 3); if (saved_bp) { - curbp = saved_bp; - set_hooked(); + set_curbp(saved_bp); } } @@ -2525,7 +2521,7 @@ buffer_search(struct re_state *rs, int cursor) const LINE_t *clp; - clp = vm_lock_line(search_line); + clp = vm_lock_line2(search_line); if (clp) { if (offset > 0) { if (ltext(clp)) { /* clip to length */ @@ -2945,10 +2941,8 @@ replace_buffer(struct re_state *rs, int interactive) rs->search_offset = edot + (0 == rs->search_result); } else if (--rs->search_offset < 0) { - LINE_t *lp; - if (--rs->search_line) { - lp = vm_lock_line(rs->search_line); + const LINE_t *lp = vm_lock_line(rs->search_line); rs->search_offset = llength(lp); vm_unlock(rs->search_offset); } diff --git a/gr/sh_win32.c b/gr/sh_win32.c index c119078d..b72accda 100644 --- a/gr/sh_win32.c +++ b/gr/sh_win32.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_sh_win32_c,"$Id: sh_win32.c,v 1.25 2020/04/13 01:24:51 cvsuser Exp $") +__CIDENT_RCSID(gr_sh_win32_c,"$Id: sh_win32.c,v 1.26 2022/03/21 15:39:39 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: sh_win32.c,v 1.25 2020/04/13 01:24:51 cvsuser Exp $ +/* $Id: sh_win32.c,v 1.26 2022/03/21 15:39:39 cvsuser Exp $ * * * This file is part of the GRIEF Editor. @@ -169,7 +169,7 @@ sys_shell(const char *cmd, const char *macro, argv[3] = NULL; args.argv = argv; // create the process - if ((hProc = w32_child_exec(&args, pd.hInput, pd.hOutput, pd.hError)) == 0) { + if ((hProc = w32_child_execA(&args, pd.hInput, pd.hOutput, pd.hError)) == 0) { ShellCleanup((void *)&pd); status = -1; diff --git a/gr/spell_hunspell.c b/gr/spell_hunspell.c index 7f86a8f4..c49d2cf2 100644 --- a/gr/spell_hunspell.c +++ b/gr/spell_hunspell.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_spell_hunspell_c,"$Id: spell_hunspell.c,v 1.17 2014/10/26 22:13:13 ayoung Exp $") +__CIDENT_RCSID(gr_spell_hunspell_c,"$Id: spell_hunspell.c,v 1.18 2021/06/10 06:13:02 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spell_hunspell.c,v 1.17 2014/10/26 22:13:13 ayoung Exp $ +/* $Id: spell_hunspell.c,v 1.18 2021/06/10 06:13:02 cvsuser Exp $ * Spell implementation - hunspell driver. * * http://sourceforge.net/hunspell/projects @@ -513,7 +513,7 @@ hs_dict_resolve(const char **paths, const char *name, int len, const char *ext) } if (NULL != (expanded = file_expand(buf, expand, sizeof(expand)))) { trace_log("=> resolve [%s -> %s]\n", buf, expanded); - if (0 == access(expanded, R_OK)) { + if (0 == sys_access(expanded, R_OK)) { return chk_salloc(expanded); } } diff --git a/gr/syntax.c b/gr/syntax.c index bc5e062c..cf64cdfe 100644 --- a/gr/syntax.c +++ b/gr/syntax.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_syntax_c,"$Id: syntax.c,v 1.58 2020/04/13 01:22:57 cvsuser Exp $") +__CIDENT_RCSID(gr_syntax_c,"$Id: syntax.c,v 1.59 2021/06/10 06:13:02 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: syntax.c,v 1.58 2020/04/13 01:22:57 cvsuser Exp $ +/* $Id: syntax.c,v 1.59 2021/06/10 06:13:02 cvsuser Exp $ * Syntax pre-processor. * * @@ -2297,8 +2297,8 @@ parse_lines(SyntaxTable_t *st, LINENO lineno, LINENO num) ED_TRACE(("syntax::parse_lines(flags:0x%04x, lineno:%d, num:%d, numline:%d)\n", \ st->st_flags, lineno, num, (int)curbp->b_numlines)) - lp = vm_lock_line(lineno); - while (1) { /* parse current line */ + lp = vm_lock_line2(lineno); + while (lp) { /* parse current line */ lineflags_t state = parse_line(st, lp); liflagclr(lp, LI_DIRTY); diff --git a/gr/sys_unix.c b/gr/sys_unix.c index 997bb132..c789621d 100644 --- a/gr/sys_unix.c +++ b/gr/sys_unix.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_sys_unix_c,"$Id: sys_unix.c,v 1.61 2020/06/03 16:31:33 cvsuser Exp $") +__CIDENT_RCSID(gr_sys_unix_c,"$Id: sys_unix.c,v 1.63 2021/06/02 15:28:38 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: sys_unix.c,v 1.61 2020/06/03 16:31:33 cvsuser Exp $ +/* $Id: sys_unix.c,v 1.63 2021/06/02 15:28:38 cvsuser Exp $ * System dependent functionality - UNIX. * * @@ -788,10 +788,30 @@ sys_copy(const char *src, const char *dst, int perms, int owner, int group) } -/* Function: sys_realpath - * Retrieve the real/absolute for the specified path. - * +/* Function: sys_xxx + * System i/o primitives. */ +int +sys_mkdir(const char *path, int amode) +{ + return mkdir(path, amode); +} + + +int +sys_access(const char *path, int amode) +{ + return access(path, amode); +} + + +int +sys_chmod(const char *path, int mode) +{ + return chmod(path, mode); +} + + int sys_realpath(const char *name, char *buf, int size) { @@ -817,6 +837,41 @@ sys_realpath(const char *name, char *buf, int size) } +int +sys_stat(const char *path, struct stat *sb) +{ + return stat(path, sb); +} + + +int +sys_lstat(const char *path, struct stat *sb) +{ + return lstat(path, sb); +} + + +int +sys_readlink(const char *path, char *buf, int maxlen) +{ + return readlink(path, buf, maxlen); +} + + +int +sys_symlink(const char *name1, const char *name2) +{ + return symlink(name1, name2); +} + + +int +sys_unlink(const char *fname) +{ + return unlink(fname); +} + + /* * sys_time --- * High resolution time, seconds plus milliseconds. diff --git a/gr/sys_win32.c b/gr/sys_win32.c index 7c51ec15..51c242f4 100644 --- a/gr/sys_win32.c +++ b/gr/sys_win32.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_sys_win32_c,"$Id: sys_win32.c,v 1.59 2020/05/03 21:41:40 cvsuser Exp $") +__CIDENT_RCSID(gr_sys_win32_c,"$Id: sys_win32.c,v 1.63 2021/07/12 15:55:01 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: sys_win32.c,v 1.59 2020/05/03 21:41:40 cvsuser Exp $ +/* $Id: sys_win32.c,v 1.63 2021/07/12 15:55:01 cvsuser Exp $ * WIN32 system support. * * @@ -351,11 +351,14 @@ ResizeCheck(unsigned *checks) static int Modifiers(const DWORD dwControlKeyState) { +#define CTRLSTATUSMASK (LEFT_ALT_PRESSED|LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED|RIGHT_CTRL_PRESSED|SHIFT_PRESSED) +#define ALT_PRESSED (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED) +#define CTRL_PRESSED (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED) int modifiers = 0; - if (dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) + if (dwControlKeyState & ALT_PRESSED) modifiers |= MOD_META; - if (dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) + if (dwControlKeyState & CTRL_PRESSED) modifiers |= MOD_CTRL; if (dwControlKeyState & SHIFT_PRESSED) modifiers |= MOD_SHIFT; @@ -388,6 +391,122 @@ MouseEvent(const DWORD dwEventFlags, const DWORD dwButtonState) } +// Alt+ event handler +// +// Alt+KeyCode works and behaves well when character only input is required, by simply +// reporting any down or up key events which populate the 'UnicodeChar' value. Whereas +// when extended keystroke handling is required, for example arrow and numpad keys, +// additional effort is needed. +// +// Alt+Keycodes are only reported within the 'UnicodeChar' value of up event on a "ALT" key +// post the valid entry of one-or-more hex characters. During KeyCode entry the API unfortunately +// does not publiciy indicate this state plus continues to return the associated virtual keys, +// including the leading 'keypad-plus' and any associated key-code elements, wherefore we need +// to filter. Furthermore, if during the key-code entry an invalid non-hex key combination is +// given, the key-code is invalidated and UnicodeChar=0 is returned on the ALT release. +// +// Notes: +// o To enable requires the registry REG_SZ value "EnableHexNumpad" under +// "HKEY_Current_User/Control Panel/Input Method" to be "1". +// +// o Hex-value overflow goes unreported, limiting input to a 16-bit unicode result. +// + +#pragma comment(lib, "Imm32.lib") + +static int +AltPlusEnabled(void) +{ + HKEY hKey = 0; + int enabled = 0; + + if (RegOpenKeyExA(HKEY_CURRENT_USER, + "Control Panel\\Input Method", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + char szEnableHexNumpad[100] = {0}; + DWORD dwSize = _countof(szEnableHexNumpad); + if (RegQueryValueExA(hKey, "EnableHexNumpad", NULL, NULL, (LPBYTE) szEnableHexNumpad, &dwSize) == ERROR_SUCCESS) { + if (szEnableHexNumpad[0] == '1' && szEnableHexNumpad[1] == 0) { + enabled = 1; + } + } + RegCloseKey(hKey); + } + return enabled; +} + +static int +AltPlusEvent(const KEY_EVENT_RECORD *ke, struct IOEvent *evt) +{ +#define ISXDIGIT(_uc) \ + ((_uc >= '0' && _uc <= '9') || (_uc >= 'a' && _uc <= 'f') || (_uc >= 'A' && _uc <= 'F') ? 1 : 0) + + static int alt_code = -2; // >0=active, 0=enabled, -1=disabled, -2=auto. + static DWORD alt_control = 0; + + if (alt_code < 0) { + if (-1 == alt_code) return -1; + if (! AltPlusEnabled()) { + alt_code = -1; + return -1; + } + alt_code = 0; + } + + if (ke->bKeyDown) { // down event + const unsigned controlKeyState = (CTRLSTATUSMASK & ke->dwControlKeyState); + + if (VK_ADD == ke->wVirtualKeyCode && + (LEFT_ALT_PRESSED == controlKeyState || RIGHT_ALT_PRESSED == controlKeyState)) { + // "Alt + ..." event + alt_control = controlKeyState; + if (alt_code == 0) { + alt_code = 1; + } + return 1; // consume + + } else if (alt_code) { + if (alt_control != controlKeyState || + (ke->uChar.UnicodeChar && 0 == ISXDIGIT(ke->uChar.UnicodeChar))) { + // new control status or non-hex, emit "Alt-Plus" and reset state + evt->type = EVT_KEYDOWN; + evt->code = KEYPAD_PLUS; + evt->modifiers = MOD_ALT; + alt_code = 0; + return 0; + } + + ++alt_code; // associated key count + return 1; // consume + } + + } else if (alt_code) { // up event + if (VK_MENU == ke->wVirtualKeyCode && + (0 == (ke->dwControlKeyState & ALT_PRESSED))) { + // Alt completion + const int oalt_code = alt_code; + + alt_code = 0; + if (1 == oalt_code && 0 == ke->uChar.UnicodeChar) { + // "Alt-Plus" only, emit + evt->type = EVT_KEYDOWN; + evt->code = KEYPAD_PLUS; + evt->modifiers = MOD_ALT; + return 0; + + } else if (ke->uChar.UnicodeChar) { + // "Alt-Plus keycode", return keycode. + evt->type = EVT_KEYDOWN; + evt->code = ke->uChar.UnicodeChar; + evt->modifiers = 0; + return 0; + } + } + } + + return -1; // unhandled +} + + /* Function: sys_getevent * Retrieve the input event from the status keyboard stream, within * the specified timeout 'tmo'. @@ -423,24 +542,34 @@ sys_getevent(struct IOEvent *evt, int tmo) ticks = DiffTicks(ticks); /* ticks (ms) as end */ if (rc == WAIT_OBJECT_0 && - ReadConsoleInput(hKbd, &k, 1, &count)) { + ReadConsoleInputW(hKbd, &k, 1, &count)) { switch (k.EventType) { - case KEY_EVENT: - if (k.Event.KeyEvent.bKeyDown) { + case KEY_EVENT: { const KEY_EVENT_RECORD *ke = &k.Event.KeyEvent; - int code; + + { /* Alt+KeyCode (experimental) */ + const int altstate = AltPlusEvent(ke, evt); + if (altstate == 0) return 0; + if (altstate == 1) break; + } + + if (k.Event.KeyEvent.bKeyDown) { + int code; /* see kbd.c */ - if ((code = key_mapwin32((unsigned) ke->dwControlKeyState, - ke->wVirtualKeyCode, ke->uChar.AsciiChar)) != -1) { - evt->type = EVT_KEYDOWN; - evt->code = code; - evt->modifiers = Modifiers(ke->dwControlKeyState); - assert(code > 0 && code < KEY_VOID); - return 0; + if ((code = key_mapwin32((unsigned) ke->dwControlKeyState, + ke->wVirtualKeyCode, ke->uChar.UnicodeChar)) != -1) { + + evt->type = EVT_KEYDOWN; + evt->code = code; + evt->modifiers = Modifiers(ke->dwControlKeyState); + assert(code > 0 && code <= (MOD_MASK|RANGE_MASK|KEY_MASK) && code != KEY_VOID); + return 0; + } + + } else { + resize = ResizeCheck(&checks); } - } else { - resize = ResizeCheck(&checks); } break; @@ -842,7 +971,7 @@ sys_copy( __CUNUSED(owner) #endif if ((rc = CopyFileA(src, dst, FALSE)) != FALSE) { - (void) fileio_chmod(dst, perms); /* FIXME: return */ + (void) sys_chmod(dst, perms); /* FIXME: return */ #ifdef HAVE_CHOWN chown(dst, owner, group); #endif @@ -852,14 +981,34 @@ sys_copy( } -/* Function: sys_realpath - * Retrieve the real/absolute for the speified path. - * +/* Function: sys_xxx + * System i/o primitives. */ +int +sys_mkdir(const char *path, int amode) +{ + return w32_mkdir(path, amode); +} + + +int +sys_access(const char *path, int amode) +{ + return w32_access(path, amode); +} + + +int +sys_chmod(const char *path, int mode) +{ + return w32_chmod(path, (mode_t)mode); +} + + int sys_realpath(const char *name, char *buf, int size) { - return (NULL == _fullpath(buf, name, size) ? -1 : 0); + return (NULL == w32_realpath2(name, buf, size) ? -1 : 0); } diff --git a/gr/sysinfo.c b/gr/sysinfo.c index 1a0936d9..094ab077 100644 --- a/gr/sysinfo.c +++ b/gr/sysinfo.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_sysinfo_c,"$Id: sysinfo.c,v 1.49 2021/04/19 16:28:49 cvsuser Exp $") +__CIDENT_RCSID(gr_sysinfo_c,"$Id: sysinfo.c,v 1.51 2021/06/02 15:29:09 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: sysinfo.c,v 1.49 2021/04/19 16:28:49 cvsuser Exp $ +/* $Id: sysinfo.c,v 1.51 2021/06/02 15:29:09 cvsuser Exp $ * System information services. * * @@ -161,7 +161,7 @@ sysinfo_homedir(char *buf, int len) t_path[0] = 0; /* XP+ */ if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, t_path)) && *t_path) { t_path[sizeof(t_path) - 1] = 0; - if (0 == fileio_access(t_path, 0)) { + if (0 == sys_access(t_path, 0)) { p = t_path; } else { char buffer[MAX_PATH*2]; @@ -255,7 +255,7 @@ sysinfo_tmpdir(void) t_path[0] = 0; /* XP+ */ if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, t_path)) && *t_path) { t_path[sizeof(t_path) - 1] = 0; - if (0 == fileio_access(t_path, 0)) { + if (0 == sys_access(t_path, 0)) { p = t_path; } } else { @@ -265,7 +265,7 @@ sysinfo_tmpdir(void) --pathlen; /* remove trailing delimiter */ } t_path[pathlen] = 0; - if (0 == fileio_access(t_path, 0)) { + if (0 == sys_access(t_path, 0)) { p = t_path; } } @@ -322,7 +322,7 @@ sysinfo_tmpdir(void) } } #endif - if (0 == fileio_access(xtmpdir, W_OK)) { + if (0 == sys_access(xtmpdir, W_OK)) { p = tmpdirs[d]; break; } @@ -343,7 +343,7 @@ tmpdir2(const char *env) const char *p; if ((p = ggetenv(env)) != NULL && p[0] && - 0 == fileio_access(p, 0)) { + 0 == sys_access(p, 0)) { return p; } return NULL; @@ -467,13 +467,13 @@ resolve_execname(const char *name) #endif if (sys_isabspath(name)) { /* absolute path */ - if (-1 != stat(name, &sb) && !S_ISDIR(sb.st_mode)) { + if (-1 != sys_stat(name, &sb) && !S_ISDIR(sb.st_mode)) { trace_log("execname: [abs], <%s>\n", name); goto done; } /* relative, resolve and test */ } else if (0 == sys_realpath((const char *)name, t_path, sizeof(t_path)) && t_path[0]) { - if (-1 != stat(t_path, &sb) && !S_ISDIR(sb.st_mode)) { + if (-1 != sys_stat(t_path, &sb) && !S_ISDIR(sb.st_mode)) { trace_log("execname: [rel], <%s>\n", t_path); name = t_path; goto done; @@ -498,7 +498,7 @@ resolve_execname(const char *name) } trace_log("execname: [path], <%s>\n", t_path); - if (stat(t_path, &sb) >= 0 && !S_ISDIR(sb.st_mode)) { + if (sys_stat(t_path, &sb) >= 0 && !S_ISDIR(sb.st_mode)) { name = t_path; goto done; } diff --git a/gr/system.h b/gr/system.h index 676c2eea..7546f4cb 100644 --- a/gr/system.h +++ b/gr/system.h @@ -1,11 +1,11 @@ #ifndef GR_SYSTEM_H_INCLUDED #define GR_SYSTEM_H_INCLUDED #include -__CIDENT_RCSID(gr_system_h,"$Id: system.h,v 1.37 2020/06/18 12:46:40 cvsuser Exp $") +__CIDENT_RCSID(gr_system_h,"$Id: system.h,v 1.38 2021/06/02 15:29:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: system.h,v 1.37 2020/06/18 12:46:40 cvsuser Exp $ +/* $Id: system.h,v 1.38 2021/06/02 15:29:27 cvsuser Exp $ * System interface. * * @@ -55,6 +55,9 @@ extern int sys_isabspath(const char *path); extern const char * sys_pathdelimiter(void); extern const char * sys_pathseparator(void); +extern int sys_mkdir(const char *path, int amode); +extern int sys_access(const char *path, int amode); +extern int sys_chmod(const char *path, int mode); extern int sys_realpath(const char *path, char *real, int size); extern const char * sys_cwd(char *cwd, int size); extern int sys_read(int fd, void *buf, int size); diff --git a/gr/termemu_vio.c b/gr/termemu_vio.c index 97104cc0..a6cb1c4f 100644 --- a/gr/termemu_vio.c +++ b/gr/termemu_vio.c @@ -2,7 +2,7 @@ /* * libtermemu console driver * - * Copyright (c) 2007, 2012 - 2020 Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -18,7 +18,7 @@ /* * Notes: - * o Extended 256 color mode is experimental/work in progress. + * o 256 color mode available under both Legacy and Win10 enhanced console. * o Use of non-monospaced fonts are not advised unless UNICODE characters are required. * o Neither wide nor combined characters are fully addressed. */ @@ -28,8 +28,14 @@ #endif #ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0500 +#define _WIN32_WINNT 0x601 +#else +#if(_WIN32_WINNT < 0x601) +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x601 +#endif #endif + #define PSAPI_VERSION 1 // EnumProcessModules and psapi.dll #if !defined(WINDOWS_MEAN_AND_LEAN) #define WINDOWS_MEAN_AND_LEAN @@ -51,6 +57,10 @@ #define WIN32_CONSOLEEXT /* extended console */ #define WIN32_CONSOLE256 /* enable 256 color console support */ +#if defined(__WATCOMC__) +#pragma disable_message(124) /* Comparison result always 0 / 1 */ +#endif + #pragma comment(lib, "Gdi32.lib") #pragma comment(lib, "User32.lib") #pragma comment(lib, "Kernel32.lib") @@ -524,6 +534,8 @@ vio_trace(const char *fmt, ...) if (debug[len-1] != '\n') debug[len] = '\n', debug[len+1] = 0; OutputDebugStringA(debug); va_end(ap); +#else //_DEBUG + (void)fmt; #endif //_DEBUG } @@ -569,7 +581,9 @@ vio_init(void) } else if (rows > VIO_MAXROWS) { rows = VIO_MAXROWS; // limit to supported width. } + if (cols < VIO_MINCOLS) cols = VIO_MINCOLS; + //Note: shouldnt occur, console limits ~6 to accommodate def buttons. if (fontprofile || vio.cols != cols || vio.rows != rows) { const WCHAR_INFO *oimage; @@ -593,7 +607,7 @@ vio_init(void) assert(vio.chandle); assert(vio.whandle); - vio.size = rows * cols; + vio.size = rows * cols; // buffer size, in elements oimage = vio.image; vio.image = (WCHAR_INFO *)calloc(vio.size, sizeof(WCHAR_INFO)); if (oimage) { // screen has resized @@ -628,6 +642,7 @@ vio_init(void) vio.c_trashed = 1; vio.rows = rows; vio.cols = cols; + vio_goto(vio.c_row, vio.c_col); // limit current cursor for (l = 0; l < rows; ++l) { @@ -859,7 +874,7 @@ vio_profile(int rebuild) vio.fcfamily = cfix.FontFamily; vio.fcweight = cfix.FontWeight; vio.fcfamily = -1; - wcstombs(vio.fcfacename, cfix.FaceName, sizeof(vio.fcfacename)); + wcstombs(vio.fcfacename, cfix.FaceName, sizeof(vio.fcfacename) /*bytes*/); } } else { @@ -948,7 +963,7 @@ vio_profile(int rebuild) TRACE_LOG(("Console Facenames (%u)\n", (unsigned)count)) TRACE_LOG((" Idx W x H Fam Wgt Facename\n")) for (f = 0; f < count; ++f, ++cursor) { - wcstombs(t_facename, cursor->FaceName, sizeof(t_facename)); + wcstombs(t_facename, cursor->FaceName, sizeof(t_facename) /*bytes*/); TRACE_LOG((" %2d: %2u x %2u, %4u, %4u, <%s>\n", (int)cursor->nFont, \ (unsigned)cursor->dwFontSize.X, (unsigned)cursor->dwFontSize.Y, \ (unsigned)cursor->FontFamily, (unsigned)cursor->FontWeight, t_facename)) @@ -1031,7 +1046,8 @@ IsVirtualConsole(int *depth) #endif #if !defined(ENABLE_INSERT_MODE) #define ENABLE_INSERT_MODE 0x0020 - // When enabled, text entered in a console window will be inserted at the current cursor location and all text following that location will not be overwritten. + // When enabled, text entered in a console window will be inserted at the current cursor location and + // all text following that location will not be overwritten. // When disabled, all following text will be overwritten. // To enable this mode, use ENABLE_INSERT_MODE | ENABLE_EXTENDED_FLAGS. // To disable this mode, use ENABLE_EXTENDED_FLAGS without this flag. @@ -1043,7 +1059,7 @@ IsVirtualConsole(int *depth) // To disable this mode, use ENABLE_EXTENDED_FLAGS without this flag. #endif #if !defined(ENABLE_EXTENDED_FLAGS) -#define ENABLE_EXTENDED_FLAGS 0x0080 +#define ENABLE_EXTENDED_FLAGS 0x0080 // Required to enable or disable extended flags. See ENABLE_INSERT_MODE and ENABLE_QUICK_EDIT_MODE. #endif @@ -1066,7 +1082,7 @@ IsVirtualConsole(int *depth) *depth = t_depth; return TRUE; } else if (SetConsoleMode(chandle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { - (void)SetConsoleMode(chandle, mode); + (void) SetConsoleMode(chandle, mode); *depth = t_depth; return TRUE; } @@ -1478,7 +1494,7 @@ CopyOut(copyoutctx_t *ctx, unsigned pos, unsigned cnt, unsigned flags) if (-1 == ctx->cursormode) { // hide cursor, if visible GetConsoleCursorInfo(chandle, &ctx->cursorinfo); if (0 != (ctx->cursormode = ctx->cursorinfo.bVisible)) { - ctx->cursorinfo.bVisible = FALSE; + ctx->cursorinfo.bVisible = FALSE; (void) SetConsoleCursorInfo(chandle, &ctx->cursorinfo); } } @@ -1730,7 +1746,7 @@ CopyOutEx(copyoutctx_t *ctx, size_t pos, size_t cnt, unsigned flags) const WCHAR_INFO cell = *cursor++; if (start >= 0) { // attribute run - if (SameAttributesFGBG(&cell, &info, fg, bg, VIO_BOLD|VIO_BLINK|VIO_ITALIC|VIO_FAINT)) { + if (SameAttributesFGBG(&cell, &info, fg, bg, VIO_BOLD|VIO_BLINK|VIO_ITALIC|VIO_FAINT|VIO_INVERSE)) { ocursor[col++] = cell; // update out image *text = (WCHAR)cell.Char.UnicodeChar; if (++text >= etext) @@ -1753,14 +1769,17 @@ CopyOutEx(copyoutctx_t *ctx, size_t pos, size_t cnt, unsigned flags) text = textbuf; info = cell.Info; COLOR256(&info, &fg, &bg); + if (info.Attributes & VIO_INVERSE) { + SWAPRGB(fg, bg); + } if (start > 0) { // if previous is space, also redraw; address font cell draw bleeding. const WCHAR_INFO backcell = cursor[-2]; if ((IsSpace(cell.Char.UnicodeChar) && - SameAttributesFGBG(&backcell, &info, fg, bg, VIO_BOLD | VIO_BLINK | VIO_ITALIC | VIO_FAINT)) || + SameAttributesFGBG(&backcell, &info, fg, bg, VIO_BOLD|VIO_BLINK|VIO_ITALIC|VIO_FAINT|VIO_INVERSE)) || (IsSpace(backcell.Char.UnicodeChar) && - SameAttributesBG(&backcell, &info, bg, VIO_BOLD | VIO_BLINK | VIO_ITALIC | VIO_FAINT))) { + SameAttributesBG(&backcell, &info, bg, VIO_BOLD|VIO_BLINK|VIO_ITALIC|VIO_FAINT|VIO_INVERSE))) { *text++ = (WCHAR)backcell.Char.UnicodeChar; --start; } @@ -1922,11 +1941,16 @@ CopyOutEx2(copyoutctx_t *ctx, size_t pos, size_t cnt, unsigned flags) do { const WCHAR_INFO cell = *cursor++; + if (0 == cell.Char.UnicodeChar) { + ++col; + continue; // NULL, padding + } + // ESC[; H CUP, Cursor Position *Cursor moves to ; coordinate within the viewport, where is the column of the line. // if (-1 == start) { if (0 == (flags & TRASHED) && - SameCell(&cell, ocursor + col)) { + SameCell(&cell, ocursor + col)) { ++col; continue; // up-to-date } @@ -2268,6 +2292,7 @@ consolefontsenum(void) // Typefaces for Source Code Beautification. // // Fonts: + // https://github.com/powerline/fonts // http://www.proggyfonts.net/ // http://www.levien.com/type/myfonts/inconsolata.html // http://terminus-font.sourceforge.net/ and https://files.ax86.net/terminus-ttf/ @@ -2543,19 +2568,26 @@ WCHAR_BUILD(const uint32_t ch, const struct WCHAR_COLORINFO *info, WCHAR_INFO *c } +static BOOL +WATTR_COMPARE(const WCHAR_INFO *c1, const struct WCHAR_COLORINFO *info2) +{ + if (c1->Info.Flags || info2->Flags) { + return (c1->Info.Flags == info2->Flags && + c1->Info.Attributes == info2->Attributes && + c1->Info.fg == info2->fg && + c1->Info.bg == info2->bg && + c1->Info.fgrgb == info2->fgrgb && + c1->Info.bgrgb == info2->bgrgb); + } + return (c1->Info.Attributes == info2->Attributes); +} + + static BOOL WCHAR_COMPARE(const WCHAR_INFO *c1, const WCHAR_INFO *c2) { if (c1->Char.UnicodeChar == c2->Char.UnicodeChar) { - if (c1->Info.Flags || c2->Info.Flags) { - return (c1->Info.Flags == c2->Info.Flags && - c1->Info.Attributes == c2->Info.Attributes && - c1->Info.fg == c2->Info.fg && - c1->Info.bg == c2->Info.bg && - c1->Info.fgrgb == c2->Info.fgrgb && - c1->Info.bgrgb == c2->Info.bgrgb); - } - return (c1->Info.Attributes == c2->Info.Attributes); + return WATTR_COMPARE(c1, &c2->Info); } return FALSE; } @@ -2764,15 +2796,16 @@ vio_save(void) rows = 1 + sbinfo.srWindow.Bottom - sbinfo.srWindow.Top; cols = 1 + sbinfo.srWindow.Right - sbinfo.srWindow.Left; - if (!vio_state.image || vio_state.rows != rows || vio_state.cols != cols) { - CHAR_INFO *newImage; + if (!vio_state.image || // initial or size change + vio_state.rows != rows || vio_state.cols != cols) { + CHAR_INFO *nimage; if (rows <= 0 || cols <= 0 || - NULL == (newImage = calloc(rows * cols, sizeof(CHAR_INFO)))) { + NULL == (nimage = calloc(rows * cols, sizeof(CHAR_INFO)))) { return; } free(vio_state.image); // release previous; if any - vio_state.image = newImage; + vio_state.image = nimage; vio_state.rows = rows; vio_state.cols = cols; } @@ -2805,8 +2838,8 @@ ImageSave(HANDLE console, unsigned pos, unsigned cnt) wr.Top = (SHORT)(pos / cols); wr.Bottom = (SHORT)((pos + (cnt - 1)) / cols); - is.Y = (SHORT)(vio.rows - wr.Top); // size of image. - is.X = (SHORT)(vio.cols); + is.Y = (SHORT)(rows - wr.Top); // size of image. + is.X = (SHORT)(cols); ic.X = 0; // top left src cell in image. ic.Y = 0; @@ -3164,6 +3197,7 @@ vio_goto(int row, int col) { if (row >= vio.rows) row = vio.rows-1; vio.c_row = row; + if (col >= vio.cols) col = vio.cols-1; vio.c_col = col; } @@ -3221,6 +3255,8 @@ vio_define_attr(int obj, const char *what, const char *fg, const char *bg) // } if (VIO_INVERSE & (fattr|battr)) { // apply inverse. + fattr &= ~VIO_INVERSE; + battr &= ~VIO_INVERSE; SWAPFGBG(fcolor, bcolor); SWAPRGB(frgb, brgb); } @@ -3282,7 +3318,11 @@ vio_define_winattr(int obj, int fg, int bg, uint16_t attributes) assert(bg >= WIN_COLOR_MIN && bg < WIN_COLOR_NUM); if (obj < 0 || obj >= MAXOBJECTS) return; - if (VIO_INVERSE & attributes) SWAPFGBG(fg, bg); + if (VIO_INVERSE & attributes) { + attributes &= ~VIO_INVERSE; + SWAPFGBG(fg, bg); + } + if (fg < 0 || bg < 0) { // specials, dynamic vio.c_attrs[obj].Flags = VIO_F16; // vt/xterm vio.c_attrs[obj].Attributes = attributes; @@ -3314,8 +3354,13 @@ vio_define_vtattr(int obj, int fg, int bg, uint16_t attributes) vio.c_attrs[obj].Flags = VIO_F256; if (vio.maxcolors > 16) vio.activecolors = 256; } + + if (VIO_INVERSE & attributes) { + attributes &= ~VIO_INVERSE; + SWAPFGBG(fg, bg); + } + vio.c_attrs[obj].Attributes = attributes; - if (VIO_INVERSE & attributes) SWAPFGBG(fg, bg); vio.c_attrs[obj].fg = (short)vtnormal(fg); vio.c_attrs[obj].bg = (short)vtnormal(bg); vio.c_attrs[obj].fgrgb = (COLORREF)-1; @@ -3333,8 +3378,13 @@ vio_define_rgbattr(int obj, int fg, int bg, uint16_t attributes) vio.c_attrs[obj].Flags = VIO_FRGB; // true-color if (vio.maxcolors > 16) vio.activecolors = 256; + + if (VIO_INVERSE & attributes) { + attributes &= ~VIO_INVERSE; + SWAPFGBG(fg, bg); + } + vio.c_attrs[obj].Attributes = attributes; - if (VIO_INVERSE & attributes) SWAPFGBG(fg, bg); vio.c_attrs[obj].fg = (short)rgb_search(16, fg); // shadow colors (vt/xterm) vio.c_attrs[obj].bg = (short)rgb_search(16, bg); vio.c_attrs[obj].fgrgb = (COLORREF)fg; // true-colors @@ -3394,7 +3444,11 @@ vio_set_wincolor(int fg, int bg, uint16_t attributes) assert(fg >= WIN_COLOR_MIN && fg < WIN_COLOR_NUM); assert(bg >= WIN_COLOR_MIN && bg < WIN_COLOR_NUM); - if (VIO_INVERSE & attributes) SWAPFGBG(fg, bg); + if (VIO_INVERSE & attributes) { + attributes &= ~VIO_INVERSE; + SWAPFGBG(fg, bg); + } + if (fg < 0 || bg < 0) { // specials, dynamic vio.c_color.Flags = VIO_F16; // vt/xterm vio.c_color.Attributes = attributes; @@ -3425,8 +3479,12 @@ vio_set_vtcolor(int fg, int bg, uint16_t attributes) vio.c_color.Flags = VIO_F16; if (fg >= 16 || bg >= 16) vio.c_color.Flags = VIO_F256; + if (VIO_INVERSE & attributes) { + attributes &= ~VIO_INVERSE; + SWAPFGBG(fg, bg); + } + vio.c_color.Attributes = attributes; - if (VIO_INVERSE & attributes) SWAPFGBG(fg, bg); vio.c_color.fg = (short)vtnormal(fg); // primary colors (vt/xterm) vio.c_color.bg = (short)vtnormal(bg); vio.c_color.fgrgb = (COLORREF)-1; // true-colors (none) @@ -3446,8 +3504,12 @@ vio_set_rgbcolor(int32_t fg, int32_t bg, uint16_t attributes) vio.c_color.Flags = VIO_FRGB; if (vio.maxcolors > 16) vio.activecolors = 256; + if (VIO_INVERSE & attributes) { + attributes &= VIO_INVERSE; + SWAPFGBG(fg, bg); + } + vio.c_color.Attributes = attributes; - if (VIO_INVERSE & attributes) SWAPFGBG(fg, bg); vio.c_color.fg = (short)rgb_search(16, fg); // shadow colors (vt/xterm) vio.c_color.bg = (short)rgb_search(16, bg); vio.c_color.fgrgb = (COLORREF)fg; // true-colors diff --git a/gr/termemu_vio.h b/gr/termemu_vio.h index eaf74fa5..fc86f421 100644 --- a/gr/termemu_vio.h +++ b/gr/termemu_vio.h @@ -1,14 +1,14 @@ #ifndef TERMEMU_VIO_H_INCLUDED #define TERMEMU_VIO_H_INCLUDED #include -__CIDENT_RCSID(termemu_vio_h,"$Id: termemu_vio.h,v 1.3 2020/05/04 20:20:18 cvsuser Exp $") +__CIDENT_RCSID(termemu_vio_h,"$Id: termemu_vio.h,v 1.4 2021/06/10 06:13:02 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * libtermemu console driver * - * Copyright (c) 2007, 2012 - 2018 Adam Young. + * Copyright (c) 2007, 2012 - 2020 Adam Young. * * This file is part of the GRIEF Editor. * diff --git a/gr/tty.c b/gr/tty.c index cad3f051..961782a1 100644 --- a/gr/tty.c +++ b/gr/tty.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_tty_c,"$Id: tty.c,v 1.29 2014/10/22 02:33:22 ayoung Exp $") +__CIDENT_RCSID(gr_tty_c,"$Id: tty.c,v 1.30 2021/06/22 15:52:54 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: tty.c,v 1.29 2014/10/22 02:33:22 ayoung Exp $ +/* $Id: tty.c,v 1.30 2021/06/22 15:52:54 cvsuser Exp $ * Common basic tty functionality. * * @@ -92,9 +92,6 @@ ttdefaults(void) x_pt.pt_lineno_columns = -1; /* Line-number display columns. */ x_pt.pt_window_minrows = -1; /* Window rows limit. */ x_pt.pt_window_mincols = -1; /* Window column limit. */ - - x_pt.pt_unicode_version = 500; /* Unicode 5.00 */ - x_pt.pt_unicode_width = 500; /* 300 or 500 */ } diff --git a/gr/ttyterm.c b/gr/ttyterm.c index 2cc851cb..3dff4c27 100644 --- a/gr/ttyterm.c +++ b/gr/ttyterm.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_ttyterm_c,"$Id: ttyterm.c,v 1.110 2021/04/05 08:04:31 cvsuser Exp $") +__CIDENT_RCSID(gr_ttyterm_c,"$Id: ttyterm.c,v 1.115 2021/10/15 10:32:48 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: ttyterm.c,v 1.110 2021/04/05 08:04:31 cvsuser Exp $ +/* $Id: ttyterm.c,v 1.115 2021/10/15 10:32:48 cvsuser Exp $ * TTY driver termcap/terminfo based. * * @@ -32,6 +32,7 @@ __CIDENT_RCSID(gr_ttyterm_c,"$Id: ttyterm.c,v 1.110 2021/04/05 08:04:31 cvsuser #include #include /* gputenvv(), ggetenv() */ + #if defined(_VMS) #include #include @@ -179,16 +180,30 @@ typedef struct { const char * termcapname; /* termcap name */ const char * terminfoname; /* terminfo name */ const char * comment; /* comment string */ - void * token; /* optional user token */ #define TC_DESC(__desc) __desc -#define TC_TOKEN(__token) (void *)(__token) - - union { - const char *i_str; - int i_val; - } value; /* value */ } Term_t; +typedef struct { + Term_t term; + int key; +#define TC_TOKEN(__token) __token + const char * svalue; /* runtime value */ +} TermKey_t; + +typedef struct { + Term_t term; + const char ** stoken; +#define TC_STRING(__token) __token + const char * svalue; /* runtime value */ +} TermString_t; + +typedef struct { + Term_t term; + int * itoken; +#define TC_FLAG(__token) __token + int ivalue; /* runtime value*/ +} TermNumeric_t; + static void term_open(scrprofile_t *profile); static void term_ready(int repaint, scrprofile_t *profile); static void term_feature(int ident, scrprofile_t *profile); @@ -521,11 +536,11 @@ static GraphicChars_t term_characters[] = { /* graphic characters */ { TACS_VLINE, TC_DESC("vertical line") } }; -static Term_t term_strings[] = { /* strings - termcap/terminfo elements */ - { "ac", "acsc", TC_DESC("acs characters"), &tc_graphic_pairs }, +static TermString_t term_strings[] = { /* strings - termcap/terminfo elements */ + { "ac", "acsc", TC_DESC("acs characters"), TC_STRING(&tc_graphic_pairs) }, { "bt", "cbt", TC_DESC("back tab")}, - { "bl", "bel", TC_DESC("audible signal (bell)"), &tc_bl }, - { "cr", "cr", TC_DESC("carriage return"), &tc_cr }, + { "bl", "bel", TC_DESC("audible signal (bell)"), TC_STRING(&tc_bl) }, + { "cr", "cr", TC_DESC("carriage return"), TC_STRING(&tc_cr) }, { "ZA", "cpi", TC_DESC("change number of characters per inch") }, { "ZB", "lpi", TC_DESC("change number of lines per inch") }, { "ZC", "chr", TC_DESC("change horizontal resolution") }, @@ -675,9 +690,9 @@ static Term_t term_strings[] = { /* strings - termcap/terminfo el { "PU", "pulse", TC_DESC("select pulse dialling") }, { "QD", "qdial", TC_DESC("dial number #1 without checking") }, { "RC", "rmclk", TC_DESC("remove clock") }, - { "rp", "rep", TC_DESC("repeat char #1 #2 times"), &tc_rp}, + { "rp", "rep", TC_DESC("repeat char #1 #2 times"), &tc_rp }, { "RF", "rfi", TC_DESC("send next input char (for ptys)") }, - { "rs", NULL, TC_DESC("terminal reset string"), &tc_rs}, + { "rs", NULL, TC_DESC("terminal reset string"), &tc_rs }, { "r1", "rs1", TC_DESC("reset string") }, { "r2", "rs2", TC_DESC("reset string") }, { "r3", "rs3", TC_DESC("reset string") }, @@ -802,8 +817,8 @@ static Term_t term_strings[] = { /* strings - termcap/terminfo el /* * Others */ - { "cS", NULL, TC_DESC("change region to line #1 to line #2, alt form"), &tc_cS}, - { "bc", NULL, TC_DESC("move left, if not ^H (old-style)"), &tc_bc}, + { "cS", NULL, TC_DESC("change region to line #1 to line #2, alt form"), &tc_cS }, + { "bc", NULL, TC_DESC("move left, if not ^H (old-style)"), &tc_bc }, { "nl", NULL, TC_DESC("use to move down") }, /* { "ko", NULL, TC_DESC("list of self-mapped keycaps") }, */ /* { "ma", NULL, TC_DESC("map arrow keys rogue(1) motion keys") }, */ @@ -858,7 +873,7 @@ static const struct { #endif /*XXX_KO*/ -static Term_t term_numbers[] = { /* numeric - termcap/terminfo elements */ +static TermNumeric_t term_numbers[] = { /* numeric - termcap/terminfo elements */ /* * standard */ @@ -900,7 +915,7 @@ static Term_t term_numbers[] = { /* numeric - termcap/terminfo el }; -static Term_t term_keys[] = { /* keys - termcap/terminfo elements */ +static TermKey_t term_keys[] = { /* keys - termcap/terminfo elements */ { "!1", "kSAV", TC_DESC("shifted save key") }, { "!2", "kSPD", TC_DESC("shifted suspend key") }, { "!3", "kUND", TC_DESC("shifted undo key"), TC_TOKEN(KEY_REDO) }, @@ -1052,14 +1067,14 @@ static Term_t term_keys[] = { /* keys - termcap/terminfo elemen { "ku", "kcuu1", TC_DESC("up-arrow key"), TC_TOKEN(KEY_UP) }, }; -static Term_t term_flags[] = { /* boolean - termcap/terminfo elements */ +static TermNumeric_t term_flags[] = { /* boolean - termcap/terminfo elements */ { "5i", "mc5i", TC_DESC("printer won't echo on screen") }, { "HC", "chts", TC_DESC("cursor is hard to see") }, - { "LP", NULL, TC_DESC("last column of last line will not scroll"), TC_TOKEN(&tf_LP) }, + { "LP", NULL, TC_DESC("last column of last line will not scroll"), TC_FLAG(&tf_LP) }, { "MT", NULL, TC_DESC("has meta key") }, /* TODO */ { "ND", "ndscr", TC_DESC("scrolling region is non-destructive") }, - { "NL", NULL, TC_DESC("move down with \\n"), TC_TOKEN(&tf_NL) }, - { "NP", "npc", TC_DESC("pad character does not exist"), TC_TOKEN(&tf_npc) }, + { "NL", NULL, TC_DESC("move down with \\n"), TC_FLAG(&tf_NL) }, + { "NP", "npc", TC_DESC("pad character does not exist"), TC_FLAG(&tf_npc) }, { "NR", "nrrmc", TC_DESC("smcup does not reverse rmcup") }, { "YA", "xhpa", TC_DESC("only positive motion for hpa/mhpa caps") }, { "YB", "crxm", TC_DESC("using cr turns off micro mode") }, @@ -1068,37 +1083,37 @@ static Term_t term_flags[] = { /* boolean - termcap/terminfo el { "YE", "sam", TC_DESC("printing in last column causes cr") }, { "YF", "cpix", TC_DESC("changing character pitch changes resolution") }, { "YG", "lpix", TC_DESC("changing line pitch changes resolution") }, - { "am", "am", TC_DESC("terminal has automatic margins"), TC_TOKEN(&tf_am) }, - { "be", NULL, TC_DESC("back color erase"), TC_TOKEN(&tf_be) }, - { "bs", NULL, TC_DESC("uses ^H to move left"), TC_TOKEN(&tf_bs) }, + { "am", "am", TC_DESC("terminal has automatic margins"), TC_FLAG(&tf_am) }, + { "be", NULL, TC_DESC("back color erase"), TC_FLAG(&tf_be) }, + { "bs", NULL, TC_DESC("uses ^H to move left"), TC_FLAG(&tf_bs) }, { "bw", "bw", TC_DESC("cub1 wraps from column 0 to last column") }, { "cc", "ccc", TC_DESC("terminal can re-define existing colors") }, { "da", "da", TC_DESC("display may be retained above the screen") }, { "db", "db", TC_DESC("display may be retained below the screen") }, { "eo", "eo", TC_DESC("can erase overstrikes with a blank") }, { "es", "eslok", TC_DESC("escape can be used on the status line") }, - { "gn", "gn", TC_DESC("generic line type"), TC_TOKEN(&tf_gn) }, - { "hc", "hc", TC_DESC("hardcopy terminal"), TC_TOKEN(&tf_hc) }, + { "gn", "gn", TC_DESC("generic line type"), TC_FLAG(&tf_gn) }, + { "hc", "hc", TC_DESC("hardcopy terminal"), TC_FLAG(&tf_hc) }, { "hl", "hls", TC_DESC("terminal uses only HLS color notation (tektronix)") }, { "hs", "hs", TC_DESC("has extra status line") }, - { "hz", "hz", TC_DESC("can't print ~'s (hazeltine)"), TC_TOKEN(&tf_hz) }, + { "hz", "hz", TC_DESC("can't print ~'s (hazeltine)"), TC_FLAG(&tf_hz) }, { "in", "in", TC_DESC("insert mode distinguishes nulls") }, - { "km", "km", TC_DESC("Has a meta key, sets msb high"), TC_TOKEN(&tf_km) }, + { "km", "km", TC_DESC("Has a meta key, sets msb high"), TC_FLAG(&tf_km) }, { "mi", "mir", TC_DESC("safe to move while in insert mode") }, - { "ms", "msgr", TC_DESC("safe to move while in standout/underline mode"), TC_TOKEN(&tf_ms) }, + { "ms", "msgr", TC_DESC("safe to move while in standout/underline mode"), TC_FLAG(&tf_ms) }, { "nc", NULL, TC_DESC("no way to go to start of line") }, { "ns", NULL, TC_DESC("crt cannot scroll") }, - { "nx", "nxon", TC_DESC("padding won't work, xon/xoff required"), TC_TOKEN(&tf_xonoff) }, + { "nx", "nxon", TC_DESC("padding won't work, xon/xoff required"), TC_FLAG(&tf_xonoff) }, { "os", "os", TC_DESC("terminal can overstrike") }, { "pt", NULL, TC_DESC("has 8-char tabs invoked with ^I") }, { "ul", "ul", TC_DESC("underline character overstrikes") }, - { "ut", "bce", TC_DESC("screen erased with background color"), TC_TOKEN(&tf_ut) }, + { "ut", "bce", TC_DESC("screen erased with background color"), TC_FLAG(&tf_ut) }, { "xb", "xsb", TC_DESC("beehive (f1=escape, f2=ctrl C)") }, - { "xn", "xenl", TC_DESC("newline ignored after 80 cols (concept)"), TC_TOKEN(&tf_xn) }, - { "xo", NULL, TC_DESC("terminal uses xon/xoff handshaking"), TC_TOKEN(&tf_xonoff) }, + { "xn", "xenl", TC_DESC("newline ignored after 80 cols (concept)"), TC_FLAG(&tf_xn) }, + { "xo", NULL, TC_DESC("terminal uses xon/xoff handshaking"), TC_FLAG(&tf_xonoff) }, { "xr", "xon", TC_DESC("return clears the line") }, - { "xs", "xhp", TC_DESC("standout not erased by overwriting (hp)"), TC_TOKEN(&tf_xs) }, - { "xt", "xt", TC_DESC("tabs destructive, magic so char (Telray 1061)"), TC_TOKEN(&tf_xt) } + { "xs", "xhp", TC_DESC("standout not erased by overwriting (hp)"), TC_FLAG(&tf_xs) }, + { "xt", "xt", TC_DESC("tabs destructive, magic so char (Telray 1061)"), TC_FLAG(&tf_xt) } }; @@ -1151,12 +1166,14 @@ static const struct colormap { /* BRIEF -> XTERM color map */ { COLOR_NONE, -1, -1, -1, -1, -1, -1, -1 } }; + /* * Scroll window */ static int tt_top = -1; /* Top of scroll region. */ static int tt_bot = -1; /* Bottom of scroll region. */ + /* * Color information */ @@ -1326,8 +1343,8 @@ ttinit(void) } else if (term_xtermlike(term)) { /* eg. xterm-color */ t_attributes = TA_XTERM | TA_XTERMLIKE; #if defined(__CYGWIN__) - if (ggetenv("COMSPEC")) { - t_attributes |= TA_DARK; /* assume cmd/mintty */ + if (ggetenv("COMSPEC")) { + t_attributes |= TA_DARK; /* assume cmd/mintty */ } #endif /*__CYGWIN__*/ } @@ -1363,17 +1380,18 @@ ttinit(void) /* * string values */ - const Term_t *ti = term_strings + i; - const char *name = ttiname(ti); + TermString_t *ti = term_strings + i; + const Term_t *term = &ti->term; + const char *name = ttiname(term); - if (name && NULL != (cp = ttigetstr(ti))) { - const char **token = term_strings[i].token; + if (name && NULL != (cp = ttigetstr(term))) { + const char **token = ti->stoken; - term_strings[i].value.i_str = cp; + ti->svalue = cp; if (token) { - *token = cp; + *token = ti->svalue; } - trace_log("\t%-50s%c %-5s : %s\n", term_strings[i].comment, + trace_log("\t%-50s%c %-5s : %s\n", term->comment, (token ? '*' : ' '), name, c_string(cp)); if (token == &tc_graphic_pairs) { @@ -1399,15 +1417,16 @@ ttinit(void) /* * keys */ - const Term_t *ti = term_keys + i; - const char *name = ttiname(ti); + TermKey_t *ti = term_keys + i; + const Term_t *term = &ti->term; + const char *name = ttiname(term); - if (name && NULL != (cp = ttigetstr(ti))) { - const size_t kcode = (size_t)term_keys[i].token; + if (name && NULL != (cp = ttigetstr(term))) { + const size_t kcode = (size_t)ti->key; - term_keys[i].value.i_str = cp; /* loaded later by ttkeys() */ + ti->svalue = cp; /* loaded later by ttkeys() */ - trace_log("\t%-50s%c %-5s : %s\n", term_keys[i].comment, + trace_log("\t%-50s%c %-5s : %s\n", term->comment, (kcode ? '*' : ' '), name, c_string(cp)); if (kcode >= F(1) && kcode <= F(10)) { @@ -1425,16 +1444,17 @@ ttinit(void) /* * numbers */ - const Term_t *ti = term_numbers + i; - const char *name = ttiname(ti); + TermNumeric_t *ti = term_numbers + i; + const Term_t *term = &ti->term; + const char *name = ttiname(term); if (name) { - term_numbers[i].value.i_val = ttigetnum(ti); - if (term_numbers[i].token) { - *((int *)term_numbers[i].token) = term_numbers[i].value.i_val; + ti->ivalue = ttigetnum(term); + if (ti->itoken) { + *ti->itoken = ti->ivalue; } - trace_log("\t%-50s%c %-5s : %d\n", term_numbers[i].comment, - (term_numbers[i].token ? '*' : ' '), name, term_numbers[i].value.i_val); + trace_log("\t%-50s%c %-5s : %d\n", term->comment, + (ti->itoken ? '*' : ' '), name, ti->ivalue); } } @@ -1443,16 +1463,17 @@ ttinit(void) /* * flags */ - const Term_t *ti = term_flags + i; - const char *name = ttiname(ti); + TermNumeric_t *ti = term_flags + i; + const Term_t *term = &ti->term; + const char *name = ttiname(term); if (name) { - term_flags[i].value.i_val = ttigetflag(ti); - if (term_flags[i].token) { - *((int *)term_flags[i].token) = term_flags[i].value.i_val; + ti->ivalue = ttigetflag(term); + if (ti->itoken) { + *ti->itoken = ti->ivalue; } - trace_log("\t%-50s%c %-5s : %d\n", term_flags[i].comment, - (term_flags[i].token ? '*' : ' '), name, term_flags[i].value.i_val); + trace_log("\t%-50s%c %-5s : %d\n", term->comment, + (ti->itoken ? '*' : ' '), name, ti->ivalue); } } } @@ -1813,9 +1834,9 @@ term_ready(int repaint, scrprofile_t *profile) } } else if (t_attributes & TA_MINTTY) { -// if (! xf_mouse) { + if (xf_mouse) { /* mouse enabled? */ ttpush("\033[?7786h"); /* mouse-wheel reports only */ -// } + } } else if (t_attributes & TA_VT100LIKE) { ttpush("\033=\033[?1]"); /* enable cursor keys */ @@ -1896,8 +1917,11 @@ term_feature(int ident, scrprofile_t *profile) break; case TF_ENCODING: + break; case TF_UNICODE_VERSION: - case TF_UNICODE_WIDTH: + if (x_pt.pt_unicode_version[0]) { + ucs_width_set(x_pt.pt_unicode_version); + } break; } } @@ -2404,8 +2428,8 @@ ttkeys(void) * Keys */ for (i = 0; i < (sizeof(term_keys)/sizeof(term_keys[0])); ++i) - if (term_keys[i].value.i_str && term_keys[i].token) { - key_define_key_seq((int)term_keys[i].token, term_keys[i].value.i_str); + if (term_keys[i].svalue && term_keys[i].key) { + key_define_key_seq(term_keys[i].key, term_keys[i].svalue); } /* @@ -3112,9 +3136,9 @@ term_tidy(void) ttpush("\033[?2000l"); /* disable RAW mode */ } } else if (t_attributes & TA_MINTTY) { -//TODO if (! xf_mouse) { - ttpush("\033[?7786l"); /* disable mouse-wheel reports */ -// } + if (xf_mouse) { /* mouse enabled? */ + ttpush("\033[?7786l"); /* disable mouse-wheel reports */ + } } term_graphic_exit(); /* graphic mode */ @@ -4724,11 +4748,11 @@ term_putc(vbyte_t c) * width character enabled displays */ if (isutf8 && MCHAR_ISUTF8(c)) { /* MCHAR */ - if ((width = mchar_ucs_width(c, -1)) >= 0) { + if ((width = ucs_width(c)) >= 0) { ED_TRACE3(("ttputc_utf8(row:%d, col:%d, char:%d/0x%x, width:%d)\n",\ ttrow, ttcol, c, c, width)) term_graphic_exit(); - t_count += mchar_ucs_encode(c, (char *)(t_buffer + t_count)); + t_count += charset_utf8_encode(c, (char *)(t_buffer + t_count)); goto complete; } width = 1; /* control */ @@ -5213,4 +5237,3 @@ do_copy_screen(void) /* void () */ } #endif /*!USE_VIO_BUFFER && !DJGPP */ - diff --git a/gr/ttyterm.c.001 b/gr/ttyterm.c.001 new file mode 100644 index 00000000..8242a42c --- /dev/null +++ b/gr/ttyterm.c.001 @@ -0,0 +1,5219 @@ +#include +__CIDENT_RCSID(gr_ttyterm_c,"$Id: ttyterm.c,v 1.110 2021/04/05 08:04:31 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* $Id: ttyterm.c,v 1.110 2021/04/05 08:04:31 cvsuser Exp $ + * TTY driver termcap/terminfo based. + * + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * The GRIEF Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License for more details. + * ==end== + */ + +// #define ED_LEVEL 2 + +#include + +#if !defined(USE_VIO_BUFFER) && !defined(DJGPP) + +#if defined(__CYGWIN__) +#include /* GetConsoleOutputCP() */ +#include /* uname */ +#endif + +#include +#include /* gputenvv(), ggetenv() */ + + +#if defined(_VMS) +#include +#include +#include +#include +#include +#include +#endif + +#if defined(HAVE_LIBNCURSESW) +#if defined(HAVE_NCURSESW_CURSESW_H) +#include +#include +#include +#elif defined(HAVE_NCURSESW_CURSES_H) +#include +#include +#include +#elif defined(HAVE_NCURSESW_H) +#include +#if defined(HAVE_TERMCAP_H) +#include +#endif +#if defined(HAVE_TERM_H) +#include +#endif +#else /*!HAVE_NCURSESW_CURSES_H || HAVE_NCURSESW_H*/ +#error "HAVE_LIBNCURSEW defined yet missing headers, check config" +#endif + +#elif defined(HAVE_LIBNCURSES) +#if defined(HAVE_NCURSES_NCURSES_H) +#include +#include +#include +#elif defined(HAVE_NCURSES_CURSES_H) +#include +#include +#include +#elif defined(HAVE_NCURSES_H) +#include +#if defined(HAVE_TERMCAP_H) +#include +#endif +#if defined(HAVE_TERM_H) +#include +#endif +#else /*!HAVE_NCURSES_CURSES_H || HAVE_NCURSES_H*/ +#error "HAVE_LIBNCURSE defined yet missing headers, check config" +#endif + +#elif defined(HAVE_LIBCURSES) +#if defined(HAVE_CURSES_H) +#include +#if defined(HAVE_TERMCAP_H) +#include +#endif +#if defined(HAVE_TERM_H) +#if defined(HAVE_TERMIO_H) +#include /* solaris (SGTTY definition) */ +#endif +#include +#else /* missing prototypes */ +extern char * tgetstr(char *, char **); +extern char * tgoto(const char * , int a, int b); +extern char * tparm(const char *, ...); +#endif +#else /*!HAVE_CURSES_H*/ +#error "HAVE_LIBCURSES defined yet missing headers, check config" +#endif + +#elif defined(HAVE_LIBTERMCAP) +#if defined(HAVE_TERMCAP_H) +#include +#else /*HAVE_TERMCAP_H*/ +#error "HAVE_LIBTERMCAP defined yet missing headers, check config" +#endif + +#elif defined(HAVE_LIBTERMLIB) +#include +#define HAVE_TERMCAP + +#else +#include "edtermcap.h" /* use local implementation -- BAD */ +#endif + +#if defined(HAVE_TERMINFO) && defined(HAVE_TERMCAP) +#define XF_TERMCAP if (xf_termcap) /* dynamic selection */ +#define XF_TERMINFO if (! xf_termcap) +#else +#if !defined(HAVE_TERMINFO) && !defined(HAVE_TERMCAP) +#error "no terminal interface style defined (TERMINFO nor TERMCAP), check cofig" +#endif +#define XF_TERMCAP +#define XF_TERMINFO +#endif + +#if !defined(HAVE_OSPEED) && !defined(__CYGWIN__) && !defined(sun) && \ + defined(OSPEED_EXTERN) /* ospeed available? (diag only) */ +#define HAVE_OSPEED +extern int ospeed; +#endif + +#if defined(HAVE_OUTFUNTYPE) /* tputs() interface */ +#define TPUTS_OUTFUNC (outfuntype) +#define TPUTS_OUTTYPE int +#elif defined(TPUTS_TAKES_CHAR) +#define TPUTS_OUTFUNC (int (*)(char)) +#define TPUTS_OUTTYPE char +#else +#define TPUTS_OUTFUNC (int (*)(int)) +#define TPUTS_OUTTYPE int +#endif + +#include /* needs to be after [n]curses.h */ +#include /* str_...()/sxprintf() */ + +#include "accum.h" /* acc_ ... */ +#include "asciidefs.h" +#include "cmap.h" /* cmap ... */ +#include "color.h" /* color ... */ +#include "debug.h" /* trace ... */ +#include "display.h" +#include "echo.h" +#include "eval.h" /* get_str() ... */ +#include "getkey.h" /* io_... */ +#include "keyboard.h" +#include "line.h" +#include "main.h" +#include "map.h" +#include "mchar.h" /* mchar_...() */ +#include "mouse.h" +#include "playback.h" +#include "procspawn.h" +#include "system.h" +#include "tty.h" +#include "undo.h" +#include "window.h" + +#define ANSI_COLORS 16 +#define XTERM_COLORS 16 +#define NOCOLOR 0x7fff + +typedef struct { + const char * termcapname; /* termcap name */ + const char * terminfoname; /* terminfo name */ + const char * comment; /* comment string */ + void * token; /* optional user token */ +#define TC_DESC(__desc) __desc +#define TC_TOKEN(__token) (void *)(__token) + + union { + const char *i_str; + int i_val; + } value; /* value */ +} Term_t; + +static void term_open(scrprofile_t *profile); +static void term_ready(int repaint, scrprofile_t *profile); +static void term_feature(int ident, scrprofile_t *profile); +static void term_display(void); +static int term_control(int action, int param, ...); +static void term_close(void); +static int hasfeature(const char *term, const char *what); + +static const char * ttisetup(void); +static const char * ttiname(const Term_t *ti); +static const char * ttigetstr(const Term_t *ti); +static int ttigetnum(const Term_t *ti); +static int ttigetflag(const Term_t *ti); + +static int term_xtermlike(const char *term); + +static void acs_dump(const char *bp); +static const char * acs_box_characters(const char *bp); +static int acs_locale_breaks(void); + +static void term_tidy(void); +static void term_move(int row, int col); +static int term_cursor(int visible, int imode, int virtual_space); +static int term_names(const char *title, const char *icon); +static void term_beep(int freq, int duration); + +static void term_colors(void); +static void term_fgbg(void); +static const char * fgbg_value(const char *src, int *result); +static unsigned fgbg_import(unsigned edefault, int udefault); + +static void xterm_colors(const char *value); +static int xterm_colors_get(char *buffer, int length); +static int xterm_colors_set(const char *value); + +static int term_isutf8(void); +static int term_identification(void); +static int term_read(char *buf, int blen, accint_t tmo); + +static __CINLINE void term_graphic_enter(void); +static __CINLINE void term_graphic_exit(void); + +static void term_clear(void); +static void term_zero(int restore); +static void term_flush(void); +static void term_sizeget(int *nrow, int *ncol); + +static void term_putc(vbyte_t c); +static int term_eeol(void); +static int term_ce(void); +static int term_lastsafe(void); +static void term_eeop(int restore); +static void term_repeat(int cnt, vbyte_t fill, int where); +static int term_insl(int row, int bot, int nlines, vbyte_t fillcolor); +static int term_dell(int row, int bot, int nlines, vbyte_t fillcolor); +static void term_scrollset(int top, int bot); +static void term_scrollreset(void); +static void term_attr(vbyte_t color); +static void term_styleon(unsigned mode); +static void term_styleoff(void); +static void term_colorreset(void); +static int term_cost(const char *s); + +static void ttputpad(const char *str); +static void ttputctl(const char *str, int a); +static void ttputctl2(const char *str, int a, int b); +static void ttprintf(const char *str, ...); +static void ttprintf2(const char *str, ...); + +static void ega_switch(int flag); + +/* + * This is the output buffer. NOBUF is how many bytes we can put in the buffer. We + * leave a lot of room for expansion because a single character may cause us to + * output multiple characters (e.g. printing top bit or graphics characters). + */ +#define NOOVFLOW 100 +#define NOBUF ((8 * 1024) - NOOVFLOW) + +static unsigned t_count; +static unsigned char t_buffer[NOBUF + NOOVFLOW]; + +/* + * Termcap buffer + */ +#define TC_SLEN (1024 * 32) /* 32k - tgetent wants >= 16k */ + +#if defined(HAVE_TERMCAP) +static char * tcapcursor; +static char tcapbuffer[TC_SLEN]; /* termcap buffer */ +static char tcapstrings[TC_SLEN]; /* termcap local storage */ +#endif + +/* + * Terminate attributes + */ +#define TA_XTERM 0x0001 +#define TA_VT100LIKE 0x0002 +#define TA_XTERMLIKE 0x0004 + +#define TA_LINUX 0x0010 +#define TA_CYGWIN 0x0020 +#define TA_KONSOLE 0x0040 +#define TA_SCREEN 0x0080 +#define TA_MINTTY 0x0100 + +#define TA_DARK 0x1000 /* generally dark background */ +#define TA_LIGHT 0x2000 /* light */ +#define TA_MONO 0x4000 /* mono terminal */ + +static unsigned t_attributes; /* attributes */ +static int t_charout; /* number of characters output. */ +static unsigned t_insdel; /* do we have both insert & delete line? */ +static int t_padchar = -1; /* pad character (if any) */ +static int t_acs_locale_breaks; + +/* + * Terminate status + */ +static unsigned t_gmode; /* graphics character set active */ +static int t_cost; /* terminal costing accumulator */ +static unsigned t_specials; /* special bits */ + +/* + * Color control + */ +static char t_colorsorg[XTERM_COLORS * 32]; +static char t_colorsuser[XTERM_COLORS * 32]; + + +/* + * Cached termap controls + * + * References: + * ANSI Standard X3.64-1979. + * X/Open System Interface Definitions, Issue 4, Version 2. + * + * http://www.xfree86.org/current/ctlseqs.html + * + * http://dickey.his.com/xterm/xterm.faq.html + * + * http://frexx.de/xterm-256-notes + * + * http://en.wikipedia.org/wiki/ANSI_escape_code + */ +static int + tf_gn, /* generic terminal. */ + tf_hc, /* hard-copy terminal. */ + tf_npc, /* no pad character. */ + tf_xonoff, /* xon/xoff required. */ + tf_am, /* has auto-margins. */ + tf_xn, /* the cursor wraps in a strange way. */ + tf_hz, /* no hazel line support. */ + tf_km, /* meta key sets msb */ + tf_LP, /* last column safe. */ + tf_NL, /* move down using \n. */ + tf_bs, /* move left using ^H. */ + tf_Colors, /* max colors */ + tf_Pairs, /* max color-pairs */ + tf_ut, /* screen erased with background color. */ + tf_be, /* back color erase (xterm). */ + tf_xs, tf_xt, /* attribute clear mode */ + tf_ms; /* save to move cursor whilst standout/underlined */ + +static int + tn_sg, /* number of glitches, 0 for invisable, -1 for none */ + tn_li, tn_co, /* lines/columns */ + tn_NC; /* attributes which dont mix with colors */ + +static const char + *tc_ti, /* Term init -- start using cursor motion. */ + *tc_te, /* Term end --- end using cursor motion. */ + *tc_ke, /* Enter keypad mode. */ + *tc_ks, /* Exit keypad mode. */ + *tc_rs, /* Reset sequence. */ + *tc_am_on, /* Turn on automatic margins. */ + *tc_bl, /* Bell. */ + + *tc_cm, /* Cursor motion. */ + *tc_ho, /* Home cursor. */ + *tc_ll, /* Left-end cursor. */ + *tc_cr, /* Cursor newline. */ + *tc_up, /* Cursor up on line. */ + *tc_pUP, /* Cursor up on line - parameterised. */ + *tc_do, /* Cursor down. */ + *tc_pDO, /* Cursor down - parameterised. */ + *tc_le, /* Cursor left (new style). */ + *tc_bc, /* Cursor left (old style). */ + *tc_pBC, /* Cursor left - parameterised. */ + *tc_nd, /* Cursor right. */ + *tc_pRI, /* Cursor right - parameterised. */ + *tc_cv, /* Cursor vertical movement. */ + *tc_ch, /* Cursor horz movement. */ + + *tc_vs, /* Enhance the cursor. */ + *tc_ve, /* Normal cursor. */ + *tc_vb, /* Visual bell. */ + *tc_vi, /* Hide cursor. */ + + *tc_cs, /* Set scroll region. */ + *tc_cS, /* Set scroll region, alt form (see Emacs). */ + *tc_sf, /* Forward index (used with scroll region). */ + *tc_sr, /* Back index (used with scroll region). */ + *tc_pSF, /* Forward index */ + *tc_pSR, /* Back index */ + + *tc_al, /* Add line */ + *tc_dl, /* Delete line */ + *tc_pAL, /* Parameterized add line. */ + *tc_pDL, /* Parameterized delete line. */ + + *tc_pc, /* Padding character */ + *tc_dc, /* Delete a character. */ + *tc_pDC, /* Parameterized character delete. */ + *tc_ic, /* Insert a single space. */ + *tc_cb, /* Clear to beginning of line. */ + *tc_cd, /* Clear to end of display. */ + *tc_ce, /* Clear to end of line. */ + *tc_cl, /* Clear screen. */ + *tc_rp, /* repeat #1 #2 times */ + *tc_ech, /* erase #1 characters */ + *tc_im, /* Insert mode. */ + *tc_ei, /* End insert mode. */ + + *tc_oc, *tc_op, /* Reset colors. */ + *tc_me, /* Turn off all attributes. */ + *tc_mm, *tc_mo, /* Turn on/off meta mode (8th-bit on). */ + *tc_so, *tc_se, /* Start/end standout mode. */ + *tc_us, *tc_ue, /* Turn on/off underline mode. */ + *tc_mb, /* Turn on blinking. */ + *tc_md, /* Make bold. */ + *tc_ZH, *tc_ZR, /* Italic (on/off). */ + *tc_mr, *tc_ZX, /* Reverse (on/off). */ + *tc_sa; /* Attribute set. */ + +static const char + *tc_acs_start, /* as */ + *tc_acs_end, /* ae */ + *tc_acs_enable; /* enable ACS */ + +static unsigned char /* ac */ + tc_acs_map[129]; + +static const char tc_graphic_default[] = + "a:j+k+l+m+q-t+u+v+w+x|n+`+f\\g#~o,<+>.v-^h#0#"; + +static const char + *tc_graphic_pairs, + *tc_box_characters; + +static const char + *tc_ANSI_Color_Fg, *tc_Color_Fg, /* color selection */ + *tc_ANSI_Color_Bg, *tc_Color_Bg; + +typedef struct { + char ident; /* internal identifier */ + const char * name; /* desc */ +} GraphicChars_t; + +enum { + /* + * ACC mappings, includes ncurse's extensions + */ + TACS_STERLING = '}', + TACS_DARROW = '.', + TACS_LARROW = ',', + TACS_RARROW = '+', + TACS_UARROW = '-', + TACS_BOARD = 'h', + TACS_BULLET = '~', + TACS_CKBOARD = 'a', + TACS_DEGREE = 'f', + TACS_DIAMOND = '`', + TACS_GEQUAL = 'z', + TACS_PI = '{', + TACS_HLINE = 'q', + TACS_LANTERN = 'i', + TACS_PLUS = 'n', + TACS_LEQUAL = 'y', + TACS_LLCORNER = 'm', + TACS_LRCORNER = 'j', + TACS_NEQUAL = '|', + TACS_PLMINUS = 'g', + TACS_S1 = 'o', + TACS_S3 = 'p', + TACS_S7 = 'r', + TACS_S9 = 's', + TACS_BLOCK = '0', + TACS_TTEE = 'w', + TACS_RTEE = 'u', + TACS_LTEE = 't', + TACS_BTEE = 'v', + TACS_ULCORNER = 'l', + TACS_URCORNER = 'k', + TACS_VLINE = 'x' + }; + +static GraphicChars_t term_characters[] = { /* graphic characters */ + { TACS_STERLING, TC_DESC("UK pound sign") }, + { TACS_DARROW, TC_DESC("arrow pointing down") }, + { TACS_LARROW, TC_DESC("arrow pointing left") }, + { TACS_RARROW, TC_DESC("arrow pointing right") }, + { TACS_UARROW, TC_DESC("arrow pointing up") }, + { TACS_BOARD, TC_DESC("board of squares") }, + { TACS_BULLET, TC_DESC("bullet") }, + { TACS_CKBOARD, TC_DESC("checker board (stipple)") }, + { TACS_DEGREE, TC_DESC("degree symbol") }, + { TACS_DIAMOND, TC_DESC("diamond") }, + { TACS_GEQUAL, TC_DESC("greater-than-or-equal-to") }, + { TACS_PI, TC_DESC("greek pi") }, + { TACS_HLINE, TC_DESC("horizontal line") }, + { TACS_LANTERN, TC_DESC("lantern symbol") }, + { TACS_PLUS, TC_DESC("large plus or crossover") }, + { TACS_LEQUAL, TC_DESC("less-than-or-equal-to") }, + { TACS_LLCORNER, TC_DESC("lower left corner") }, + { TACS_LRCORNER, TC_DESC("lower right corner") }, + { TACS_NEQUAL, TC_DESC("not-equal") }, + { TACS_PLMINUS, TC_DESC("plus/minus") }, + { TACS_S1, TC_DESC("scan line 1") }, + { TACS_S3, TC_DESC("scan line 3") }, + { TACS_S7, TC_DESC("scan line 7") }, + { TACS_S9, TC_DESC("scan line 9") }, + { TACS_BLOCK, TC_DESC("solid square block") }, + { TACS_TTEE, TC_DESC("tee pointing down") }, + { TACS_RTEE, TC_DESC("tee pointing left") }, + { TACS_LTEE, TC_DESC("tee pointing right") }, + { TACS_BTEE, TC_DESC("tee pointing up") }, + { TACS_ULCORNER, TC_DESC("upper left corner") }, + { TACS_URCORNER, TC_DESC("upper right corner") }, + { TACS_VLINE, TC_DESC("vertical line") } + }; + +static Term_t term_strings[] = { /* strings - termcap/terminfo elements */ + { "ac", "acsc", TC_DESC("acs characters"), &tc_graphic_pairs }, + { "bt", "cbt", TC_DESC("back tab")}, + { "bl", "bel", TC_DESC("audible signal (bell)"), &tc_bl }, + { "cr", "cr", TC_DESC("carriage return"), &tc_cr }, + { "ZA", "cpi", TC_DESC("change number of characters per inch") }, + { "ZB", "lpi", TC_DESC("change number of lines per inch") }, + { "ZC", "chr", TC_DESC("change horizontal resolution") }, + { "ZD", "cvr", TC_DESC("change vertical resolution") }, + { "cs", "csr", TC_DESC("change region to line #1 to line #2"), &tc_cs }, + { "rP", "rmp", TC_DESC("like ip but when in insert mode") }, + { "ct", "tbc", TC_DESC("clear all tab stops") }, + { "MC", "mgc", TC_DESC("clear right and left soft margins") }, + { "cl", "clear", TC_DESC("clear screen and home cursor"), &tc_cl }, + { "cb", "el1", TC_DESC("clear to beginning of line"), &tc_cb }, + { "ce", "el", TC_DESC("clr eol"), &tc_ce }, + { "cd", "ed", TC_DESC("clear to end of screen"), &tc_cd }, + { "ch", "hpa", TC_DESC("horizontal position #1, absolute"), &tc_ch }, + { "CC", "cmdch", TC_DESC("terminal settable cmd character in prototype !?") }, + { "CW", "cwin", TC_DESC("define a window #1 from #2, #3 to #4, #5") }, + { "cm", "cup", TC_DESC("move to row #1 columns #2"), &tc_cm }, + { "do", "cud1", TC_DESC("down one line"), &tc_do }, + { "ho", "home", TC_DESC("home cursor (if no cup)"), &tc_ho }, + { "vi", "civis", TC_DESC("make cursor invisible"), &tc_vi }, + { "le", "cub1", TC_DESC("move left one space"), &tc_le }, + { "CM", "mrcup", TC_DESC("memory relative cursor addressing") }, + { "ve", "cnorm", TC_DESC("make cursor appear normal (undo civis/cvvis)"), &tc_ve }, + { "nd", "cuf1", TC_DESC("move right one space"), &tc_nd }, + { "ll", "ll", TC_DESC("last line, first column (if no cup)"), &tc_ll }, + { "up", "cuu1", TC_DESC("up one line"), &tc_up }, + { "vs", "cvvis", TC_DESC("make cursor very visible"), &tc_vs }, + { "ZE", "defc", TC_DESC("define a character") }, + { "dc", "dch1", TC_DESC("delete character"), &tc_dc }, + { "dl", "dl1", TC_DESC("delete line"), &tc_dl }, + { "DI", "dial", TC_DESC("dial number #1") }, + { "ds", "dsl", TC_DESC("disable status line") }, + { "DK", "dclk", TC_DESC("display clock at (#1,#2)") }, + { "hd", "hd", TC_DESC("half a line down") }, + { "eA", "enacs", TC_DESC("enable alternate char set"), &tc_acs_enable }, + { "as", "smacs", TC_DESC("enter alt charset mode"), &tc_acs_start }, + { "SA", "smam", TC_DESC("turn on automatic margins"), &tc_am_on }, + { "mb", "blink", TC_DESC("turn on blinking"), &tc_mb }, + { "md", "bold", TC_DESC("turn on bold (extra bright) mode"), &tc_md }, + { "ti", "smcup", TC_DESC("string to start programs using cup"), &tc_ti }, + { "dm", "smdc", TC_DESC("enter delete mode") }, + { "mh", "dim", TC_DESC("turn on half-bright mode") }, + { "ZF", "swidm", TC_DESC("enter double-wide mode") }, + { "ZG", "sdrfq", TC_DESC("enter draft-quality mode") }, + { "im", "smir", TC_DESC("enter insert mode"), &tc_im }, + { "ZH", "sitm", TC_DESC("enter italic mode"), &tc_ZH }, + { "ZI", "slm", TC_DESC("start leftward carriage motion") }, + { "ZJ", "smicm", TC_DESC("start micro-motion mode") }, + { "ZK", "snlq", TC_DESC("enter NLQ mode") }, + { "ZL", "snrmq", TC_DESC("enter normal-quality mode") }, + { "mp", "prot", TC_DESC("turn on protected mode") }, + { "mr", "rev", TC_DESC("turn on reverse video mode"), &tc_mr }, + { "mk", "invis", TC_DESC("turn on blank mode (characters invisible)") }, + { "ZM", "sshm", TC_DESC("enter shadow-print mode") }, + { "so", "smso", TC_DESC("begin standout mode"), &tc_so }, + { "ZN", "ssubm", TC_DESC("enter subscript mode") }, + { "ZO", "ssupm", TC_DESC("enter superscript mode") }, + { "us", "smul", TC_DESC("begin underline mode"), &tc_us }, + { "ZP", "sum", TC_DESC("start upward carriage motion") }, + { "SX", "smxon", TC_DESC("turn on xon/xoff handshaking") }, + { "ec", "ech", TC_DESC("erase #1 characters"), &tc_ech }, + { "ae", "rmacs", TC_DESC("exit alt charset mode"), &tc_acs_end }, + { "RA", "rmam", TC_DESC("turn off automatic margins") }, + { "me", "sgr0", TC_DESC("turn off all attributes"), &tc_me }, + { "te", "rmcup", TC_DESC("strings to end programs using cup"), &tc_te }, + { "ed", "rmdc", TC_DESC("end delete mode") }, + { "ZQ", "rwidm", TC_DESC("end double-wide mode") }, + { "ei", "rmir", TC_DESC("exit insert mode"), &tc_ei }, + { "ZR", "ritm", TC_DESC("end italic mode"), &tc_ZR }, + { "ZS", "rlm", TC_DESC("end left-motion mode") }, + { "ZU", "rmicm", TC_DESC("end shadow-print mode") }, + { "ZT", "rshm", TC_DESC("end micro-motion mode") }, + { "se", "rmso", TC_DESC("exit standout mode"), &tc_se }, + { "ZV", "rsubm", TC_DESC("exit_subscript_mode") }, + { "ZW", "rsupm", TC_DESC("end superscript mode") }, + { "ue", "rmul", TC_DESC("exit underline mode"), &tc_ue }, + { "ZX", "rum", TC_DESC("end reverse character motion"), &tc_ZX }, + { "RX", "rmxon", TC_DESC("turn off xon/xoff handshaking") }, + { "PA", "pause", TC_DESC("pause for 2-3 seconds") }, + { "fh", "hook", TC_DESC("flash switch hook") }, + { "vb", "flash", TC_DESC("visible bell (may not move cursor)"), &tc_vb }, + { "ff", "ff", TC_DESC("hardcopy terminal page eject") }, + { "fs", "fsl", TC_DESC("return from status line") }, + { "WG", "wingo", TC_DESC("go to window #1") }, + { "HU", "hup", TC_DESC("hang-up phone") }, + { "i1", "is1", TC_DESC("initialization string") }, + { "is", "is2", TC_DESC("initialization string") }, + { "i2", NULL, TC_DESC("secondary initialization string") }, + { "i3", "is3", TC_DESC("initialization string") }, + { "if", "if", TC_DESC("name of initialization file") }, + { "iP", "iprog", TC_DESC("path name of program for initialization") }, + { "Ic", "initc", TC_DESC("initialize color #1 to (#2,#3,#4)") }, + { "Ip", "initp", TC_DESC("initialize color pair #1 to fg=(#2,#3,#4), bg=(#5,#6,#7)") }, + { "ic", "ich1", TC_DESC("insert character"), &tc_ic }, + { "al", "il1", TC_DESC("insert line"), &tc_al }, + { "ip", "ip", TC_DESC("insert padding after inserted character") }, + { "ke", "rmkx", TC_DESC("leave 'keyboard_transmit' mode"), &tc_ke }, + { "ks", "smkx", TC_DESC("enter 'keyboard_transmit' mode"), &tc_ks }, + { "l0", "lf0", TC_DESC("label on function key f0 if not f0") }, + { "l1", "lf1", TC_DESC("label on function key f1 if not f1") }, + { "l2", "lf10", TC_DESC("label on function key f2 if not f2") }, + { "l3", "lf2", TC_DESC("label on function key f3 if not f3") }, + { "l4", "lf3", TC_DESC("label on function key f4 if not f4") }, + { "l5", "lf4", TC_DESC("label on function key f5 if not f5") }, + { "l6", "lf5", TC_DESC("label on function key f6 if not f6") }, + { "l7", "lf6", TC_DESC("label on function key f7 if not f7") }, + { "l8", "lf7", TC_DESC("label on function key f8 if not f8") }, + { "l9", "lf8", TC_DESC("label on function key f9 if not f9") }, + { "la", "lf9", TC_DESC("label on function key f10 if not f10") }, + { "Lf", "fln", TC_DESC("label format") }, + { "LF", "rmln", TC_DESC("turn off soft labels") }, + { "LO", "smln", TC_DESC("turn on soft labels") }, + { "mo", "rmm", TC_DESC("turn off meta mode"), &tc_mo }, + { "mm", "smm", TC_DESC("turn on meta mode (8th-bit on)"), &tc_mm }, + { "ZY", "mhpa", TC_DESC("like column_address in micro mode") }, + { "ZZ", "mcud1", TC_DESC("like cursor_down in micro mode") }, + { "Za", "mcub1", TC_DESC("like cursor_left in micro mode") }, + { "Zb", "mcuf1", TC_DESC("like cursor_right in micro mode") }, + { "Zc", "mvpa", TC_DESC("like row_address in micro mode") }, + { "Zd", "mcuu1", TC_DESC("like cursor_up in micro mode") }, + { "nw", "nel", TC_DESC("newline (behave like cr followed by lf)") }, + { "Ze", "porder", TC_DESC("match software bits to print-head pins") }, + { "oc", "oc", TC_DESC("set all color pairs to the original ones"), &tc_oc }, + { "op", "op", TC_DESC("set default pair to its original value"), &tc_op }, + { "pc", "pad", TC_DESC("padding char (instead of null)"), &tc_pc }, + { "DC", "dch", TC_DESC("delete #1 chars"), &tc_pDC }, + { "DL", "dl", TC_DESC("parm_delete_line"), &tc_pDL }, + { "DO", "cud", TC_DESC("down #1 lines"), &tc_pDO }, + { "Zf", "mcud", TC_DESC("like parm down cursor in micro mode") }, + { "IC", "ich", TC_DESC("insert #1 chars") }, + { "SF", "indn", TC_DESC("scroll forward #1 lines"), &tc_pSF }, + { "AL", "il", TC_DESC("parm insert line"), &tc_pAL }, + { "LE", "cub", TC_DESC("move #1 chars to the left"), &tc_pBC }, + { "Zg", "mcub", TC_DESC("Like parm left cursor in micro mode") }, + { "RI", "cuf", TC_DESC("parm right cursor"), &tc_pRI }, + { "Zh", "mcuf", TC_DESC("Like parm right cursor in micro mode") }, + { "SR", "rin", TC_DESC("scroll back #1 lines"), &tc_pSR }, + { "UP", "cuu", TC_DESC("up #1 lines"), &tc_pUP }, + { "Zi", "mcuu", TC_DESC("Like parm_up_cursor in micro mode") }, + { "pk", "pfkey", TC_DESC("program function key #1 to type string #2") }, + { "pl", "pfloc", TC_DESC("program function key #1 to execute string #2") }, + { "px", "pfx", TC_DESC("program function key #1 to transmit string #2") }, + { "pn", "pln", TC_DESC("program label #1 to show string #2") }, + { "ps", "mc0", TC_DESC("print contents of screen") }, + { "pO", "mc5p", TC_DESC("turn on printer for #1 bytes") }, + { "pf", "mc4", TC_DESC("turn off printer") }, + { "po", "mc5", TC_DESC("turn on printer") }, + { "PU", "pulse", TC_DESC("select pulse dialling") }, + { "QD", "qdial", TC_DESC("dial number #1 without checking") }, + { "RC", "rmclk", TC_DESC("remove clock") }, + { "rp", "rep", TC_DESC("repeat char #1 #2 times"), &tc_rp}, + { "RF", "rfi", TC_DESC("send next input char (for ptys)") }, + { "rs", NULL, TC_DESC("terminal reset string"), &tc_rs}, + { "r1", "rs1", TC_DESC("reset string") }, + { "r2", "rs2", TC_DESC("reset string") }, + { "r3", "rs3", TC_DESC("reset string") }, + { "rf", "rf", TC_DESC("name of reset file") }, + { "rc", "rc", TC_DESC("restore cursor to last position of sc") }, + { "cv", "vpa", TC_DESC("vertical position #1 absolute"), &tc_cv }, + { "sc", "sc", TC_DESC("save current cursor position") }, + { "sf", "ind", TC_DESC("scroll text up"), &tc_sf }, + { "sr", "ri", TC_DESC("scroll text down"), &tc_sr }, + { "Zj", "scs", TC_DESC("select character set") }, + { "sa", "sgr", TC_DESC("define video attributes #1-#9 (PG9)"), &tc_sa }, + { "Sb", "setb", TC_DESC("set background (color)"), &tc_Color_Bg }, + { "Zk", "smgb", TC_DESC("set bottom margin at current line") }, + { "Zl", "smgbp", TC_DESC("set bottom margin at line #1 or #2 lines from bottom") }, + { "SC", "sclk", TC_DESC("set clock, #1 hrs #2 mins #3 secs") }, + { "sp", "scp", TC_DESC("set current color pair to #1") }, + { "Sf", "setf", TC_DESC("set foreground (color)"), &tc_Color_Fg }, + { "ML", "smgl", TC_DESC("set left soft margin") }, + { "Zm", "smglp", TC_DESC("set left (right) margin at column #1 (#2)") }, + { "MR", "smgr", TC_DESC("set right soft margin") }, + { "Zn", "smgrp", TC_DESC("set right margin at column #1") }, + { "st", "hts", TC_DESC("set a tab in every row, current columns") }, + { "Zo", "smgt", TC_DESC("set top margin at current line") }, + { "Zq", "smgtp", TC_DESC("start printing bit image braphics") }, + { "wi", "wind", TC_DESC("current window is lines #1-#2 cols #3-#4") }, + { "Zq", "sbim", TC_DESC("start bit image") }, + { "Zr", "scsd", TC_DESC("start character set definition") }, + { "Zs", "rbim", TC_DESC("stop printing bit image graphics") }, + { "Zt", "rcsd", TC_DESC("end definition of character aet") }, + { "Zu", "subcs", TC_DESC("list of subscriptable characters") }, + { "Zv", "supcs", TC_DESC("list of superscriptable characters") }, + { "ta", "ht", TC_DESC("tab to next 8-space hardware tab stop") }, + { "Zw", "docr", TC_DESC("printing any of these chars causes CR") }, + { "ts", "tsl", TC_DESC("move to status line") }, + { "TO", "tone", TC_DESC("select touch tone dialing") }, + { "uc", "uc", TC_DESC("underline char and move past it") }, + { "hu", "hu", TC_DESC("half a line up") }, + { "u0", "u0", TC_DESC("user string #0") }, + { "u1", "u1", TC_DESC("user string #1") }, + { "u2", "u2", TC_DESC("user string #2") }, + { "u3", "u3", TC_DESC("user string #3") }, + { "u4", "u4", TC_DESC("user string #4") }, + { "u5", "u5", TC_DESC("user string #5") }, + { "u6", "u6", TC_DESC("user string #6") }, + { "u7", "u7", TC_DESC("user string #7") }, + { "u8", "u8", TC_DESC("user string #8") }, + { "u9", "u9", TC_DESC("user string #9") }, + { "WA", "wait", TC_DESC("wait for dial-tone") }, + { "XF", "xoffc", TC_DESC("XOFF character") }, + { "XN", "xonc", TC_DESC("XON character") }, + { "Zx", "zerom", TC_DESC("no motion for subsequent character") }, + + /* + * The following string capabilities are present in the SVr4.0 term + * structure, but were originally not documented in the man page. + */ + { "S8", "scesa", TC_DESC("alternate escape for scancode emulation") }, + { "Yv", "bicr", TC_DESC("move to beginning of same row") }, + { "Zz", "binel", TC_DESC("move to next row of the bit image") }, + { "Xy", "birep", TC_DESC("repeat bit image cell #1 #2 times") }, + { "Zy", "csnm", TC_DESC("list of character set names") }, + { "ci", "csin", TC_DESC("init sequence for multiple codesets") }, + { "Yw", "colornm", TC_DESC("give name for color #1") }, + { "Yx", "defbi", TC_DESC("define rectangualar bit image region") }, + { "dv", "devt", TC_DESC("indicate language/codeset support") }, + { "S1", "dispc", TC_DESC("display PC character") }, + { "Yy", "endbi", TC_DESC("end a bit-image region") }, + { "S2", "smpch", TC_DESC("enter PC character display mode") }, + { "S4", "smsc", TC_DESC("enter PC scancode mode") }, + { "S3", "rmpch", TC_DESC("exit PC character display mode") }, + { "S5", "rmsc", TC_DESC("exit PC scancode mode") }, + { "Gm", "getm", TC_DESC("curses should get button events") }, + { "Km", "kmous", TC_DESC("mouse event has occurred") }, + { "Mi", "minfo", TC_DESC("mouse status information") }, + { "S6", "pctrm", TC_DESC("PC terminal options") }, + { "xl", "pfxl", TC_DESC("program function key #1 to type string #2 and show string #3") }, + { "RQ", "reqmp", TC_DESC("request mouse position") }, + { "S7", "scesc", TC_DESC("escape for scancode emulation") }, + { "s0", "s0ds", TC_DESC("shift to code set 0 (EUC set 0, ASCII)") }, + { "s1", "s1ds", TC_DESC("shift to code set 1") }, + { "s2", "s2ds", TC_DESC("shift to code set 2") }, + { "s3", "s3ds", TC_DESC("shift to code set 3") }, + { "AB", "setab", TC_DESC("set ANSI color background"), &tc_ANSI_Color_Bg }, + { "AF", "setaf", TC_DESC("set ANSI color foreground"), &tc_ANSI_Color_Fg }, + { "Yz", "setcolor", TC_DESC("change to ribbon color #1") }, + { "ML", "smglr", TC_DESC("set both left and right margins to #1, #2") }, + { "YZ", "slines", TC_DESC("set page length to #1 lines") }, + { "MT", "smgtb", TC_DESC("sets both top and bottom margins to #1, #2") }, + + /* + * The XSI Curses standard added these. They are some post-4.1 versions + * of System V curses, e.g., Solaris 2.5 and IRIX 6.x. The ncurses term- + * cap names for them are invented; according to the XSI Curses standard, + * they have no termcap names. If your compiled terminfo entries use + * these, they may not be binary-compatible with System V terminfo + * entries after SVr4.1; beware! + */ + { "Xh", "ehhlm", TC_DESC("enter horizontal highlight mode") }, + { "Xl", "elhlm", TC_DESC("enter left highlight mode") }, + { "Xo", "elohlm", TC_DESC("enter low highlight mode") }, + { "Xr", "erhlm", TC_DESC("enter right highlight mode") }, + { "Xt", "ethlm", TC_DESC("enter top highlight mode") }, + { "Xv", "evhlm", TC_DESC("enter vertical highlight mode") }, + + /* + * Characters, Note: have only seen 'bx' under AIX, which must be ordered + * after "ac" for correct selection. + */ + { "G1", NULL, TC_DESC("single upper right") }, + { "G2", NULL, TC_DESC("single upper left") }, + { "G3", NULL, TC_DESC("single lower left") }, + { "G4", NULL, TC_DESC("single lower right") }, + { "GC", NULL, TC_DESC("single intersection") }, + { "GD", NULL, TC_DESC("tee pointing down") }, + { "GH", NULL, TC_DESC("single horizontal line") }, + { "GL", NULL, TC_DESC("tee pointing left") }, + { "GR", NULL, TC_DESC("tee pointing right") }, + { "GU", NULL, TC_DESC("tee pointing up") }, + { "GV", NULL, TC_DESC("single vertical line") }, + { "bx", NULL, TC_DESC("box chars primary set"), &tc_box_characters }, + + /* + * Others + */ + { "cS", NULL, TC_DESC("change region to line #1 to line #2, alt form"), &tc_cS}, + { "bc", NULL, TC_DESC("move left, if not ^H (old-style)"), &tc_bc}, + { "nl", NULL, TC_DESC("use to move down") }, + /* { "ko", NULL, TC_DESC("list of self-mapped keycaps") }, */ + /* { "ma", NULL, TC_DESC("map arrow keys rogue(1) motion keys") }, */ + { "ml", NULL, TC_DESC("memory lock above") }, + { "mu", NULL, TC_DESC("memory unlock") } + }; + +#if (XXX_KO) +/* + ko capability, consists of a comma-separated capability list. + For each capability, it should be assumed there is a keycap + that sends the string which is the value of that capability. + + String listing the other function keys the terminal has. + + This is a very obsolete way of describing the same + information found in the `kH' ... `kT' keys. + + The string contains a list of two-character termcap + capability names, separated by commas. The meaning is that + for each capability name listed, the terminal has a key which + sends the string which is the value of that capability. + + For example, the value `:ko=cl, ll, sf, sr:' says that the + terminal has four function keys which mean "clear screen", + "home down", "scroll forward" and "scroll reverse + */ +static const struct { + const char *from; + const char *to; +} ko_xlate[] = { + { "al", "kil1" }, /* insert line key */ + { "bt", "kcbt" }, /* back tab */ + { "cd", "ked" }, /* clear-to-eos key */ + { "ce", "kel" }, /* clear-to-eol key */ + { "cl", "kclr" }, /* clear key */ + { "ct", "tbc" }, /* clear all tabs */ + { "dc", "kdch1" }, /* delete char */ + { "dl", "kdl1" }, /* delete line */ + { "do", "kcud1" }, /* down key */ + { "ei", "krmir" }, /* exit insert key */ + { "ho", "khome" }, /* home key */ + { "ic", "kich1" }, /* insert char key */ + { "im", "kIC" }, /* insert-mode key */ + { "le", "kcub1" }, /* le key */ + { "nd", "kcuf1" }, /* nd key */ + { "nl", "kent" }, /* new line key */ + { "st", "khts" }, /* set-tab key */ + { "ta", "kcan" }, /* cancel */ + { "up", "kcuu1" }, /* up-arrow key */ + }; +#endif /*XXX_KO*/ + + +static Term_t term_numbers[] = { /* numeric - termcap/terminfo elements */ + /* + * standard + */ + { "MW", "wnum", TC_DESC("max number of defineable windows") }, + { "co", "cols", TC_DESC("number of columns"), &tn_co }, + { "it", "it", TC_DESC("tabs initially every # spaces") }, + { "Nl", "nlab", TC_DESC("number of labels") }, + { "lh", "lh", TC_DESC("rows in each label") }, + { "li", "lines", TC_DESC("number of lines on screen or page"), &tn_li }, + { "lm", "lm", TC_DESC("lines of memory if > line, 0 means varies") }, + { "lw", "lw", TC_DESC("columns in each label") }, + { "ma", "ma", TC_DESC("max combined attributes") }, + { "pb", "pb", TC_DESC("lowest baud rate needing padding") }, + { "sg", "xmc", TC_DESC("number of blank chars left by smso or rmso"), &tn_sg }, + { "vt", "vt", TC_DESC("virtual terminal number") }, + { "ws", "wsl", TC_DESC("number of columns within status line") }, + + /* + * SRV 4.0 color + */ + { "Co", "colors", TC_DESC("max color"), &tf_Colors }, + { "pa", "pairs", TC_DESC("max of color-pairs"), &tf_Pairs }, + { "NC", "ncv", TC_DESC("video attributes that cannot be used with colors"), &tn_NC }, + + /* + * The following numeric capabilities are present in the SVr4.0 term structure, + * but are not yet documented in the man page. They came in with SVr4's printer support. + */ + { "BT", NULL, TC_DESC("number of buttons on the mouse") }, + + /* + * Padding times + */ + { "dC", NULL, TC_DESC("msec of padding for carriage-return character") }, + { "dN", NULL, TC_DESC("msec of padding for newline (linefeed) character") }, + { "dB", NULL, TC_DESC("msec of padding for backspace character") }, + { "dF", NULL, TC_DESC("msec of padding for formfeed character") }, + { "dT", NULL, TC_DESC("msec of padding for tab character") } + }; + + +static Term_t term_keys[] = { /* keys - termcap/terminfo elements */ + { "!1", "kSAV", TC_DESC("shifted save key") }, + { "!2", "kSPD", TC_DESC("shifted suspend key") }, + { "!3", "kUND", TC_DESC("shifted undo key"), TC_TOKEN(KEY_REDO) }, + { "#1", "kHLP", TC_DESC("shifted help key") }, /* KEY_HELP */ + { "#2", "kHOM", TC_DESC("shifted home key"), TC_TOKEN(MOD_SHIFT|KEY_HOME) }, + { "#3", "kIC", TC_DESC("shifted insert-character key") }, + { "#4", "kLFT", TC_DESC("shifted left-arrow key") }, + { "%0", "krdo", TC_DESC("redo key"), TC_TOKEN(KEY_REDO) }, + { "%1", "khlp", TC_DESC("help key"), TC_TOKEN(KEY_HELP) }, + { "%2", "kmrk", TC_DESC("mark key") }, /* KEY_MARK */ + { "%3", "kmsg", TC_DESC("message key") }, + { "%4", "kmov", TC_DESC("move key") }, + { "%5", "knxt", TC_DESC("next key"), TC_TOKEN(KEY_NEXT) }, + { "%6", "kopn", TC_DESC("open key"), TC_TOKEN(KEY_OPEN) }, + { "%7", "kopt", TC_DESC("options key"), TC_TOKEN(KEY_MENU) }, + { "%8", "kprv", TC_DESC("previous key"), TC_TOKEN(KEY_PREV) }, + { "%9", "kprt", TC_DESC("print key") }, /* KEY_PRINT */ + { "%a", "kMSG", TC_DESC("shifted message key") }, + { "%b", "kMOV", TC_DESC("shifted move key") }, + { "%c", "kNXT", TC_DESC("shifted next key") }, + { "%d", "kOPT", TC_DESC("shifted options key") }, + { "%e", "kPRV", TC_DESC("shifted previous key") }, + { "%f", "kPRT", TC_DESC("shifted print key") }, + { "%g", "kRDO", TC_DESC("shifted redo key") }, + { "%h", "kRPL", TC_DESC("shifted replace key") }, + { "%i", "kRIT", TC_DESC("shifted right-arrow key") }, + { "%j", "kRES", TC_DESC("shifted resume key") }, + { "&0", "kCAN", TC_DESC("shifted cancel key") }, + { "&1", "kref", TC_DESC("reference key") }, + { "&2", "krfr", TC_DESC("refresh key") }, /* KEY_REFRESH */ + { "&3", "krpl", TC_DESC("replace key"), TC_TOKEN(KEY_REPLACE) }, + { "&4", "krst", TC_DESC("restart key") }, + { "&5", "kres", TC_DESC("resume key") }, + { "&6", "ksav", TC_DESC("save key"), TC_TOKEN(KEY_SAVE) }, + { "&7", "kspd", TC_DESC("suspend key") }, + { "&8", "kund", TC_DESC("undo key"), TC_TOKEN(KEY_UNDO_CMD) }, + { "&9", "kBEG", TC_DESC("shifted begin key") }, + { "*0", "kFND", TC_DESC("shifted find key") }, + { "*1", "kCMD", TC_DESC("shifted command key") }, + { "*2", "kCPY", TC_DESC("shifted copy key") }, + { "*3", "kCRT", TC_DESC("shifted create key") }, + { "*4", "kDC", TC_DESC("shifted delete-char") }, + { "*5", "kDL", TC_DESC("shifted delete-line key") }, + { "*6", "kslt", TC_DESC("select key") }, + { "*7", "kEND", TC_DESC("shifted end key"), TC_TOKEN(MOD_SHIFT|KEY_END) }, + { "*8", "kEOL", TC_DESC("shifted clear-to-end-of-line key") }, + { "*9", "kEXT", TC_DESC("shifted exit key") }, + { "@0", "kfnd", TC_DESC("find key"), TC_TOKEN(KEY_SEARCH) }, + { "@1", "kbeg", TC_DESC("begin key") }, + { "@2", "kcan", TC_DESC("cancel key"), TC_TOKEN(KEY_CANCEL) }, + { "@3", "kclo", TC_DESC("close key") }, + { "@4", "kcmd", TC_DESC("command key"), TC_TOKEN(KEY_COMMAND) }, + { "@5", "kcpy", TC_DESC("copy key"), TC_TOKEN(KEY_COPY_CMD) }, + { "@6", "kcrt", TC_DESC("create key") }, + { "@7", "kend", TC_DESC("end key"), TC_TOKEN(KEY_END) }, + { "@8", "kent", TC_DESC("enter/send key") }, + { "@9", "kext", TC_DESC("exit key"), TC_TOKEN(KEY_EXIT) }, + { "F1", "kf11", TC_DESC("F11 function key"), TC_TOKEN(F(11)) }, + { "F2", "kf12", TC_DESC("F12 function key"), TC_TOKEN(F(12)) }, + { "F3", "kf13", TC_DESC("F13 function key") /*, TC_TOKEN(F(13))*/ }, + { "F4", "kf14", TC_DESC("F14 function key") /*, TC_TOKEN(F(14))*/ }, + { "F5", "kf15", TC_DESC("F15 function key") /*, TC_TOKEN(F(15))*/ }, + { "F6", "kf16", TC_DESC("F16 function key") /*, TC_TOKEN(F(16))*/ }, + { "F7", "kf17", TC_DESC("F17 function key") /*, TC_TOKEN(F(17))*/ }, + { "F8", "kf18", TC_DESC("F18 function key") /*, TC_TOKEN(F(18))*/ }, + { "F9", "kf19", TC_DESC("F19 function key") /*, TC_TOKEN(F(19))*/ }, + { "FA", "kf20", TC_DESC("F20 function key") /*, TC_TOKEN(F(20))*/ }, + { "FB", "kf21", TC_DESC("F21 function key") }, + { "FC", "kf22", TC_DESC("F22 function key") }, + { "FD", "kf23", TC_DESC("F23 function key") }, + { "FE", "kf24", TC_DESC("F24 function key") }, + { "FF", "kf25", TC_DESC("F25 function key") }, + { "FG", "kf26", TC_DESC("F26 function key") }, + { "FH", "kf27", TC_DESC("F27 function key") }, + { "FI", "kf28", TC_DESC("F28 function key") }, + { "FJ", "kf29", TC_DESC("F29 function key") }, + { "FK", "kf30", TC_DESC("F30 function key") }, + { "FL", "kf31", TC_DESC("F31 function key") }, + { "FM", "kf32", TC_DESC("F32 function key") }, + { "FN", "kf33", TC_DESC("F33 function key") }, + { "FO", "kf34", TC_DESC("F34 function key") }, + { "FP", "kf35", TC_DESC("F35 function key") }, + { "FQ", "kf36", TC_DESC("F36 function key") }, + { "FR", "kf37", TC_DESC("F37 function key") }, + { "FS", "kf38", TC_DESC("F38 function key") }, + { "FT", "kf39", TC_DESC("F39 function key") }, + { "FU", "kf40", TC_DESC("F40 function key") }, + { "FV", "kf41", TC_DESC("F41 function key") }, + { "FW", "kf42", TC_DESC("F42 function key") }, + { "FX", "kf43", TC_DESC("F43 function key") }, + { "FY", "kf44", TC_DESC("F44 function key") }, + { "FZ", "kf45", TC_DESC("F45 function key") }, + { "Fa", "kf46", TC_DESC("F46 function key") }, + { "Fb", "kf47", TC_DESC("F47 function key") }, + { "Fc", "kf48", TC_DESC("F48 function key") }, + { "Fd", "kf49", TC_DESC("F49 function key") }, + { "Fe", "kf50", TC_DESC("F50 function key") }, + { "Ff", "kf51", TC_DESC("F51 function key") }, + { "Fg", "kf52", TC_DESC("F52 function key") }, + { "Fh", "kf53", TC_DESC("F53 function key") }, + { "Fi", "kf54", TC_DESC("F54 function key") }, + { "Fj", "kf55", TC_DESC("F55 function key") }, + { "Fk", "kf56", TC_DESC("F56 function key") }, + { "Fl", "kf57", TC_DESC("F57 function key") }, + { "Fm", "kf58", TC_DESC("F58 function key") }, + { "Fn", "kf59", TC_DESC("F59 function key") }, + { "Fo", "kf60", TC_DESC("F60 function key") }, + { "Fp", "kf61", TC_DESC("F61 function key") }, + { "Fq", "kf62", TC_DESC("F62 function key") }, + { "Fr", "kf63", TC_DESC("F63 function key") }, + { "K1", "ka1", TC_DESC("upper left of keypad"), TC_TOKEN(KEYPAD_7) }, + { "K2", "kb2", TC_DESC("center of keypad"), TC_TOKEN(KEYPAD_9) }, + { "K3", "ka3", TC_DESC("upper right of key-pad"), TC_TOKEN(KEYPAD_5) }, + { "K4", "kc1", TC_DESC("lower left of keypad"), TC_TOKEN(KEYPAD_1) }, + { "K5", "kc3", TC_DESC("lower right of key-pad"), TC_TOKEN(KEYPAD_3) }, + { "k0", "kf0", TC_DESC("F0 function key"), TC_TOKEN(F(10)) }, + { "k1", "kf1", TC_DESC("F1 function key"), TC_TOKEN(F(1)) }, + { "k2", "kf2", TC_DESC("F2 function key"), TC_TOKEN(F(2)) }, + { "k3", "kf3", TC_DESC("F3 function key"), TC_TOKEN(F(3)) }, + { "k4", "kf4", TC_DESC("F4 function key"), TC_TOKEN(F(4)) }, + { "k5", "kf5", TC_DESC("F5 function key"), TC_TOKEN(F(5)) }, + { "k6", "kf6", TC_DESC("F6 function key"), TC_TOKEN(F(6)) }, + { "k7", "kf7", TC_DESC("F7 function key"), TC_TOKEN(F(7)) }, + { "k8", "kf8", TC_DESC("F8 function key"), TC_TOKEN(F(8)) }, + { "k9", "kf9", TC_DESC("F9 function key"), TC_TOKEN(F(9)) }, + { "k;", "kf10", TC_DESC("F10 function key"), TC_TOKEN(F(10)) }, + { "kA", "kil1", TC_DESC("insert-line key") }, + { "kB", "kcbt", TC_DESC("back-tab key"), TC_TOKEN(BACK_TAB) }, + { "kC", "kclr", TC_DESC("clear-screen or erase key") }, + { "kD", "kdch1", TC_DESC("delete-character key"), TC_TOKEN(KEY_DEL) }, + { "kE", "kel", TC_DESC("clear-to-end-of-line key") }, + { "kF", "kind", TC_DESC("scroll-forward key") }, + { "kH", "kll", TC_DESC("lower-left key (home down)"), TC_TOKEN(KEY_END) }, + { "kI", "kich1", TC_DESC("insert-character key"), TC_TOKEN(KEY_INS) }, + { "kL", "kdl1", TC_DESC("delete-line key") }, + { "kM", "krmir", TC_DESC("sent by rmir or smi rin insert mode") }, + { "kN", "knp", TC_DESC("next-page key"), TC_TOKEN(KEY_PAGEDOWN) }, + { "kP", "kpp", TC_DESC("previous-page key"), TC_TOKEN(KEY_PAGEUP) }, + { "kR", "kri", TC_DESC("scroll-backward key") }, + { "kS", "ked", TC_DESC("clear-to-end-of-screen key") }, + { "kT", "khts", TC_DESC("set-tab key") }, + { "ka", "ktbc", TC_DESC("clear-all-tabs key") }, + { "kb", "kbs", TC_DESC("backspace key"), TC_TOKEN(CTRL_H) }, + { "kd", "kcud1", TC_DESC("down-arrow key"), TC_TOKEN(KEY_DOWN) }, + { "kh", "khome", TC_DESC("home key"), TC_TOKEN(KEY_HOME) }, + { "kl", "kcub1", TC_DESC("left-arrow key"), TC_TOKEN(KEY_LEFT) }, + { "kr", "kcuf1", TC_DESC("right-arrow key"), TC_TOKEN(KEY_RIGHT) }, + { "kt", "kctab", TC_DESC("clear-tab key") }, + { "ku", "kcuu1", TC_DESC("up-arrow key"), TC_TOKEN(KEY_UP) }, + }; + +static Term_t term_flags[] = { /* boolean - termcap/terminfo elements */ + { "5i", "mc5i", TC_DESC("printer won't echo on screen") }, + { "HC", "chts", TC_DESC("cursor is hard to see") }, + { "LP", NULL, TC_DESC("last column of last line will not scroll"), TC_TOKEN(&tf_LP) }, + { "MT", NULL, TC_DESC("has meta key") }, /* TODO */ + { "ND", "ndscr", TC_DESC("scrolling region is non-destructive") }, + { "NL", NULL, TC_DESC("move down with \\n"), TC_TOKEN(&tf_NL) }, + { "NP", "npc", TC_DESC("pad character does not exist"), TC_TOKEN(&tf_npc) }, + { "NR", "nrrmc", TC_DESC("smcup does not reverse rmcup") }, + { "YA", "xhpa", TC_DESC("only positive motion for hpa/mhpa caps") }, + { "YB", "crxm", TC_DESC("using cr turns off micro mode") }, + { "YC", "daisy", TC_DESC("printer needs operator to change character set") }, + { "YD", "xvpa", TC_DESC("only positive motion for vpa/mvpa caps") }, + { "YE", "sam", TC_DESC("printing in last column causes cr") }, + { "YF", "cpix", TC_DESC("changing character pitch changes resolution") }, + { "YG", "lpix", TC_DESC("changing line pitch changes resolution") }, + { "am", "am", TC_DESC("terminal has automatic margins"), TC_TOKEN(&tf_am) }, + { "be", NULL, TC_DESC("back color erase"), TC_TOKEN(&tf_be) }, + { "bs", NULL, TC_DESC("uses ^H to move left"), TC_TOKEN(&tf_bs) }, + { "bw", "bw", TC_DESC("cub1 wraps from column 0 to last column") }, + { "cc", "ccc", TC_DESC("terminal can re-define existing colors") }, + { "da", "da", TC_DESC("display may be retained above the screen") }, + { "db", "db", TC_DESC("display may be retained below the screen") }, + { "eo", "eo", TC_DESC("can erase overstrikes with a blank") }, + { "es", "eslok", TC_DESC("escape can be used on the status line") }, + { "gn", "gn", TC_DESC("generic line type"), TC_TOKEN(&tf_gn) }, + { "hc", "hc", TC_DESC("hardcopy terminal"), TC_TOKEN(&tf_hc) }, + { "hl", "hls", TC_DESC("terminal uses only HLS color notation (tektronix)") }, + { "hs", "hs", TC_DESC("has extra status line") }, + { "hz", "hz", TC_DESC("can't print ~'s (hazeltine)"), TC_TOKEN(&tf_hz) }, + { "in", "in", TC_DESC("insert mode distinguishes nulls") }, + { "km", "km", TC_DESC("Has a meta key, sets msb high"), TC_TOKEN(&tf_km) }, + { "mi", "mir", TC_DESC("safe to move while in insert mode") }, + { "ms", "msgr", TC_DESC("safe to move while in standout/underline mode"), TC_TOKEN(&tf_ms) }, + { "nc", NULL, TC_DESC("no way to go to start of line") }, + { "ns", NULL, TC_DESC("crt cannot scroll") }, + { "nx", "nxon", TC_DESC("padding won't work, xon/xoff required"), TC_TOKEN(&tf_xonoff) }, + { "os", "os", TC_DESC("terminal can overstrike") }, + { "pt", NULL, TC_DESC("has 8-char tabs invoked with ^I") }, + { "ul", "ul", TC_DESC("underline character overstrikes") }, + { "ut", "bce", TC_DESC("screen erased with background color"), TC_TOKEN(&tf_ut) }, + { "xb", "xsb", TC_DESC("beehive (f1=escape, f2=ctrl C)") }, + { "xn", "xenl", TC_DESC("newline ignored after 80 cols (concept)"), TC_TOKEN(&tf_xn) }, + { "xo", NULL, TC_DESC("terminal uses xon/xoff handshaking"), TC_TOKEN(&tf_xonoff) }, + { "xr", "xon", TC_DESC("return clears the line") }, + { "xs", "xhp", TC_DESC("standout not erased by overwriting (hp)"), TC_TOKEN(&tf_xs) }, + { "xt", "xt", TC_DESC("tabs destructive, magic so char (Telray 1061)"), TC_TOKEN(&tf_xt) } + }; + + +static const unsigned ansicolor_map[] = { /* BRIEF -> ANSI color map */ +/* BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, WHITE */ + 0, 4, 2, 6, 1, 5, 3, 7, + 8, 12, 10, 14, 9, 13, 11, 15 + }; + + +static const struct colormap { /* BRIEF -> XTERM color map */ + int ident; + int c8; + int c16; + int c16_pc; + int c88_compat; /* 8/16 color compat */ + int c256_compat; /* 8/16 color compat */ + int c88; + int c256; + +} color_map[] = { + /* Ident 8 16 16/PC 88/C 256/C 88 256 */ + { BLACK, 0, 0, 0, 0, 0, 0, 0 }, + { BLUE, 4, 4, 1, 1, 4, 12, 12 }, + { GREEN, 2, 2, 2, 2, 2, 10, 10 }, + { CYAN, 6, 6, 3, 3, 6, 14, 14 }, + { RED, 1, 1, 4, 4, 1, 9, 9 }, + { MAGENTA, 5, 5, 5, 5, 5, 13, 13 }, + { BROWN, 3, 3, 6, 6, 130, 32, 130 }, + { WHITE, 7, 7, 7, 7, 7, 84, 248 }, + + { GREY, 0, 8, 8, 8, 8, 7, 7 }, + { LTBLUE, 4, 12, 9, 12, 12, 43, 81 }, + { LTGREEN, 2, 10, 10, 10, 10, 61, 121 }, + { LTCYAN, 6, 14, 11, 14, 14, 63, 159 }, + { LTRED , 1, 9, 12, 9, 9, 74, 224 }, + { LTMAGENTA, 5, 13, 13, 13, 13, 75, 225 }, + { YELLOW , 3, 11, 14, 11, 11, 11, 11 }, + { LTWHITE, 7, 15, 15, 15, 15, 1, 15 }, + + { DKGREY, 0, 0, 0, 0, 0, 82, 242 }, + { DKBLUE, 4, 4, 1, 1, 4, 4, 4 }, + { DKGREEN, 2, 2, 2, 2, 2, 2, 2 }, + { DKCYAN, 6, 6, 3, 3, 6, 6, 6 }, + { DKRED, 1, 1, 4, 4, 1, 1, 1 }, + { DKMAGENTA, 5, 5, 5, 5, 5, 5, 5 }, + { DKYELLOW, 3, 3, 6, 6, 130, 72, 130 }, + { LTYELLOW, 3, 11, 14, 11, 11, 78, 229 }, + + { COLOR_NONE, -1, -1, -1, -1, -1, -1, -1 } + }; + +/* + * Scroll window + */ +static int tt_top = -1; /* Top of scroll region. */ +static int tt_bot = -1; /* Bottom of scroll region. */ + +/* + * Color information + */ +static int tt_colors = 8; /* color depth (-1 unknown) */ + +static int tt_defaultfg = NOCOLOR; +static int tt_defaultbg = NOCOLOR; + +static int tt_fg = NOCOLOR; /* foreground color */ +static int tt_bg = NOCOLOR; /* background color */ +static int tt_style; /* text standout/underline mode */ + +static int tt_active = 0; /* display status */ +static int tt_cursor = 0; /* cursor status */ + +static vbyte_t tt_hue = 0; /* current attribute */ + + /* BRIEF -> TERM-COLORS */ +static int tt_colormap[COLOR_NONE + 1]; + + +/* Function: ttinit + * Initialize the terminal when the editor gets started up. + * + * Calling Sequence: + *> ttinit + *> -> term_init + *> ttopen + *> -> term_open + *> ttready + *> -> term_ready + *> macro tty/ + *> [ttfeature] + *> ttdisplay + *> -> term_display + *> [ttfeature] + * + *> ttfeature + *> ttprocess + *> -> term_control + *> ttwinch + *> -> term_control + * + *> ttclose + *> -> term_close + * + * Parameters: + * none. + * + * Configuration: + * + * Terminal identification. + * + * o TERM - + * General terminal identification. + * o KONSOLE_DCOP or KONSOLE_DBUS_SESSION - + * kconsole identification. + * o XTERM_VERSION - + * xterm version. + * o LINES/COLUMNS - + * Terminal size. + * + * Terminal capabilities. + * + * o COLORTERM_BCE - + * Assume BCE capabilities. + * o COLORTERM - + * slang style color terminal configuration, if set color assumed. + * o NCURSES_NO_UTF8_ACS - + * When running in a UTF-8 locale several terminals (including Linux console and GNU screen) + * ignore alternative character selection. If set use unicode box drawing characters in all + * cases. + * o NCURSES_ASSUMED_COLORS - + * Foreground and background colors. + * o COLORFGBG - + * rxvt/mrxvt terminal default color specification. + * o DEFAULT_COLORS - + * Default colors. + * + * Returns: + * nothing. + */ +void +ttinit(void) +{ + const char *term; + + trace_log("ttinit()\n"); + + /* + * profile + */ + x_scrfn.scr_open = term_open; + x_scrfn.scr_ready = term_ready; + x_scrfn.scr_feature = term_feature; + x_scrfn.scr_display = term_display; + x_scrfn.scr_control = term_control; + x_scrfn.scr_close = term_close; + + x_scrfn.scr_move = term_move; + x_scrfn.scr_cursor = term_cursor; + x_scrfn.scr_winch = term_sizeget; + + x_scrfn.scr_names = term_names; + x_scrfn.scr_beep = term_beep; + + x_scrfn.scr_clear = term_clear; + x_scrfn.scr_print = NULL; + x_scrfn.scr_putc = term_putc; + x_scrfn.scr_flush = term_flush; + + x_scrfn.scr_insl = term_insl; + x_scrfn.scr_dell = term_dell; + x_scrfn.scr_eeol = term_eeol; + x_scrfn.scr_repeat = term_repeat; + + term = ttisetup(); + + /* + * build attributes + */ + if (0 == strncmp(term, "linux", 5)) { /* linux console */ + t_attributes = TA_LINUX | TA_DARK; + + } else if (0 == strncmp(term, "cygwin", 5)) { + const char *cygwin = ggetenv("CYGWIN"); + + if (cygwin) { + trace_log("\tCYGWIN:%s\n", cygwin); + + if (strstr(cygwin, "codepage:oem")) { + if (xf_disptype < 0) { /* 8bit terminal */ + xf_disptype = DISPTYPE_8BIT; + } + x_pt.pt_codepage = 850; + + } else if (strstr(cygwin, "codepage:utf8")) { + if (xf_disptype < 0) { /* UTF8 enabled */ + xf_disptype = DISPTYPE_UTF8; + } + } + } + t_attributes = TA_CYGWIN|TA_XTERMLIKE|TA_DARK; + +#if defined(linux) + } else if (0 == strncmp(term, "con", 3)) { /* console, con80x25 etc */ + t_attributes = TA_LINUX|TA_DARK; +#endif + + } else if (0 == strncmp(term, "konsole", 7) || + getenv("KONSOLE_DCOP") || getenv("KONSOLE_DBUS_SESSION")) { + t_attributes = TA_KONSOLE | TA_XTERMLIKE; + + } else if (0 == strncmp(term, "screen", 6)) { + t_attributes = TA_SCREEN; + if (0 == strcmp(term, "screen.linux")) { + t_attributes |= TA_DARK; + } + + } else if (0 == strcmp(term, "putty")) { + t_attributes |= TA_DARK; + + } else if (strcmp(term, "vt52") != 0 && /* vt100+ */ + term[0] == 'v' && term[1] == 't' && term[2] >= '1' && term[2] <= '9') { + t_attributes = TA_VT100LIKE; + + } else if (term_xtermlike(term)) { /* eg. xterm-color */ + t_attributes = TA_XTERM | TA_XTERMLIKE; +#if defined(__CYGWIN__) + if (ggetenv("COMSPEC")) { + t_attributes |= TA_DARK; /* assume cmd/mintty */ + } +#endif /*__CYGWIN__*/ + } + + if (hasfeature(term, "rv")) { + t_attributes |= TA_LIGHT; /* rv = reverse video (black on white) */ + + } else if (hasfeature(term, "m") || hasfeature(term, "mono")) { + t_attributes |= TA_MONO; /* m = monochrome, suppress color support */ + } + + trace_log("terminal: %s (%s%s%s%s%s%s%s%s)\n", term, + (t_attributes & TA_LINUX ? "linux," : ""), + (t_attributes & TA_CYGWIN ? "cygwin," : ""), + (t_attributes & TA_VT100LIKE ? "vt100like," : ""), + (t_attributes & TA_XTERM ? "xterm," : ""), + (t_attributes & TA_XTERMLIKE ? "xtermlike," : ""), + (t_attributes & TA_LIGHT ? "light," : ""), + (t_attributes & TA_DARK ? "dark," : ""), + (t_attributes & TA_MONO ? "mono," : "")); + + /* + * Load termcap values. + */ + { + unsigned i, fkeys = 0; + const char *cp; + + trace_log("termcap:\n"); + + trace_log(" General:\n"); + for (i = 0; i < (sizeof(term_strings)/sizeof(term_strings[0])); i++) { + /* + * string values + */ + const Term_t *ti = term_strings + i; + const char *name = ttiname(ti); + + if (name && NULL != (cp = ttigetstr(ti))) { + const char **token = term_strings[i].token; + + term_strings[i].value.i_str = cp; + if (token) { + *token = cp; + } + trace_log("\t%-50s%c %-5s : %s\n", term_strings[i].comment, + (token ? '*' : ' '), name, c_string(cp)); + + if (token == &tc_graphic_pairs) { + acs_dump(cp); + x_pt.pt_attributes |= TF_AGRAPHICCHARACTERS; + + } else if (token == &tc_box_characters) { + const char *t_acs; + + if (NULL == tc_graphic_pairs && + (NULL != (t_acs = acs_box_characters(cp)))) { + acs_dump(t_acs); + tc_graphic_pairs = t_acs; + x_pt.pt_attributes |= TF_AGRAPHICCHARACTERS; + } + } + } + } + + fkeys = 0; + trace_log(" Keys:\n"); + for (i = 0; i < (sizeof(term_keys)/sizeof(term_keys[0])); ++i) { + /* + * keys + */ + const Term_t *ti = term_keys + i; + const char *name = ttiname(ti); + + if (name && NULL != (cp = ttigetstr(ti))) { + const size_t kcode = (size_t)term_keys[i].token; + + term_keys[i].value.i_str = cp; /* loaded later by ttkeys() */ + + trace_log("\t%-50s%c %-5s : %s\n", term_keys[i].comment, + (kcode ? '*' : ' '), name, c_string(cp)); + + if (kcode >= F(1) && kcode <= F(10)) { + ++fkeys; + } + } + } + + if (fkeys >= 10) { /* have all 10 function keys */ + x_pt.pt_attributes |= TF_AFUNCTIONKEYS; + } + + trace_log(" Numeric:\n"); + for (i = 0; i < (sizeof(term_numbers)/sizeof(term_numbers[0])); ++i) { + /* + * numbers + */ + const Term_t *ti = term_numbers + i; + const char *name = ttiname(ti); + + if (name) { + term_numbers[i].value.i_val = ttigetnum(ti); + if (term_numbers[i].token) { + *((int *)term_numbers[i].token) = term_numbers[i].value.i_val; + } + trace_log("\t%-50s%c %-5s : %d\n", term_numbers[i].comment, + (term_numbers[i].token ? '*' : ' '), name, term_numbers[i].value.i_val); + } + } + + trace_log(" Boolean/Flags:\n"); + for (i = 0; i < (sizeof(term_flags)/sizeof(term_flags[0])); ++i) { + /* + * flags + */ + const Term_t *ti = term_flags + i; + const char *name = ttiname(ti); + + if (name) { + term_flags[i].value.i_val = ttigetflag(ti); + if (term_flags[i].token) { + *((int *)term_flags[i].token) = term_flags[i].value.i_val; + } + trace_log("\t%-50s%c %-5s : %d\n", term_flags[i].comment, + (term_flags[i].token ? '*' : ' '), name, term_flags[i].value.i_val); + } + } + } + + /* color */ + term_fgbg(); + + if (NULL != ggetenv("COLORTERM_BCE")) { + tf_be = 1; /* slang compat override */ + } + + if (NULL == tc_Color_Fg || NULL == tc_Color_Fg) { + if (tc_ANSI_Color_Fg && tc_ANSI_Color_Bg) { + tc_Color_Fg = tc_ANSI_Color_Fg; + tc_Color_Bg = tc_ANSI_Color_Bg; + } + } + + /* fixup defective termcap/terminfo databases */ + if (NULL == tc_graphic_pairs && + (t_attributes & TA_VT100LIKE)) { /* VT1xx */ + tc_acs_start = "\016"; + tc_acs_end = "\017"; + tc_acs_enable = "\033)0"; + } + + if (NULL == tc_graphic_pairs && + strncmp(term, "aixterm", 7) == 0) { /* aixterm (VT102) */ + tc_acs_start = "\016"; + tc_acs_end = "\017"; + tc_acs_enable = "\033(B\033)0"; + } + + if (tc_graphic_pairs && NULL == tc_acs_start) { + tc_acs_start = "\016"; + tc_acs_end = "\017"; + } + /* VT2xx+ */ + if (((t_attributes & TA_VT100LIKE) && term[2] != '1') || + (t_attributes & (TA_LINUX|TA_XTERMLIKE)) ) { + if (NULL == tc_pDL) tc_pDL = "\033[%dM"; + if (NULL == tc_pAL) tc_pAL = "\033[%dL"; + if (NULL == tc_cm) tc_cm = "\033[%i%d;%dH"; + } + + if (t_attributes & (TA_LINUX|TA_XTERM)) { /* VT2xx */ + if (NULL == tc_cb) tc_cb = "\033[1K"; + if (NULL == tc_ce) tc_ce = "\033[K"; + } + + /* stand-out mode equiv checks */ + if (tc_se) { + if (tc_ZH && 0 == strcmp(tc_ZH, tc_se)) { + tc_ZH = tc_se; + + } else if (NULL == tc_ZH) { + tc_mr = NULL; /* ignore or assume same as 'se' */ + } + + if (tc_ue && 0 == strcmp(tc_us, tc_se)) { + tc_ue = tc_se; + } + + if (tc_ZR && 0 == strcmp(tc_ZR, tc_se)) { + tc_ZR = tc_se; + } + } + + if (NULL == tc_do && tf_NL) { + tc_do = "\n"; + } else if (tc_do && tc_do[0] == '\n' && !tf_NL) { + tc_do = NULL; + } + + if (NULL == tc_le && NULL == tc_bc && + (tf_bs || (t_attributes & TA_XTERMLIKE))) { + tc_bc = "\b"; + } + + /* + * Verify min requirements + */ + if (tf_gn) { + fprintf(stderr, "Generic terminal '%s', you have not specified your real terminal type.\n", term); + exit(1); + + } else if (tf_hc) { + fprintf(stderr, "Hard copy terminal '%s', not supported.\n", term); + exit(1); + + } else if (tf_xonoff) { + fprintf(stderr, "Terminal '%s' requires xon/xoff, not supported (try --curses).\n", term); + exit(1); + + } else if (tn_sg >= 1) { + fprintf(stderr, "Terminal '%s' using magic-cookie's, not supported (try --curses).\n", term); + exit(1); + + } else if (NULL == tc_cm && (NULL == tc_cv || NULL == tc_ch)) { + fprintf(stderr, "Terminal '%s' missing cursor move capabilities, not supported.\n", term); + exit(1); + + } else if (tf_xs >= 1 || tf_xt >= 1) { + fprintf(stderr, "Terminal '%s' requires old-style attribute handling, not supported.\n", term); + exit(1); + } + +#if defined(__CYGWIN__) + /* + * o retrieve display code page + * o plus enable tf_xn as the terminal cursor wrap misbehaves + * then in full screen mode resulting in screen corruption. + */ + if (-1 == x_pt.pt_codepage) { + x_pt.pt_codepage = GetConsoleOutputCP(); + trace_log("\tcodepage: %d\n", x_pt.pt_codepage); + } + if (TA_CYGWIN & t_attributes) { + x_pt.pt_attributes |= TF_ACYGWIN; /* Cygwin terminal */ + tf_xn = 1; + } +#endif /*__CYGWIN__*/ + + if (tf_km) { + x_pt.pt_attributes |= TF_AMETAKEY; + } + + if (0 == x_pt.pt_codepage) { + x_pt.pt_codepage = 437; /* default */ + } +} + + +static int +hasfeature(const char *term, const char *what) +{ + const char *p = strstr(term, what); + + if (p > term) { /* -rv[-] */ + const unsigned len = strlen(what); + + if ('-' == p[-1] && ('-' == p[len] || 0 == p[len])) { + return 1; + } + } + return 0; +} + + +/* Function: ttdefaultscheme + * Retrieve the derived/guessed default background color based on the either + * the published terminal background or the terminal type. + * + * Parameters: + * none. + * + * Returns: + * Name of default color scheme dark or light. + */ +const char * +ttdefaultscheme(void) +{ + int isdark = 0; + + if (x_pt.pt_schemedark >= 0) { /* explicit configuration */ + isdark = x_pt.pt_schemedark; + + } else if (0 == (TA_LIGHT & t_attributes)) { + if (tt_defaultbg != NOCOLOR) { /* 0-6 or 8 */ + if (tt_defaultbg <= 6 || 8 == tt_defaultbg) { + isdark = 1; + } + } else { /* generally dark */ + if (TA_DARK & t_attributes) { + isdark = 1; + } + } + } + + x_pt.pt_schemedark = isdark; + trace_log("ttdefaultscheme=%s\n", (isdark ? "dark" : "light")); + return (isdark ? "dark" : "light"); +} + + +/* Function: term_open + * Open the console. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static void +term_open(scrprofile_t *profile) +{ + io_device_add(TTY_INFD); /* stream registration */ + sys_initialise(); + term_identification(); /* terminal identification */ + term_sizeget(&profile->sp_rows, &profile->sp_cols); + profile->sp_colors = tt_colors; +} + + +/* Function: term_close + * Close the console. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static void +term_close(void) +{ + term_tidy(); + sys_shutdown(); + tty_egaflag = -1; +} + + +/* Function: term_ready + * Run-time initialisation. + * + * Parameters: + * repaint - *true* if the screen should be repainted. + * profile - console profile. + * + * Returns: + * nothing. + */ +static void +term_ready(int repaint, scrprofile_t *profile) +{ + static unsigned once; + + trace_log("term_ready(%d)\n", repaint); + + /* + * dump configuration + */ + if (! once) { + const char *o_CS = tc_cs; + + if (! xf_scrollregions) { + tc_cs = tc_cS = NULL; /* disable scrolling region */ + } + + if (! tc_ce) { /* erasing a line */ + tty_tceeol = ttcols(); + } else { + tty_tceeol = term_cost(tc_ce); + } + + if (tc_cs && tc_sr) { /* inserting a line */ + tty_tcinsl = term_cost(tc_cs) * 2 + term_cost(tc_sr); + } else if (tc_pAL) { + tty_tcinsl = term_cost(tc_pAL); + } else if (tc_al) { + tty_tcinsl = term_cost(tc_al); + } else { + tty_tcinsl = 0xffff; + } + + if (tc_cs) { /* delete a line */ + tty_tcdell = term_cost(tc_cs) * 2 + 1; + } else if (tc_pDL) { + tty_tcdell = term_cost(tc_pDL); + } else if (tc_dl) { + tty_tcdell = term_cost(tc_dl); + } else { + tty_tcdell = 0xffff; + } + /* we can ins/del lines */ + t_insdel = (tc_al || tc_pAL) && (tc_dl || tc_pDL); + t_padchar = (tf_npc ? -1 : (tc_pc ? *tc_pc : 0)); + t_acs_locale_breaks = acs_locale_breaks(); + + trace_log("TTY summary:\n"); + + if (-1 == t_padchar) { + trace_log("\tNo padding character\n"); + } else { +#if defined(HAVE_OSPEED) + trace_log("\tPadding character %d, at ospeed %d\n", t_padchar, ospeed); +#else + trace_log("\tPadding character %d, at baud %d\n", t_padchar, baudrate()); +#endif + } + + if (t_insdel) { + trace_log("\tInsert/delete scrolling available.\n"); + } + + if (o_CS) { + trace_log("\tScroll regions available.\n"); + } + + if (! xf_graph) { + trace_log("\tAlternative character support disabled.\n"); + } else if (tc_acs_enable || x_pt.pt_graphics_mode[0]) { + trace_log("\tAlternative character support available.\n"); + } + if (t_acs_locale_breaks) { + trace_log("\tlocale breaks alternative character support.\n"); + } + + if (xf_noinit) { + trace_log("\ttermcap init/reinit disabled.\n"); + } + + if (xf_nokeypad) { + trace_log("\ttermcap keypad init/reinit disabled.\n"); + } + + trace_log("\tDeleting lines using %s\n", + ((tc_cs) ? "scrolling regions" : t_insdel ? "line del/ins" : "hard refresh")); + trace_log("\tInserting lines using %s\n", + ((tc_cs && tc_sr) ? "scrolling regions" : t_insdel ? "line del/ins" : "hard refresh")); + trace_log("\t%-55s : %d\n", "Erase line cost", tty_tceeol); + trace_log("\t%-55s : %d\n", "Insert line cost", tty_tcinsl); + trace_log("\t%-55s : %d\n", "Delete line cost", tty_tcdell); + trace_log("\t%-55s : %d\n", "Colors", tt_colors); + trace_log("\t%-55s : %d\n", " Default fg", tt_defaultfg); + trace_log("\t%-55s : %d\n", " Default bg", tt_defaultbg); + ++once; + } + + /* + * configure terminal + */ + term_colorreset(); + + if (repaint) { + if (x_pt.pt_init[0]) /* terminal specific init */ + ttputctl2(x_pt.pt_init, 0, 0); + xterm_colors(t_colorsuser); + if (! xf_noinit) + ttputpad(tc_ti); /* enable cup (cursor addressing) */ + if (! xf_nokeypad) + ttputpad(tc_ks); /* put terminal in ``keypad-transmit'' */ + if (xf_graph) + ttputpad(tc_acs_enable); /* enable alt character set */ + ttputpad(tc_vs ? tc_vs : tc_ve); /* enable enhanced cursor */ + if (tf_am) + ttputpad(tc_am_on); /* enable automatic margins */ + ttputpad(tc_mm); /* enable meta key-codes */ + } + + /* + * terminal specific specials + */ + if (t_attributes & TA_CYGWIN) { + if (xf_cygwinkb) { + ttpush("\033[?2000h"); /* enable RAW mode (gives us WIN32 scancodes) */ + } + + } else if (t_attributes & TA_MINTTY) { + if (xf_mouse) { /* mouse enabled? */ + ttpush("\033[?7786h"); /* mouse-wheel reports only */ + } + + } else if (t_attributes & TA_VT100LIKE) { + ttpush("\033=\033[?1]"); /* enable cursor keys */ + } + + if (profile) { + profile->sp_lastsafe = term_lastsafe(); + profile->sp_colors = tt_colors; + } + + tt_style = 0; + tt_cursor = 1; + tt_active = 1; + term_flush(); +} + + +/* Function: term_feature + * Signal a terminal feature change. + * + * Parameters: + * ident - Feature identifier. + * + * Returns: + * nothing. + */ +static void +term_feature(int ident, scrprofile_t *profile) +{ + trace_log("term_feature(%d)\n", ident); + + switch (ident) { + case TF_INIT: + if (tty_open && x_pt.pt_init[0]) { + ttputctl2(x_pt.pt_init, 0, 0); + } + break; + + case TF_COLORDEPTH: + case TF_DEFAULT_FG: + case TF_DEFAULT_BG: + case TF_XTERM_PALETTE: + if (tty_open) { + term_colors(); + profile->sp_colors = tt_colors; + } + break; + + case TF_COLORMAP: /* terminal color palette */ + if (x_pt.pt_colormap[0]) { + strxcpy(t_colorsuser, x_pt.pt_colormap, sizeof(t_colorsuser)); + if (tty_open) { + xterm_colors(t_colorsuser); + } + } + break; + + case TF_COLORPALETTE: { /* user defined palette */ + const char *cursor = x_pt.pt_colorpalette; + unsigned col = 0; + + for (col = 0; col < (sizeof(tt_colormap)/sizeof(tt_colormap[0])); ++col) { + if (cursor && *cursor) { + if (isdigit(*cursor)) { + int val; + + if ((val = atoi(cursor)) >= 0) { + tt_colormap[col] = val; + } + } + if (NULL != (cursor = strchr(cursor, ','))) { + ++cursor; + } + } + } + x_pt.pt_xtpalette = -2; + } + break; + + case TF_ENCODING: + break; + case TF_UNICODE_VERSION: + if (x_pt.pt_unicode_version[0]) { + ucs_width_set(x_pt.pt_unicode_version); + } + break; + } +} + + +/* Function: term_display + * Invoked upon the display being enabled. + * + * This interface is hooked into the display_windows() primitive which (by default) is + * post execution of any terminal specific macros, for example + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static void +term_display(void) +{ + trace_log("term_display()\n"); + + if (term_isutf8()) { /* auto-detect UTF8 term support */ + x_pt.pt_attributes |= TF_AUTF8ENCODING; /* publish UTF8 */ + if (0 == x_pt.pt_encoding[0]) { + strcpy(x_pt.pt_encoding, "UTF-8"); + } + if (xf_disptype < 0) { + xf_disptype = DISPTYPE_UTF8; + } + x_display_ctrl |= DC_UNICODE; + + } else { + if (xf_disptype < 0) { /* default disp-type */ + if (vtis8bit()) { + if (0 == x_pt.pt_encoding[0]) { + strcpy(x_pt.pt_encoding, "latin1"); + } + xf_disptype = DISPTYPE_8BIT; + } else { + if (0 == x_pt.pt_encoding[0]) { + strcpy(x_pt.pt_encoding, "us-ascii"); + } + xf_disptype = DISPTYPE_7BIT; + } + } + } + + if (! xf_graph) { /* no graphic */ + ttboxcharacters(TRUE); + } +} + + +static int +term_control(int action, int param, ...) +{ + switch (action) { + case SCR_CTRL_NORMAL: /* normal color */ + if (tty_open) { + term_colorreset(); + } + break; + + case SCR_CTRL_SAVE: + if (tty_open) { + ttmove(ttrows()-1, 0); + if (param) { + term_tidy(); + } else { + term_colorreset(); + term_styleoff(); + tteeol(); + } + } + break; + + case SCR_CTRL_RESTORE: + if (! tty_open) { + ttopen(); + } + term_ready(TRUE, NULL); + break; + + case SCR_CTRL_COLORS: /* color change */ + break; + + default: + return -1; + } + return 0; +} + + +/* Function: ttisetup + * TERMINFO/TERMCAP setup. + * + * Parameters: + * none. + * + * Returns: + * Terminal name on success, otherwise the interface exits. + */ +static const char * +ttisetup(void) +{ + const char *term; + + if (NULL == (term = ggetenv("TERM"))) { + fprintf(stderr, "Environment variable TERM not defined!\n"); + exit(1); + } + +#if defined(HAVE_TERMINFO) + XF_TERMINFO { + trace_log("TERMINFO(%s) open\n", term); + if (setupterm((char *)term, fileno(stdout), NULL) != 0) { + fprintf(stderr, "Terminal type '%s' not found in terminfo database.\n", term); + exit(1); + } + } +#endif +#if defined(HAVE_TERMCAP) + XF_TERMCAP { + tcapcursor = tcapstrings; + memset(tcapstrings, 0, sizeof(tcapstrings)); + + trace_log("TERMCAP(%s) open\n", term); + if (tgetent(tcapbuffer, (char *)term) != 1) { + fprintf(stderr, "Terminal type '%s' not found in termcap.\n", term); + exit(1); + } + } +#endif + + return term; +} + + +/* Function: ttiname + * Retrieve the attribute name. + * + * Parameters: + * ti - Attribute specification. + * + * Returns: + * Attribute name. + */ +static const char * +ttiname(const Term_t *ti) +{ + const char *name = NULL; + +#if defined(HAVE_TERMINFO) + XF_TERMINFO name = ti->terminfoname; +#endif +#if defined(HAVE_TERMCAP) + XF_TERMCAP name = ti->termcapname; +#endif + return name; +} + + +/* Function: ttigetstr + * t[i]getstr() interface. + * + * Parameters: + * ti - Attribute specification. + * + * Returns: + * Sequence buffer address, otherwis NULL. + */ +static const char * +ttigetstr(const Term_t *ti) +{ + char *s = NULL; + +#if defined(HAVE_TERMINFO) + XF_TERMINFO { + const char *name = ti->terminfoname; + + s = tigetstr((char *) name); + if ((char *)-1 == s) { /* 'name' is not a string capability */ + trace_log("\ttgetstr(%s) = unknown\n", name); + s = NULL; + } + } +#endif +#if defined(HAVE_TERMCAP) + XF_TERMCAP { + /* + * Under normal conditions tgetstr() should perform as descripted but doesn't on + * all systems so workout known issues. + * + * "The tgetstr routine returns the string entry for id, or zero if it is not + * available. Use tputs to output the returned string. The return value will also + * be copied to the buffer pointed to by area, and the area value will be updated + * to point past the null ending this value." + * + * Note, only seen under an older curses implementation. + */ + const char *name = ti->termcapname; + char *ocursor = tcapcursor; /* current storage addr */ + + if (NULL != (s = tgetstr((char *) name, &tcapcursor)) && *s) { + const int slen = strlen(s); + + if (ocursor == tcapcursor) { /* broken tgetstr() */ + strcpy(ocursor, s); + tcapcursor = ocursor + slen + 1; + } + s = ocursor; /* lookup result */ + if (tcapcursor >= tcapstrings + TC_SLEN) { + fprintf(stderr, "Terminal description too large (>%dk)\n", (TC_SLEN/1024) + 1); + exit(1); + } + assert(tcapcursor == ocursor + slen + 1); + } else { + s = NULL; /* not found, zero length */ + } + } +#endif + return s; +} + + +/* Function: ttigetnum + * t[i]getnum() interface. + * + * Parameters: + * ti - Attribute specification. + * + * Returns: + * Attribute value, otherwise -1. + */ +static int +ttigetnum(const Term_t *ti) +{ + const char *name = "n/a"; + int num = -1; + +#if defined(HAVE_TERMINFO) + XF_TERMINFO { + name = ti->terminfoname; + num = tigetnum((char *) name); + } +#endif +#if defined(HAVE_TERMCAP) + XF_TERMCAP { + name = ti->termcapname; + num = tgetnum((char *) name); + } +#endif + if (num < -1) { + trace_log("\ttgetnum(%s) = error (%d)\n", name, num); + } + return (num >= -1 ? num : -1); /* -1 or greater */ +} + + +/* Function: ttigetflag + * t[i]getflag() interface. + * + * Parameters: + * ti - Attribute specification. + * + * Returns: + * Attribute value of either 0 or 1. + */ +static int +ttigetflag(const Term_t *ti) +{ + const char *name = "n/a"; + int flag = -1; + +#if defined(HAVE_TERMINFO) + XF_TERMINFO { + name = ti->terminfoname; + flag = tigetflag((char *) name); + } +#endif +#if defined(HAVE_TERMCAP) + XF_TERMCAP { + name = ti->termcapname; + flag = tgetflag((char *) name); + } +#endif + if (flag < 0) { + trace_log("\ttgetflag(%s) = error (%d)\n", name, flag); + } + return (flag >= 0 ? flag : 0); /* 0 or 1 */ +} + + +int +ttisetstr(const char *tag, int taglen, const char *value) +{ + __CUNUSED(tag) __CUNUSED(taglen) __CUNUSED(value) + return -1; +} + + +int +ttisetnum(const char *tag, int taglen, const char *value) +{ + __CUNUSED(tag) __CUNUSED(taglen) __CUNUSED(value) + return -1; +} + + +int +ttisetflag(const char *tag, int taglen, const char *value) +{ + __CUNUSED(tag) __CUNUSED(taglen) __CUNUSED(value) + return -1; +} + + +/* Function: acs_dump + * Alternative character dump. + * + * Parameters: + * bp - Buffer object address. + * + * Returns: + * nothing. + */ +static void +acs_dump(const char *bp) +{ + const unsigned char *p = (unsigned char *)bp; + unsigned char ident, ch; + unsigned i; + + while (*p) { + const char *desc = "unknown"; + + ident = *p++; + if (! isprint(ident)) { + continue; /* unsure, yet needed for rxvt-cygwin */ + } + ch = *p++; + + for (i = 0; i < (sizeof(term_characters)/sizeof(term_characters[0])); ++i) + if (term_characters[i].ident == ident) { + desc = term_characters[i].name; + break; + } + + trace_log("\t\t%-30s %c/0x%x : %u/0x%x\n", desc, ident, ident, ch, ch); + } +} + + +/* Function: acs_boxcharacters + * Alternative character box character import. + * + * Parameters: + * bx - Box character spec. + * + * Returns: + * Converted box characters into an acs specification. + */ +static const char * +acs_box_characters(const char *bx) +{ + char acs[32], *t_acs = acs; + +#define acs_push_bx(_i, _c) *t_acs++ = _i, *t_acs++ = _c + + acs_push_bx(TACS_ULCORNER, bx[0]); /* 'l' */ + acs_push_bx(TACS_HLINE, bx[1]); /* 'q' */ + acs_push_bx(TACS_URCORNER, bx[2]); /* 'k' */ + acs_push_bx(TACS_VLINE, bx[3]); /* 'x' */ + acs_push_bx(TACS_LRCORNER, bx[4]); /* 'j' */ + acs_push_bx(TACS_LLCORNER, bx[5]); /* 'm' */ + acs_push_bx(TACS_TTEE, bx[6]); /* 'w' */ + acs_push_bx(TACS_RTEE, bx[7]); /* 'u' */ + acs_push_bx(TACS_BTEE, bx[8]); /* 'v' */ + acs_push_bx(TACS_LTEE, bx[9]); /* 't' */ + acs_push_bx(TACS_PLUS, bx[10]); /* 'n' */ + +#undef acs_push_bx + *t_acs = 0; + + return chk_salloc(acs); +} + + +/* Function: acs_locale_breaks + * Check for known cases where a UTF-8 locale breaks the alternate character set. + * + * Parameters: + * none. + * + * Returns: + * TRUE or FALSE. + */ +static int +acs_locale_breaks(void) +{ + const char *env; + + if ((env = ggetenv("NCURSES_NO_UTF8_ACS")) != 0) { + return atoi(env); /* ncurses compatibility */ + + } else if ((env = ggetenv("TERM")) != 0) { + if (strstr(env, "linux")) { + return TRUE; + } + + if (strstr(env, "screen") && + ((env = ggetenv("TERMCAP")) != 0 && strstr(env, "screen") != 0) && + strstr(env, "hhII00") != 0) { + +#define IS_CTRLN(s) ((s) != 0 && strstr(s, "\016") != 0) +#define IS_CTRLO(s) ((s) != 0 && strstr(s, "\017") != 0) + + if (IS_CTRLN(tc_acs_start) || IS_CTRLO(tc_acs_start) || + IS_CTRLN(set_attributes) || IS_CTRLO(set_attributes)) { + return TRUE; + } + +#undef IS_CTRLN +#undef IS_CTRLO + } + } + return FALSE; +} + + +/* Function: term_xtermlike + * Determine the current terminal is an xterm style. + * + * Parameters: + * term - Terminate name. + * + * Returns: + * nothing. + */ +static int +term_xtermlike(const char *term) +{ + static const struct { + const char *desc; + unsigned len; + } xtermlike[] = { +#define XTERMLIKE(x) { x, sizeof(x)-1 } + XTERMLIKE("xterm"), /* generic */ + XTERMLIKE("aixterm"), /* AIX */ + XTERMLIKE("mintty"), /* non-standard. normally "xterm-256color" */ + XTERMLIKE("rxvt"), + XTERMLIKE("urxvt"), /* Unicode rxvt */ + XTERMLIKE("Eterm"), + XTERMLIKE("gnome"), /* gnome-terminal */ + XTERMLIKE("dtterm"), /* CDE terminal */ + XTERMLIKE("cygwin") /* Cygwin console */ + }; +#undef XTERMLIKE + int ret = 0; + + if (term) { + unsigned i; + + if (x_pt.pt_xtcompat >= 0) { + ret = x_pt.pt_xtcompat; /* feature override */ + } else { + for (i = 0; i < (unsigned)(sizeof(xtermlike)/sizeof(xtermlike[0])); ++i) + if (0 == strncmp(term, xtermlike[i].desc, xtermlike[i].len) && + ('\0' == term[xtermlike[i].len] || '-' == term[xtermlike[i].len])) { + /* + * for example, + * xterm-color + */ + ret = 1; + break; + } + } + } + trace_log("\txtermlike(%s) : %d\n", (term ? term : ""), ret); + x_pt.pt_xtcompat = ret; + return ret; +} + + +/* Function: ttkeys + * Map keys from termcap database to our keys. These are often overridden by the term + * macros, but at least we can set up some sensible default that are likely to work. + * + * Parameters: + * repaint - *true* if the screen should be repainted. + * + * Returns: + * nothing. + */ +void +ttkeys(void) +{ + unsigned i; + + trace_log("ttkeys()\n"); + + /* + * Keys + */ + for (i = 0; i < (sizeof(term_keys)/sizeof(term_keys[0])); ++i) + if (term_keys[i].value.i_str && term_keys[i].token) { + key_define_key_seq((int)term_keys[i].token, term_keys[i].value.i_str); + } + + /* + * Color + */ + if (tf_Colors > 2 /*user specification*/ || + (tc_Color_Fg && tc_Color_Bg) || (tc_ANSI_Color_Fg && tc_ANSI_Color_Bg) || + ggetenv("COLORTERM") /*override*/) { + x_pt.pt_color = TRUE; + } + + term_colors(); + + /* + * Graphic (alt) characters + */ + for (i = 0; i < sizeof(tc_acs_map); ++i) { /* one-to-one */ + tc_acs_map[i] = (unsigned char)(i < 32 ? ' ' : i); + } + + if (tc_acs_start && xf_graph /*-1 or 1*/) { + const char *p; + + if (NULL == (p = tc_graphic_pairs)) { /* build character map */ + p = tc_graphic_default; + } + + while (*p) { + i = *p++; + if (! isprint(i)) { + continue; /* unsure, yet needed for rxvt-cygwin */ + } + tc_acs_map[i & 0x7f] = *p++; + } + + x_pt.pt_tty_graphicsbox = TRUE; + x_pt.pt_top_left[0] = tc_acs_map[TACS_ULCORNER]; + x_pt.pt_top_right[0] = tc_acs_map[TACS_URCORNER]; + x_pt.pt_bot_left[0] = tc_acs_map[TACS_LLCORNER]; + x_pt.pt_bot_right[0] = tc_acs_map[TACS_LRCORNER]; + x_pt.pt_vertical[0] = tc_acs_map[TACS_VLINE]; + x_pt.pt_horizontal[0] = tc_acs_map[TACS_HLINE]; + x_pt.pt_top_join[0] = tc_acs_map[TACS_TTEE]; + x_pt.pt_bot_join[0] = tc_acs_map[TACS_BTEE]; + x_pt.pt_cross[0] = tc_acs_map[TACS_PLUS]; + x_pt.pt_left_join[0] = tc_acs_map[TACS_RTEE]; + x_pt.pt_right_join[0] = tc_acs_map[TACS_LTEE]; + + trace_ilog("ACS mapping\n"); + trace_ilog(" top %d/0x%x\n", x_pt.pt_top_right[0], x_pt.pt_top_right[0]); + trace_ilog(" bot %d/0x%x\n", x_pt.pt_bot_left[0], x_pt.pt_bot_left[0]); + trace_ilog(" bot %d/0x%x\n", x_pt.pt_bot_right[0], x_pt.pt_bot_right[0]); + trace_ilog(" verti %d/0x%x\n", x_pt.pt_vertical[0], x_pt.pt_vertical[0]); + trace_ilog(" horiz %d/0x%x\n", x_pt.pt_horizontal[0], x_pt.pt_horizontal[0]); + trace_ilog(" top %d/0x%x\n", x_pt.pt_top_join[0], x_pt.pt_top_join[0]); + trace_ilog(" bot %d/0x%x\n", x_pt.pt_bot_join[0], x_pt.pt_bot_join[0]); + trace_ilog(" cross %d/0x%x\n", x_pt.pt_cross[0], x_pt.pt_cross[0]); + trace_ilog(" left %d/0x%x\n", x_pt.pt_left_join[0], x_pt.pt_left_join[0]); + trace_ilog(" right %d/0x%x\n", x_pt.pt_right_join[0], x_pt.pt_right_join[0]); + } +} + + +/* Function: term_colors + * Load the given color specification. + * + * Parameters: + * value - Color scheme. + * + * Returns: + * nothing. + */ +static void +term_colors(void) +{ /* save user color specification */ + int col, source = 0; + + /* configure color depth */ + if (xf_color > 1) { + tt_colors = xf_color; /* command line override */ + source = 2; + + } else if (TA_MONO & t_attributes) { + tt_colors = 2; /* mono feature (xterm-mono) */ + source = 3; + + } else if (x_pt.pt_colordepth > 1) { + tt_colors = x_pt.pt_colordepth; /* set_term_feature() */ + source = 1; + + } else if (x_pt.pt_color /*-1 or 1*/) { + if (t_attributes & TA_XTERMLIKE) { + tt_colors = ANSI_COLORS; + + } else if (0 == (tt_colors = tf_Colors)) { + if (tc_ANSI_Color_Fg && tc_ANSI_Color_Bg) { + tt_colors = 16; + } else if (tc_Color_Fg && tc_Color_Bg) { + tt_colors = 8; + } else { + tt_colors = 0; + } + } + } + + /* configure colors */ + assert((COLOR_NONE + 1) == (sizeof(tt_colormap)/sizeof(tt_colormap[0]))); + assert((COLOR_NONE + 1) == (sizeof(color_map)/sizeof(color_map[0]))); + + trace_ilog("ttcolormap:\n"); + for (col = 0; col <= COLOR_NONE; ++col) { + int color = -1; + + if (-2 == x_pt.pt_xtpalette) { /* user defined palette */ + if ((color = tt_colormap[col]) <= 0) { + color = -1; + } + } + + if (color < 0) { + if (tt_colors >= 256) { + if (0 == x_pt.pt_xtpalette) { /* compat-16 mode */ + color = color_map[col].c256_compat; + } else { + color = color_map[col].c256; + } + + } else if (tt_colors >= 88) { + if (0 == x_pt.pt_xtpalette) { /* compat-16 mode */ + color = color_map[col].c88_compat; + } else { + color = color_map[col].c88; + } + + } else if (tt_colors >= 16) { + color = color_map[col].c16; + + } else { + color = color_map[col].c8; + } + } + + tt_colormap[col] = color; + trace_ilog("\t%16s [%2d] = %d\n", color_name(col, "unknown"), col, tt_colormap[col]); + assert(color_map[col].ident == col); + } + + trace_ilog("term_colors(source=%d,depth=%d)\n", source, tt_colors); + x_pt.pt_colordepth = tt_colors; /* derived depth */ + + if (tt_colors > 2) { + x_display_ctrl |= DC_SHADOW_SHOWTHRU; + } + term_fgbg(); +} + + +/* Function: term_fgbg + * Load the environment settings (if any) which define the default colors configurations. + * + * The supported configurations are NCURSES_ASSUMED_COLORS, COLORFGBG (rxvt/mrxvt) + * and DEFAULT_COLORS. + * + * The following are examples of their settings; + * + * NCURSES_ASSUMED_COLORS='0;15' + * + * COLORFGBG='0;default;15' + * + * DEFAULT_COLORS='0;15' + * + * Notes: + * The format of the COLORFGBG variable is not documented as such and there two + * known formats. The two formats correspond to whether the xpm library is used or + * not. + * + * If rxvt is compiled with xpm support, the variable has three fields. In either + * case, the background color is the last field. + * + * Parameters: + * src - Buffer cursor. + * result - Storage for decoded result. + * + * Returns: + * Final cursor position. + */ +static void +term_fgbg(void) +{ + const char *env; + + tt_defaultfg = tt_defaultbg = NOCOLOR; /* unknown */ + + if (NULL != (env = ggetenv("NCURSES_ASSUMED_COLORS"))) { + int count, fg = NOCOLOR, bg = NOCOLOR; + char sep; + + if ((count = sscanf(env, "%d%c%d%c", &fg, &sep, &bg, &sep)) >= 1) { + if (fg >= 0 && fg <= 255) tt_defaultfg = fg; + if (count >= 3) { + if (bg >= 0 && bg <= 255) tt_defaultbg = bg; + } + } + + } else { + if (NULL != (env = ggetenv("COLORFGBG")) || + NULL != (env = ggetenv("DEFAULT_COLORS"))) { + env = fgbg_value(env, &tt_defaultfg); + env = fgbg_value(env, &tt_defaultbg); + if (*env) { /* XPM support, last field is background */ + fgbg_value(env, &tt_defaultbg); + } + } + } + /* apply color */ + tt_defaultfg = fgbg_import(tt_defaultfg, x_pt.pt_defaultfg); + tt_defaultbg = fgbg_import(tt_defaultbg, x_pt.pt_defaultbg); +} + + +/* Function: fgbg_value + * Decode a COLORFGBG or DEFAULT_COLORS color specification. + * + * Parameters: + * src - Buffer cursor. + * result - Storage for decoded result. + * + * Returns: + * Final cursor position. + */ +static const char * +fgbg_value(const char *src, int *result) +{ + const char *end = NULL; + + if (0 == strncmp(src, "default", 7)) { + end = src + 7; /* special case */ + } else { + char *endp = 0; + int value = (int) strtol(src, &endp, 0); + + if (0 == endp) { + end = src; + } else if (value >= 0 && value <= 255) { + *result = (unsigned) value; + end = endp; + } + while (*end && *end != ';') { + ++end; + } + } + + if (*end == ';') { + ++end; + } + return end; +} + + +static unsigned +fgbg_import(unsigned edefault, int udefault) +{ + if (NOCOLOR == edefault) { + if (udefault >= 0) { + return udefault; + } + return NOCOLOR; + } + if (edefault < ANSI_COLORS) { + return ansicolor_map[ edefault ]; + } + return edefault; +} + + +/* Function: xterm_colors + * Manage the xterm color pairs + * + * Parameters: + * value - Specification. + * + * Notes: + * ESC]4; c; spec ? + * + * Change Color Number c to the color specified by spec, i.e., a name or RGB + * specification as per XParseColor. Any number of c name pairs may be given. + * + * The color numbers correspond to the ANSI colors 0-7, their bright versions 8-15, + * and if supported, the remainder of the 88-color or 256-color table. Each successive + * parameter changes the next color in the list. The value of Ps tells the starting + * point in the list. The colors are specified by name or RGB specification as per + * XParseColor. + * + * If a "?" is given rather than a name or RGB specification, xterm replies with a + * control sequence of the same form which can be used to set the corresponding color. + * Because more than one pair of color number and specification can be given in one + * control sequence, xterm can make more than one reply. + * + * Returns: + * nothing. + */ +static void +xterm_colors(const char *value) +{ + if (0 == (t_attributes & TA_XTERMLIKE)) /* xterm specific */ + return; + + if (NULL == value || 0 == value[0]) + return; + + trace_ilog("xterm_colors(%s)\n", value); + + if (value != t_colorsorg) { + if (0 == t_colorsorg[0]) { /* retrieve and save existing */ + xterm_colors_get(t_colorsorg, sizeof(t_colorsorg)); + } + } + + if (0 != t_colorsorg[0]) { /* set new value (if save was possible) */ + xterm_colors_set(value); + } +} + + +static int +xterm_colors_get(char *buffer, int length) +{ + int color, len; + + if (0 == (t_attributes & TA_XTERM)) { /* xterm specific */ + return -1; + } + + term_flush(); /* clear existing obuf */ + + for (len = 0, color = 0; color < XTERM_COLORS; ++color) { + /* + * foreach(color) + */ + int cnt = sprintf((char *)t_buffer, "\033]4;%d;?\007", color); + + if (cnt != sys_write(1, t_buffer, cnt) || + (cnt = term_read((char *)t_buffer, sizeof(t_buffer), 5 * 1000)) <= 0 || + sscanf((char *)t_buffer, "%*[^;];%*[^;];%s", buffer + len + (len ? 1 : 0)) != 1) { + /* + * Note, 'rxvt' and the 'linux console' only support set. + * + * rxvt shall report (on stderr)/ + * rxvt: can't determine colour: ? + */ + trace_ilog("\terr[%d] (%*s)\n", color, cnt, t_buffer); + break; + } + + trace_ilog("\tget[%d]=%s\n", color, buffer + len + (len ? 1 : 0)); + + if (len) { + buffer[len] = ','; /* separator */ + } + len += strlen(buffer + len); + assert(len < length-1); + + if ('\007' == buffer[len-1]) { /* strip terminator */ + buffer[len-1] = '\0', --len; + } + } + return 0; +} + + +static int +xterm_colors_set(const char *value) +{ + const char *term; + int color, len, cnt; + + if (0 == (t_attributes & TA_XTERMLIKE)) { /* xterm specific */ + return -1; + } + + term_flush(); /* clear existing obuf */ + + cnt = sprintf((char *)t_buffer, "\033]4"); /* dynamic color command */ + + for (color = 0; color < XTERM_COLORS; ++color) { + + if ((const char *)NULL == (term = strchr(value, ','))) { + len = strlen(value); + } else { + len = term - value; + } + + trace_ilog("\tset[%d]=%.*s\n", color, len, value ); + if (len) { + cnt += sprintf((char *)(t_buffer + cnt), ";%d;%.*s", color, len, value); + } + + assert(cnt < (int)sizeof(t_buffer)); + if (NULL == term) { + break; + } + + value = term + 1; /* next field */ + } + + cnt += sprintf((char *)(t_buffer + cnt), "\007"); + sys_write(1, t_buffer, cnt); /* terminator */ + return 0; +} + + +/* Function: term_identification + * Request the terminal (VT100 and xterm style) to echo the "Device Attributes" + * report containing terminal type and version. + * + * Parameters: + * none. + * + * Returns: + * Length of the buffer retrieved. + */ +static int +term_identification(void) +{ +#define XTERM_DEVICE_ATTR (sizeof(xterm_device_attr)-1) + static char xterm_device_attr[] = "\033[>c"; + int ret = -1; + +#if defined(__CYGWIN__) + if (TA_CYGWIN & t_attributes) { + /* + * CYGWIN + */ + struct utsname u = {0}; + int r1 = 0, r2 = 0; + + ret = -3; + if (uname(&u) >= 0) { + if (2 == sscanf(u.release, "%d.%d", &r1, &r2)) { + x_pt.pt_vtdatype = -3; /* source: xterm_cygwin */ + x_pt.pt_vtdaversion = (r1 * 100) + (r2 > 99 ? 99 : r2); + } + trace_ilog("\tcygwin_uname(%s) = %d.%d\n", u.release, r1, r2); + } + return ret; + } +#endif /*__CYGWIN__*/ + + if ((TA_VT100LIKE|TA_XTERM|TA_XTERMLIKE) & t_attributes) { + /* + * xterm and compatible terminals + */ + const char *vstring; + + /* + * XTERM_VERSION/ + * Xterm(256) ==> 256 + */ + if (NULL != (vstring = ggetenv("XTERM_VERSION"))) { + char vname[32] = {0}; + int vnumber = 0; + /* decode and return patch/version number */ + if (2 == sscanf(vstring, "%32[^(](%u)", vname, &vnumber)) + if (vnumber > 0) { + x_pt.pt_vtdatype = -2; /* source: xterm_version */ + x_pt.pt_vtdaversion = vnumber; + ret = 0; + } + trace_ilog("XTERM_VERSION(%s) = %d (%s)\n", vstring, vnumber, vname); + } + + /* + * device attribute + */ + if (-1 == ret) { + char buffer[32] = {0}; + int len = 0; + + term_flush(); + if (XTERM_DEVICE_ATTR == sys_write(1, xterm_device_attr, XTERM_DEVICE_ATTR) && + (len = term_read(buffer, sizeof(buffer), -2)) > 1) { + /* + * Example/ + * \033[>82;20710;0c + * ^type + * ^version + * + * Known terminal types/ + * xterm (0) 0;256;0c + * mintty (77) 77;10003;0c + * screen (83) + * old rxvt (82) + * rxvt unicode (85) + */ + trace_ilog("device_attr(%d, %s)\n", len, buffer); + + if ('\033' == buffer[0] && '[' == buffer[1] && + ('>' == buffer[2] || '?' == buffer[2])) { + int datype, daversion; + + if (2 == sscanf(buffer + 3, "%d;%d", &datype, &daversion)) { + trace_ilog("==> type:%d, version:%d\n", datype, daversion); + x_pt.pt_vtdatype = datype; + x_pt.pt_vtdaversion = daversion; + if (77 == datype) { + t_attributes |= TA_MINTTY; + ++tf_xn; + } + ret = 0; + } + } + } + } + } + + return ret; +} + + +/* Function: term_isutf8 + * Determine whether the terminal supports UTF8 character encoding. + * + * Where possible limit terminal interaction, as such test *all* + * configuration/environment setting prior. + * + * Parameters: + * none. + * + * Returns: + * *true* if UTF8, otherwise *false*. + */ +static int +term_isutf8(void) +{ + int ret = 0; + + if (DISPTYPE_UTF8 == xf_disptype) { /* explicitly enabled -- command line */ + ret = 1; + + } else if (DISPTYPE_7BIT == xf_disptype || DISPTYPE_8BIT == xf_disptype) { + ret = 0; /* explicitly disabled -- command line */ + + } else if (TA_LINUX & t_attributes) { /* linux console, not supported */ + ret = -2; + + } else if (TA_CYGWIN & t_attributes) { /* cygwin version (1.7+) */ + if (-3 == x_pt.pt_vtdatype) { + const int r1 = x_pt.pt_vtdaversion / 100; + const int r2 = x_pt.pt_vtdaversion % 100; + + if (2 <= r1 || (1 == r1 && 7 <= r2)) { + ret = 3; + } + } + + } else if (x_pt.pt_encoding[0]) { /* terminal encoding/locale */ + ret = (mchar_locale_utf8(x_pt.pt_encoding) ? 2 : -1); + + } else if (sys_unicode_locale(TRUE)) { /* BTERM_LOCAL or LOCALE */ + ret = 4; + + } else if (TA_XTERM & t_attributes) { + /* + * Write a single utf8 character and check resulting cursor position. + * + * Source: ICU27 and general discussions + */ +#define XTERM_UTF8_TEST1 (sizeof(xterm_utf8_test1)-1) +#define XTERM_UTF8_CLEAN1 (sizeof(xterm_utf8_clean1)-1) + + static unsigned char xterm_utf8_test1[] = "\r" "\xc3\xb6" "\033[6n"; + static unsigned char xterm_utf8_clean1[] = "\r \r"; + + ret = -5; + term_flush(); + if (XTERM_UTF8_TEST1 == sys_write(1, (void *)xterm_utf8_test1, XTERM_UTF8_TEST1)) { + int row = -1, col = -1; + char buffer[32] = {0}; + int len; + + if ((len = term_read(buffer, sizeof(buffer), -2)) >= 4 && + 2 == sscanf(buffer, "\033[%d;%dR", &row, &col)) { + if (2 == col) { + ret = 5; /* cursor in second column */ + } + } + trace_ilog("\tisutf8A(%d) = col:%d\n", len, col); + sys_write(1, (void *)xterm_utf8_clean1, XTERM_UTF8_CLEAN1); + } + + } + + trace_ilog("UTF8 support=%d\n", ret); + return (ret >= 1 ? 1 : 0); +} + + +#if (XXX_MCHAR_DETECT) +static void +term_utf8_features(void) +{ +#define XTERM_UTF8_TEST2 (sizeof(xterm_utf8_test2)-1) + + static unsigned char xterm_utf8_test2[] = { + '\r', /* UTF* features */ + 0xa5, + 0xc3, 0x84, 0xd9, + 0xa7, + 0xd8, 0xb8, 0xe0, 0xe0, + 0xa9, + 0xa9, + 0xb8, 0x88, 0xe5, 0xe5, 0x88, + 0xa2, 0xa2, + 0x1b, '[', '6', 'n', /* cursor position */ + 0x00 /* NUL */ + }; + + term_flush(); + + if (XTERM_UTF8_TEST2 == sys_write(1, xterm_utf8_test2, XTERM_UTF8_TEST2)) { + int row = -1, col = -1; + char buffer[32] = {0}; + int len; + + /* + * check cursor column after test string, determine screen mode + * + * 6 -> UTF-8, no double-width, with LAM/ALEF ligature joining + * 7 -> UTF-8, no double-width, no LAM/ALEF ligature joining + * 8 -> UTF-8, double-width, with LAM/ALEF ligature joining + * 9 -> UTF-8, double-width, no LAM/ALEF ligature joining + * 11,16 -> CJK terminal (with luit) + * 10,15 -> 8 bit terminal or CJK terminal + * 13 -> Poderosa terminal emulator, UTF-8, or TIS620 terminal + * 14,17 -> CJK terminal + * 16 -> Poderosa, ISO Latin-1 + * (17) -> Poderosa, (JIS) + * 18 -> CJK terminal (or 8 bit terminal, e.g. Linux console) + */ + if ((len = term_read(buffer, sizeof(buffer), -2)) >= 4) { + sscanf(buffer, "\033[%d;%dR", &row, &col); + } + + trace_ilog("\tisutf8B(%d) = col:%d\n", len, col); + } +} +#endif /*XXX_MCHAR_DETECT*/ + + +/* Function: term_read + * Determine if the terminal supports UTF8 character encoding. + * + * Parameters: + * buf - Buffer. + * len - Length of the buffer, in bytes. + * tmo - Timeout is milliseconds. + * + * Returns: + * Number of bytes read. + */ +static int +term_read(char *buf, int len, accint_t tmo) +{ + int ch, cnt = 0; + + if (-2 == tmo) { + tmo = io_escdelay(); + } + + assert(buf); + assert(len); + assert(tmo >= -1); + + --len; + if ((ch = io_get_raw(tmo)) > 0) { + do { /* secondary characters */ + buf[cnt++] = (char) ch; + } while ((ch = io_get_raw(50)) > 0 && cnt < len); + } + buf[cnt] = '\0'; + return cnt; +} + + +/* Function: term_tidy + * Cleanup/restore the state of the console. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static void +term_tidy(void) +{ + if (0 == tt_active) + return; + + term_flush(); + + if (t_attributes & TA_CYGWIN) { + if (xf_cygwinkb) { + ttpush("\033[?2000l"); /* disable RAW mode */ + } + } else if (t_attributes & TA_MINTTY) { +//TODO if (! xf_mouse) { + ttpush("\033[?7786l"); /* disable mouse-wheel reports */ +// } + } + + term_graphic_exit(); /* graphic mode */ + + term_colorreset(); + term_styleoff(); + xterm_colors_set(t_colorsorg); + + /* ttputpad(tc_mo); -* restore meta key-codes */ + + ttputpad(tc_ve); /* restore normal cursor */ + + if (! xf_nokeypad) { + ttputpad(tc_ke); /* out of ``keypad-transmit'' mode */ + } + + if ((NULL == tc_rs && 0 == x_pt.pt_reset[0]) || x_pt.pt_noaltscreen) { + term_zero(TRUE); /* remove image */ + ttmove(ttrows() - 1, 0); + } else { + term_scrollreset(); /* scroll window */ + } + + ttputpad(tc_rs); /* set the term back to normal mode */ + + if (x_pt.pt_reset[0]) { /* terminal specific reset */ + ttputctl2(x_pt.pt_reset, 0, 0); + } + term_flush(); + + if (! xf_noinit) { + ttputpad(tc_te); /* disable cup (cursor addressing) */ + } + term_flush(); + + trace_log("term_tidy(0x%0x)\n", t_specials); + + tt_cursor = 0; + tt_active = 0; +} + + +/* Function: term_cursor + * Set the cursor status. + * + * Parameters: + * visible - Visible status. + * imode - Insert mode. + * virtual_space - Virtual space mode. + * + * Returns: + * returns the current visible status, otherwise -1 on error. + */ +static int +term_cursor(int visible, int imode, int virtual_space) +{ + if (visible >= 0) { + if (visible != tt_cursor) + if (tc_vi && (tc_vs || tc_ve)) { + if (visible) { /* enable cursor, enhanced if available */ + ttputpad(tc_vs ? tc_vs : tc_ve); + } else { + ttputpad(tc_vi); /* hide cursor */ + } + } + tt_cursor = visible; + } + + if (tt_cursor && imode >= 0) { + if (imode) { /* insert mode */ + if (x_pt.pt_vicursor[0]) { + ttprintf(virtual_space ? x_pt.pt_vicursor : x_pt.pt_icursor); + + } else if (x_pt.pt_xtcursor >= 1 || + (-1 == x_pt.pt_xtcursor && (t_attributes & TA_XTERMLIKE))) { +#if defined(DO_SPECIALS) + if (0 == (t_specials & 0x0010)) + t_specials |= 0x0010, trace_log("SPECIAL(ttcursor) 'imode'\n"); + ttprintf("\033]12;%s\007", "Black"); +#endif + } + } else { /* overstrike/overtype mode */ + if (x_pt.pt_vocursor[0]) { + ttputpad(virtual_space ? x_pt.pt_vocursor : x_pt.pt_ocursor); + + } else if (x_pt.pt_xtcursor >= 1 || + (-1 == x_pt.pt_xtcursor && (t_attributes & TA_XTERMLIKE))) { +#if defined(DO_SPECIALS) + if (0 == (t_specials & 0x0020)) { + t_specials |= 0x0020, trace_log("SPECIALS(ttcursor) 'omode'\n"); + } + ttprintf("\033]12;%s\007", "RoyalBlue1"); +#endif + } + } + } + + return (tt_cursor ? 1 : 0); +} + + +/* Function: ttmove + * Move the cursor to the specified origin 0 row and column position. Try to + * optimize out extra moves; redisplay may have left the cursor in the right + * location last time! + * + * Parameters: + * row - Screen row (0 .. rows - 1). + * col - Column (0 .. rows - 1). + * + * Returns: + * nothing. + */ +static void +term_move(int row, int col) +{ + const int rows = ttrows() - 1, cols = ttcols() - 1, + ttrow = ttatrow(), ttcol = ttatcol(); + + assert(row >= 0); + assert(row <= rows); + assert(col >= 0); + assert(col <= cols); + + if (ttrow == row && ttcol == col) { + ED_TERM(("ttmove(%d,%d->%d,%d)\n", ttrow, ttcol, row, col)) + return; + } + ED_TERM(("ttmove(%d,%d->%d,%d)", ttrow, ttcol, row, col)) + + /* + * Moving cursor, check ms flag. + * the 'ms' flag whose presence means that it is safe to move the cursor + * while the appearance modes are not in the normal state. If this flag + * is absent, programs should always turn off underlining/standout + * before moving the cursor. + */ + if (1 != tf_ms) + if (tt_style) { + term_styleoff(); + tt_hue = -1; + } + + if (tc_ho && 0 == col && 0 == row) { /* */ + ED_TERM(("->putpad(ho)\n")) + ttputpad(tc_ho); + + } else { + /* + * optimise based on current position (if known) + */ + int done = TRUE; + + if (ttcol < 0 || ttrow < 0) { + /* + * invalid existing position. + */ + done = FALSE; + + } else if (tc_ll && row == rows && 0 == col) { + ED_TERM(("->putpad(ll)\n")) /* */ + ttputpad(tc_ll); + + } else { + /* + * If within column zero avoid using UP and DO under XTERM (others??) + * otherwise we shall find ourselves in the last column of the + * previous line; believe related to terminal automatic-margin + * support. + * + * Note: this is generally only a visible problem when running borderless mode. + */ +#define COLUMNOK() (col > 0 || 0 == (t_attributes & TA_XTERM)) + +#define PCOST 4 /* parameterised version cost */ + + if (col == ttcol) { /* row changes */ + + /* cursor up - one line (ignore first column) */ + if (tc_up && COLUMNOK() && row == ttrow - 1) { + ED_TERM(("->putpad(UP)\n")) + ttputpad(tc_up); + + /* cursor up - parameterized (ignore first column) */ + } else if (tc_pUP && COLUMNOK() && row < ttrow /*-PCOST*/) { + const int p1 = (int)(ttrow - row); + + ED_TERM(("->putctl(pUP,%d)\n", p1)) + ttputctl(tc_pUP, p1); + + /* cursor down - one line (ignore bottom left corner) */ + } else if (tc_do && COLUMNOK() && row == ttrow + 1 && (row < rows || col < (cols - 1))) { + ED_TERM(("->putpad(DO)\n")) + ttputpad(tc_do); + + /* cursor down - parameterized */ + } else if (tc_pDO && COLUMNOK() && row > ttrow /*+PCOST*/) { + const int p1 = (int)(row - ttrow); + + ED_TERM(("->putctl(pDO,%d)\n", p1)) + ttputctl(tc_pDO, p1); + + /* cursor vertical movement */ + } else if (tc_cv) { + ED_TERM(("->putctl(cv,%d)\n", row)) + ttputctl(tc_cv, row); + + } else { + done = FALSE; + } + + } else if (row == ttrow) { /* column changes */ + + /* cursor left */ + if (tc_cr && 0 == col) { + ED_TERM(("->putpad(cr)\n")) + ttputpad(tc_cr); + + /* cursor left - one column */ + } else if (tc_le && col < ttcol && col >= (ttcol - 3)) { + int p1 = (int)(ttcol - col); + + ED_TERM(("->putpad(le,%d)\n", p1)) + while (p1--) ttputpad(tc_le); + + /* cursor back */ + } else if (tc_bc && col < ttcol && col >= (ttcol - 3)) { + int p1 = (int)(ttcol - col); + + ED_TERM(("->putpad(bc,%d)\n", p1)) + while (p1-- > 0) ttputpad(tc_bc); + + /* cursor left - parameterised */ + } else if (tc_pBC && col < (ttcol - 2)) { + const int p1 = (int)(ttcol - col); + + ED_TERM(("->putctl(pBC,%d)\n", p1)) + ttputctl(tc_pBC, p1); + + /* cursor right - one column */ + } else if (tc_nd && col == ttcol + 1) { + ED_TERM(("->putpad(ND)\n")) + ttputpad(tc_nd); + + /* cursor right - parameterised */ + } else if (tc_pRI && col > ttcol && col > 1 && col < cols) { + const int p1 = (int)(col - ttcol); + + ED_TERM(("->putctl(pRI,%d)\n", p1)) + ttputctl(tc_pRI, p1); + + /* cursor right - parameterised */ + } else if (x_pt.pt_cursor_right[0] && col > ttcol /*+PCOST*/) { + const int p1 = (int)(col - ttcol); + + ED_TERM(("->putctl(pCR,%d)\n", p1)) + ttprintf(x_pt.pt_cursor_right, p1); + + /* cursor horz movement */ + } else if (tc_ch) { + ED_TERM(("->putctl(ch,%d)\n", col)) + ttputctl(tc_ch, col); + + } else { + done = FALSE; + } + + } else { + done = FALSE; /* do by hand */ + } + } + +#undef PCOST + + /* absolute cursor movement */ + if (! done) { + if (tc_cm) { + ED_TERM(("->cm(%d, %d)\n", col, row)) + ttputctl2(tc_cm, col, row); + } else { /* use vertical/horiz movement */ + ED_TERM(("->cvch(%d, d)\n", col, row)) + ttputctl(tc_cv, row); + ttputctl(tc_ch, col); + } + } + } + + ttposset(row, col); +} + + +/* Function: term_names + * Set the console title. + * + * Parameters: + * title - Title buffer. + * + * Returns: + * nothing. + */ +static int +term_names(const char *title, const char *icon) +{ + __CUNUSED(icon) + + if (x_pt.pt_xttitle >= 1 || + (-1 == x_pt.pt_xttitle && (t_attributes & TA_XTERMLIKE))) { + + const unsigned char *t = (const unsigned char *) title; + const size_t len = 16 + strlen(title); + char *c; + + if (NULL != (c = chk_alloc(len))) { + unsigned char *p = + (unsigned char *)(c + sprintf(c, "\033]0;")); + + do { + *p++ = (unsigned char)(*t < 32 || *t > 127 ? '?' : *t); + } while (*++t); + *p++ = '\007'; + *p = '\0'; + + ttpush(c); + chk_free(c); + } + } + return 0; +} + + +/* Function: term_beep + * Make a noise. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static void +term_beep(int freq, int duration) +{ + __CUNUSED(freq) __CUNUSED(duration) + + if (xf_visbell && tc_vb) { /* visual bell */ + ttputpad(tc_vb); + } else if (tc_bl) { + ttputpad(tc_bl); + } else { + static const char bel[] = {ASCIIDEF_BEL, 0}; + ttpush(bel); + } + term_flush(); +} + + +/* Function: normalbg + * Determine whether the current background is the terminals + * default/normal background color. + * + * One of the following conditions are confirmed, checking the current + * hues ground against, + * + * o Background is the terminal default (see COLORFGBG and tt_defaultfg). + * + * o Background is NONE. + * + * Parameters: + * bg - Storage returned with the cooked color enumeration. + * + * Returns: + * *true* or *false* + */ +static int +normalbg(int *bg) +{ + colattr_t ca; + + *bg = -1; + color_definition(tt_hue, &ca); + return (COLORSOURCE_SYMBOLIC == ca.bg.source && + (tt_defaultbg == (*bg = (int)tt_colormap[ca.bg.color]) || COLOR_NONE == ca.bg.color)); +} + + +/* Function: clearbg + * Determine whether a terminal clear command will (hopefully) function correctly with + * the current background color, otherwise the operation shall fail resulting in the + * cleared region being an incorrect background color; hence should be avoided. + * + * One of the following conditions are confirmed, + * + * o BE or UT, if BE (Back color erase - xterm) or UT (Screen erased with background + * color) are true the terminal clears using the current hue. + * + * o Current hue is the terminals default/normal background. + * + * o Terminal feature clrisblack is enabled and background is BLACK. + * + * o No color mode and the hue is NORMAL. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static int +clearbg(void) +{ + int bg; + + if (tf_be || tf_ut) + return TRUE; /* erase in current color */ + if (normalbg(&bg)) + return TRUE; /* current background is normal/default */ + if (x_pt.pt_clrisblack && BLACK == bg) { + return TRUE; + } + if (!vtiscolor() && ATTR_NORMAL == tt_hue) { + return TRUE; + } + return FALSE; +} + + +/* Function: term_clear + * Clear the terminal. + * + * Parameters: + * restore - *true* if the screen image should be restored. + * + * Returns: + * nothing. + */ +static void +term_clear(void) +{ + ED_TERM(("term_clear()\n")) + term_zero(FALSE); +} + + +/* Function: term_zero + * Zero the terminal image. + * + * Parameters: + * restore - *true* if the screen image should be restored. + * + * Returns: + * nothing. + */ +static void +term_zero(int restore) +{ + ED_TERM(("term_zero(%d)\n", restore)) + term_scrollreset(); + ttmove(0, 0); + term_attr(VBYTE_ATTR(ATTR_NORMAL)); + if (tc_cl && (restore || clearbg())) { /* clear screen command (and home cursor) */ + ED_TERM(("->putpad(CL)\n")) + ttputpad(tc_cl); + } else { /* erase to end of page */ + ED_TERM(("->eeop()\n")) + term_eeop(restore); + } + term_colorreset(); + term_flush(); +} + + +/* Function: term_eeol + * Erase to end of line in the 'current' color. + * + * Parameters: + * none. + * + * Returns: + * *true* if eeol successful, otherwise *false*. + */ +static int +term_eeol(void) +{ + const int rows = ttrows() - 1, cols = ttcols() - 1, + row = ttatrow(), col = ttatcol(); + + ED_TERM(("term_eeol(%d, %d)\n", row, col)) + + assert(row <= rows); + assert(col <= cols); + + if (col < cols) { + /* + * Clear to end of line. + */ + if (term_ce() && clearbg()) { + ED_TERM(("->putpad(CE)\n")) + ttputpad(tc_ce); + + /* + * Character based + * Avoid writing to the lower right corner; as the terminal does not have CE, + * then it probably does not have what it takes not to scroll upon hitting + * the bottom-right corner. + */ + } else { + int cnt = cols - col; /* column count to end-of-line */ + + if (row >= rows) { + --cnt; /* ignore last column */ + } + term_repeat(cnt, ' ' | VBYTE_ATTR(tt_hue), WHERE_START); + } + } + return TRUE; +} + + +/* Function: term_ce + * Is clear to end of line (CE) available. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static int +term_ce(void) +{ + return (tc_ce && tc_ce[0]); +} + + +/* Function: term_lastsafe + * Return whether it is safe to write to the last character within the bottom column. + * + * Parameters: + * none. + * + * Returns: + * TRUE or FALSE. + */ +static int +term_lastsafe(void) +{ + if (TA_CYGWIN & t_attributes) { + return FALSE; /* needs further investigations */ + } + return (term_ce() || tf_LP > 0 ? TRUE : FALSE); +} + + +/* Function: term_eeop + * Erase to end of page. + * + * Parameters: + * restore - Executed during a restore operation. + * + * Returns: + * nothing. + */ +static void +term_eeop(int restore) +{ + const int rows = ttrows() - 1, cols = ttcols() - 1; + int row = ttatrow(), col = ttatcol(); + + ED_TERM(("term_eeop(%d, %d)\n", row, col)) + + assert(row <= rows); + assert(col <= cols); + + if (tc_cd && (restore || clearbg())) { /* clear to end of display (cursor unchanged). */ + ED_TERM(("->putpad(CD)\n")) + ttputpad(tc_cd); + + } else { /* long-hand */ + int done = FALSE; + + if (col > 0) { + term_eeol(); /* remove remaining of line */ + ++row; + } + + if (row <= rows) { + if (t_insdel && !x_pt.pt_noinsdel && (restore || clearbg())) { + done = term_dell(row, rows, rows - row, 0 /*current*/); + if (done) { + ED_TERM(("->ttdell()\n")) + } + } + + if (! done) { /* do it by hand. */ + ED_TERM(("->line-by-line()\n")) + for (; row <= rows; ++row) { + ttmove(row, 0); + term_eeol(); + } + } + } + } +} + + +/* Function: term_repeat + * Function to repeat a character from the current location. + * + * 'where' says whether we want the cursor to stick at the starting point or stick + * at the end of the region. If set to 2 then this is a don't care -- i.e. leave + * cursor as it is. + * + * Parameters: + * cnt - Character count. + * fill - Fill character. + * where - Where to leave the cursor (0=end, 1=start, 2=dontcare). + * + * Returns: + * nothing. + */ +static void +term_repeat(int cnt, vbyte_t fill, int where) +{ + const int orow = ttatrow(), ocol = ttatcol(); + + ED_TERM(("term_repeat(%d,'%c')\n", cnt, VBYTE_CHAR_GET(fill))) + + if (cnt <= 0) return; + + term_attr(fill & VBYTE_ATTR_MASK); + + if (cnt >= (4 + (WHERE_DONTCARE == where ? 0 : 4))) { + const int ch = (int) VBYTE_CHAR_GET(fill); + int bg = 0; + /* erase #1 characters (no cursor move) */ + if (tc_ech && ' ' == ch && normalbg(&bg)) { + + if (0 == (t_specials & 0x0001)) + t_specials |= 0x0001, trace_log("SPECIAL(erase-repeat,%s,%d)\n", tc_ech, cnt); + + ttputctl(tc_ech, cnt); + ttposinvalid(); + if (WHERE_END == where) { + ttmove(orow, ocol + cnt); + } else if (WHERE_START == where) { + ttmove(orow, ocol); + } + cnt = 0; + /* repeat character (cursor move) */ + } else if (tc_rp && (orow < (ttrows() - 1))) { + + if (0 == (t_specials & 0x0002)) + t_specials |= 0x0002, trace_log("SPECIAL(repeat-char,%s,%d)\n", tc_rp, cnt); + + ttputctl2(tc_rp, cnt, ch); + ttposinvalid(); + if (WHERE_END == where) { + ttmove(orow, ocol + cnt); + } else if (WHERE_START == where) { + ttmove(orow, ocol); + } + cnt = 0; + /* erase #1 characters (no cursor move) */ + } else if (x_pt.pt_repeat_space[0] && ' ' == ch && normalbg(&bg)) { + + if (0 == (t_specials & 0x0004)) + t_specials |= 0x0004, trace_log("SPECIAL(erase-repeat,%s)\n", x_pt.pt_repeat_space); + + ttprintf(x_pt.pt_repeat_space, cnt); + ttposinvalid(); + if (WHERE_END == where) { + ttmove(orow, ocol + cnt); + } else if (WHERE_START == where) { + ttmove(orow, ocol); + } + cnt = 0; + + } else if (x_pt.pt_repeat_last[0] && /* repeat last (cursor move *not* assumed) */ + (orow < (ttrows() - 1)) && normalbg(&bg)) { + + if (0 == (t_specials & 0x0008)) + t_specials |= 0x0008, trace_log("SPECIAL(repeat-last,%s,%d)\n", x_pt.pt_repeat_last, cnt); + + term_putc(fill); + ttprintf(x_pt.pt_repeat_last, cnt - 1); + ttposinvalid(); + if (WHERE_END == where) { + ttmove(orow, ocol + cnt); + } else if (WHERE_START == where) { + ttmove(orow, ocol); + } + cnt = 0; + } + } + + if (cnt > 0) { /* by-hand */ + ED_TERM(("->byhand()\n")) + while (cnt-- > 0) { + term_putc(fill); + } + if (WHERE_START == where) { + ttmove(orow, ocol); + } + } +} + + +/* Function: term_insl + * Insert the specified number of blank lines 'lines' onto the screen using the region + * 'row' and 'bot', scrolling the last line within the region off the screen. + * + * Use the scrolling region commands if possible for a smoother display, otherwise + * when no scrolling region, use a set of insert and delete line sequences. + * + * Parameters: + * row - Top row of region. + * bot - Bottom of region. + * nlines - Number of lines to be inserted. + * fillcolor - Fill attribute. + * + * Returns: + * TRUE if the operation could be performed, otherwise FALSE. + */ +static int +term_insl(int row, int bot, int nlines, vbyte_t fillcolor) +{ + int i; + + trace_log("term_insl(row:%d, bot:%d, nlines:%d)\n", row, bot, nlines); + + assert(row >= 0); + assert(bot >= 0); + assert(row < ttrows()); + assert(bot < ttrows()); + assert(bot >= row); + assert(nlines > 0); + assert(nlines <= (bot - row)); + + term_attr(fillcolor); + + if (row == bot) { /* one line, simple optimisation */ + ttmove(row, 0); + term_eeol(); + return TRUE; + } + /* scroll region and back index */ + if (tc_cs && tc_sr && !x_pt.pt_scroll_disable) { + term_scrollset(row, bot); + ttmove(row, 0); + if (nlines > 1 && tc_pSR) { + ttputctl(tc_pSR, nlines); + } else { + for (i = 0; i < nlines; ++i) { + ttputpad(tc_sr), term_eeol(); + } + } + term_scrollreset(); + ttmove(row, 0); + return TRUE; + } + + if (t_insdel && !x_pt.pt_noinsdel) { /* line ins/del */ + ttmove(1 + bot - nlines, 0); + if (nlines > 1 && tc_pDL) { + ttputctl(tc_pDL, nlines); + } else { + for (i = 0; i < nlines; ++i) { + ttputpad(tc_dl); + } + } + + ttmove(row, 0); + if (nlines > 1 && tc_pAL) { + ttputctl(tc_pAL, nlines); + } else { + for (i = 0; i < nlines; ++i) { + ttputpad(tc_al); + } + } + + if (!tf_be || !tf_ut) /* must erase line for correct colouring */ + for (i = 0; i < nlines; ++i) { + ttmove(row + i, 0); + term_eeol(); + } + + ttposinvalid(); + return TRUE; + } + return FALSE; +} + + +/* Function: term_dell + * Delete the specified number of blank lines 'nlines' onto the screen using the region + * 'row' and 'bot', replacing the last line within a blank line. + * + * Use the scrolling region commands if possible for a smoother display, otherwise + * when no scrolling region, use a set of insert and delete line sequences. + * + * Knownledge that the echo-line shall always be presence, removes the end-of-screeen + * boundary condition. + * + * Parameters: + * row - Top row of region. + * bot - Bottom of region. + * nlines - Number of lines to be deleted. + * fillcolor - Fill attribute. + * + * Returns: + * TRUE if the operation could be performed, otherwise FALSE. + */ +static int +term_dell(int row, int bot, int nlines, vbyte_t fillcolor) +{ + int i; + + trace_log("term_dell(row:%d, bot:%d, nlines:%d)\n", row, bot, nlines); + + assert(row >= 0); + assert(bot >= 0); + assert(row < ttrows()); + assert(bot < ttrows()); + assert(bot >= row); + assert(nlines > 0); + assert(nlines <= (bot - row)); + + term_attr(fillcolor); + + if (row == bot) { /* one line special case */ + ttmove(row, 0); + term_eeol(); + return TRUE; + } + + if (tc_cs && !x_pt.pt_scroll_disable && /* scrolling region and within limits */ + (x_pt.pt_scroll_max <= 2 || (bot - row) <= x_pt.pt_scroll_max)) { + term_scrollset(row, bot); + ttmove(bot, 0); + if (nlines > 1 && tc_pSF) { + ttputctl(tc_pSF, nlines); /* 24/11/08 */ + } else { + for (i = 0; i < nlines; ++i) { + ttputpad(tc_sf ? tc_sf : "\n"), term_eeol(); + } + } + term_scrollreset(); + ttmove(bot, 0); + return TRUE; + } + /* ins/del, unless disabled or fast */ + if (t_insdel && !x_pt.pt_noinsdel && x_pt.pt_tty_fast <= 0) { + ttmove(row, 0); + if (nlines > 1 && tc_pDL) { + ttputctl(tc_pDL, nlines); + } else { + for (i = 0; i < nlines; ++i) { + ttputpad(tc_dl); + } + } + ttmove(1 + bot - nlines, 0); + if (nlines > 1 && tc_pAL) { + ttputctl(tc_pAL, nlines); + } else { + for (i = 0; i < nlines; ++i) { + ttputpad(tc_al); + } + } + ttposinvalid(); + return TRUE; + } + return FALSE; +} + + +/* Function: term_scrollset + * Setup the display scrolling window. + * + * Note: + * Setting a scroll region invalidates the cursor position. As such the cursor + * position is also invalidated to ensure that the next call to "ttmove" does + * not turn into a no-op (the window adjustment moves the cursor). + * + * Parameters: + * top - Top row of the scroll region. + * bot - Bottom row. + * + * Returns: + * nothing. + */ +static void +term_scrollset(int top, int bot) +{ + assert(top >= 0); + assert(top < ttrows()); + assert(bot >= 0); + assert(bot < ttrows()); + assert(-1 == top || top != bot); /* one line, should be avoided */ + assert(top < bot); + assert(tc_cs); /* should always be the case */ + + if (tc_cs) { /* scroll region avail ? */ + if (-1 == top || -1 == bot) { + top = 0, bot = ttrows() - 1; /* reset */ + } + + if (tt_top != top || tt_bot != bot) { /* update */ + ttputctl2(tc_cs, tt_bot = bot, tt_top = top); + ttposinvalid(); + } + } +} + + +/* Function: term_scrollreset + * Reset the current scroll region. + * + * Note: + * Setting a scroll region invalidates the cursor position. As such the cursor + * position is also invalidated to ensure that the next call to "ttmove" does + * not turn into a no-op (the window adjustment moves the cursor). + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static void +term_scrollreset(void) +{ + if (tc_cs) { + ttputctl2(tc_cs, tt_bot = ttrows() - 1, tt_top = 0); + ttposinvalid(); + } +} + + +/* Function: term_attr + * Set the current attribute color to the specified color. + * + * The following function optimises based on the required color change and the + * current known state (if any). + * + * Parameters: + * color - Required color attribute. + * + * Returns: + * nothing. + */ +static void +term_attr(vbyte_t color) +{ + vbyte_t attr = VBYTE_ATTR_GET(color); /* encode attribute */ + + if (tt_hue == attr) { + return; + } + tt_hue = attr; + + ED_TERM(("ttattr(%d/0x%x)", attr, attr)) + + if (! vtiscolor()) { + /* + * black-wbite/no-color mode + * \033[0m Normal. + * \033[1m Bold (extra bright). + * \033[4m Underline. + * \033[5m Blink (appears as Bold on Xterm etc). + * \033[7m Inverse (hilight). + * + * optional: + * \033[22m Normal (neither bold nor faint). + * \033[24m End underline. + */ + const int nstyle = ttbandw(attr, tc_us?1:0, tc_ZH?1:0, tc_mb?1:0); + + if (tt_style != nstyle) { + term_styleoff(); + term_styleon(nstyle); + } + + } else { + colattr_t ca = {0}; + int fg, bg, sf; + + color_definition(attr, &ca); + fg = ca.fg.color; + bg = ca.bg.color; + sf = ca.sf; + + ED_TERM((", curr(fg:%d, bg:%d, sf:%d), attr(fg:%d, bg:%d, sf:%d)", tt_fg, tt_bg, tt_style, fg, bg, sf)) + + if (tt_colors >= 88 /*88 or 256*/) { + /* 256 color mode + * + * \033[0m Set normal (foreground, background and styles) + * \033[39m Normal foreground color. + * \033[49m Normal background color. + * \033[38;5;#m Set the foreground color to index # + * \033[48;5;#m Set the background color to index # + */ + if (COLORSOURCE_SYMBOLIC == ca.fg.source) fg = tt_colormap[fg]; + if (COLORSOURCE_SYMBOLIC == ca.bg.source) bg = tt_colormap[bg]; + + ED_TERM(("->map(fg:%d, bg:%d)", fg, bg)) + + if (fg != tt_fg || bg != tt_bg || sf != tt_style) { + char ebuf[64]; + + if (tt_style) term_styleoff(); + + if (fg >= 0 && bg >= 0) { /* foreground,background */ + // if (x_pt.pt_colorsetfgbg[0]) { + // sxprintf(ebuf, sizeof(ebuf), x_pt.pt_colorsetfgbg, 0xff & fg, 0xff & bg); + // + // } else if (x_pt.pt_colorsetfg[0] && x_pt.pt_colorsetbg[0]) { + // int len = sxprintf(ebuf, sizeof(ebuf), x_pt.pt_colorsetfg, 0xff & fg); + // sxprintf(ebuf + len, sizeof(ebuf) - len, x_pt.pt_colorsetbg, 0xff & bg); + // + // } else { + sxprintf(ebuf, sizeof(ebuf), "\033[38;5;%u;48;5;%um", 0xff & fg, 0xff & bg); + // } + ttputpad(ebuf); + + } else if (fg >= 0) { /* foreground,normal */ + // if (x_pt.pt_colorsetfgbg[0]) { + // sxprintf(ebuf, sizeof(ebuf), x_pt.pt_colorsetfgbg, 0xff & fg, 0); + // + // } else if (x_pt.pt_colorsetfg[0] && x_pt.pt_colorsetbg[0]) { + // int len = sxprintf(ebuf, sizeof(ebuf), x_pt.pt_colorsetfg, 0xff & fg); + // sxprintf(ebuf + len, sizeof(ebuf) - len, x_pt.pt_colorsetbg, 0); + // + // } else { + sxprintf(ebuf, sizeof(ebuf), "\033[49;38;5;%um", 0xff & fg); + // } + ttputpad(ebuf); + + } else if (bg >= 0) { /* normal,background */ + // if (x_pt.pt_colorsetfgbg[0]) { + // sxprintf(ebuf, sizeof(ebuf), x_pt.pt_colorsetfgbg, 0, 0xff & bg); + // + // } else if (x_pt.pt_colorsetfg[0] && x_pt.pt_colorsetbg[0]) { + // int len = sxprintf(ebuf, sizeof(ebuf), x_pt.pt_colorsetfg, 0); + // sxprintf(ebuf + len, sizeof(ebuf) - len, x_pt.pt_colorsetbg, 0xff & bg); + // + // } else { + sxprintf(ebuf, sizeof(ebuf), "\033[39;48;5;%um", 0xff & bg); + // } + ttputpad(ebuf); + + } else { /* normal */ + sxprintf(ebuf, sizeof(ebuf), "\033[0m"); + ttputpad(tc_me ? tc_me : "\033[0m"); + } + + if (sf) term_styleon(sf); + } + + } else if (tt_colors > 8 || NULL == tc_Color_Bg || NULL == tc_Color_Fg) { + /* 16 color mode (standard - ANSI) + * + * \033[0m Set normal (foreground and background) + * + * \033[30m Set foreground color to Black + * \033[31m Set foreground color to Red + * \033[32m Set foreground color to Green + * \033[33m Set foreground color to Yellow + * \033[34m Set foreground color to Blue + * \033[35m Set foreground color to Magenta + * \033[36m Set foreground color to Cyan + * \033[37m Set foreground color to White + * \033[1;%dm Set foreground color (bright, 30 .. 37) + * + * \033[40m Set background color to Black + * \033[41m Set background color to Red + * \033[42m Set background color to Green + * \033[43m Set background color to Yellow + * \033[44m Set background color to Blue + * \033[45m Set background color to Magenta + * \033[46m Set background color to Cyan + * \033[47m Set background color to White + * \033[5;%dm Set background color (bright, 40 -- 47) + * + */ + char ebuf[48] = "\033["; /* leading */ + int l = 2; + + if (COLORSOURCE_SYMBOLIC == ca.fg.source) fg = tt_colormap[fg]; + if (COLORSOURCE_SYMBOLIC == ca.bg.source) bg = tt_colormap[bg]; + if (fg == bg && bg >= 0) { + if (TA_DARK & t_attributes) { + fg = tt_colormap[WHITE]; + bg = tt_colormap[BLACK]; + } else { + fg = tt_colormap[BLACK]; + bg = tt_colormap[WHITE]; + } + } + + /* do we need/can reset to normal */ + if (fg < 0 || bg < 0) { + strcpy(ebuf+l, "0;"); /* normal */ + tt_fg = (fg < 0 ? fg : NOCOLOR); + tt_bg = (bg < 0 ? bg : NOCOLOR); + tt_style = 0; + l += 2; + + } else { + if ((NOCOLOR == tt_fg) || + (!(bg & 0x8) && (tt_bg & 0x8)) || (!(fg & 0x8) && (tt_fg & 0x8)) || + (tt_defaultfg == fg && fg != tt_fg) || (tt_defaultbg == bg && bg != tt_bg)) { + strcpy(ebuf+l, "0;"); /* normal */ + tt_fg = (tt_defaultfg == fg ? fg : NOCOLOR); + tt_bg = (tt_defaultbg == bg ? bg : NOCOLOR); + tt_style = 0; + l += 2; + } + } + + if (tt_style != sf && tt_style) { + term_styleoff(); + } + + /* color selection */ + if (fg != tt_fg) { /* foreground 30 - 37 */ + l += sprintf(ebuf+l, (fg & 8) ? "1;%u" : "%u", 30 + (fg & 7)); + } + + if (bg != tt_bg) { /* background 40 - 47 */ + if (l > 2) { + ebuf[l++] = ';'; + } + l += sprintf(ebuf+l, (bg & 8) ? "5;%u" : "%u", 40 + (bg & 7)); + } + + if (l > 2) { /* flush result */ + ebuf[l++] = 'm'; + ebuf[l++] = 0; + assert(l < (int)sizeof(ebuf)); + ttputpad(ebuf); + } + + if (tt_style != sf) { + term_styleon(sf); /* style changes */ + } + + } else if (tc_Color_Fg == tc_ANSI_Color_Fg) { + /* + * ANSI - 16+8 color mode + */ + if (COLORSOURCE_SYMBOLIC == ca.fg.source) fg = color_map[fg].c16; + if (COLORSOURCE_SYMBOLIC == ca.bg.source) bg = color_map[bg].c16; + if (fg == bg && bg >= 0) { + if (TA_DARK & t_attributes) { + fg = color_map[WHITE].c16; + bg = color_map[BLACK].c16; + } else { + fg = color_map[BLACK].c16; + bg = color_map[WHITE].c16; + } + } + + if (fg < 0 || bg < 0) { + ttputpad(tc_me ? tc_me : "\033[0m"); + tt_fg = (fg < 0 ? fg : NOCOLOR); + tt_bg = (bg < 0 ? bg : NOCOLOR); + tt_style = 0; + } + + if (tt_style != sf && tt_style) { + term_styleoff(); + } + + if (fg != tt_fg) { + ttputpad((fg & 0x8) ? tc_md : tc_se); + ttputctl(tc_Color_Fg, (fg & 7)); + } + + if (bg != tt_bg) { + ttputctl(tc_Color_Bg, (bg & 7)); + } + + if (tt_style != sf) { + term_styleon(sf); /* style changes */ + } + + } else { + /* + * PC - 16+8 color mode + */ + if (COLORSOURCE_SYMBOLIC == ca.fg.source) fg = color_map[fg].c16_pc; + if (COLORSOURCE_SYMBOLIC == ca.bg.source) bg = color_map[bg].c16_pc; + if (fg == bg && bg >= 0) { + if (TA_DARK & t_attributes) { + fg = color_map[WHITE].c16_pc; + bg = color_map[BLACK].c16_pc; + } else { + fg = color_map[BLACK].c16_pc; + bg = color_map[WHITE].c16_pc; + } + } + + if (fg < 0 || bg < 0) { + ttputpad(tc_me ? tc_me : "\033[0m"); + tt_fg = (fg < 0 ? fg : NOCOLOR); + tt_bg = (bg < 0 ? bg : NOCOLOR); + tt_style = 0; + } + + if (tt_style != sf && tt_style) { + term_styleoff(); + } + + if (fg != tt_fg) { + ttputpad((fg & 0x8) ? tc_md : tc_se); + ttputctl(tc_Color_Fg, fg & 7); + } + + if (bg != tt_bg) { + ttputctl(tc_Color_Bg, bg & 7); + } + + if (tt_style != sf) { + term_styleon(sf); /* style changes */ + } + } + + tt_fg = fg; + tt_bg = bg; + } + + ED_TERM(("\n")) +} + + +/* Function: term_styleon + * Enable the states styles. + * + * Parameters: + * ntype - New style bitmap. + * + * Returns: + * nothing. + */ +static void +term_styleon(unsigned nstyle) +{ + if (vtiscolor() && tn_NC > 0) { + return; /* XXX - color/attributes dont mix, should mask */ + } + +#if defined(HAVE_TERMINFO) + if (tc_sa && !vtiscolor()) { + ttputpad(tparm((char *)tc_sa, /* attribute set, mono only */ + /*STANDOUT*/ (nstyle & (COLORSTYLE_STANDOUT|COLORSTYLE_INVERSE)) != 0, + /*UNDERLINE*/ (nstyle & COLORSTYLE_UNDERLINE) != 0, + /*REVERSE*/ (nstyle & COLORSTYLE_REVERSE) != 0, + /*BLINK*/ (nstyle & COLORSTYLE_BLINK) != 0, + /*DIM*/ (nstyle & COLORSTYLE_DIM) != 0, + /*BOLD*/ (nstyle & COLORSTYLE_BOLD) != 0, + /*INVISIBLE*/ 0, + /*PROTECT*/ 0, + /*ALTCHAR*/ (t_gmode ? 1 : 0))); + tt_style |= nstyle; + return; + } +#endif /*HAVE_TERMINFO*/ + +#define ACTIVATE_STYLE(x) \ + ((nstyle & (x)) && 0 == (tt_style & (x))) + + if (ACTIVATE_STYLE(COLORSTYLE_STANDOUT)) { + ttputpad(tc_so); /* standout mode. */ + } else if (ACTIVATE_STYLE(COLORSTYLE_INVERSE)) { + ttputpad(tc_so); + } + + if (ACTIVATE_STYLE(COLORSTYLE_REVERSE)) { + ttputpad(tc_mr ? tc_mr : tc_so); /* reverse */ + } + + if (ACTIVATE_STYLE(COLORSTYLE_UNDERLINE)) { + ttputpad(tc_us); /* underline */ + } + + if (ACTIVATE_STYLE(COLORSTYLE_BOLD)) { + ttputpad(tc_md); /* bold */ + } + + if (ACTIVATE_STYLE(COLORSTYLE_BLINK)) { + ttputpad(tc_mb); /* blink */ + } + + if (ACTIVATE_STYLE(COLORSTYLE_ITALIC)) { + ttputpad(tc_ZH); /* italic */ + } + + tt_style |= nstyle; +} + + +/* Function: term_styleoff + * Disable any current styles. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static void +term_styleoff(void) +{ + if (tt_style && tc_me) { /* simple */ + ttputpad(tc_me); + + } else { /* case-by-case */ + if (tt_style & (COLORSTYLE_STANDOUT|COLORSTYLE_INVERSE|COLORSTYLE_BOLD|COLORSTYLE_BLINK)) { + /* + * end standout mode + */ + if (tc_se == tc_ZH) tt_style &= (unsigned)(~COLORSTYLE_REVERSE); + if (tc_se == tc_ue) tt_style &= (unsigned)(~COLORSTYLE_UNDERLINE); + if (tc_se == tc_ZR) tt_style &= (unsigned)(~COLORSTYLE_ITALIC); + ttputpad(tc_se); /* inverse, bold ... */ + } + + if (tt_style & COLORSTYLE_REVERSE) { + ttputpad(tc_ZX); /* reverse */ + } + + if (tt_style & COLORSTYLE_UNDERLINE) { /* underline */ + ttputpad(tc_ue); + } + + if (tt_style & COLORSTYLE_ITALIC) { /* italic */ + ttputpad(tc_ZR); + } + } + tt_style = 0; +} + + +/* Function: term_colorreset + * Reset the terminal color to the system default. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static void +term_colorreset(void) +{ + ttputpad(tc_me ? tc_me : "\033[0m"); + tt_fg = tt_bg = NOCOLOR; + tt_hue = 0; +} + + +/* Function: putfakech + * Fake character output support callback for term_cost(). + * + * Parameters: + * c - Character value. + * + * Returns: + * Always zero. + */ +static int +putfakech(TPUTS_OUTTYPE c) +{ + (void)c; + ++t_cost; + return 0; +} + + +/* Function: term_cost + * Calculate the cost of displaying the specified string 'str'. + * + * Parameters: + * str - Control sequence. + * + * Returns: + * cost in characters. + */ +static int +term_cost(const char *str) +{ + t_cost = 0; + tputs((char *)str, ttrows(), TPUTS_OUTFUNC putfakech); + return t_cost; +} + + +/* Function: putpadch + * termcap ttputpad() callback. + * + * Parameters: + * ch - Character value. + * + * Returns: + * Always zero, + */ +static int +putpadch(TPUTS_OUTTYPE ch) +{ + if (ch == t_padchar && x_pt.pt_tty_fast > 0) { + return 0; /* consume padding characters */ + } + if (t_count >= sizeof(t_buffer)) { + panic("ttputpad buffer overflow."); + } + t_buffer[ t_count++ ] = (unsigned char)ch; + return 0; +} + + +/* Function: ttputpad + * termcap/terminfo output primitive. + * + * Parameters: + * str - Control sequence. + * + * Returns: + * nothing. + */ +static void +ttputpad(const char *str) +{ + if (str && str[0]) { + if (t_count + strlen(str) >= NOBUF) { + term_flush(); + } + ED_TRACE3(("ttputpad(\"%s\")\n", str)) + tputs((char *)str, 1, TPUTS_OUTFUNC putpadch); + } +} + + +/* Function: ttputctl + * termcap/terminfo print output primitive. + * + * Parameters: + * str - Control sequence. + * p1 - Argument. + * + * Returns: + * nothing. + */ +static void +ttputctl(const char *str, int p1) +{ + if (str && str[0]) { +#if defined(HAVE_TERMINFO) + ttputpad(tparm((char *)str, p1, 0)); +#else + ttputpad(tgoto((char *)str, 0, p1)); +#endif + } +} + + +/* Function: ttputctl2 + * termcap/terminfo print output primitive. + * + * Parameters: + * str - Control sequence. + * p2 - Second parameter. + * p1 - First parameter. + * + * Returns: + * nothing. + */ +static void +ttputctl2(const char *str, int p2, int p1) +{ + if (str && str[0]) { +#if defined(HAVE_TERMINFO) + ttputpad(tparm((char *)str, p1, p2, 0)); +#else + ttputpad(tgoto((char *)str, p2, p1)); +#endif + } +} + + +/* Function: ttprintf + * Non-termcap print output primitive. + * + * Parameters: + * str - Format specification. + * ... - optional argument. + * + * Returns: + * nothing. + */ +static void +ttprintf(const char *str, ...) +{ + va_list ap; + char buf[512]; + + va_start(ap, str); + vsxprintf(buf, sizeof(buf), str, ap); + ttputpad(buf); + va_end(ap); +} + + +/* Function: ttpush + * Push characters into the output buffer. + * + * Parameters: + * cp - Character buffer. + * + * Returns: + * nothing. + */ +void +ttpush(const char *cp) +{ + const int len = strlen(cp); + + if ((t_count + len) > sizeof(t_buffer)) { + panic("ttpush buffer overflow."); + } + memcpy(t_buffer + t_count, cp, len); + t_count += len; +} + + +/* Function: ttputc + * Write character to the display. + * + * Characters are buffered up, to make things a little bit more efficient. + * + * Parameters: + * c - Character value. + * + * Returns: + * nothing. + */ +static void +term_putc(vbyte_t c) +{ + const int rows = ttrows() - 1, cols = ttcols() - 1; + int ttrow = ttatrow(), ttcol = ttatcol(); + int width = 1; + + assert(ttrow <= rows); + assert(ttcol <= cols); + + if (t_count >= (NOBUF - (MCHAR_MAX_LENGTH * 2))) { + term_flush(); + } + + /* + * colorize + */ + term_attr(c & VBYTE_ATTR_MASK); + c &= VBYTE_CHAR_MASK; + if (0 == c) { /* color-change only */ + return; + } + + /* + * UNICODE and special characters + */ + if (c >= 0x80) { + const int isutf8 = vtisutf8(); + + /* + * internal characters + */ + if (c >= CH_MIN && c <= CH_MAX) { + const int unicode = (xf_graph && isutf8 && + (t_acs_locale_breaks || 0 == (DC_ASCIIONLY & x_display_ctrl))); + int uch; + + ED_TRACE3(("graphic(isutf8:%d, char:%d/0x%x)\n", isutf8, c, c)) + if (unicode && (uch = cmap_specunicode(c)) > 0) { + if (CH_PADDING == (c = uch)) { + ED_TRACE3(("ttputc_pad(row:%d, col:%d\n", ttrow, ttcol)) + return; + } + } else { + const char *cp; + + if (NULL != (cp = ttspecchar(c))) { + ED_TRACE3(("ttputc_spec(row:%d, col:%d, char:%d/0x%x, cp:%s)\n",\ + ttrow, ttcol, c, c, cp)) + if (x_pt.pt_tty_graphicsbox) { + term_graphic_enter(); + } + ttpush(cp); + goto complete; + } + ED_TRACE3(("--> no mapping\n")) + } + } + + /* + * width character enabled displays + */ + if (isutf8 && MCHAR_ISUTF8(c)) { /* MCHAR */ + if ((width = ucs_width(c)) >= 0) { + ED_TRACE3(("ttputc_utf8(row:%d, col:%d, char:%d/0x%x, width:%d)\n",\ + ttrow, ttcol, c, c, width)) + term_graphic_exit(); + t_count += charset_utf8_encode(c, (char *)(t_buffer + t_count)); + goto complete; + } + width = 1; /* control */ + } + } + + /* + * others + */ + ED_TRACE3(("ttputc_norm(row:%d, col:%d, char:%d/0x%x/%c)\n",\ + ttrow, ttcol, c, c, (c >= 32 && c < 0x7f ? c : '.'))) + + term_graphic_exit(); + if (ASCIIDEF_ESC == c && x_pt.pt_escape[0]) { + ttpush(x_pt.pt_escape); + goto complete; + + } else if (c >= 0x80) { + if (c >= 0xa0 || 0 == x_pt.pt_character[0]) { + goto hell; + } + + ED_TERM(("ttchar(ch:0x%2x/?, wid:%d, pos:%2d/%2d, cnt:%d)\n",\ + c, width, ttrow, ttcol, t_count)) + t_count += sprintf((char *)(t_buffer + t_count), x_pt.pt_character, (int)c); + goto complete; + } + + if ('~' == c && tf_hz) { /* no hazel support (rare) - remap */ + c = '^'; + } + +hell:; + ED_TERM(("ttchar(ch:0x%2x/%c, attr:0x%2x, wid:%d, pos:%2d/%2d, cnt:%d)\n", \ + c, (c <= 0x79 ? c : ' '), width, ttrow, ttcol, t_count)) + + t_buffer[t_count++] = (unsigned char)(c); + assert(c >= ' '); + + if ('\b' == c) { /* backspace */ + if (ttcol) { + ED_TRACE3(("ttmove(%d,%d->back\n", ttrow, ttcol)) + ttposset(ttrow, ttcol - 1); + } else { + ttposinvalid(); + } + return; + + } else if ('\n' == c) { /* new-line */ + if (ttrow < rows) { + ED_TRACE3(("ttmove(%d,%d->newline\n", ttrow, ttcol)) + ttposset(ttrow + 1, ttcol); + } else { + ttposinvalid(); + } + return; + + } else if ('\r' == c) { /* return */ + ED_TRACE3(("ttmove(%d,%d->return\n", ttrow, ttcol)) + ttposset(ttrow, 0); + return; + + } else if (ASCIIDEF_BEL == c) { /* bell (noisy) */ + ED_TRACE3(("ttmove(%d,%d)->bell\n", ttrow, ttcol)) + return; + } + +complete:; + ttcol += width; + + ED_TRACE3(("ttmove(%d,%d)-", ttrow, ttcol)) + + if (ttcol > cols) { /* cursor wrap */ + /* + * Source: http://www.gnu.org/software/termutils/manual/ + */ + if (tf_xn && (cols >= 80 || ttrow == rows)) { + /* + * undefined/strange eol cursor rules/NL ignore after 80th column + */ + ED_TRACE3(("xn-(-1,-1)\n")) + ttposinvalid(); + return; + + } else if (tf_am) { + /* + * obeys margins + */ + ED_TRACE3(("wrap(%d,%d)", tt_top, tt_bot)) + if (tt_bot >= 0) { + if (++ttrow > tt_bot) { + ttrow = tt_bot; /* scroll region active */ + } + } else if (++ttrow > rows) { + ttrow = rows; /* otherwise physical screen */ + } + ttcol = 0; + + } else { + /* + * nowrap/ignored + */ + ED_TRACE3(("->nowrap", ttrow, ttcol)) + --ttcol; + } + } + + ED_TRACE3(("-(%d,%d)\n", ttrow, ttcol)) + ttposset(ttrow, ttcol); +} + + +/* Function: term_graphic_enter + * Switch terminal into graphics/altnative character set mode. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static __CINLINE void +term_graphic_enter(void) +{ + if (xf_graph) { + if (FALSE == t_gmode) { + const char *cmd = x_pt.pt_graphics_mode; + + if (0 == cmd[0]) { + cmd = tc_acs_start; /* default */ + } + if (cmd[0]) { + ttputpad(cmd); + t_gmode = TRUE; + } + ED_TRACE3(("term_graphic_enter(%d)\n", t_gmode)) + } + } +} + + +/* Function: term_graphic_exit + * Switch terminal out of graphics/alternative character set mode. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static __CINLINE void +term_graphic_exit(void) +{ + if (t_gmode) { + const char *cmd = x_pt.pt_text_mode; + + if (0 == cmd[0]) { + cmd = tc_acs_end; /* default */ + } + if (cmd[0]) { + ttputpad(cmd); + } + t_gmode = FALSE; + ED_TRACE3(("term_graphic_exit()\n")) + } +} + + +/* Function: term_flush + * Flush the tty buffer. + * + * Parameters: + * none. + * + * Returns: + * nothing. + */ +static void +term_flush(void) +{ + if (t_count > sizeof(t_buffer)) { + panic("ttbuffer overflow."); + } + + if (t_count > 0) { + t_charout += t_count; + if (FALSE == x_background) { + if (!xf_compat) { /* TRUE=normal i/o otherwise optimised */ + sys_tty_delay(TTY_OUTFD, 1); + } + ED_TERM(("term_flush(length:%d)\n", t_count)) +#if defined(ED_LEVEL) && (ED_LEVEL >= 1) + if (DB_TERMINAL & x_dflags) { + trace_data(t_buffer, t_count, "\n"); + } +#endif + sys_write(TTY_OUTFD, t_buffer, t_count); + } + t_count = 0; + } +} + + +/* Function: term_sizeget + * Retrieve the display screen. + * + * Parameters: + * nrow - Storage for row number. + * ncol - Number of columns. + * + * Returns: + * void + */ +static void +term_sizeget(int *nrow, int *ncol) +{ + const char *env; +#if defined(TIOCGWINSZ) + struct winsize ws = {0}; + + do { + if ((ioctl(1, TIOCGWINSZ, (char *) &ws) == 0) || + (ioctl(0, TIOCGWINSZ, (char *) &ws) == 0) || + (ioctl(2, TIOCGWINSZ, (char *) &ws) == 0)) { + if (ws.ws_row > 0 && ws.ws_col > 0) { + *nrow = ws.ws_row; + *ncol = ws.ws_col; + trace_ilog("term_size1(%d, %d)\n", *nrow, *ncol); + return; + } + } + } while (errno == EINTR); + +#elif defined(TIOCGSIZE) + struct ttysize ts = {0}; /* SUN */ + + do { + if ((ioctl(1, TIOCGSIZE, (char *) &ts) == 0) || + (ioctl(0, TIOCGSIZE, (char *) &ts) == 0) || + (ioctl(2, TIOCGSIZE, (char *) &ts) == 0)) { + if (ts.ts_lines > 0 && ts.ts_linesncol > 0) { + *nrow = ts.ts_lines; + *ncol = ts.ts_cols; + trace_ilog("term_size2(%d, %d)\n", *nrow, *ncol); + return; + } + } + } while (errno == EINTR); +#endif + +#if defined(_VMS) + { /* UNTESTED/OLD */ + unsigned short chan; + + $DESCRIPTOR(dev_dsc, "SYS$INPUT:"); + if (sys$assign(&dev_dsc, &chan, 0, 0, 0) & 1) { + int status_col, status_row, code; + + code = DVI$_DEVBUFSIZ; + status_col = lib$getdvi(&code, &chan, 0, ncol, 0, 0); + code = DVI$_TT_PAGE; + status_row = lib$getdvi(&code, &chan, 0, nrow, 0, 0); + sys$dassgn(chan); + if ((status_col & 1) && (status_row & 1)) { + return; + } + } + } +#endif + + if (tn_li > 0 && tn_co > 0) { /* terminal */ + *nrow = tn_li; + *ncol = tn_co; + } else { + *nrow = 24; + *ncol = 80; + } + /* old school */ + if (NULL != (env = ggetenv("LINES")) && *env) { + *nrow = atoi(env); + tf_am = FALSE; + } + + if (NULL != (env = ggetenv("COLUMNS")) && *env) { + *ncol = atoi(env); + tf_am = FALSE; + } +} + + +#if (NOTUSED) +/* Function: term_sizeset + * Attempt to set the current window size. + * + * Parameters: + * row - Screen rows. + * col - Columns. + * + * Returns: + * On success 0, otherwise -1. + */ +static int +term_sizeset(int rows, int cols) +{ + if (x_pt.pt_winsetsize[0]) { + ttprintf(x_pt.pt_winsetsize, rows, cols); + return 0; + } + return -1; +} +#endif + + +/* Function: ega_switch + * EGA/VGA console mode switch support + * + * Parameters: + * flag - EGA mode. + * + * Returns: + * nothing. + */ +static void +ega_switch(int flag) +{ + const int orows = ttrows(); + + if (tty_egaflag == flag) { + return; + } + + switch (flag) { +#if defined(SW_VGA_C80x60) + case 60: /* 60 line mode */ + ioctl(1, SW_VGA_C80x60, 1); + ttrows() = 60; + break; +#endif + +#if defined(SW_VGA_C80x50) + case 50: /* 50 line mode */ + ioctl(1, SW_VGA_C80x50, 1); + ttrows() = 50; + break; +#endif + +#if defined(SW_ENH_C80x43) + case 43: /* 43 line mode */ + if (ioctl(1, SW_ENH_C80x43, 1) == 0) { + ttrows() = 43; + } + break; +#endif + +#if defined(SW_VGA_C80x25) || defined(SW_ENH_C80x25) + case 25: /* 25 line mode */ +#if defined(SW_VGA_C80x25) + ioctl(1, SW_VGA_C80x25, 1); +#endif +#if defined(SW_ENH_C80x25) + ioctl(1, SW_ENH_C80x25, 1); +#endif + ttrows() = 25; + break +#endif + + default: + acc_assign_int(-1); + return; + } + + tty_egaflag = xf_ega43 = flag; + vtwinch(ttcols(), orows); + term_colorreset(); +} + + +/* Function: do_ega + * ega primitive. + * + * Parameters: + * none. + * + * Returns: + * nothing. + * + *<> + Macro: ega - Terminal line display. + + int + ega(int lines) + + Macro Description: + The 'ega()' primitive attempts to configure the console size + to the specified number of 'lines' with an implied width of + 80 columns on supporting terminals. + + Possible screen dimensions include. + + o 60 x 80 + o 50 x 80 + o 43 x 80 + o 25 x 80 + + Macro Parameters: + lines - Optional integer specifing the required number of + console lines. Under WIN32 if -1 the console size shall toggled + bewteen minimized and maximised. If omitted, then only the + current state is returned. + + Notes!: + When running within a windows console, before Windows 7 one could press + to run the application in full screen. As of Windows 7 this + functionality is no longer available resulting in the following. + +> This system does not support full screen mode + + The ega() primitive can be used to emulate this functionality, using + the special -1 flag, which shall toggle between a minimized or maximised + sized console. + +> ega(-1) + + Macro Returns: + The 'ega()' primitive returns the previous status, otherwise -1 upon + an error. + + Macro Portability: + A Grief extension. + + Macro See Also: + set_term_feature + */ +void +do_ega(void) /* int (int mode) */ +{ + acc_assign_int((accint_t) xf_ega43); + if (isa_integer(1)) { /* (mode < 80 sets rows), otherwise (mode >= 80 sets columns). */ + const int flag = get_xinteger(1, 0); + if (flag >= 0) { + ega_switch(flag); + } + } +} + + +/* Function: do_copy_screen + * copy_screen primitive, defunct. + * + * Parameters: + * none. + * + * Returns: + * nothing. + * + *<> + Macro: copy_screen - Copy the current screen. + + void + copy_screen() + + Macro Description: + The 'copy_screen()' primitive exports an image of the + current editor windows to the current buffer. + + Macro Parameters: + none + + Macro Returns: + nothing + + Macro Portability: + A Grief extension; this primitive is subject for removal, + and has been removed from recent CrispEdit(tm) releases. + + Macro See Also: + transfer + */ +void +do_copy_screen(void) /* void () */ +{ +} + +#endif /*!USE_VIO_BUFFER && !DJGPP */ diff --git a/gr/ttyvio.c b/gr/ttyvio.c index a3500d5a..2b416ddd 100644 --- a/gr/ttyvio.c +++ b/gr/ttyvio.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_ttyvio_c,"$Id: ttyvio.c,v 1.68 2020/05/03 18:24:42 cvsuser Exp $") +__CIDENT_RCSID(gr_ttyvio_c,"$Id: ttyvio.c,v 1.72 2021/07/05 15:01:27 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: ttyvio.c,v 1.68 2020/05/03 18:24:42 cvsuser Exp $ +/* $Id: ttyvio.c,v 1.72 2021/07/05 15:01:27 cvsuser Exp $ * TTY VIO implementation. * * @@ -25,6 +25,8 @@ __CIDENT_RCSID(gr_ttyvio_c,"$Id: ttyvio.c,v 1.68 2020/05/03 18:24:42 cvsuser Exp #include #include /* gputenvv(), ggetenv() */ #include +#include "../libchartable/libchartable.h" +#include "../libwidechar/widechar.h" #if defined(WIN32) #ifndef _WIN32_WINNT @@ -403,8 +405,11 @@ term_feature(int ident, scrprofile_t *profile) break; case TF_ENCODING: + break; case TF_UNICODE_VERSION: - case TF_UNICODE_WIDTH: + if (x_pt.pt_unicode_version[0]) { + ucs_width_set(x_pt.pt_unicode_version); + } break; } } @@ -806,8 +811,10 @@ term_font(int setlen, char *font) static void term_print(int row, int col, int len, const VCELL_t *vvp) { + static VIOCELL null = { 0 }; + if (len > 0) { - const int isuc = (DC_CMAPFRAME & x_display_ctrl) || vtisutf8() || vtisunicode(); + const int isuc = (DC_CMAPFRAME & x_display_ctrl) || vtisunicode() || vtisutf8(); VIOCELL *p = currScreen + (row * ttcols()) + col; vbyte_t cattr = VBYTE_ATTR_GET(vvp->primary); @@ -817,6 +824,12 @@ term_print(int row, int col, int len, const VCELL_t *vvp) const vbyte_t attr = VBYTE_ATTR_GET(vvp->primary); vbyte_t c = VBYTE_CHAR_GET(vvp->primary); + if (CH_PADDING == c) { /* wide character padding */ + *p++ = null; + ++vvp; + continue; + } + if (cattr != attr) { /* attribute change */ cattr = attr, term_attribute(cattr); } @@ -844,7 +857,7 @@ term_print(int row, int col, int len, const VCELL_t *vvp) /* Function: term_putc - * Write character to the display. + * Write character to the display. Generally unsed, as term_print() has priority. * * Parameters: * c - Character value. @@ -857,6 +870,10 @@ term_putc(vbyte_t c) { int ttrow = ttatrow(), ttcol = ttatcol(); + if (CH_PADDING == c) { /* wide character padding */ + return; + } + term_attribute(VBYTE_ATTR_GET(c)); c = VBYTE_CHAR_GET(c); @@ -864,7 +881,7 @@ term_putc(vbyte_t c) * special characters */ if (c >= CH_MIN && c <= CH_MAX) { - const int isuc = (DC_CMAPFRAME & x_display_ctrl) || vtisutf8() || vtisunicode(); + const int isuc = (DC_CMAPFRAME & x_display_ctrl) || vtisunicode() || vtisutf8(); int unicode; if (isuc && (unicode = cmap_specunicode(c)) > 0) { diff --git a/gr/ttywin32.c b/gr/ttywin32.c index 10eb3985..661369c6 100644 --- a/gr/ttywin32.c +++ b/gr/ttywin32.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_ttywin32_c,"$Id: ttywin32.c,v 1.50 2020/05/03 18:57:00 cvsuser Exp $") +__CIDENT_RCSID(gr_ttywin32_c,"$Id: ttywin32.c,v 1.52 2021/07/11 08:24:15 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: ttywin32.c,v 1.50 2020/05/03 18:57:00 cvsuser Exp $ +/* $Id: ttywin32.c,v 1.52 2021/07/11 08:24:15 cvsuser Exp $ * WIN32 VIO driver. * see: http://www.edm2.com/index.php/Category:Vio * @@ -49,8 +49,6 @@ __CIDENT_RCSID(gr_ttywin32_c,"$Id: ttywin32.c,v 1.50 2020/05/03 18:57:00 cvsuser #define TERMEMU_VIO_STATIC /* private interface */ #include "termemu_vio.c" -#include "unicode_cp437.h" - static void VioInitialise(void); static void VioEncoding(void); @@ -976,4 +974,4 @@ DosBeep(int freq, int duration) #endif // USE_VIO_BUFFER #endif // WIN32 -/*end*/ \ No newline at end of file +/*end*/ diff --git a/gr/ttyx11kb.h b/gr/ttyx11kb.h index 7ac1aada..17a64bdb 100644 --- a/gr/ttyx11kb.h +++ b/gr/ttyx11kb.h @@ -1,11 +1,11 @@ #ifndef GR_TTYX11KB_H_INCLUDED #define GR_TTYX11KB_H_INCLUDED #include -__CIDENT_RCSID(gr_ttyx11kb_h,"$Id: ttyx11kb.h,v 1.4 2014/10/22 02:33:24 ayoung Exp $") +__CIDENT_RCSID(gr_ttyx11kb_h,"$Id: ttyx11kb.h,v 1.5 2021/07/18 23:03:19 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: ttyx11kb.h,v 1.4 2014/10/22 02:33:24 ayoung Exp $ +/* $Id: ttyx11kb.h,v 1.5 2021/07/18 23:03:19 cvsuser Exp $ * X11 keyboard translation tables. * * These tables direct the translation of X keyboard events into our internal @@ -90,7 +90,7 @@ static const KeyboardXlat plainXlatSeed[] = { { XK_Find, KEY_SEARCH }, { XK_Cancel, KEY_CANCEL }, { XK_Help, KEY_HELP }, - { XK_Break, KEY_VOID }, + { XK_Break, KEY_BREAK }, { XK_Mode_switch, KEY_VOID }, { XK_script_switch, KEY_VOID }, { XK_Num_Lock, KEY_VOID }, diff --git a/gr/undo.c b/gr/undo.c index a3229065..f0fa0a16 100644 --- a/gr/undo.c +++ b/gr/undo.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_undo_c,"$Id: undo.c,v 1.49 2021/04/14 14:09:54 cvsuser Exp $") +__CIDENT_RCSID(gr_undo_c,"$Id: undo.c,v 1.50 2021/06/10 06:13:02 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: undo.c,v 1.49 2021/04/14 14:09:54 cvsuser Exp $ +/* $Id: undo.c,v 1.50 2021/06/10 06:13:02 cvsuser Exp $ * undo and redo facilities. * * @@ -215,7 +215,7 @@ undo_close(void) if (u_fp) { fclose(u_fp); if (u_fname[0]) { - fileio_unlink(u_fname); + sys_unlink(u_fname); } u_fname[0] = 0; u_fp = NULL; @@ -289,7 +289,7 @@ u_insert(FSIZE_t length, int dot) undo.u_length = n; uwrite_op(&undo); - lp = vm_lock_line(cline); + lp = vm_lock_line2(cline); while (n > 0 && cline <= numlines) { /* NEWLINE */ FSIZE_t x, w; diff --git a/gr/version.c b/gr/version.c index f75b5fd5..9a18bdbd 100644 --- a/gr/version.c +++ b/gr/version.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_version_c,"$Id: version.c,v 1.27 2020/05/03 21:41:54 cvsuser Exp $") +__CIDENT_RCSID(gr_version_c,"$Id: version.c,v 1.28 2021/04/20 13:59:56 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: version.c,v 1.27 2020/05/03 21:41:54 cvsuser Exp $ +/* $Id: version.c,v 1.28 2021/04/20 13:59:56 cvsuser Exp $ * Version strings. * * @@ -26,6 +26,6 @@ const int x_edit_version = GR_VERSION_3; const char * x_version = GR_VERSION; const char * x_compiled = __DATE__ " " __TIME__; -const char * x_copyright = "(C) 1998-2020 A. Young, 1991 P. Fox"; +const char * x_copyright = "(C) 1998-2021 A. Young, 1991 P. Fox"; /*end*/ diff --git a/gr/widgets_tty.c b/gr/widgets_tty.c index 3060ba81..c1abfa28 100644 --- a/gr/widgets_tty.c +++ b/gr/widgets_tty.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_widgets_tty_c,"$Id: widgets_tty.c,v 1.35 2020/04/19 23:55:19 cvsuser Exp $") +__CIDENT_RCSID(gr_widgets_tty_c,"$Id: widgets_tty.c,v 1.37 2021/08/01 14:42:51 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: widgets_tty.c,v 1.35 2020/04/19 23:55:19 cvsuser Exp $ +/* $Id: widgets_tty.c,v 1.37 2021/08/01 14:42:51 cvsuser Exp $ * Dialog widgets, tty interface. * * @@ -32,7 +32,9 @@ __CIDENT_RCSID(gr_widgets_tty_c,"$Id: widgets_tty.c,v 1.35 2020/04/19 23:55:19 c #include "kill.h" #include "line.h" #include "lisp.h" +#include "mchar.h" #include "main.h" + #include "tty.h" #include "widgets.h" #include "widgets_tty.h" @@ -285,15 +287,16 @@ tty_str(LINEATTR attr, const char *str) * ch - * * Returns: - * nothing. + * int - Character display width. */ -static void +static int tty_char(LINEATTR attr, int ch) { const LINEATTR oattr = *cur_attr; *cur_attr = attr; lwritec(ch); *cur_attr = oattr; + return Wcwidth(ch); } @@ -302,7 +305,8 @@ tty_isunicode(int special) { __CUNUSED(special) #if defined(WIN32) || defined(__CYGWIN__) - if (special) return FALSE; /* generally aren't available */ + if (special) /* FIXME; generally aren't available. */ + return FALSE; #endif return (DC_UNICODE == ((DC_UNICODE|DC_ASCIIONLY) & x_display_ctrl)); } @@ -2926,6 +2930,7 @@ lb_paint(Listbox_t *lb, WIDGET_t *w, int repaint) } } + move(w, 1, frame + y); /* left align */ ++y, ++idx; } } @@ -3033,9 +3038,17 @@ typedef struct { int ef_length; /* buffer length, in bytes */ const char * ef_placeholder; /* placeholder text, if any */ - char ef_buffer[ MAX_CMDLINE ]; + +#define EWIDECHAR +#if defined(EWIDECHAR) +#define ECHAR WChar_t + char ef_xbuffer[ MAX_CMDLINE ]; +#else +#define ECHAR char +#endif + ECHAR ef_buffer[ MAX_CMDLINE ]; + ECHAR ef_restore[ MAX_CMDLINE ]; char ef_complete[ MAX_CMDLINE ]; - char ef_restore[ MAX_CMDLINE ]; } Editfield_t; static void ef_init(Editfield_t *ef, uint32_t flags); @@ -3045,6 +3058,8 @@ static void ef_destroy(Editfield_t *ef); static void ef_save(Editfield_t *ef); static void ef_restore(Editfield_t *ef); static void ef_set(Editfield_t *ef, const char *value); +static const char * ef_get(Editfield_t *ef); +static int ef_empty(const Editfield_t *ef); static int ef_assign(Editfield_t *ef, const WIDGETDATA_t *data); static int ef_value_set(Editfield_t *ef, const WIDGETARG_t p1, const WIDGETDATA_t *data); static int ef_value_get(Editfield_t *ef, const WIDGETARG_t p1, WIDGETDATA_t *data); @@ -3067,7 +3082,7 @@ ef_init(Editfield_t *ef, uint32_t flags) ef->ef_changed = 0; ef->ef_format = EDITFORMAT_TEXT; ef->ef_seqno = 0; - ef->ef_length = sizeof(ef->ef_buffer) - 1; + ef->ef_length = _countof(ef->ef_buffer)-1; ef->ef_editable = TRUE; ef->ef_visibility = TRUE; ef->ef_validate = FALSE; @@ -3079,6 +3094,9 @@ ef_init(Editfield_t *ef, uint32_t flags) ef->ef_filters = 0; ef->ef_placeholder = NULL; ef->ef_buffer[0] = 0; +#if defined(EWIDECHAR) + ef->ef_xbuffer[0] = 0; +#endif ef->ef_complete[0] = 0; ef->ef_restore[0] = 0; ef->ef_restoreseqno = 0; @@ -3129,17 +3147,22 @@ ef_destroy(Editfield_t *ef) static void ef_save(Editfield_t *ef) { - const int diff = strcmp(ef->ef_buffer, ef->ef_restore); + const ECHAR *buffer = ef->ef_buffer; +#if defined(EWIDECHAR) + const int diff = Wcscmp(buffer, ef->ef_restore); + Wcscpy(ef->ef_restore, buffer); +#else + const int diff = strcmp(buffer, ef->ef_restore); + strcpy(ef->ef_restore, buffer); +#endif - strcpy(ef->ef_restore, (const char *)ef->ef_buffer); ef->ef_restoreseqno = ef->ef_seqno; - if (diff) ++ef->ef_seqno; ef->ef_quote = FALSE; ef->ef_cursor = 0; ef->ef_loffset = 0; ef->ef_marked = - (((EF_FISAUTOCOMPLETE & ef->ef_flags) || 1 == ef->ef_seqno) && ef->ef_buffer[0] ? TRUE : FALSE); + (((EF_FISAUTOCOMPLETE & ef->ef_flags) || 1 == ef->ef_seqno) && buffer[0] ? TRUE : FALSE); ef->ef_append = FALSE; ef->ef_changed = 0; ef->ef_complete[0] = 0; @@ -3149,7 +3172,8 @@ ef_save(Editfield_t *ef) static void ef_restore(Editfield_t *ef) { - strcpy(ef->ef_buffer, (const char *)ef->ef_restore); + assert(sizeof(ef->ef_buffer) == sizeof(ef->ef_restore)); + memcpy(ef->ef_buffer, (const void *)ef->ef_restore, sizeof(ef->ef_buffer)); ef->ef_seqno = ef->ef_restoreseqno; ef->ef_quote = FALSE; ef->ef_changed = 0; @@ -3164,12 +3188,38 @@ ef_set(Editfield_t *ef, const char *value) ef->ef_quote = FALSE; ef->ef_marked = FALSE; ef->ef_append = FALSE; +#if defined(EWIDECHAR) + Wcsfromutf8((value ? value : ""), ef->ef_buffer, _countof(ef->ef_buffer)); +#else strxcpy(ef->ef_buffer, (value ? value : ""), sizeof(ef->ef_buffer)); +#endif ef->ef_complete[0] = 0; ++ef->ef_changed; } +static const char * +ef_get(Editfield_t *ef) +{ +#if defined(EWIDECHAR) + ef->ef_xbuffer[0] = 0; + if (ef->ef_buffer[0]) { + Wcstoutf8(ef->ef_buffer, ef->ef_xbuffer, sizeof(ef->ef_xbuffer)); + } + return ef->ef_xbuffer; +#else + return ef->ef_buffer; +#endif +} + + +static int +ef_empty(const Editfield_t *ef) +{ + return (*ef->ef_buffer == 0); +} + + static int ef_assign(Editfield_t *ef, const WIDGETDATA_t *data) { @@ -3266,7 +3316,7 @@ ef_value_get(Editfield_t *ef, const WIDGETARG_t p1, WIDGETDATA_t *data) switch (attr) { case DLGA_VALUE: - data->d_u.svalue = ef->ef_buffer; + data->d_u.svalue = ef_get(ef); data->d_type = D_STR; return TRUE; case DLGA_EDEDITABLE: @@ -3376,13 +3426,18 @@ ef_value_get(Editfield_t *ef, const WIDGETARG_t p1, WIDGETDATA_t *data) static int ef_key(Editfield_t *ef, WIDGET_t *w, int key, int (*validate)(Editfield_t *, WIDGET_t *w, void *), void *arg) { - char previous_buffer[ MAX_CMDLINE ]; - int oipos = ef->ef_cursor, ipos = oipos; - char *buf = ef->ef_buffer; - int repaint = FALSE; - int edit = FALSE; - + ECHAR previous_buffer[ MAX_CMDLINE ]; + ECHAR *buf = ef->ef_buffer; + int oipos = ef->ef_cursor, ipos = oipos; + int repaint = FALSE; + int edit = FALSE; + +#if defined(EWIDECHAR) + Wcsncpy(previous_buffer, (const WChar_t *)buf, _countof(previous_buffer)); +#else strxcpy(previous_buffer, (const char *)buf, sizeof(previous_buffer)); +#endif + if (ef->ef_quote) { ef->ef_quote = FALSE; goto quote; @@ -3431,22 +3486,38 @@ ef_key(Editfield_t *ef, WIDGET_t *w, int key, int (*validate)(Editfield_t *, WID if (ef->ef_marked) { repaint = TRUE, ef->ef_marked = 0; } +#if defined(EWIDECHAR) + ipos = (int)Wcslen(buf); +#else ipos = (int)strlen(buf); +#endif break; case KEY_WLEFT: /* Cursor word left/decrement */ case KEY_WLEFT2: { double val = 0; if (EF_FISNUMERIC & ef->ef_flags) { -decrement:; if (*ef->ef_buffer) { - val = atof(ef->ef_buffer); +decrement:; if (*buf) { +#if defined(EWIDECHAR) + val = Wcstod(buf, NULL); +#else + val = atof(buf); +#endif } val -= ef->ef_increment; +#if defined(EWIDECHAR) + if (ef->ef_digits <= 0) { + ipos = Wsnprintf(buf, _countof(ef->ef_buffer), "%d", (int) val); + } else { + ipos = Wsnprintf(buf, _countof(ef->ef_buffer), "%*f", ef->ef_digits, val); + } +#else if (ef->ef_digits <= 0) { - ipos = sprintf(ef->ef_buffer, "%d", (int) val); + ipos = sprintf(buf, "%d", (int) val); } else { - ipos = sprintf(ef->ef_buffer, "%*f", ef->ef_digits, val); + ipos = sprintf(buf, "%*f", ef->ef_digits, val); } +#endif edit = TRUE; } else { while (isspace(buf[ipos]) && ipos > 0) { @@ -3463,15 +3534,27 @@ decrement:; if (*ef->ef_buffer) { case KEY_WRIGHT2: { double val = 0; if (EF_FISNUMERIC & ef->ef_flags) { -increment:; if (*ef->ef_buffer) { - val = atof(ef->ef_buffer); +increment:; if (*buf) { +#if defined(EWIDECHAR) + val = Wcstod(buf, NULL); +#else + val = atof(buf); +#endif } val += ef->ef_increment; +#if defined(EWIDECHAR) + if (ef->ef_digits <= 0) { + ipos = Wsnprintf(buf, _countof(ef->ef_buffer), "%d", (int) val); + } else { + ipos = Wsnprintf(buf, _countof(ef->ef_buffer), "%*f", ef->ef_digits, val); + } +#else if (ef->ef_digits <= 0) { - ipos = sprintf(ef->ef_buffer, "%d", (int) val); + ipos = sprintf(buf, "%d", (int) val); } else { - ipos = sprintf(ef->ef_buffer, "%*f", ef->ef_digits, val); + ipos = sprintf(buf, "%*f", ef->ef_digits, val); } +#endif edit = TRUE; } else { while (isspace(buf[ipos]) && buf[ipos]) { @@ -3490,24 +3573,34 @@ increment:; if (*ef->ef_buffer) { repaint = TRUE, ef->ef_marked = 0; } if (ipos > 0) { - --ipos, strcpy(buf + ipos, buf + ipos + 1); + --ipos; +#if defined(EWIDECHAR) + Wcscpy(buf + ipos, buf + ipos + 1); +#else + strcpy(buf + ipos, buf + ipos + 1); +#endif edit = TRUE; } } break; case KEY_DEL: /* delete character under the cursor */ - case 0x7F: + case KEY_DELETE: case CTRL_D: if (ef->ef_editable) { if (ef->ef_marked) { - edit = TRUE, ef->ef_marked = 0; + ef->ef_marked = 0; memset(ef->ef_complete, 0, sizeof(ef->ef_complete)); - memset(buf, 0, ef->ef_length); + memset(buf, 0, sizeof(ef->ef_buffer)); + edit = TRUE; ipos = 0; } else if (buf[ipos]) { +#if defined(EWIDECHAR) + Wcscpy(buf + ipos, buf + ipos + 1); +#else strcpy(buf + ipos, buf + ipos + 1); +#endif edit = TRUE; } } @@ -3525,9 +3618,9 @@ increment:; if (*ef->ef_buffer) { case CTRL_X: case CTRL_U: if (ef->ef_editable) { - ipos = 0; buf[0] = '\0'; edit = TRUE; + ipos = 0; } break; @@ -3545,7 +3638,11 @@ increment:; if (*ef->ef_buffer) { } else { while (ipos < ef->ef_length && scount--) { if (ef->ef_insmode) { +#if defined(EWIDECHAR) + Wmemmove(buf + ipos + 1, (const WChar_t *)(buf + ipos), (size_t)ef->ef_length - ipos); +#else memmove(buf + ipos + 1, (const char *)(buf + ipos), (size_t)ef->ef_length - ipos); +#endif } if (0 == buf[ ipos ]) { buf[ ipos+1 ] = '\0'; @@ -3595,7 +3692,11 @@ increment:; if (*ef->ef_buffer) { goto decrement; } else if ('.' == key) { - if (ef->ef_digits <= 0 || strchr(ef->ef_buffer, '.')) { +#if defined(EWIDECHAR) + if (ef->ef_digits <= 0 || Wcschr(buf, '.')) { +#else + if (ef->ef_digits <= 0 || strchr(buf, '.')) { +#endif return FALSE; } @@ -3609,8 +3710,13 @@ increment:; if (*ef->ef_buffer) { } } -quote:; if (ef->ef_marked) { /* zap marked text */ + quote:; + if (ef->ef_marked) { /* zap marked text */ +#if defined(EWIDECHAR) + Wmemset(buf, 0, ef->ef_length); +#else memset(buf, 0, ef->ef_length); +#endif ef->ef_marked = 0; edit = TRUE; ipos = 0; @@ -3620,7 +3726,11 @@ quote:; if (ef->ef_marked) { /* zap marked text */ ttbeep(); /* end-of-buffer */ } else { if (ef->ef_insmode) { /* insert mode */ +#if defined(EWIDECHAR) + Wmemmove(buf + ipos + 1, (const WChar_t *)(buf + ipos), (size_t)ef->ef_length - ipos); +#else memmove(buf + ipos + 1, (const char *)(buf + ipos), (size_t)ef->ef_length - ipos); +#endif } if (0 == buf[ ipos ]) { /* make sure buffer is terminated */ buf[ ipos+1 ] = '\0'; @@ -3636,13 +3746,22 @@ quote:; if (ef->ef_marked) { /* zap marked text */ ++ef->ef_changed; if (validate) { if (! validate(ef, w, arg)) { /* reject, restore previous value */ - strxcpy(ef->ef_buffer, (const char *)previous_buffer, sizeof(ef->ef_buffer)); +#if defined(EWIDECHAR) + Wcsncpy(buf, (const WChar_t *)previous_buffer, _countof(ef->ef_buffer)); +#else + strxcpy(buf, (const char *)previous_buffer, sizeof(ef->ef_buffer)); +#endif --ef->ef_changed; ef->ef_cursor = oipos; edit = FALSE; } else { if (ef->ef_complete[0]) { /* auto-complete, trim cursor */ - if ((ipos = (int)strlen(ef->ef_buffer)) < ef->ef_cursor) { +#if defined(EWIDECHAR) + ipos = (int)Wcslen(buf); +#else + ipos = (int)strlen(buf); +#endif + if (ipos < ef->ef_cursor) { ef->ef_cursor = ipos; } } @@ -3672,12 +3791,16 @@ ef_paint(Editfield_t *ef, WIDGET_t *w) const int32_t cols = (EF_FISCOMBO & ef->ef_flags ? (w->w_cols > 3 ? w->w_cols - 3 : 1) : (EF_FISNUMERIC & ef->ef_flags ? (w->w_cols > 4 ? w->w_cols - 4 : 1) : w->w_cols)); - const char *complete = (ef->ef_append ? ef->ef_complete : ""); - const char *buffer = (!HasFocus(w) && ef->ef_placeholder && !*ef->ef_buffer && !*complete ? - ef->ef_placeholder : ef->ef_buffer); - int32_t len2 = (int32_t)strlen(complete); - int32_t len = (int32_t)strlen(buffer); + const char *complete = (ef->ef_append ? ef->ef_complete : ""); + const int placeholder = (!HasFocus(w) && ef->ef_placeholder && ef_empty(ef) && !*complete ? 1 : 0); + + int32_t len2 = (int32_t)strlen(complete); +#if defined(EWIDECHAR) + int32_t len = (int32_t)(placeholder ? strlen(ef->ef_placeholder) : Wcslen(ef->ef_buffer)); +#else + int32_t len = (int32_t)(placeholder ? strlen(ef->ef_placeholder) : strlen(ef->ef_buffer)); +#endif int32_t offset = ef->ef_loffset; int32_t cursor = 0; @@ -3692,25 +3815,33 @@ ef_paint(Editfield_t *ef, WIDGET_t *w) len = cols; } - buffer += offset; - if (ef->ef_visibility || /* normal/visible mode/placeholder-text */ - (buffer == ef->ef_placeholder)) { + if (placeholder) { /* placeholder text */ + const char *buffer = ef->ef_placeholder + offset; + tty_move(w, 0, 0); tty_strn(attr, buffer, len); cursor += len; + } else if (ef->ef_visibility) { /* normal/visible mode text */ + const ECHAR *buffer = ef->ef_buffer + offset; + + while (len-- > 0) { + tty_move(w, cursor, 0); + cursor += tty_char(attr, *buffer++); + } + } else { /* invisible, only show previous character when focused */ const int vcharacter = ef->ef_invisiblech; if (vcharacter > 0) { /* 0=hidden text (ie. no user feeback) */ + const ECHAR *buffer = ef->ef_buffer + offset; const int vpos = (HasFocus(w) && ef->ef_changed ? (ef->ef_cursor - offset) - 1 : -1); while (len-- > 0) { tty_move(w, cursor, 0); /* only if last changed character */ - tty_char(attr, 0 == len && vpos == cursor ? *buffer : vcharacter); + cursor += tty_char(attr, 0 == len && vpos == cursor ? *buffer : vcharacter); ++buffer; - ++cursor; } } } @@ -4282,7 +4413,7 @@ combofield_open(WCombofield_t *cf) Listbox_t *lb = &cf->cf_listimpl; int32_t idx = -1; /* prime active and cursor */ - idx = lb_active(lb, lb_item_match(lb, NULL, ef->ef_buffer, &idx) ? idx : -1); + idx = lb_active(lb, lb_item_match(lb, NULL, ef_get(ef), &idx) ? idx : -1); lb_cursor(lb, w, idx); ef_save(ef); /* open and save edit buffer */ @@ -4394,7 +4525,7 @@ combofield_autocomplete(Editfield_t *ef, WIDGET_t *w, void *arg) { WCombofield_t *cf = (WCombofield_t *)arg; Listbox_t *lb = &cf->cf_listimpl; - char *buffer = ef->ef_buffer; + const char *buffer = ef_get(ef); char *complete = ef->ef_complete; const ListboxItem_t *n = NULL; int32_t idx = 0; @@ -4407,14 +4538,18 @@ combofield_autocomplete(Editfield_t *ef, WIDGET_t *w, void *arg) n = lb_item_find(lb, "", 0, &idx); /* element index */ } else if ((LB_FINDEXMODE & lb->lb_flags) && isdigit(*buffer)) { + char t_buffer[32]; int value; if ((value = strtol(buffer, NULL, 10)) < 1 || value > (int)lb_item_count(lb) || NULL == (n = lb_item_get(lb, idx = (uint32_t)(value - 1)))) { return FALSE; } + lb_filter(lb, 0, NULL); - sxprintf(buffer, sizeof(ef->ef_buffer), "%d", value); + sxprintf(t_buffer, sizeof(t_buffer), "%d", value); + ef_set(ef, t_buffer); + strxcpy(complete + 1, n->li_display, sizeof(ef->ef_complete) - 1); complete[0] = '-'; @@ -4488,15 +4623,15 @@ combofield_listbox(WCombofield_t *cf, const int state) switch (state) { // case CB_POPUPSTATE_HIDDEN: -// switch (current_state) { -// case CB_POPUPSTATE_FOCUS: -// case CB_POPUPSTATE_VISIBLE: -// if (dialog_tty_popup_focus(w->w_root, -1)) { -// cf->cf_popupstate = CB_POPUPSTATE_HIDDEN; -// } -// break; -// } -// break; +// switch (current_state) { +// case CB_POPUPSTATE_FOCUS: +// case CB_POPUPSTATE_VISIBLE: +// if (dialog_tty_popup_focus(w->w_root, -1)) { +// cf->cf_popupstate = CB_POPUPSTATE_HIDDEN; +// } +// break; +// } +// break; case CB_POPUPSTATE_VISIBLE: switch (current_state) { @@ -4546,13 +4681,13 @@ combofield_value_get(WCombofield_t *cf, int iscomplete) { Editfield_t *ef = &cf->cf_editimpl; Listbox_t *lb = &cf->cf_listimpl; - const char *buffer = ef->ef_buffer; + const char *buffer = ef_get(ef); char *outbuffer = cf->cf_buffer; const ListboxItem_t *n; if (! iscomplete) { if (! cf->cf_open) { /* current value */ - strxcpy(outbuffer, (const char *)ef->ef_buffer, sizeof(ef->ef_buffer)); + strxcpy(outbuffer, buffer, sizeof(cf->cf_buffer)); return outbuffer; } } @@ -4578,7 +4713,11 @@ combofield_value_get(WCombofield_t *cf, int iscomplete) /*FALLTHRU*/ default: +#if defined(EWIDECHAR) + Wcstoutf8(ef->ef_restore, outbuffer, sizeof(cf->cf_buffer)); +#else strxcpy(outbuffer, ef->ef_restore, sizeof(cf->cf_buffer)); +#endif if (iscomplete) { ef_restore(ef); iscomplete = FALSE; @@ -4590,7 +4729,7 @@ combofield_value_get(WCombofield_t *cf, int iscomplete) } if (iscomplete) { - strxcpy(ef->ef_buffer, outbuffer, sizeof(ef->ef_buffer)); + ef_set(ef, outbuffer); } return outbuffer; } @@ -4894,4 +5033,6 @@ combofield_callback(WCombofield_t *cf, WIDGETMSG_t msg, WIDGETARG_t p1, WIDGETAR } return FALSE; } + /*end*/ + diff --git a/gr/window.c b/gr/window.c index 5a100e03..6da5261d 100644 --- a/gr/window.c +++ b/gr/window.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_window_c,"$Id: window.c,v 1.41 2020/04/21 00:01:57 cvsuser Exp $") +__CIDENT_RCSID(gr_window_c,"$Id: window.c,v 1.45 2021/10/17 03:54:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: window.c,v 1.41 2020/04/21 00:01:57 cvsuser Exp $ +/* $Id: window.c,v 1.45 2021/10/17 03:54:22 cvsuser Exp $ * Window basics. * * @@ -23,6 +23,8 @@ __CIDENT_RCSID(gr_window_c,"$Id: window.c,v 1.41 2020/04/21 00:01:57 cvsuser Exp #endif #include +#include "../libchartable/libchartable.h" +#include "../libwidechar/widechar.h" #include /* str_...()/sxprintf() */ #include "accum.h" /* acc_...() */ @@ -195,13 +197,13 @@ window_create(int type, const char *title, int x, int y, int w, int h) acc_assign_int((accint_t) wp->w_num); if (W_MENU == type) { - wp->w_x = 0; + wp->w_x = 0; wp->w_y = 0; - wp->w_h = 1; + wp->w_h = 1; wp->w_w = (uint16_t)(ttcols() - 1); } else { - const int titlelen = (title ? (int)strlen(title) : 0); + const int titlelen = (title ? (int)utf8_swidth(title) : 0); /*MCHAR*/ if (x < 0) { /* x within view */ x = 0; @@ -273,8 +275,7 @@ window_create(int type, const char *title, int x, int y, int w, int h) window_title(wp, "", (title ? title : "")); window_append(wp); - curwp = wp; /* current window */ - set_hooked(); + set_curwp(wp); /* current window */ } return (NULL == wp ? -1 : wp->w_num); } @@ -371,8 +372,7 @@ attach_buffer(WINDOW_t *wp, BUFFER_t *bp) wp->w_status |= WFHARD; window_title(wp, bp->b_title ? bp->b_title : sys_basename(bp->b_fname), NULL); - curbp = bp; - set_hooked(); + set_curbp(bp); } } diff --git a/grcpp/.cvsignore b/grcpp/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/grcpp/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/grmandoc/.cvsignore b/grmandoc/.cvsignore index 865fe283..dc0bfd7d 100644 --- a/grmandoc/.cvsignore +++ b/grmandoc/.cvsignore @@ -1,4 +1,8 @@ -mdocml-1.12.*/ -mdocml-1.13.*/ -mandoc-1.14.*/ +mdocml-1.12.* +mdocml-1.13.* +mandoc-1.14.* mdocversion.h +Makefile +.unpacked* +*.err + diff --git a/grmandoc/.gitignore b/grmandoc/.gitignore index 865fe283..3ec04542 100644 --- a/grmandoc/.gitignore +++ b/grmandoc/.gitignore @@ -2,3 +2,6 @@ mdocml-1.12.*/ mdocml-1.13.*/ mandoc-1.14.*/ mdocversion.h +Makefile +.unpacked* + diff --git a/grmandoc/Makefile.in b/grmandoc/Makefile.in index b57d2760..162d8e9a 100644 --- a/grmandoc/Makefile.in +++ b/grmandoc/Makefile.in @@ -1,9 +1,9 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.26 2021/04/05 15:22:36 cvsuser Exp $ +# $Id: Makefile.in,v 1.27 2022/03/22 11:00:41 cvsuser Exp $ # libbsdmdoc and grmanddoc # # -# Copyright (c) 2014 - 2021, Adam Young. +# Copyright (c) 2014 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. diff --git a/grunch/.cvsignore b/grunch/.cvsignore new file mode 100644 index 00000000..6a9be135 --- /dev/null +++ b/grunch/.cvsignore @@ -0,0 +1,5 @@ +yygen.h +y.tab.c +crntypes.h +Makefile +*.err diff --git a/grunch/crlex.c b/grunch/crlex.c index 61ab1748..5531e117 100644 --- a/grunch/crlex.c +++ b/grunch/crlex.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_crlex_c,"$Id: crlex.c,v 1.36 2020/04/23 12:35:50 cvsuser Exp $") +__CIDENT_RCSID(gr_crlex_c,"$Id: crlex.c,v 1.37 2021/06/07 16:04:23 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: crlex.c,v 1.36 2020/04/23 12:35:50 cvsuser Exp $ +/* $Id: crlex.c,v 1.37 2021/06/07 16:04:23 cvsuser Exp $ * Lexical analyser for the GRUNCH language. * * @@ -236,6 +236,7 @@ static int get_line(lexer_t *lexer); static void get_while(lexer_t *lexer, int chclass); static void get_string(lexer_t *lexer, int wchar); static void get_unquoted(lexer_t *lexer, const int end); +static const char * utf8_decode(const void *src, const void *cpend, int *result); static int utf8_encode(int ch, void *buffer); static int get_character(lexer_t *lexer, int wchar); static int get_escape(lexer_t *lexer, unsigned wchar, unsigned limit, int *value); @@ -966,6 +967,88 @@ get_unquoted(lexer_t *lexer, const int end) } } +/* + * 00000000-01111111 00-7F 0-127 Single-byte encoding (compatible with US-ASCII). + * 10000000-10111111 80-BF 128-191 Second, third, or fourth byte of a multi-byte sequence. + * 11000000-11000001 C0-C1 192-193 Overlong encoding: start of 2-byte sequence, but would encode a code point 127. + * 11000010-11011111 C2-DF 194-223 Start of 2-byte sequence. + * 11100000-11101111 E0-EF 224-239 Start of 3-byte sequence. + * 11110000-11110100 F0-F4 240-244 Start of 4-byte sequence. + * 11110101-11110111 F5-F7 245-247 Restricted by RFC 3629: start of 4-byte sequence for codepoint above 10FFFF. + * 11111000-11111011 F8-FB 248-251 Restricted by RFC 3629: start of 5-byte sequence. + * 11111100-11111101 FC-FD 252-253 Restricted by RFC 3629: start of 6-byte sequence. + * 11111110-11111111 FE-FF 254-255 Invalid: not defined by original UTF-8 specification. + */ +static const char * +utf8_decode(const void *src, const void *cpend, int *result) +{ + register const unsigned char *t_src = (const unsigned char *)src; + unsigned char ch; + int32_t ret = 0; + int remain; + + /* + // Bits Last code point Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 + // 7 U+007F 0xxxxxxx + // 11 U+07FF 110xxxxx 10xxxxxx + // 16 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx + // 21 U+1FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + // 26 U+3FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + // 31 U+7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + assert(src < cpend); + ch = *t_src++; + + if (ch & 0x80) { + /* C0-C1 192-193 Overlong encoding: start of 2-byte sequence. */ + if ((ch & 0xE0) == 0xC0) { /* C2-DF 194-223 Start of 2-byte sequence. */ + remain = 1; + ret = ch & 0x1F; + + } else if ((ch & 0xF0) == 0xE0) { /* E0-EF 224-239 Start of 3-byte sequence. */ + remain = 2; + ret = ch & 0x0F; + + } else if ((ch & 0xF8) == 0xF0) { /* F0-F4 240-244 Start of 4-byte sequence. */ + remain = 3; + ret = ch & 0x07; + + } else if ((ch & 0xFC) == 0xF8) { /* F8-FB 248-251 Start of 5-byte sequence. */ + remain = 4; + ret = ch & 0x03; + + } else if ((ch & 0xFE) == 0xFC) { /* FC-FD 252-253 Start of 6-byte sequence. */ + remain = 5; + ret = ch & 0x01; + + } else { /* invalid continuation (0x80 - 0xbf). */ + ret = -ch; + goto done; + } + + while (remain--) { + if (t_src >= (const unsigned char *)cpend) { + ret = -ret; + goto done; + } + ch = *t_src++; + if (0x80 != (0xc0 & ch)) { /* invalid secondary byte (0x80 - 0xbf). */ + --t_src; + ret = -ret; + goto done; + } + ret <<= 6; + ret |= (ch & 0x3f); + } + } else { + ret = ch; + } + +done:; + *result = ret; + return (const void *)t_src; +} + static int utf8_encode(int ch, void *buffer) @@ -1033,6 +1116,7 @@ utf8_encode(int ch, void *buffer) static int get_character(lexer_t *lexer, int wchar) { + char buffer[6 + 1] = {0}; /* UTF8 working buffer */ int ch, error = 0; int value = 0; @@ -1059,14 +1143,11 @@ bad:; if (0 == ch) { if (get_escape(lexer, wchar, FALSE, &ch) < 0) { goto bad; } - - if (wchar) { /* upper bytes */ - value = (value << 8) + ((ch & 0xFFFFFF00) >> 8); - ch &= 0x00FF; - } } - value = (value << 8) + ch; + value = ch; + if (nchars < (sizeof(buffer) - 1)) + buffer[nchars] = ch; ++nchars; if ('\'' == (ch = lexget(lexer))) { @@ -1074,11 +1155,16 @@ bad:; if (0 == ch) { } } - if (nchars > 1) { - if (!error) { + if (nchars > 1 && !error) { + if (!wchar) { crerrorx(RC_CHARACTER_WIDE, "character constant too large"); + ++error; + + } else if (nchars > 6 || + utf8_decode(buffer, buffer + nchars, &value) != (buffer + nchars)) { + crerrorx(RC_CHARACTER_WIDE, "invalid multi-character character constant"); + ++error; } - ++error; } } diff --git a/grunch/crsubs.c b/grunch/crsubs.c index 394d22c0..85ba1623 100644 --- a/grunch/crsubs.c +++ b/grunch/crsubs.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_crsubs_c,"$Id: crsubs.c,v 1.28 2020/04/23 12:35:50 cvsuser Exp $") +__CIDENT_RCSID(gr_crsubs_c,"$Id: crsubs.c,v 1.29 2021/08/14 17:09:30 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: crsubs.c,v 1.28 2020/04/23 12:35:50 cvsuser Exp $ +/* $Id: crsubs.c,v 1.29 2021/08/14 17:09:30 cvsuser Exp $ * Parser ultities. * * @@ -393,7 +393,7 @@ node_opt(int op, node_t *b, node_t *c) return b; case O_MOD: if (0 == c->atom.ival) { - crwarn(RC_ERROR, "constant expression modulo zero"); + crwarn(RC_ERROR, "constant expression modulo by zero"); b->atom.ival = 0; } else { b->atom.ival %= c->atom.ival; @@ -408,6 +408,22 @@ node_opt(int op, node_t *b, node_t *c) case O_AND: b->atom.ival &= c->atom.ival; return b; + case O_LSHIFT: + if (0 == c->atom.ival) { + crwarn(RC_ERROR, "constant expression shift by zero"); + } else if (c->atom.ival < 0 || c->atom.ival >= (sizeof(accint_t) * 8)) { + crwarn(RC_ERROR, "constant expression shift overflow"); + } + b->atom.ival <<= c->atom.ival; + return b; + case O_RSHIFT: + if (0 == c->atom.ival) { + crwarn(RC_ERROR, "constant expression shift by zero"); + } else if (c->atom.ival < 0 || c->atom.ival >= (sizeof(accint_t) * 8)) { + crwarn(RC_ERROR, "constant expression shift overflow"); + } + b->atom.ival >>= c->atom.ival; + return b; default: break; } diff --git a/grunch/cry.y b/grunch/cry.y index e1b9bdb1..43d8f0d1 100644 --- a/grunch/cry.y +++ b/grunch/cry.y @@ -1,5 +1,5 @@ /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: cry.y,v 1.35 2021/04/05 09:18:23 cvsuser Exp $ +/* $Id: cry.y,v 1.36 2021/08/14 17:09:30 cvsuser Exp $ * grunch/crunch grammer, extended c99 * * @@ -525,9 +525,9 @@ additive_expression: shift_expression: additive_expression | shift_expression O_LSHIFT additive_expression - { $$ = node(O_LSHIFT, $1, $3); } + { $$ = node_opt(O_LSHIFT, $1, $3); } | shift_expression O_RSHIFT additive_expression - { $$ = node(O_RSHIFT, $1, $3); } + { $$ = node_opt(O_RSHIFT, $1, $3); } ; relational_expression: diff --git a/hlpdoc/.cvsignore b/hlpdoc/.cvsignore index 48f2c2c9..a361cc61 100644 --- a/hlpdoc/.cvsignore +++ b/hlpdoc/.cvsignore @@ -3,5 +3,7 @@ doc/html/ doc/mandoc/ ndplus Makefile +*.err +*.pdf ref diff --git a/include/asciidefs.h b/include/asciidefs.h index 041a6fd7..461c59b7 100644 --- a/include/asciidefs.h +++ b/include/asciidefs.h @@ -1,17 +1,17 @@ #ifndef GR_ASCIIDEFS_H_INCLUDED #define GR_ASCIIDEFS_H_INCLUDED #include -__CIDENT_RCSID(gr_asciidefs_h,"$Id: asciidefs.h,v 1.10 2019/03/15 23:03:05 cvsuser Exp $") +__CIDENT_RCSID(gr_asciidefs_h,"$Id: asciidefs.h,v 1.11 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: asciidefs.h,v 1.10 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: asciidefs.h,v 1.11 2022/03/21 14:55:27 cvsuser Exp $ * ASCII character value definitions * For portibality avoid where possible use of c/+cc escapes (ie. '\n'). * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/chkalloc.h b/include/chkalloc.h index f6ae7733..09f8ba44 100644 --- a/include/chkalloc.h +++ b/include/chkalloc.h @@ -1,11 +1,11 @@ #ifndef GR_CHKALLOC_H_INCLUDED #define GR_CHKALLOC_H_INCLUDED #include -__CIDENT_RCSID(gr_chkalloc_h,"$Id: chkalloc.h,v 1.23 2020/06/03 14:17:01 cvsuser Exp $") +__CIDENT_RCSID(gr_chkalloc_h,"$Id: chkalloc.h,v 1.24 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: chkalloc.h,v 1.23 2020/06/03 14:17:01 cvsuser Exp $ +/* $Id: chkalloc.h,v 1.24 2022/03/21 14:55:27 cvsuser Exp $ * Memory management interface. * * #define CHKALLOC_DEBUG 1 @@ -33,7 +33,7 @@ __CPRAGMA_ONCE * CHKALLOC_WHERE * Extended trace information. * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/config.hin b/include/config.hin index 734115c8..5d972ca7 100644 --- a/include/config.hin +++ b/include/config.hin @@ -1,11 +1,11 @@ #ifndef CR_CONFIG_H_INCLUDED #define CR_CONFIG_H_INCLUDED #include -__CIDENT_RCSID(config_h, "$Id: config.hin,v 1.54 2021/04/19 14:57:19 cvsuser Exp $") +__CIDENT_RCSID(config_h, "$Id: config.hin,v 1.57 2021/08/02 16:10:31 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; set-indent: 4; -*- */ -/* $Id: config.hin,v 1.54 2021/04/19 14:57:19 cvsuser Exp $ +/* $Id: config.hin,v 1.57 2021/08/02 16:10:31 cvsuser Exp $ * Machine configuration. * * @@ -79,6 +79,7 @@ __CPRAGMA_ONCE #undef HAVE_STDARG_H #undef HAVE_STDLIB_H #undef HAVE_STDIO_H +#undef HAVE_STDDEF_H #undef HAVE_LIMITS_H /* AC_HEADER_DIRENT */ @@ -115,6 +116,7 @@ __CPRAGMA_ONCE #undef HAVE_SYS_UTSNAME_H #undef HAVE_SYS_SELECT_H #undef HAVE_SYS_SOCKET_H +#undef HAVE_SYS_SENDFILE_H #undef HAVE_SYS_WAIT_H #undef HAVE_SYS_STAT_H #undef HAVE_SYS_STATFS_H @@ -138,6 +140,7 @@ __CPRAGMA_ONCE #undef HAVE_THREAD_H #undef HAVE_PTHREAD_H +#undef HAVE_PTHREAD_PRIO_INHERIT #undef HAVE_FCNTL_H #undef HAVE_SHARE_H @@ -170,6 +173,7 @@ __CPRAGMA_ONCE #undef HAVE_ERR_H #undef HAVE_FTS_H + /* * Available allocator functionality */ @@ -223,6 +227,8 @@ __CPRAGMA_ONCE #undef HAVE_NCURSESW_NCURSESW_H #undef HAVE_NCURSESW_CURSES_H +#undef HAVE_NCURSESW_TERMCAP_H +#undef HAVE_NCURSESW_TERM_H #undef HAVE_NCURSESW_H #undef HAVE_CURSES_H @@ -345,7 +351,7 @@ __CPRAGMA_ONCE */ /* environ support */ - + #undef HAVE_ENVIRON #undef HAVE__ENVIRON #undef HAVE___ENVIRON @@ -379,9 +385,11 @@ __CPRAGMA_ONCE #undef HAVE_SELECT #undef HAVE_POLL #undef HAVE_LINK +#undef HAVE_STAT #undef HAVE_LSTAT #undef HAVE_SYMLINK #undef HAVE_RENAME +#undef HAVE_FSEEKO #undef HAVE_FGETPOS #undef HAVE_FSETPOS @@ -458,6 +466,7 @@ __CPRAGMA_ONCE #undef HAVE_PREAD #undef HAVE_PWRITE +#undef HAVE_SENDFILE #undef HAVE_GETW #undef HAVE_PUTW @@ -486,6 +495,8 @@ __CPRAGMA_ONCE #undef HAVE_STRINGLIST #undef HAVE_REALLOCARRAY +#undef HAVE_LIBNSL + #undef HAVE_SIGSETMASK #undef HAVE_SIGACTION #undef HAVE_SIGINTERRUPT @@ -502,6 +513,7 @@ __CPRAGMA_ONCE #undef HAVE_WMEMCMP #undef HAVE_WMEMMOVE #undef HAVE_WMEMCPY +#undef HAVE_WCWIDTH #undef HAVE_MMAP #undef HAVE_MPROTECT @@ -577,6 +589,7 @@ __CPRAGMA_ONCE #undef HAVE_X11_XFT_XFT_H #undef HAVE_X11_XKBLIB_H #undef HAVE_X11_XLIB_H +#undef HAVE_XFT_XLBLIB_H #undef HAVE_XFT_XFT_H #undef HAVE_XKBBELL #undef HAVE_LIBX11 @@ -668,6 +681,7 @@ __CPRAGMA_ONCE #undef HAVE_LIBGUESS #undef HAVE_LIBGUESS_EXTENSIONS #undef HAVE_LIBGUESS_H +#undef HAVE_LIBGUESS_LIBGUESS_H /* libmagic and magic.h */ #undef HAVE_LIBMAGIC @@ -743,4 +757,3 @@ __CPRAGMA_ONCE #define GRIEF_DATADIR "/usr/local/lib/grief/" #endif /*CR_CONFIG_H_INCLUDED*/ - diff --git a/include/edalt.h b/include/edalt.h index 3c191462..e8009e41 100644 --- a/include/edalt.h +++ b/include/edalt.h @@ -1,15 +1,15 @@ #ifndef GR_EDALT_H_INCLUDED #define GR_EDALT_H_INCLUDED #include -__CIDENT_RCSID(gr_edalt_h,"$Id: edalt.h,v 1.27 2020/06/18 12:53:03 cvsuser Exp $") +__CIDENT_RCSID(gr_edalt_h,"$Id: edalt.h,v 1.32 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edalt.h,v 1.27 2020/06/18 12:53:03 cvsuser Exp $ +/* $Id: edalt.h,v 1.32 2022/03/21 14:55:27 cvsuser Exp $ * Key definitions. * ==noguard== * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -36,41 +36,13 @@ __CPRAGMA_ONCE /* * The following scheme is used for encoding function keys. * - * This scheme is used because it simplifies converting ASCII key names to the - * internal codes and vice-versa. Also we keep the internal keycodes out of the - * ASCII range so users are free to use those for input if necessary, e.g. on - * foreign language keyboards. + * Unicode defines a codespace for 1,114,112 code points in range + * 0 to 10FFFF leaving the top bits. * + * These are utilised for attributes are used to create seperate + * namespaces for UNICODE, FUNCTION and others. * - * 0x000..0x0ff ASCII ASCII range. - * 0x100..0x1ff Fn keys Support for upto 255 unshifted function keys - * 0x200..0x2ff Keypad Upto 256 keypad keys. - * 0x300..0x3ff Misc Miscellaneous - * 0x400..0x7ff Multikey Used when user does something like: - * assign_to_key("xyz", .. ie. multi-key stroke. - * 0x800..0x8ff Private Private key definitions for users. - * 0x900..0x91f Button down Mouse buttons - * 0x920..0x93f Button up Mouse buttons - * 0x940..0x95f Pointer motion Mouse buttons - * - * These ranges can be OR'ed with the following bits to indicate - * a modifier key is in operation. - * - * 0x1000 SHIFT - * 0x2000 CTRL Not used for ASCII range. - * 0x4000 META - * - */ - -/* - * New Key encoding: - * - * Unicode defines a codespace for 1,114,112 code points in range - * 0 to 10FFFF leaving the top bits. - * - * These are utilised for attributes are used to create seperate - * namespaces for ASCII, UNICODE, FUNCTION and others, plus - * Shift, Ctrl and Meta modifiers. + * Within these ranges can be OR'ed with the modifiers SHIFT, CTRL and META. * * ----------------------------------------------------------------- * | attributes | character | @@ -78,34 +50,21 @@ __CPRAGMA_ONCE * 4 3 2 1 4 3 2 1 4 3 2 1 4 2 3 1 4 3 2 1 4 2 3 1 4 3 2 1 4 2 3 1 * 1 f . . . f . . . f . . . f . . . f . . . * - * x Shift - * x Ctrl/control - * x Meta - * s . . . r r r r Character ranges/namespaces + * x Shift - MOD_SHIFT + * x Ctrl/control - MOD_CTRL + * x Meta - MOD_META + * x App - MOD_APP + * s . r r r r . Character ranges/namespaces - RANGE_MASK * - + * RANGE_CHARACTER, RANGE_FUNCTION, RANGE_KEYPAD, + * RANGE_MISC, RANGE_MULTIKEY, RANGE_PRIVATE, RANGE_BUTTON + * + * s = sign/reserved. + * . = reserved/unused. + * + typedef int32_t KEY; -#define KEY_MASK 0x001fffff // 0..10ffff -#define KEY_ATTRMASK 0x8fe00000 - -#define RANGE_ASCII 0x00000000 // namespaces -#define RANGE_UNICODE 0x01000000 -#define RANGE_FN 0x02000000 -#define RANGE_KEYPAD 0x03000000 -#define RANGE_MISC 0x04000000 -#define RANGE_MULTIKEY 0x05000000 -#define RANGE_PRIVATE 0x0a000000 -#define RANGE_BUTTON 0x0b000000 -#define RANGE_MASK 0x0f000000 - -#define MOD_SHIFT 0x00200000 // modifiers -#define MOD_CTRL 0x00400000 -#define MOD_META 0x00800000 - -#define KEY_VOID 0x001fffff - - * */ #if defined(_WIN32) || defined(WIN32) @@ -138,6 +97,7 @@ typedef int32_t KEY; #undef KEY_REPLACE #undef KEY_ENTER #undef KEY_BACKSPACE +#undef KEY_BREAK #endif /* @@ -153,36 +113,40 @@ typedef int32_t KEY; #define KEY_TAB __TAB #define KEY_ENTER __ENTER #define KEY_NEWLINE '\n' -#define KEY_WINCH 0x7ffe -#define KEY_VOID 0x7fff +#define KEY_DELETE 0x7f -/* - * Macro to check whether key is a normal ASCII key. +/* + * Namespaces and modifiers. */ -#define IS_ASCII(x) ((x & ~KEY_MASK) == 0) -#define IS_MULTIKEY(x) ((x) >= RANGE_MULTIKEY && (x) <= RANGE_MULTIKEY + MULTIKEY_SIZE) -#define KEY_MASK 0x00ff +#define KEY_MASK 0x001fffff // 0..10ffff +#define RANGE_CHARACTER 0x00000000 // namespaces +#define RANGE_FUNCTION (1 << 26) +#define RANGE_KEYPAD (2 << 26) +#define RANGE_MISC (3 << 26) +#define RANGE_MULTIKEY (4 << 26) +#define RANGE_PRIVATE (5 << 26) +#define RANGE_BUTTON (6 << 26) +#define RANGE_MAX (15 << 26) +#define RANGE_MASK 0x3c000000 -/* - * Modifier bits. - */ -#define MOD_SHIFT 0x1000 -#define MOD_CTRL 0x2000 -#define MOD_META 0x4000 +#define MULTIKEY_SIZE 0x0400 +#define IS_CHARACTER(x) (((x) & ~KEY_MASK) == 0) // unmodified character. +#define IS_FUNCTION(x) (((x) & RANGE_MASK) == RANGE_FUNCTION) // function key. +#define IS_MULTIKEY(x) ((x) >= RANGE_MULTIKEY && (x) <= (RANGE_MULTIKEY + MULTIKEY_SIZE)) +#define IS_BUTTON(x) (((x) & RANGE_MASK) == RANGE_BUTTON) // mouse button. + +#define MOD_SHIFT 0x00200000 // modifiers +#define MOD_CTRL 0x00400000 +#define MOD_META 0x00800000 +#define MOD_APP 0x01000000 // reserved +#define MOD_MASK 0x01e00000 /* - * Key ranges. + * Specials */ -#define RANGE_ASCII 0x0000 -#define RANGE_FN 0x0100 -#define RANGE_KEYPAD 0x0200 -#define RANGE_MISC 0x0300 -#define RANGE_MULTIKEY 0x0400 /* 0x400 .. 0x7ff */ -#define RANGE_PRIVATE 0x0800 /* 0x800 .. 0x8ff */ -#define RANGE_BUTTON 0x0900 -#define RANGE_MASK 0x0f00 - -#define MULTIKEY_SIZE 0x0400 +#define KEY_VOID 0x001fffff // null +#define KEY_WINCH 0x001ffffe // winch/resize event +#define KEY_UNICODE 0x001ffff0 // keyboard special /* * Control characters @@ -231,11 +195,11 @@ typedef int32_t KEY; /* * Function key definitions. */ -#define F(__x) (RANGE_FN + (__x) - 1) -#define SF(__x) (MOD_SHIFT | (RANGE_FN + (__x) - 1)) -#define CF(__x) (MOD_CTRL | (RANGE_FN + (__x) - 1)) -#define CSF(__x) (MOD_CTRL | MOD_SHIFT | (RANGE_FN + (__x) - 1)) -#define AF(__x) (MOD_META | (RANGE_FN + (__x) - 1)) +#define F(__x) (RANGE_FUNCTION + (__x) - 1) +#define SF(__x) (MOD_SHIFT | (RANGE_FUNCTION + (__x) - 1)) +#define CF(__x) (MOD_CTRL | (RANGE_FUNCTION + (__x) - 1)) +#define CSF(__x) (MOD_CTRL | MOD_SHIFT | (RANGE_FUNCTION + (__x) - 1)) +#define AF(__x) (MOD_META | (RANGE_FUNCTION + (__x) - 1)) /* * Alt-letter definitions. @@ -336,7 +300,7 @@ typedef int32_t KEY; /* * Control keypad keys. */ -#define __CTRL_KEYPAD(__x) (MOD_CTRL | RANGE_KEYPAD | (__x)) +#define __CTRL_KEYPAD(__x) (MOD_CTRL | RANGE_KEYPAD | (__x)) #define CTRL_KEYPAD_0 __CTRL_KEYPAD(0) #define CTRL_KEYPAD_1 __CTRL_KEYPAD(1) #define CTRL_KEYPAD_2 __CTRL_KEYPAD(2) @@ -453,6 +417,7 @@ typedef int32_t KEY; #define KEY_OPEN (RANGE_MISC | 20) #define KEY_SAVE (RANGE_MISC | 21) #define KEY_MENU (RANGE_MISC | 22) +#define KEY_BREAK (RANGE_MISC | 23) #define WHEEL_UP (RANGE_MISC | 31) /* Mouse scroll wheel */ #define WHEEL_DOWN (RANGE_MISC | 32) diff --git a/include/edassert.h b/include/edassert.h index ab183a2b..2c8b6f9d 100644 --- a/include/edassert.h +++ b/include/edassert.h @@ -1,15 +1,15 @@ #ifndef GR_EDASSERT_H_INCLUDED #define GR_EDASSERT_H_INCLUDED #include -__CIDENT_RCSID(gr_edassert_h,"$Id: edassert.h,v 1.14 2019/03/15 23:03:05 cvsuser Exp $") +__CIDENT_RCSID(gr_edassert_h,"$Id: edassert.h,v 1.15 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edassert.h,v 1.14 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: edassert.h,v 1.15 2022/03/21 14:55:27 cvsuser Exp $ * Custom assert interface * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edcm.h b/include/edcm.h index 8b07abcb..3f3de694 100644 --- a/include/edcm.h +++ b/include/edcm.h @@ -1,16 +1,16 @@ #ifndef GR_EDCM_H_INCLUDED #define GR_EDCM_H_INCLUDED #include -__CIDENT_RCSID(gr_edcm_h,"$Id: edcm.h,v 1.21 2020/04/20 23:21:26 cvsuser Exp $") +__CIDENT_RCSID(gr_edcm_h,"$Id: edcm.h,v 1.22 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edcm.h,v 1.21 2020/04/20 23:21:26 cvsuser Exp $ +/* $Id: edcm.h,v 1.22 2022/03/21 14:55:27 cvsuser Exp $ * clisp macro constructs. * * * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edconfig.h b/include/edconfig.h index 0af0adba..dee213d0 100644 --- a/include/edconfig.h +++ b/include/edconfig.h @@ -1,11 +1,11 @@ #ifndef GR_EDCONFIG_H_INCLUDED #define GR_EDCONFIG_H_INCLUDED #include -__CIDENT_RCSID(gr_edconfig_h,"$Id: edconfig.h,v 1.12 2019/03/15 23:03:05 cvsuser Exp $") +__CIDENT_RCSID(gr_edconfig_h,"$Id: edconfig.h,v 1.13 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edconfig.h,v 1.12 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: edconfig.h,v 1.13 2022/03/21 14:55:27 cvsuser Exp $ * Configuration. * * GRINIT_FILE @@ -29,7 +29,7 @@ __CPRAGMA_ONCE * GRINIT_OBJECT * Initialisation macro object, containing GRINIT_MACRO. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/eddebug.h b/include/eddebug.h index caa525ef..aeea538a 100644 --- a/include/eddebug.h +++ b/include/eddebug.h @@ -1,16 +1,16 @@ #ifndef GR_EDDEBUG_H_INCLUDED #define GR_EDDEBUG_H_INCLUDED #include -__CIDENT_RCSID(gr_eddebug_h,"$Id: eddebug.h,v 1.27 2019/03/15 23:03:05 cvsuser Exp $") +__CIDENT_RCSID(gr_eddebug_h,"$Id: eddebug.h,v 1.28 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: eddebug.h,v 1.27 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: eddebug.h,v 1.28 2022/03/21 14:55:27 cvsuser Exp $ * Debug functions. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/eddir.h b/include/eddir.h index 163b46f6..304b9191 100644 --- a/include/eddir.h +++ b/include/eddir.h @@ -1,16 +1,16 @@ #ifndef GR_EDDIR_H_INCLUDED #define GR_EDDIR_H_INCLUDED #include -__CIDENT_RCSID(gr_eddir_h,"$Id: eddir.h,v 1.13 2020/06/18 12:52:43 cvsuser Exp $") +__CIDENT_RCSID(gr_eddir_h,"$Id: eddir.h,v 1.14 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: eddir.h,v 1.13 2020/06/18 12:52:43 cvsuser Exp $ +/* $Id: eddir.h,v 1.14 2022/03/21 14:55:27 cvsuser Exp $ * Directory management. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edendian.h b/include/edendian.h index 82de5a28..61a27157 100644 --- a/include/edendian.h +++ b/include/edendian.h @@ -1,16 +1,16 @@ #ifndef GR_EDENDIAN_H_INCLUDED #define GR_EDENDIAN_H_INCLUDED #include -__CIDENT_RCSID(gr_edendian_h,"$Id: edendian.h,v 1.14 2019/03/15 23:03:05 cvsuser Exp $") +__CIDENT_RCSID(gr_edendian_h,"$Id: edendian.h,v 1.15 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edendian.h,v 1.14 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: edendian.h,v 1.15 2022/03/21 14:55:27 cvsuser Exp $ * Endian interface. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edenv.h b/include/edenv.h index 11ca1c76..d920fc3e 100644 --- a/include/edenv.h +++ b/include/edenv.h @@ -1,16 +1,16 @@ #ifndef GR_EDENV_H_INCLUDED #define GR_EDENV_H_INCLUDED #include -__CIDENT_RCSID(gr_edenv_h,"$Id: edenv.h,v 1.16 2019/03/15 23:03:05 cvsuser Exp $") +__CIDENT_RCSID(gr_edenv_h,"$Id: edenv.h,v 1.17 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edenv.h,v 1.16 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: edenv.h,v 1.17 2022/03/21 14:55:27 cvsuser Exp $ * Environment interface. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edfeatures.h b/include/edfeatures.h index 187b7d3b..0c19f37f 100644 --- a/include/edfeatures.h +++ b/include/edfeatures.h @@ -1,16 +1,16 @@ #ifndef GR_EDFEATURES_H_INCLUDED #define GR_EDFEATURES_H_INCLUDED #include -__CIDENT_RCSID(gr_edfeatures_h,"$Id: edfeatures.h,v 1.13 2019/03/15 23:03:05 cvsuser Exp $") +__CIDENT_RCSID(gr_edfeatures_h,"$Id: edfeatures.h,v 1.15 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edfeatures.h,v 1.13 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: edfeatures.h,v 1.15 2022/03/21 14:55:27 cvsuser Exp $ * Editor features. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -101,8 +101,7 @@ __CBEGIN_DECLS #define TF_ENCODING 100 /* terminal character encoding */ #define TF_ENCODING_GUESS 101 /* text encoding guess specification */ -#define TF_UNICODE_VERSION 102 /* UNICODE version, 300 = 3.00 */ -#define TF_UNICODE_WIDTH 103 /* width table version */ +#define TF_UNICODE_VERSION 102 /* UNICODE version; eg. "6.0.0" */ /*--end--*/ /*--export--defines--*/ @@ -234,8 +233,7 @@ struct _features { int pt_screen_rows; /* INT, Screen rows. */ int pt_screen_cols; /* INT, Screen columns. */ - int pt_unicode_version; /* INT, UNICODE version. */ - int pt_unicode_width; /* INT, UNICODE width version. */ + char pt_unicode_version[PT_NAME]; /* STRING, UNICODE version. */ char pt_encoding[PT_NAME]; /* STRING, Encoding. */ char pt_colormap[512]; /* STRING, XTERM color map. */ diff --git a/include/edfileio.h b/include/edfileio.h index bba966d0..af54344e 100644 --- a/include/edfileio.h +++ b/include/edfileio.h @@ -1,17 +1,15 @@ #ifndef GR_EDFILEIO_H_INCLUDED #define GR_EDFILEIO_H_INCLUDED #include -__CIDENT_RCSID(gr_edfileio_h,"$Id: edfileio.h,v 1.16 2020/06/18 12:53:31 cvsuser Exp $") +__CIDENT_RCSID(gr_edfileio_h,"$Id: edfileio.h,v 1.18 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edfileio.h,v 1.16 2020/06/18 12:53:31 cvsuser Exp $ +/* $Id: edfileio.h,v 1.18 2022/03/21 14:55:27 cvsuser Exp $ * File input/output functionality system api names. * Required by non-posix environments (ie. WIN32). * - * - * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -58,17 +56,11 @@ __CBEGIN_DECLS /* * MSVC and WATCOMC */ -#define fileio_open(_fn, _of, _om) _open(_fn, _of, _om) +#define fileio_open(_fn, _of, _om) w32_open(_fn, _of, _om) #define fileio_close(_fd) _close(_fd) #define fileio_read(_fd, _ib, _is) _read(_fd, _ib, _is) #define fileio_write(_fd, _ob, _is) _write(_fd, _ob, _is) #define fileio_lseek(_fd, _o, _w) _lseek(_fd, _o, _w) - -#define fileio_access(_fn, _m) _access(_fn, _m) -#define fileio_chmod(_fn, _m) _chmod(_fn, _m) -#define fileio_unlink(_fn) _unlink(_fn) -#define fileio_mkdir(_dn, _m) w32_mkdir(_dn, _m) - #define fileio_fdopen(_fd, _om) _fdopen(_fd, _om) #define fileio_fileno(_fs) _fileno(_fs) #define fileio_umask(_mk) _umask(_mk) @@ -79,12 +71,6 @@ __CBEGIN_DECLS #define fileio_read(_fd, _ib, _is) read(_fd, _ib, _is) #define fileio_write(_fd, _ob, _is) write(_fd, _ob, _is) #define fileio_lseek(_fd, _o, _w) lseek(_fd, _o, _w) - -#define fileio_access(_fn, _m) access(_fn, _m) -#define fileio_chmod(_fn, _m) chmod(_fn, _m) -#define fileio_unlink(_fn) unlink(_fn) -#define fileio_mkdir(_dn, _m) mkdir(_dn, _m) - #define fileio_fdopen(_fd, _om) fdopen(_fd, _om) #define fileio_fileno(_fs) fileno(_fs) #define fileio_umask(_mk) umask(_mk) @@ -93,4 +79,5 @@ __CBEGIN_DECLS __CEND_DECLS #endif /*GR_EDFILEIO_H_INCLUDED*/ + /*end*/ diff --git a/include/edgetopt.h b/include/edgetopt.h index 57fdbcd5..c91f557e 100644 --- a/include/edgetopt.h +++ b/include/edgetopt.h @@ -1,16 +1,16 @@ #ifndef GR_EDGETOPT_H_INCLUDED #define GR_EDGETOPT_H_INCLUDED #include -__CIDENT_RCSID(gr_edgetopt_h,"$Id: edgetopt.h,v 1.17 2020/06/18 12:53:56 cvsuser Exp $") +__CIDENT_RCSID(gr_edgetopt_h,"$Id: edgetopt.h,v 1.18 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edgetopt.h,v 1.17 2020/06/18 12:53:56 cvsuser Exp $ +/* $Id: edgetopt.h,v 1.18 2022/03/21 14:55:27 cvsuser Exp $ * getopt() interface/implemenation. * * * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edhandles.h b/include/edhandles.h index 632bdfe5..fd65b264 100644 --- a/include/edhandles.h +++ b/include/edhandles.h @@ -1,16 +1,16 @@ #ifndef GR_EDHANDLES_H_INCLUDED #define GR_EDHANDLES_H_INCLUDED #include -__CIDENT_RCSID(gr_edhandles_h,"$Id: edhandles.h,v 1.7 2019/03/15 23:03:05 cvsuser Exp $") +__CIDENT_RCSID(gr_edhandles_h,"$Id: edhandles.h,v 1.8 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edhandles.h,v 1.7 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: edhandles.h,v 1.8 2022/03/21 14:55:27 cvsuser Exp $ * Internal handle base identifiers. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edheaders.h b/include/edheaders.h index c81d646c..61d9d16a 100644 --- a/include/edheaders.h +++ b/include/edheaders.h @@ -1,16 +1,16 @@ #ifndef GR_EDHEADERS_H_INCLUDED #define GR_EDHEADERS_H_INCLUDED #include -__CIDENT_RCSID(gr_edheaders_h,"$Id: edheaders.h,v 1.16 2019/03/15 23:03:05 cvsuser Exp $") +__CIDENT_RCSID(gr_edheaders_h,"$Id: edheaders.h,v 1.17 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edheaders.h,v 1.16 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: edheaders.h,v 1.17 2022/03/21 14:55:27 cvsuser Exp $ * System headers. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edidentifier.h b/include/edidentifier.h index af9bc39c..7a6de5ad 100644 --- a/include/edidentifier.h +++ b/include/edidentifier.h @@ -2,7 +2,7 @@ #define GR_EDIDENTIFIER_H_INCLUDED /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edidentifier.h,v 1.17 2019/03/15 23:03:05 cvsuser Exp $ +/* $Id: edidentifier.h,v 1.18 2022/03/21 14:55:27 cvsuser Exp $ * Compiler specific object identify functionality. * * __CIDENT(description) @@ -11,7 +11,7 @@ * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/editor.h b/include/editor.h index 6d55ed12..c6e41596 100644 --- a/include/editor.h +++ b/include/editor.h @@ -1,16 +1,16 @@ #ifndef GR_EDITOR_H_INCLUDED #define GR_EDITOR_H_INCLUDED #include -__CIDENT_RCSID(gr_editor_h,"$Id: editor.h,v 1.35 2019/03/15 23:03:08 cvsuser Exp $") +__CIDENT_RCSID(gr_editor_h,"$Id: editor.h,v 1.36 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: editor.h,v 1.35 2019/03/15 23:03:08 cvsuser Exp $ +/* $Id: editor.h,v 1.36 2022/03/21 14:55:27 cvsuser Exp $ * GRIEF Editor global definitions. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edlargefile.h b/include/edlargefile.h index 0ec07d09..8d653147 100644 --- a/include/edlargefile.h +++ b/include/edlargefile.h @@ -1,16 +1,16 @@ #ifndef GR_EDLARGEFILE_H_INCLUDED #define GR_EDLARGEFILE_H_INCLUDED #include -__CIDENT_RCSID(gr_edlargefile_h,"$Id: edlargefile.h,v 1.10 2019/03/15 23:03:08 cvsuser Exp $") +__CIDENT_RCSID(gr_edlargefile_h,"$Id: edlargefile.h,v 1.11 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edlargefile.h,v 1.10 2019/03/15 23:03:08 cvsuser Exp $ +/* $Id: edlargefile.h,v 1.11 2022/03/21 14:55:27 cvsuser Exp $ * Large file support interface. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edmacros.h b/include/edmacros.h index 789ee381..d8cb4c2d 100644 --- a/include/edmacros.h +++ b/include/edmacros.h @@ -1,14 +1,14 @@ #ifndef GR_EDMACROS_H_INCLUDED #define GR_EDMACROS_H_INCLUDED #include -__CIDENT_RCSID(gr_edmacros_h,"$Id: edmacros.h,v 1.20 2020/04/21 21:21:14 cvsuser Exp $") +__CIDENT_RCSID(gr_edmacros_h,"$Id: edmacros.h,v 1.21 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edmacros.h,v 1.20 2020/04/21 21:21:14 cvsuser Exp $ +/* $Id: edmacros.h,v 1.21 2022/03/21 14:55:27 cvsuser Exp $ * Macro and symbolic interpreter information. * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edopcode.h b/include/edopcode.h index 6a25fcc6..14463e21 100644 --- a/include/edopcode.h +++ b/include/edopcode.h @@ -1,16 +1,16 @@ #ifndef GR_EDOPCODE_H_INCLUDED #define GR_EDOPCODE_H_INCLUDED #include -__CIDENT_RCSID(gr_edopcode_h,"$Id: edopcode.h,v 1.21 2020/04/21 21:21:14 cvsuser Exp $") +__CIDENT_RCSID(gr_edopcode_h,"$Id: edopcode.h,v 1.22 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edopcode.h,v 1.21 2020/04/21 21:21:14 cvsuser Exp $ +/* $Id: edopcode.h,v 1.22 2022/03/21 14:55:27 cvsuser Exp $ * List types. * * * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edpack0.h b/include/edpack0.h index 64e4a6d1..36c1ac6f 100644 --- a/include/edpack0.h +++ b/include/edpack0.h @@ -1,9 +1,9 @@ /* -*- mode: c; indent-width: 4; -*- - * $Id: edpack0.h,v 1.5 2019/03/15 23:03:08 cvsuser Exp $ + * $Id: edpack0.h,v 1.6 2022/03/21 14:55:27 cvsuser Exp $ * Structure packing. * ==noguard== * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edpack1.h b/include/edpack1.h index 4959b56a..0918564a 100644 --- a/include/edpack1.h +++ b/include/edpack1.h @@ -1,9 +1,9 @@ /* -*- mode: c; indent-width: 4; -*- - * $Id: edpack1.h,v 1.5 2019/03/15 23:03:09 cvsuser Exp $ + * $Id: edpack1.h,v 1.6 2022/03/21 14:55:27 cvsuser Exp $ * Structure packing. * ==noguard== * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edpackage.h.in b/include/edpackage.h.in index c778b99d..6ad7317d 100644 --- a/include/edpackage.h.in +++ b/include/edpackage.h.in @@ -1,15 +1,15 @@ #ifndef GR_EDPACKAGE_H_INCLUDED #define GR_EDPACKAGE_H_INCLUDED #include -__CIDENT_RCSID(edpackage_h, "$Id: edpackage.h.in,v 1.7 2020/06/18 20:35:17 cvsuser Exp $") +__CIDENT_RCSID(edpackage_h, "$Id: edpackage.h.in,v 1.8 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: h; set-indent: 4; -*- */ -/* $Id: edpackage.h.in,v 1.7 2020/06/18 20:35:17 cvsuser Exp $ +/* $Id: edpackage.h.in,v 1.8 2022/03/21 14:55:27 cvsuser Exp $ * Package configuration. * * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edpaths.h b/include/edpaths.h index 89278bac..094403e4 100644 --- a/include/edpaths.h +++ b/include/edpaths.h @@ -1,11 +1,11 @@ #ifndef GR_EDPATHS_H_INCLUDED #define GR_EDPATHS_H_INCLUDED #include -__CIDENT_RCSID(gr_edpaths_h,"$Id: edpaths.h,v 1.19 2020/06/18 12:52:11 cvsuser Exp $") +__CIDENT_RCSID(gr_edpaths_h,"$Id: edpaths.h,v 1.20 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edpaths.h,v 1.19 2020/06/18 12:52:11 cvsuser Exp $ +/* $Id: edpaths.h,v 1.20 2022/03/21 14:55:27 cvsuser Exp $ * Default system paths ... * * Example: @@ -14,7 +14,7 @@ __CPRAGMA_ONCE * * o Win32, ROOT=C:/Program Files/Grief * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edrefobj.h b/include/edrefobj.h index ec244cd8..1578760a 100644 --- a/include/edrefobj.h +++ b/include/edrefobj.h @@ -1,16 +1,16 @@ #ifndef GR_EDREFOBJ_H_INCLUDED #define GR_EDREFOBJ_H_INCLUDED #include -__CIDENT_RCSID(gr_edrefobj_h,"$Id: edrefobj.h,v 1.21 2019/03/15 23:03:09 cvsuser Exp $") +__CIDENT_RCSID(gr_edrefobj_h,"$Id: edrefobj.h,v 1.22 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edrefobj.h,v 1.21 2019/03/15 23:03:09 cvsuser Exp $ +/* $Id: edrefobj.h,v 1.22 2022/03/21 14:55:27 cvsuser Exp $ * Reference strings * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edringbuf.h b/include/edringbuf.h index 7e571283..9b44d4b9 100644 --- a/include/edringbuf.h +++ b/include/edringbuf.h @@ -1,16 +1,16 @@ #ifndef GR_EDRINGBUF_H_INCLUDED #define GR_EDRINGBUF_H_INCLUDED #include -__CIDENT_RCSID(gr_edringbuf_h,"$Id: edringbuf.h,v 1.7 2019/03/15 23:03:09 cvsuser Exp $") +__CIDENT_RCSID(gr_edringbuf_h,"$Id: edringbuf.h,v 1.8 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edringbuf.h,v 1.7 2019/03/15 23:03:09 cvsuser Exp $ +/* $Id: edringbuf.h,v 1.8 2022/03/21 14:55:27 cvsuser Exp $ * Basic binary ringbuffer ... * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edstacktrace.h b/include/edstacktrace.h index a07a4a08..72b21e19 100644 --- a/include/edstacktrace.h +++ b/include/edstacktrace.h @@ -1,16 +1,16 @@ #ifndef GR_EDSTACKTRACE_H_INCLUDED #define GR_EDSTACKTRACE_H_INCLUDED #include -__CIDENT_RCSID(gr_edstacktrace_h,"$Id: edstacktrace.h,v 1.7 2019/03/15 23:03:09 cvsuser Exp $") +__CIDENT_RCSID(gr_edstacktrace_h,"$Id: edstacktrace.h,v 1.8 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edstacktrace.h,v 1.7 2019/03/15 23:03:09 cvsuser Exp $ +/* $Id: edstacktrace.h,v 1.8 2022/03/21 14:55:27 cvsuser Exp $ * Diagnostics support. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edstdarg.h b/include/edstdarg.h index bce44595..8682900b 100644 --- a/include/edstdarg.h +++ b/include/edstdarg.h @@ -1,17 +1,18 @@ #ifndef GR_EDSTDARG_H_INCLUDED #define GR_EDSTDARG_H_INCLUDED #include -__CIDENT_RCSID(gr_edstdarg_h,"$Id: edstdarg.h,v 1.1 2019/01/25 15:50:42 cvsuser Exp $") +__CIDENT_RCSID(gr_edstdarg_h,"$Id: edstdarg.h,v 1.2 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edstdarg.h,v 1.1 2019/01/25 15:50:42 cvsuser Exp $ +/* $Id: edstdarg.h,v 1.2 2022/03/21 14:55:27 cvsuser Exp $ * stdarg() interface/implemenation. * * * Copyright (c) Adam Young. * All rights reserved. * + * Copyright (c) 1998 - 2022, Adam Young. * This file is part of the GRIEF Editor. * * The GRIEF Editor is free software: you can redistribute it diff --git a/include/edstruct.h b/include/edstruct.h index af62a374..6e113522 100644 --- a/include/edstruct.h +++ b/include/edstruct.h @@ -1,16 +1,16 @@ #ifndef GR_EDSTRUCT_H_INCLUDED #define GR_EDSTRUCT_H_INCLUDED #include -__CIDENT_RCSID(gr_edstruct_h,"$Id: edstruct.h,v 1.69 2020/06/18 12:51:55 cvsuser Exp $") +__CIDENT_RCSID(gr_edstruct_h,"$Id: edstruct.h,v 1.71 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edstruct.h,v 1.69 2020/06/18 12:51:55 cvsuser Exp $ +/* $Id: edstruct.h,v 1.71 2022/03/21 14:55:27 cvsuser Exp $ * Window, buffer, line and character-map definitions. * * * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -75,7 +75,7 @@ enum _marks { * Key table element */ struct k_tbl { - uint16_t key; + KEY key; const char * name; }; diff --git a/include/edsym.h b/include/edsym.h index e40b1b4b..d7890ca5 100644 --- a/include/edsym.h +++ b/include/edsym.h @@ -1,16 +1,16 @@ #ifndef GR_EDSYM_H_INCLUDED #define GR_EDSYM_H_INCLUDED #include -__CIDENT_RCSID(gr_edsym_h,"$Id: edsym.h,v 1.23 2020/04/21 21:21:14 cvsuser Exp $") +__CIDENT_RCSID(gr_edsym_h,"$Id: edsym.h,v 1.24 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edsym.h,v 1.23 2020/04/21 21:21:14 cvsuser Exp $ +/* $Id: edsym.h,v 1.24 2022/03/21 14:55:27 cvsuser Exp $ * Symbol management. * * * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edtermcap.h b/include/edtermcap.h index b47139b0..653d612f 100644 --- a/include/edtermcap.h +++ b/include/edtermcap.h @@ -1,16 +1,16 @@ #ifndef GR_EDTERMCAP_H_INCLUDED #define GR_EDTERMCAP_H_INCLUDED #include -__CIDENT_RCSID(gr_edtermcap_h,"$Id: edtermcap.h,v 1.13 2019/03/15 23:03:10 cvsuser Exp $") +__CIDENT_RCSID(gr_edtermcap_h,"$Id: edtermcap.h,v 1.14 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edtermcap.h,v 1.13 2019/03/15 23:03:10 cvsuser Exp $ +/* $Id: edtermcap.h,v 1.14 2022/03/21 14:55:27 cvsuser Exp $ * Terminal interface. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edtermio.h b/include/edtermio.h index 102c92b4..32333c56 100644 --- a/include/edtermio.h +++ b/include/edtermio.h @@ -1,16 +1,16 @@ #ifndef GR_EDTERMIO_H_INCLUDED #define GR_EDTERMIO_H_INCLUDED #include -__CIDENT_RCSID(gr_edtermio_h,"$Id: edtermio.h,v 1.13 2019/03/15 23:03:10 cvsuser Exp $") +__CIDENT_RCSID(gr_edtermio_h,"$Id: edtermio.h,v 1.14 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edtermio.h,v 1.13 2019/03/15 23:03:10 cvsuser Exp $ +/* $Id: edtermio.h,v 1.14 2022/03/21 14:55:27 cvsuser Exp $ * Terminal i/o related definitions. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edthreads.h b/include/edthreads.h index 54be4a14..ff1349ea 100644 --- a/include/edthreads.h +++ b/include/edthreads.h @@ -1,18 +1,18 @@ #ifndef GR_EDTHREADS_H_INCLUDED #define GR_EDTHREADS_H_INCLUDED #include -__CIDENT_RCSID(gr_edthreads_h,"$Id: edthreads.h,v 1.16 2021/04/03 03:42:53 cvsuser Exp $") +__CIDENT_RCSID(gr_edthreads_h,"$Id: edthreads.h,v 1.17 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edthreads.h,v 1.16 2021/04/03 03:42:53 cvsuser Exp $ +/* $Id: edthreads.h,v 1.17 2022/03/21 14:55:27 cvsuser Exp $ * Threads interface * ISO/IEC 9899:201x Committee Draft * April 12, 2011 N1570 * * * - * Copyright (c) 1998 - 2021, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edthreads_pthread.h b/include/edthreads_pthread.h index f94ec236..970241b8 100644 --- a/include/edthreads_pthread.h +++ b/include/edthreads_pthread.h @@ -1,11 +1,11 @@ #ifndef GR_EDTHREADS_PTHREAD_H_INCLUDED #define GR_EDTHREADS_PTHREAD_H_INCLUDED #include -__CIDENT_RCSID(gr_edthreads_pthread_h,"$Id: edthreads_pthread.h,v 1.9 2019/03/15 23:03:10 cvsuser Exp $") +__CIDENT_RCSID(gr_edthreads_pthread_h,"$Id: edthreads_pthread.h,v 1.10 2022/03/21 14:55:27 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edthreads_pthread.h,v 1.9 2019/03/15 23:03:10 cvsuser Exp $ +/* $Id: edthreads_pthread.h,v 1.10 2022/03/21 14:55:27 cvsuser Exp $ * Threads interface * ISO/IEC 9899:201x Committee Draft * April 12, 2011 N1570 @@ -86,7 +86,7 @@ __CPRAGMA_ONCE * which is returned by a function to indicate that the requested operation * failed because it was unable to allocate memory. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edthreads_win32.h b/include/edthreads_win32.h index ce5e595c..c26e269d 100644 --- a/include/edthreads_win32.h +++ b/include/edthreads_win32.h @@ -1,11 +1,11 @@ #ifndef GR_EDTHREADS_WIN32_H_INCLUDED #define GR_EDTHREADS_WIN32_H_INCLUDED #include -__CIDENT_RCSID(gr_edthreads_win32_h,"$Id: edthreads_win32.h,v 1.16 2020/06/18 12:51:29 cvsuser Exp $") +__CIDENT_RCSID(gr_edthreads_win32_h,"$Id: edthreads_win32.h,v 1.17 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edthreads_win32.h,v 1.16 2020/06/18 12:51:29 cvsuser Exp $ +/* $Id: edthreads_win32.h,v 1.17 2022/03/21 14:55:28 cvsuser Exp $ * Threads interface * ISO/IEC 9899:201x Committee Draft * April 12, 2011 N1570 @@ -86,7 +86,7 @@ __CPRAGMA_ONCE * which is returned by a function to indicate that the requested operation * failed because it was unable to allocate memory. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edtrace.h b/include/edtrace.h index 980011ee..8f4eb9ac 100644 --- a/include/edtrace.h +++ b/include/edtrace.h @@ -1,16 +1,16 @@ #ifndef GR_EDTRACE_H_INCLUDED #define GR_EDTRACE_H_INCLUDED #include -__CIDENT_RCSID(gr_edtrace_h,"$Id: edtrace.h,v 1.28 2019/03/15 23:03:10 cvsuser Exp $") +__CIDENT_RCSID(gr_edtrace_h,"$Id: edtrace.h,v 1.29 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edtrace.h,v 1.28 2019/03/15 23:03:10 cvsuser Exp $ +/* $Id: edtrace.h,v 1.29 2022/03/21 14:55:28 cvsuser Exp $ * trace log. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/edtypes.h b/include/edtypes.h index 8255ab4c..44cade2e 100644 --- a/include/edtypes.h +++ b/include/edtypes.h @@ -1,16 +1,16 @@ #ifndef GR_EDTYPES_H_INCLUDED #define GR_EDTYPES_H_INCLUDED #include -__CIDENT_RCSID(gr_edtypes_h,"$Id: edtypes.h,v 1.36 2020/04/21 21:19:41 cvsuser Exp $") +__CIDENT_RCSID(gr_edtypes_h,"$Id: edtypes.h,v 1.39 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edtypes.h,v 1.36 2020/04/21 21:19:41 cvsuser Exp $ +/* $Id: edtypes.h,v 1.39 2022/03/21 14:55:28 cvsuser Exp $ * Editor base types. * * * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -130,8 +130,8 @@ typedef unsigned long u_long; typedef unsigned char uchar_t; typedef unsigned int uint_t; -typedef off_t FSIZE_t; /* Type for file/region sizes */ -typedef unsigned short KEY; /* Type for internal keystrokes */ +typedef off_t FSIZE_t; /* file/region sizes */ +typedef int32_t KEY; /* internal keystrokes */ #define LINEMAX 0x7fffffff diff --git a/include/iniparser.h b/include/iniparser.h index dd5b0f54..1dd44e9f 100644 --- a/include/iniparser.h +++ b/include/iniparser.h @@ -1,16 +1,16 @@ #ifndef GR_INIPARSER_H_INCLUDED #define GR_INIPARSER_H_INCLUDED #include -__CIDENT_RCSID(gr_iniparser_h,"$Id: iniparser.h,v 1.7 2019/03/15 23:03:10 cvsuser Exp $") +__CIDENT_RCSID(gr_iniparser_h,"$Id: iniparser.h,v 1.8 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: iniparser.h,v 1.7 2019/03/15 23:03:10 cvsuser Exp $ +/* $Id: iniparser.h,v 1.8 2022/03/21 14:55:28 cvsuser Exp $ * INI parser. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/libllist.h b/include/libllist.h index 6d33f346..26e782a9 100644 --- a/include/libllist.h +++ b/include/libllist.h @@ -1,16 +1,16 @@ #ifndef GR_LIBLLIST_H_INCLUDED #define GR_LIBLLIST_H_INCLUDED #include -__CIDENT_RCSID(gr_llist_h,"$Id: libllist.h,v 1.17 2019/03/15 23:03:10 cvsuser Exp $") +__CIDENT_RCSID(gr_llist_h,"$Id: libllist.h,v 1.18 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: libllist.h,v 1.17 2019/03/15 23:03:10 cvsuser Exp $ +/* $Id: libllist.h,v 1.18 2022/03/21 14:55:28 cvsuser Exp $ * Linked list management system * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/libmisc.h b/include/libmisc.h index da211531..651d8927 100644 --- a/include/libmisc.h +++ b/include/libmisc.h @@ -1,16 +1,16 @@ #ifndef GR_LIBMISC_H_INCLUDED #define GR_LIBMISC_H_INCLUDED #include -__CIDENT_RCSID(gr_libmisc_h,"$Id: libmisc.h,v 1.19 2019/03/15 23:03:10 cvsuser Exp $") +__CIDENT_RCSID(gr_libmisc_h,"$Id: libmisc.h,v 1.20 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: libmisc.h,v 1.19 2019/03/15 23:03:10 cvsuser Exp $ +/* $Id: libmisc.h,v 1.20 2022/03/21 14:55:28 cvsuser Exp $ * libmisc - Miscellaneous library functions. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/libsplay.h b/include/libsplay.h index 65179d68..51ae4c6e 100644 --- a/include/libsplay.h +++ b/include/libsplay.h @@ -1,11 +1,11 @@ #ifndef GR_LIBSPLAY_H_INCLUDED #define GR_LIBSPLAY_H_INCLUDED #include -__CIDENT_RCSID(gr_libsplay_h,"$Id: libsplay.h,v 1.19 2019/03/15 23:03:10 cvsuser Exp $") +__CIDENT_RCSID(gr_libsplay_h,"$Id: libsplay.h,v 1.20 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: libsplay.h,v 1.19 2019/03/15 23:03:10 cvsuser Exp $ +/* $Id: libsplay.h,v 1.20 2022/03/21 14:55:28 cvsuser Exp $ * A SPLAY tree is a self-adjusting binary search tree with the additional property that * recently accessed elements are quick to access again. It performs basic operations such as * insertion, look-up and removal in O(log n) amortized time. For many sequences of non-random @@ -23,7 +23,7 @@ __CPRAGMA_ONCE * Reference: https://www.cs.cmu.edu/~sleator/papers/self-adjusting.pdf * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/libstr.h b/include/libstr.h index 6e09dc0f..a7ea913b 100644 --- a/include/libstr.h +++ b/include/libstr.h @@ -1,16 +1,16 @@ #ifndef GR_LIBSTR_H_INCLUDED #define GR_LIBSTR_H_INCLUDED #include -__CIDENT_RCSID(gr_str_h,"$Id: libstr.h,v 1.22 2019/03/15 23:03:11 cvsuser Exp $") +__CIDENT_RCSID(gr_str_h,"$Id: libstr.h,v 1.23 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: libstr.h,v 1.22 2019/03/15 23:03:11 cvsuser Exp $ +/* $Id: libstr.h,v 1.23 2022/03/21 14:55:28 cvsuser Exp $ * libstr - String utility library. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/libtime.h b/include/libtime.h index d9283fcf..56a7c5f9 100644 --- a/include/libtime.h +++ b/include/libtime.h @@ -1,16 +1,16 @@ #ifndef GR_LIBTIME_H_INCLUDED #define GR_LIBTIME_H_INCLUDED #include -__CIDENT_RCSID(gr_libtime_h,"$Id: libtime.h,v 1.5 2019/03/15 23:03:11 cvsuser Exp $") +__CIDENT_RCSID(gr_libtime_h,"$Id: libtime.h,v 1.6 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: libtime.h,v 1.5 2019/03/15 23:03:11 cvsuser Exp $ +/* $Id: libtime.h,v 1.6 2022/03/21 14:55:28 cvsuser Exp $ * libtime - Miscellaneous time library functions. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/msvcversions.h b/include/msvcversions.h index 93daaaa5..49baacf2 100644 --- a/include/msvcversions.h +++ b/include/msvcversions.h @@ -1,14 +1,14 @@ #ifndef GR_MSVCVERSIONS_H_INCLUDED #define GR_MSVCVERSIONS_H_INCLUDED #include -__CIDENT_RCSID(gr_msvcversions_h,"$Id: msvcversions.h,v 1.2 2020/03/26 22:55:21 cvsuser Exp $") +__CIDENT_RCSID(gr_msvcversions_h,"$Id: msvcversions.h,v 1.3 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: msvcversions.h,v 1.2 2020/03/26 22:55:21 cvsuser Exp $ +/* $Id: msvcversions.h,v 1.3 2022/03/21 14:55:28 cvsuser Exp $ * _MSC_VER definitions * - * Copyright (c) 2017 - 2020, Adam Young. + * Copyright (c) 2017 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/patmatch.h b/include/patmatch.h index 8b70dbb7..e42a2be8 100644 --- a/include/patmatch.h +++ b/include/patmatch.h @@ -1,16 +1,16 @@ #ifndef GR_PATMATCH_H_INCLUDED #define GR_PATMATCH_H_INCLUDED #include -__CIDENT_RCSID(gr_patmatch_h,"$Id: patmatch.h,v 1.8 2020/03/27 18:08:15 cvsuser Exp $") +__CIDENT_RCSID(gr_patmatch_h,"$Id: patmatch.h,v 1.9 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: patmatch.h,v 1.8 2020/03/27 18:08:15 cvsuser Exp $ +/* $Id: patmatch.h,v 1.9 2022/03/21 14:55:28 cvsuser Exp $ * Simple pattern matching. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/stable.h b/include/stable.h index 6b4598db..e8d29cb0 100644 --- a/include/stable.h +++ b/include/stable.h @@ -1,11 +1,11 @@ #ifndef GR_STABLE_H_INCLUDED #define GR_STABLE_H_INCLUDED #include -__CIDENT_RCSID(gr_stable_h,"$Id: stable.h,v 1.11 2019/03/15 23:03:11 cvsuser Exp $") +__CIDENT_RCSID(gr_stable_h,"$Id: stable.h,v 1.12 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: stable.h,v 1.11 2019/03/15 23:03:11 cvsuser Exp $ +/* $Id: stable.h,v 1.12 2022/03/21 14:55:28 cvsuser Exp $ * Self-organising string hash data structure. * * This is a library of routines for storing a data structure where the @@ -13,7 +13,7 @@ __CPRAGMA_ONCE * hash using chaining to address clashes. Upon the key count exceeding the * fill factory, the hash shall extend by doubling in size. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/stype.h b/include/stype.h index 37bfc940..6b72fc47 100644 --- a/include/stype.h +++ b/include/stype.h @@ -1,11 +1,11 @@ #ifndef GR_STYPE_H_INCLUDED #define GR_STYPE_H_INCLUDED #include -__CIDENT_RCSID(gr_stype_h,"$Id: stype.h,v 1.11 2019/03/15 23:03:11 cvsuser Exp $") +__CIDENT_RCSID(gr_stype_h,"$Id: stype.h,v 1.12 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: stype.h,v 1.11 2019/03/15 23:03:11 cvsuser Exp $ +/* $Id: stype.h,v 1.12 2022/03/21 14:55:28 cvsuser Exp $ * Self-organising integer data structure * * library of routines for storing a data structure where the primary key is an integer. @@ -15,7 +15,7 @@ __CPRAGMA_ONCE * The implementation maintains an array of integer/pointer pairs, which is sorted * into order every when necessary; allowing access in numerical order. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/vm_alloc.h b/include/vm_alloc.h index eccf9736..c9032329 100644 --- a/include/vm_alloc.h +++ b/include/vm_alloc.h @@ -1,15 +1,15 @@ #ifndef GR_VM_ALLOC_H_INCLUDED #define GR_VM_ALLOC_H_INCLUDED #include -__CIDENT_RCSID(gr_vm_alloc_h,"$Id: vm_alloc.h,v 1.12 2019/03/15 23:03:11 cvsuser Exp $") +__CIDENT_RCSID(gr_vm_alloc_h,"$Id: vm_alloc.h,v 1.13 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vm_alloc.h,v 1.12 2019/03/15 23:03:11 cvsuser Exp $ +/* $Id: vm_alloc.h,v 1.13 2022/03/21 14:55:28 cvsuser Exp $ * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/include/vtype.h b/include/vtype.h index db8dc5f7..d7ec0964 100644 --- a/include/vtype.h +++ b/include/vtype.h @@ -1,16 +1,16 @@ #ifndef GR_VTYPE_H_INCLUDED #define GR_VTYPE_H_INCLUDED #include -__CIDENT_RCSID(gr_vtype_h,"$Id: vtype.h,v 1.10 2019/03/15 23:03:11 cvsuser Exp $") +__CIDENT_RCSID(gr_vtype_h,"$Id: vtype.h,v 1.11 2022/03/21 14:55:28 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vtype.h,v 1.10 2019/03/15 23:03:11 cvsuser Exp $ +/* $Id: vtype.h,v 1.11 2022/03/21 14:55:28 cvsuser Exp $ * Self-organising integer vector data structure. * * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libbsdio/.cvsignore b/libbsdio/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/libbsdio/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/libbsdio/vfprintf.c b/libbsdio/vfprintf.c index 7e5e424f..ac1ae85e 100644 --- a/libbsdio/vfprintf.c +++ b/libbsdio/vfprintf.c @@ -42,9 +42,9 @@ #endif //disabled functionality -// USE_MBRTOWC -// USE_MMAP -// USE_DTOA +// USE_MBRTOWC +// USE_MMAP +// USE_DTOA #ifdef HAVE_STDARG_H #include diff --git a/libchartable/.cvsignore b/libchartable/.cvsignore index ee27b282..e32c4822 100644 --- a/libchartable/.cvsignore +++ b/libchartable/.cvsignore @@ -1,7 +1,11 @@ Makefile +*.err charsetdesc.h +charsetdict.h charsetlocales.h charsetnames.h charsettables.h +charsettable.* cnvtables data +ref diff --git a/libchartable/.gitignore b/libchartable/.gitignore index 86ec5a1a..656b59ed 100644 --- a/libchartable/.gitignore +++ b/libchartable/.gitignore @@ -1,6 +1,7 @@ charsetdesc.h +charsetdict.h charsetlocales.h charsetnames.h charsettables.h cnvtables/ -data/ \ No newline at end of file +data/ diff --git a/libchartable/Makefile.in b/libchartable/Makefile.in index e9612cb1..cbe8db6f 100644 --- a/libchartable/Makefile.in +++ b/libchartable/Makefile.in @@ -1,9 +1,9 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.24 2020/06/18 20:35:17 cvsuser Exp $ +# $Id: Makefile.in,v 1.29 2022/03/21 15:11:49 cvsuser Exp $ # libchartable makefile. # # -# Copyright (c) 2010 - 2020, Adam Young. +# Copyright (c) 2010 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. @@ -126,8 +126,9 @@ CTBLOBJS=\ $(D_OBJ)/charsetutf32$(O) \ $(D_OBJ)/charsetutf16$(O) \ $(D_OBJ)/charsetutf8$(O) \ - $(D_OBJ)/charsetwidth$(O) \ - $(D_OBJ)/charsetwidth_cjk$(O) + $(D_OBJ)/charsetwidth_cjk$(O) \ + \ + $(D_OBJ)/utf8$(O) MODULES= $(notdir $(basename $(wildcard cnvtables/cx*.c))) @@ -153,6 +154,7 @@ debug: $(CTBLLIB): charsetlocales.h \ charsettable.c \ + charsetdesc.h \ $(D_OBJ)/.created \ $(CTBLOBJS) $(RM) $(RMFLAGS) $@ @@ -170,7 +172,7 @@ charsetlocales.h: makelocale.pl charsettable.c: charsettables.h -charsettables.h: makechartable.pl cnvtables/.created +charsetdesc.h charsettables.h: makechartable.pl cnvtables/.created @echo building character tables $(PERL) makechartable.pl --crunch --dynamic --packaged @@ -182,12 +184,11 @@ data/.import: data/.created \ data/MAPPINGS/.import \ data/Unihan.zip \ data/UCD.zip \ - data/uniset.tar.gz \ - data/Zeichenreferenz + data/uniset.tar.gz @echo "++ do not delete, managed content ++" > $@ data/MAPPINGS/.import: data/MAPPINGS/.created - $(WGET) -P data -r -nv -nH -e robots=off --cut-dirs=1 --no-parent --reject "index.html.*" http://ftp.unicode.org/Public/MAPPINGS/ + $(WGET) -P data -r -nv -nH -e robots=off --cut-dirs=1 --no-parent --reject "index.html?*" http://ftp.unicode.org/Public/MAPPINGS/ @echo "++ do not delete, managed content ++" > $@ data/Unihan.zip: diff --git a/libchartable/charsetalias.c b/libchartable/charsetalias.c index 4a918c63..3d4704a5 100644 --- a/libchartable/charsetalias.c +++ b/libchartable/charsetalias.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetalias_c,"$Id: charsetalias.c,v 1.13 2020/06/18 13:10:35 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetalias_c,"$Id: charsetalias.c,v 1.14 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* Locale/multibyte character information. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libchartable/charsetcurrent.c b/libchartable/charsetcurrent.c index a81a82c8..03f269e6 100644 --- a/libchartable/charsetcurrent.c +++ b/libchartable/charsetcurrent.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetcurrent_c,"$Id: charsetcurrent.c,v 1.9 2020/06/18 13:10:35 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetcurrent_c,"$Id: charsetcurrent.c,v 1.10 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* libcharset current. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libchartable/charsetfstream.c b/libchartable/charsetfstream.c index c536f0a1..e41b80ef 100644 --- a/libchartable/charsetfstream.c +++ b/libchartable/charsetfstream.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetfstream_c,"$Id: charsetfstream.c,v 1.8 2018/10/01 22:10:52 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetfstream_c,"$Id: charsetfstream.c,v 1.9 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* iconv FILE stream support. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libchartable/charseticonv.c b/libchartable/charseticonv.c index 324fb36f..0ceee410 100644 --- a/libchartable/charseticonv.c +++ b/libchartable/charseticonv.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charseticonv_c,"$Id: charseticonv.c,v 1.19 2020/06/18 13:10:07 cvsuser Exp $") +__CIDENT_RCSID(gr_charseticonv_c,"$Id: charseticonv.c,v 1.22 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* Conversion tables loader/interface. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -45,6 +45,8 @@ __CIDENT_RCSID(gr_charseticonv_c,"$Id: charseticonv.c,v 1.19 2020/06/18 13:10:07 #include #include +#include /* str_...()/sxprintf() */ + #if defined(ENOSYS) #define ENOTSUPPORTED ENOSYS #elif defined(ENOTSUP) @@ -223,10 +225,10 @@ charset_iconv_open(const char *name, int flags) namelen = strlen(name); if (NULL != (mod = strchr(name, '/'))) { /* giconv style modifiers */ - if (0 == strcmp(mod, "//TRANSLIT")) { + if (0 == str_icmp(mod, "//TRANSLIT")) { flags |= CS_ICONV_TRANSLIT; - } else if (0 == strcmp(mod, "//IGNORE")) { + } else if (0 == str_icmp(mod, "//IGNORE")) { flags |= CS_ICONV_IGNORE; } namelen = mod - name; /* remove modifier */ @@ -241,12 +243,12 @@ charset_iconv_open(const char *name, int flags) unsigned i; if (NULL != (charset = charset_canonicalize(name, namelen, canon_buffer, sizeof(canon_buffer))) || - NULL != (charset = charset_alias_lookup(name, namelen))) { - charsetlen = strlen(charset); - if (charsetlen == namelen && 0 == charset_compare(charset, name, namelen)) { - charset = NULL; - } - } + NULL != (charset = charset_alias_lookup(name, namelen))) { + charsetlen = strlen(charset); + if (charsetlen == namelen && 0 == charset_compare(charset, name, namelen)) { + charset = NULL; + } + } if (NULL != (dlmod = dlmod_byname(name, namelen)) || (charset && NULL != (dlmod = dlmod_byname(charset, charsetlen)))) { @@ -388,7 +390,7 @@ iconv_alloc(struct dlmodule *dlmod, int flags) if (CHARTABLE_SIGNATURE(CHARTABLE_CCS, 0x100) == signature) { ic->ic_desc = dlmod->dl_names[0]; ic->ic_data = cm->cm_desc; - ic->ic_decode = ccs1_decode; + ic->ic_decode = ccs1_decode; ic->ic_encode = ccs1_encode; ic->ic_import = ccs1_import; ic->ic_export = ccs1_export; @@ -492,7 +494,7 @@ ccs1_export(struct charset_iconv *ic, const char **inbuf, size_t *inbytes, char const char *end; int32_t raw, ch; - if (NULL == (end = charset_utf8_decode(icursor, icursor + icount, &ch, &raw))) { + if (NULL == (end = charset_utf8_decode_cook(icursor, icursor + icount, &ch, &raw))) { errno = EINVAL; /* an complete sequence */ res = (size_t)-1; break; @@ -740,7 +742,7 @@ dlmod_byname(const char *name, int namelen) const char **names = dlmod->dl_names; if (names) { - const char *charset; + const char *charset; while (NULL != (charset = *names++)) { if (0 == charset_compare(charset, name, namelen)) { @@ -912,5 +914,5 @@ dospath(char *path) } *path = 0; } -#endif /*WIN32*/ +#endif /*WIN32*/ /*end*/ diff --git a/libchartable/charsetistream.c b/libchartable/charsetistream.c index 7ce8b134..ab4ee43c 100644 --- a/libchartable/charsetistream.c +++ b/libchartable/charsetistream.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetistream_c,"$Id: charsetistream.c,v 1.10 2020/06/18 13:09:48 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetistream_c,"$Id: charsetistream.c,v 1.11 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* iconv stream support. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libchartable/charsetlocale.c b/libchartable/charsetlocale.c index a6f81669..838022bd 100644 --- a/libchartable/charsetlocale.c +++ b/libchartable/charsetlocale.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetlocale_c,"$Id: charsetlocale.c,v 1.10 2018/10/01 22:10:52 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetlocale_c,"$Id: charsetlocale.c,v 1.11 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* libcharset locale map. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libchartable/charsetstream.c b/libchartable/charsetstream.c index 7c7be21e..5546085e 100644 --- a/libchartable/charsetstream.c +++ b/libchartable/charsetstream.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetstream_c,"$Id: charsetstream.c,v 1.10 2018/10/01 22:10:52 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetstream_c,"$Id: charsetstream.c,v 1.12 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* conversion stream support. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -172,10 +172,11 @@ iconv_stream_open(iconv_cvtfn_t cnvfn, void *cd, iconv_rdfn_t rdfn, iconv_wrfn_t { iconv_stream_t *s; - if (NULL == (s = (iconv_stream_t *)malloc(sizeof(iconv_stream_t)))) { + if (NULL == (s = (iconv_stream_t *)calloc(sizeof(iconv_stream_t), 1))) { return NULL; } s->s_iconv = cnvfn; + s->s_ierrno = NULL; s->s_cd = cd; s->s_inbytes = 0; s->s_outbytes = 0; diff --git a/libchartable/charsettable.c b/libchartable/charsettable.c index 11949b1d..3da277aa 100644 --- a/libchartable/charsettable.c +++ b/libchartable/charsettable.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsettable_c,"$Id: charsettable.c,v 1.13 2018/10/01 22:10:52 cvsuser Exp $") +__CIDENT_RCSID(gr_charsettable_c,"$Id: charsettable.c,v 1.16 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* conversion tables. * * - * Copyright (c) 2012 - 2018, Adam Young. + * Copyright (c) 2012 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -121,27 +121,43 @@ done:; const char * -charset_description(int32_t ch, char *buffer, int buflen) +charset_description(int32_t unicode, char *buffer, int buflen) { - if (ch >= 0) { - const unsigned char *desc = charsetdesc((uint32_t)ch); + if (unicode >= 0) { + const unsigned char *desc = charsetdesc((uint32_t)unicode); if (desc) { char *cursor = buffer, *end = cursor + (buflen - 1); unsigned char dc; + int32_t idx; while (0 != (dc = *desc) && (cursor < end)) { if (dc >= 0x60) { /* word reference, UFT8 encoded character */ - desc = utf8_decode(desc, &ch); + desc = utf8_decode(desc, &idx); - if ((ch -= 0x60) >= 0 && - ch < (sizeof(x_charsetdesc_words)/sizeof(x_charsetdesc_words[0]))) { + if ((idx -= 0x60) >= 0 && + idx < (sizeof(x_charsetdesc_words)/sizeof(x_charsetdesc_words[0]))) { - const char *word = x_charsetdesc_words[ch]; + const char *word = x_charsetdesc_words[idx]; + + if (*word == '-') { /* leading '-', join previous word */ + if (cursor > buffer && cursor[-1] == ' ') { + --cursor; + } + } while (0 != (dc = *word++) && (cursor < end)) { + if ('#' == dc) { /* inline character-value */ + char t_charvalue[16], *charvalue = t_charvalue; + + sprintf(t_charvalue, "%X", (unsigned)unicode); + while (0 != (dc = *charvalue++) && (cursor < end)) { + *cursor++ = dc; + } + continue; + } *cursor++ = dc; } @@ -154,6 +170,11 @@ charset_description(int32_t ch, char *buffer, int buflen) } } else { + if (dc == '-') { /* leading '-', join previous word */ + if (cursor > buffer && cursor[-1] == ' ') { + --cursor; + } + } *cursor++ = dc; /* character literal */ ++desc; } @@ -172,6 +193,7 @@ charset_description(int32_t ch, char *buffer, int buflen) // // test framework // +#include "./charsetdict.h" #include static size_t @@ -181,6 +203,7 @@ sizearray(const char **array) for (;*array;++array) { bytes += strlen(*array) + 1; //non-unique string!!; } + return bytes; } void diff --git a/libchartable/charsetutf16.c b/libchartable/charsetutf16.c index f8a49798..cdf5f41b 100644 --- a/libchartable/charsetutf16.c +++ b/libchartable/charsetutf16.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetutf16_c,"$Id: charsetutf16.c,v 1.10 2018/10/01 22:10:53 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetutf16_c,"$Id: charsetutf16.c,v 1.12 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* Multibyte character - UTF16 utility functionality. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -101,7 +101,7 @@ utf16_legal(const int32_t ch) } return 1; } - + const void * charset_utf16_decode(int endian, const void *src, const void *cpend, int32_t *cooked, int32_t *raw) diff --git a/libchartable/charsetutf32.c b/libchartable/charsetutf32.c index ea26dfc3..6c8db616 100644 --- a/libchartable/charsetutf32.c +++ b/libchartable/charsetutf32.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetutf32_c,"$Id: charsetutf32.c,v 1.12 2020/06/18 13:11:40 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetutf32_c,"$Id: charsetutf32.c,v 1.13 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* Multibyte character - UTF32 utility functionality. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libchartable/charsetutf8.c b/libchartable/charsetutf8.c index d22635f9..c612809a 100644 --- a/libchartable/charsetutf8.c +++ b/libchartable/charsetutf8.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetutf8_c,"$Id: charsetutf8.c,v 1.13 2018/10/01 22:10:53 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetutf8_c,"$Id: charsetutf8.c,v 1.20 2022/03/21 14:59:57 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* Multibyte character - UTF8 utility functionality. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -54,17 +54,26 @@ static __CINLINE int utf8_overlong(const int32_t ch, const size_t length) { if (ch <= 0x80) { - if (1 != length) return TRUE; + if (1 != length) + return TRUE; } else if (ch < 0x800) { - if (2 != length) return TRUE; + if (2 != length) + return TRUE; } else if (ch < 0x10000) { - if (3 != length) return TRUE; + if (3 != length) + return TRUE; } else if (ch < 0x200000) { - if (4 != length) return TRUE; - } else if (ch < 0x4000000) { - if (5 != length) return TRUE; + if (4 != length) + return TRUE; } else { - if (6 != length) return TRUE; +// if (ch < 0x4000000) { +// if (5 != length) +// return TRUE; +// } else { +// if (6 != length) +// return TRUE; +// } + return TRUE; // RFC 3629, <= 4 bytes } return FALSE; } @@ -125,8 +134,8 @@ utf8_decode(const void *src, const void *cpend, int32_t *result) ret = ch & 0x01; } else { /* invalid continuation (0x80 - 0xbf). */ + remain = 0; ret = -ch; - goto done; } while (remain--) { @@ -154,7 +163,14 @@ done:; const void * -charset_utf8_decode(const void *src, const void *cpend, int32_t *cooked, int32_t *raw) +charset_utf8_decode(const void *src, const void *cpend, int32_t *raw) +{ + return utf8_decode(src, cpend, raw); +} + + +const void * +charset_utf8_decode_cook(const void *src, const void *cpend, int32_t *cooked, int32_t *raw) { int32_t result = 0; const char *ret = utf8_decode(src, cpend, &result); @@ -185,6 +201,32 @@ charset_utf8_decode_safe(const void *src, const void *cpend, int32_t *cooked) } +int +charset_utf8_count(const void *src, const void *cpend) +{ + int result = 0; + const void *end; + int32_t wch; + + while (src < cpend) { + if ((end = charset_utf8_decode_safe(src, cpend, &wch)) > src) { + ++result; + src = end; + continue; + } + break; + } + return result; +} + + +int +charset_utf8_scount(const void *src) +{ + return charset_utf8_count(src, (const char *)src + strlen((const char *)src)); +} + + int charset_utf8_length(const int32_t ch) { @@ -256,4 +298,5 @@ charset_utf8_encode(const int32_t ch, void *buffer) } return count; } + /*end*/ diff --git a/libchartable/charsetutil.c b/libchartable/charsetutil.c index 034dc09c..eef37aca 100644 --- a/libchartable/charsetutil.c +++ b/libchartable/charsetutil.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_charsetutil_c,"$Id: charsetutil.c,v 1.11 2020/06/18 13:09:28 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetutil_c,"$Id: charsetutil.c,v 1.12 2022/03/21 14:59:58 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* utility functions. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libchartable/charsetwidth.c b/libchartable/charsetwidth.c deleted file mode 100644 index 2a8f47bf..00000000 --- a/libchartable/charsetwidth.c +++ /dev/null @@ -1,455 +0,0 @@ -#include -__CIDENT_RCSID(gr_charsetwidth_c,"$Id: charsetwidth.c,v 1.12 2018/10/01 22:10:53 cvsuser Exp $") - -/* -*- mode: c; indent-width: 4; -*- */ -/* - * This is an implementation of wcwidth() and wcswidth() - * (defined in IEEE Std 1002.1-2001) for Unicode. - * - * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html - * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html - * - * In fixed-width output devices, Latin characters all occupy a single "cell" position of - * equal width, whereas ideographic CJK characters occupy two such cells. Interoperability - * between terminal-line applications and (teletype-style) character terminals using the - * UTF-8 encoding requires agreement on which character should advance the cursor by how - * many cell positions. No established formal standards exist at present on which Unicode - * character shall occupy how many cell positions on character terminals. These routines - * are a first attempt of defining such behavior based on simple rules applied to data - * provided by the Unicode Consortium. - * - * For some graphical characters, the Unicode standard explicitly defines a character-cell - * width via the definition of the East Asian FullWidth (F), Wide (W), Half-width (H), and - * Narrow (Na) classes. In all these cases, there is no ambiguity about which width a - * terminal shall use. For characters in the East Asian Ambiguous (A) class, the width - * choice depends purely on a preference of backward compatibility with either historic CJK - * or Western practice. Choosing single-width for these characters is easy to justify as - * the appropriate long-term solution, as the CJK practice of displaying these characters - * as double-width comes from historic implementation simplicity (8-bit encoded characters - * were displayed single-width and 16-bit ones double-width, even for Greek, Cyrillic, - * etc.) and not any typographic considerations. - * - * Much less clear is the choice of width for the Not East Asian (Neutral) class. Existing - * practice does not dictate a width for any of these characters. It would nevertheless - * make sense typographically to allocate two character cells to characters such as for - * instance EM SPACE or VOLUME INTEGRAL, which cannot be represented adequately with a - * single-width glyph. The following routines at present merely assign a single-cell width - * to all neutral characters, in the interest of simplicity. This is not entirely - * satisfactory and should be reconsidered before establishing a formal standard in this - * area. At the moment, the decision which Not East Asian (Neutral) characters should be - * represented by double-width glyphs cannot yet be answered by applying a simple rule from - * the Unicode database content. Setting up a proper standard for the behavior of UTF-8 - * character terminals will require a careful analysis not only of each Unicode character, - * but also of each presentation form, something the author of these routines has avoided - * to do so far. - * - * http://www.unicode.org/unicode/reports/tr11/ - * - * Markus Kuhn -- 2007-05-26 (Unicode 5.0) - * - * Permission to use, copy, modify, and distribute this software for any purpose and - * without fee is hereby granted. The author disclaims all warranties with regard to this - * software. - * - * Latest version: - * http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - * - * Copyright (c) 2010 - 2018, Adam Young. - * All rights reserved. - * - * This file is part of the GRIEF Editor. - * - * The GRIEF Editor is free software: you can redistribute it - * and/or modify it under the terms of the GRIEF Editor License. - * - * Redistributions of source code must retain the above copyright - * notice, and must be distributed with the license document above. - * - * Redistributions in binary form must reproduce the above copyright - * notice, and must include the license document above in - * the documentation and/or other materials provided with the - * distribution. - * - * The GRIEF Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. - * ==end== - */ - -#include -#include "libchartable.h" - -#define USYSTEM 0 -#define U300 0 -#define U500 0 /* xterm */ -#define U600 1 /* gnome-term */ - -struct interval { - int32_t first; - int32_t last; -}; - - -#if (U300) -/* - * Unicode 3 - older xterm.kconsole. - */ -static const struct interval U300_combining[] = { - { 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 }, - { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 }, - { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, - { 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 }, - { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, - { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, - { 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C }, - { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 }, - { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, - { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, - { 0x0A02, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, - { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, - { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, - { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 }, - { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, - { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, - { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, - { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, - { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, - { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA }, - { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, - { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, - { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, - { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, - { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, - { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC }, - { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 }, - { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 }, - { 0x1160, 0x11FF }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 }, - { 0x17C9, 0x17D3 }, { 0x180B, 0x180E }, { 0x18A9, 0x18A9 }, - { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x206A, 0x206F }, - { 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A }, - { 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, - { 0xFFF9, 0xFFFB } - }; -#endif - -#if (U500) -/* - * Unicode 5 - * - * sorted list of non-overlapping intervals of non-spacing characters - * generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" - */ -static const struct interval U500_combining[] = { - { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, - { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, - { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, - { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, - { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, - { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, - { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, - { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, - { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, - { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, - { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, - { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, - { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, - { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, - { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, - { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, - { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, - { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, - { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, - { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, - { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, - { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, - { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, - { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, - { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, - { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, - { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, - { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, - { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, - { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, - { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, - { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, - { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, - { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, - { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, - { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, - { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, - { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, - { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, - { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, - { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, - { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, - { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, - { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, - { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, - { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, - { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, - { 0xE0100, 0xE01EF } - }; -#endif - -#if (U600) -static const struct interval U600_combining[] = { - { 0x0300, 0x036F }, { 0x0483, 0x0489 }, { 0x0591, 0x05BD }, - { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05C4, 0x05C5 }, - { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, { 0x0610, 0x061A }, - { 0x064B, 0x065F }, { 0x0670, 0x0670 }, { 0x06D6, 0x06DD }, - { 0x06DF, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, - { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, - { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0816, 0x0819 }, - { 0x081B, 0x0823 }, { 0x0825, 0x0827 }, { 0x0829, 0x082D }, - { 0x0859, 0x085B }, { 0x0900, 0x0902 }, { 0x093A, 0x093A }, - { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, - { 0x0951, 0x0957 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, - { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, - { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, - { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, - { 0x0A51, 0x0A51 }, { 0x0A70, 0x0A71 }, { 0x0A75, 0x0A75 }, - { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, - { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0AE2, 0x0AE3 }, - { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, - { 0x0B41, 0x0B44 }, { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, - { 0x0B62, 0x0B63 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, - { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, - { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0C62, 0x0C63 }, - { 0x0CBC, 0x0CBC }, { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, - { 0x0CCC, 0x0CCD }, { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D44 }, - { 0x0D4D, 0x0D4D }, { 0x0D62, 0x0D63 }, { 0x0DCA, 0x0DCA }, - { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, - { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, - { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, - { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, - { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, - { 0x0F86, 0x0F87 }, { 0x0F8D, 0x0F97 }, { 0x0F99, 0x0FBC }, - { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1037 }, - { 0x1039, 0x103A }, { 0x103D, 0x103E }, { 0x1058, 0x1059 }, - { 0x105E, 0x1060 }, { 0x1071, 0x1074 }, { 0x1082, 0x1082 }, - { 0x1085, 0x1086 }, { 0x108D, 0x108D }, { 0x109D, 0x109D }, - { 0x1160, 0x11FF }, { 0x135D, 0x135F }, { 0x1712, 0x1714 }, - { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, { 0x1772, 0x1773 }, - { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 }, - { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, { 0x180B, 0x180D }, - { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, { 0x1927, 0x1928 }, - { 0x1932, 0x1932 }, { 0x1939, 0x193B }, { 0x1A17, 0x1A18 }, - { 0x1A56, 0x1A56 }, { 0x1A58, 0x1A5E }, { 0x1A60, 0x1A60 }, - { 0x1A62, 0x1A62 }, { 0x1A65, 0x1A6C }, { 0x1A73, 0x1A7C }, - { 0x1A7F, 0x1A7F }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, - { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, - { 0x1B6B, 0x1B73 }, { 0x1B80, 0x1B81 }, { 0x1BA2, 0x1BA5 }, - { 0x1BA8, 0x1BA9 }, { 0x1BE6, 0x1BE6 }, { 0x1BE8, 0x1BE9 }, - { 0x1BED, 0x1BED }, { 0x1BEF, 0x1BF1 }, { 0x1C2C, 0x1C33 }, - { 0x1C36, 0x1C37 }, { 0x1CD0, 0x1CD2 }, { 0x1CD4, 0x1CE0 }, - { 0x1CE2, 0x1CE8 }, { 0x1CED, 0x1CED }, { 0x1DC0, 0x1DE6 }, - { 0x1DFC, 0x1DFF }, { 0x200B, 0x200F }, { 0x202A, 0x202E }, - { 0x2060, 0x2064 }, { 0x206A, 0x206F }, { 0x20D0, 0x20F0 }, - { 0x2CEF, 0x2CF1 }, { 0x2D7F, 0x2D7F }, { 0x2DE0, 0x2DFF }, - { 0x302A, 0x302F }, { 0x3099, 0x309A }, { 0xA66F, 0xA672 }, - { 0xA67C, 0xA67D }, { 0xA6F0, 0xA6F1 }, { 0xA802, 0xA802 }, - { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, { 0xA825, 0xA826 }, - { 0xA8C4, 0xA8C4 }, { 0xA8E0, 0xA8F1 }, { 0xA926, 0xA92D }, - { 0xA947, 0xA951 }, { 0xA980, 0xA982 }, { 0xA9B3, 0xA9B3 }, - { 0xA9B6, 0xA9B9 }, { 0xA9BC, 0xA9BC }, { 0xAA29, 0xAA2E }, - { 0xAA31, 0xAA32 }, { 0xAA35, 0xAA36 }, { 0xAA43, 0xAA43 }, - { 0xAA4C, 0xAA4C }, { 0xAAB0, 0xAAB0 }, { 0xAAB2, 0xAAB4 }, - { 0xAAB7, 0xAAB8 }, { 0xAABE, 0xAABF }, { 0xAAC1, 0xAAC1 }, - { 0xABE5, 0xABE5 }, { 0xABE8, 0xABE8 }, { 0xABED, 0xABED }, - { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, { 0xFE20, 0xFE26 }, - { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, { 0x101FD, 0x101FD }, - { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, - { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x11001, 0x11001 }, - { 0x11038, 0x11046 }, { 0x11080, 0x11081 }, { 0x110B3, 0x110B6 }, - { 0x110B9, 0x110BA }, { 0x110BD, 0x110BD }, { 0x1D167, 0x1D169 }, - { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, - { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, - { 0xE0100, 0xE01EF } - }; -#endif - -#if (U600) -static const struct interval U600_wide[] = { - /* sorted list of wide characters */ - { 0x1100, 0x1159 }, { 0x115f, 0x115f }, - { 0x2329, 0x232a }, - { 0x2e80, 0x2e99 }, { 0x2e9b, 0x2ef3 }, - { 0x2f00, 0x2fd5 }, { 0x2ff0, 0x2ffb }, - { 0x3000, 0x303e }, { 0x3041, 0x3096 }, { 0x3099, 0x30ff }, { 0x3105, 0x312d }, - { 0x3131, 0x318e }, { 0x3190, 0x31b7 }, { 0x31c0, 0x31e3 }, { 0x31f0, 0x321e }, - { 0x3220, 0x3243 }, { 0x3250, 0x32fe }, { 0x3300, 0x4db5 }, - { 0x4e00, 0x9fc3 }, - { 0xa000, 0xa48c }, { 0xa490, 0xa4c6 }, - { 0xac00, 0xd7a3 }, - { 0xf900, 0xfa2d }, - { 0xfa30, 0xfa6a }, { 0xfa70, 0xfad9 }, - { 0xfe10, 0xfe19 }, { 0xfe30, 0xfe52 }, { 0xfe54, 0xfe66 }, { 0xfe68, 0xfe6b }, - { 0xff01, 0xff60 }, { 0xffe0, 0xffe6 }, - { 0x20000, 0x2fffd }, { 0x30000, 0x3fffd } - }; -#endif - - -/* - * auxiliary function for binary search in interval table - */ -static __CINLINE int -bisearch(const wchar_t ucs, const struct interval *table, int max) -{ - if (ucs >= table[0].first && ucs <= table[max].last) { - int mid, min = 0; - - while (max >= min) { - mid = (min + max) / 2; - if (ucs > table[mid].last) { - min = mid + 1; - } else if (ucs < table[mid].first) { - max = mid - 1; - } else { - return 1; - } - } - } - return 0; -} - - -/* - * The following two functions define the column width of an ISO 10646 - * character as follows: - * - * - The null character (U+0000) has a column width of 0. - * - * - Other C0/C1 control characters and DEL will lead to a return - * value of -1. - * - * - Non-spacing and enclosing combining characters (general - * category code Mn or Me in the Unicode database) have a - * column width of 0. - * - * - SOFT HYPHEN (U+00AD) has a column width of 1. - * - * - Other format characters (general category code Cf in the Unicode - * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. - * - * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) - * have a column width of 0. - * - * - Spacing characters in the East Asian Wide (W) or East Asian - * Full-width (F) category as defined in Unicode Technical - * Report #11 have a column width of 2. - * - * - All remaining characters (including all printable - * ISO 8859-1 and WGL4 characters, Unicode control characters, - * etc.) have a column width of 1. - * - * This implementation assumes that wchar_t characters are encoded in ISO 10646. - */ -int -charset_width_ucs(int32_t ucs, int bad) -{ - /* test for 8-bit control characters */ - if (0 == ucs) { - return 0; /* nul */ - } - - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) { - return bad; /* non UNICODE */ - } - -#if (USYSTEM) - return wcwidth(ucs); -#endif - -#if (U300) - /* width data version <= U300 */ - - /* binary search ucs against table of non-spacing characters */ - if (bisearch(ucs, U300_combining, (sizeof(U300_combining)/sizeof(U300_combining[0]))-1)) { - return 0; - } - - /* ucs is neither a combining or C0/C1 control character */ - const int plane_2_double_width = 1; - if (ucs < 0x1100) return 1; /* base range check */ - return 1 + - /* Wide character ranges - * Unicode 3.0 - * wcwidth 2001-01-12 - * xterm 157 ... 166 - * - * Sourced from the earlier wcwidth version (2001.01.12) - */ - (ucs >= 0x1100 && ucs <= 0x115f) || /* Hangul Jamo */ - (ucs >= 0x2e80 && ucs <= 0xa4cf && /* CJK ... Yi */ - (ucs & (uint32_t) ~0x0011) != 0x300a && ucs != 0x303f) || - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2ffff && - plane_2_double_width); /* missing before xterm 157 */ -#endif - -#if (U500) - /* binary search ucs against table of non-spacing characters */ - if (bisearch(ucs, U500_combining, (sizeof(U500_combining)/sizeof(U500_combining[0]))-1)) { - return 0; - } - - /* ucs is neither a combining or C0/C1 control character */ - return 1 + - /* wide character ranges - * Unicode 3.2 - * wcwidth 2002-05-08 - * xterm 167 ... 179 - * Unicode 4.0 - * wcwidth 2003-05-20 - * xterm 180 ... 225 - * Unicode 4.1 - * wcwidth 2007-05-25 - * xterm 226 ... - */ - (ucs >= 0x1100 && - (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - ucs == 0x2329 || ucs == 0x232a || /* CJK ... Yi */ - (ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ - (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2fffd) || - (ucs >= 0x30000 && ucs <= 0x3fffd))); -#endif - -#if (U600) - if (bisearch(ucs, U600_combining, (sizeof(U600_combining)/sizeof(U600_combining[0]))-1)) { - return 0; - } - - if (bisearch(ucs, U600_wide, (sizeof(U600_wide)/sizeof(U600_wide[0]))-1)) { - return 2; - } - return 1; -#endif -} - - -int -charset_swidth_ucs(const int32_t *pwcs, size_t n) -{ - int w, width = 0; - - for (;*pwcs && n-- > 0; ++pwcs) { - if ((w = charset_width_ucs(*pwcs, -1)) < 0) { - return -1; - } - width += w; - } - return width; -} -/*end*/ diff --git a/libchartable/charsetwidth_cjk.c b/libchartable/charsetwidth_cjk.c index 252d2598..8824d8cb 100644 --- a/libchartable/charsetwidth_cjk.c +++ b/libchartable/charsetwidth_cjk.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_charsetwidth_cjk_c,"$Id: charsetwidth_cjk.c,v 1.13 2018/10/01 22:10:53 cvsuser Exp $") +__CIDENT_RCSID(gr_charsetwidth_cjk_c,"$Id: charsetwidth_cjk.c,v 1.16 2022/03/22 11:29:04 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* @@ -36,6 +36,7 @@ __CIDENT_RCSID(gr_charsetwidth_cjk_c,"$Id: charsetwidth_cjk.c,v 1.13 2018/10/01 */ #include +#include "../libwidechar/widechar.h" #include "libchartable.h" struct interval { @@ -149,7 +150,7 @@ charset_width_cjk(int32_t ucs) sizeof(ambiguous) / sizeof(struct interval) - 1)) { return 2; } - return charset_width_ucs(ucs, -1); + return ucs_width(ucs); } diff --git a/libchartable/chartable_module.h b/libchartable/chartable_module.h index 7ccc7f13..2c5c3dda 100644 --- a/libchartable/chartable_module.h +++ b/libchartable/chartable_module.h @@ -1,14 +1,14 @@ #ifndef GR_CHARTABLE_MODULE_H_INCLUDED #define GR_CHARTABLE_MODULE_H_INCLUDED #include -__CIDENT_RCSID(gr_chartable_module_h,"$Id: chartable_module.h,v 1.17 2020/06/18 13:09:28 cvsuser Exp $") +__CIDENT_RCSID(gr_chartable_module_h,"$Id: chartable_module.h,v 1.18 2022/03/21 14:59:58 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* Chartable module interface * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libchartable/iconv_stream.h b/libchartable/iconv_stream.h index cbc3c6a0..5afd4a17 100644 --- a/libchartable/iconv_stream.h +++ b/libchartable/iconv_stream.h @@ -1,14 +1,14 @@ #ifndef GR_ICONV_STREAM_H_INCLUDED #define GR_ICONV_STREAM_H_INCLUDED #include -__CIDENT_RCSID(gr_iconv_stream_h,"$Id: iconv_stream.h,v 1.11 2018/10/01 22:10:53 cvsuser Exp $") +__CIDENT_RCSID(gr_iconv_stream_h,"$Id: iconv_stream.h,v 1.12 2022/03/21 14:59:58 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* iconv_stream. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libchartable/libchartable.h b/libchartable/libchartable.h index e7703174..1b592b11 100644 --- a/libchartable/libchartable.h +++ b/libchartable/libchartable.h @@ -1,14 +1,14 @@ #ifndef GR_LIBCHARTABLE_H_INCLUDED #define GR_LIBCHARTABLE_H_INCLUDED #include -__CIDENT_RCSID(gr_libchartable_h,"$Id: libchartable.h,v 1.12 2018/10/01 22:10:53 cvsuser Exp $") +__CIDENT_RCSID(gr_libchartable_h,"$Id: libchartable.h,v 1.17 2022/03/21 14:59:58 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* libchartable. * * - * Copyright (c) 2010 - 2018, Adam Young. + * Copyright (c) 2010 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -108,6 +108,7 @@ extern const char * charset_current(const char *env, const char *def extern const char * charset_canonicalize(const char *name, int namelen, char *buffer, int bufsiz); extern int charset_compare(const char *primary, const char *name, int namelen); +extern void charset_iconv_init(void); extern void charset_iconv_home(const char *path); extern void charset_iconv_path(const char *path); extern struct charset_iconv * charset_iconv_open(const char *name, int flags); @@ -120,18 +121,19 @@ extern size_t charset_iconv_import(struct charset_iconv *ic, extern size_t charset_iconv_export(struct charset_iconv *ic, const char **inbuf, size_t *inbytes, char **outbuf, size_t *outbytes); -extern int charset_width_ucs(int32_t ucs, int bad); -extern int charset_swidth_ucs(const int32_t *pwcs, size_t n); - extern int charset_width_cjk(int32_t ucs); extern int charset_swidth_cjk(const int32_t *pwcs, size_t n); extern int charset_locale_utf8(const char *encoding); -extern const void * charset_utf8_decode(const void *src, const void *cpend, int32_t *cooked, int32_t *raw); +extern const void * charset_utf8_decode(const void *src, const void *cpend, int32_t *raw); +extern const void * charset_utf8_decode_cook(const void *src, const void *cpend, int32_t *cooked, int32_t *raw); extern const void * charset_utf8_decode_safe(const void *src, const void *cpend, int32_t *cooked); extern int charset_utf8_encode(const int32_t ch, void *buffer); extern int charset_utf8_length(const int32_t ch); +extern int charset_utf8_count(const void *src, const void *cpend); +extern int charset_utf8_scount(const void *src); + extern const void * charset_utf16_decode(int endian, const void *src, const void *cpend, int32_t *cooked, int32_t *raw); extern const void * charset_utf16_decode_safe(int endian, const void *src, const void *cpend, int32_t *cooked); extern int charset_utf16_encode(int endian, const int32_t ch, void *buffer); diff --git a/libchartable/makechartable.pl b/libchartable/makechartable.pl index 6c3cb000..cab905be 100644 --- a/libchartable/makechartable.pl +++ b/libchartable/makechartable.pl @@ -1,9 +1,9 @@ #!/usr/bin/perl # -*- mode: perl; tabs: 8; indent-width: 4; -*- -# $Id: makechartable.pl,v 1.20 2020/03/27 12:36:03 cvsuser Exp $ +# $Id: makechartable.pl,v 1.23 2022/03/21 14:59:58 cvsuser Exp $ # Character table generation. # -# Copyright (c) 2010 - 2020, Adam Young. +# Copyright (c) 2010 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. @@ -240,7 +240,7 @@ BEGIN ); my $COPYRIGHT = - " * Copy"."right (c) 2010 - 2020, Adam Young.\n". + " * Copy"."right (c) 2010 - 2022, Adam Young.\n". " * All rights reserved.\n". " *\n". " * This"." file is part of the GRIEF Editor.\n". @@ -253,11 +253,13 @@ BEGIN " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n". " * See the License for more details.\n"; -my %description_uchar; -my %description_index; -my @description_strings; -my @description_hits; +my %description_text; # unique description text +my %description_index; # description index by unicode +my %description_words; # word index +my @description_strings; # description by index +my @description_unicode; # unicode by index +my @description_hits; # hits by index my $x_timestamp = ctime(time()); chomp($x_timestamp); @@ -283,6 +285,7 @@ BEGIN sub NameTable($); sub DefinitionTable($); sub DescriptionTable($); +sub DictionaryTable($); sub Unicode2UTF8($); sub Usage; @@ -373,6 +376,7 @@ BEGIN NameTable("charsetnames"); DefinitionTable("charsettables"); DescriptionTable("charsetdesc"); + DictionaryTable("charsetdict"); } @@ -969,25 +973,26 @@ BEGIN $desc =~ s/[\t ]+/ /g; # compress $desc = uc($desc); - if (! exists $description_uchar{$uchar}) { + if (! exists $description_index{$uchar}) { # new value/ # asign description record # - if (! exists $description_index{$desc}) { + if (! exists $description_text{$desc}) { # new description/ # assign unique description index # - $description_index{$desc} = scalar @description_strings; + $description_text{$desc} = scalar @description_strings; push @description_strings, $desc; push @description_hits, 0; } - my $sidx = $description_index{$desc}; - $description_uchar{$uchar} = $sidx; + my $sidx = $description_text{$desc}; + $description_index{$uchar} = $sidx; + $description_unicode[$sidx] = $uchar; $description_hits[$sidx]++; } else { if ($x_warnings) { # description diff - my $t_desc = $description_strings[$description_uchar{$uchar}]; + my $t_desc = $description_strings[$description_index{$uchar}]; printf "WARNING: $source ($.): ${t_desc} != ${desc}\n" if ($t_desc ne $desc); } @@ -1203,8 +1208,11 @@ BEGIN print "crunching\n"; + # initial checks/filters + for (my $sidx = 0; $sidx < scalar @description_strings; ++$sidx) { my $desc = $description_strings[$sidx]; + my $hex = sprintf("%X", $description_unicode[$sidx]); $desc =~ s/-/ -/g; # seperate words $description_strings[$sidx] = $desc; @@ -1222,8 +1230,15 @@ BEGIN die "bad desc '$desc'\n" if ($desc =~ /[^<>A-Z0-9 ,.()=-]/); } + + if ($desc =~ /${hex}/i) { # replace inline character-value with '#' + $desc =~ s/-${hex}/-#/i; + $description_strings[$sidx] = $desc; + } } + # build string table + my $last = $longest--; for (my $phase = 1; $phase <= $last; ++$phase) { my $wordnext = 0; @@ -1233,7 +1248,7 @@ BEGIN --$longest; for (my $sidx = 0; $sidx < scalar @description_strings; ++$sidx) { - my $desc = $description_strings[$sidx]; + my $desc = $description_strings[$sidx]; my @words = split(/[ ]+/, $desc); my $wcnt = scalar @words; my $widx = 0; @@ -1273,7 +1288,7 @@ BEGIN $delimiter = 1; } } - $new =~ s/ -/-/g; # join words + $new =~ s/ \-/-/g; # join words $desccooked[$sidx] = $new; } else { @@ -1331,7 +1346,7 @@ BEGIN "\n"; # sentences - # + for (my $sidx = 0; $sidx < scalar @description_strings; ++$sidx) { if ($description_hits[$sidx] > 1) { my $desc = $description_strings[$sidx]; @@ -1351,7 +1366,7 @@ BEGIN } # word table - # + print OUT "\n". "static const char * x_${tablename}_words[] = {\n"; @@ -1369,7 +1384,7 @@ BEGIN "\n"; # character table - # + print OUT "\n". "static const char * x_${tablename}_characters[] = {\n"; @@ -1379,8 +1394,8 @@ BEGIN ## my $hits_run = 0; my $idx = 0; - foreach my $val (sort { $a <=> $b } keys %description_uchar) { - my $sidx = $description_uchar{$val}; + foreach my $val (sort { $a <=> $b } keys %description_index) { + my $sidx = $description_index{$val}; my $hits = $description_hits[$sidx]; # multiple instances, replace with common definition @@ -1408,6 +1423,10 @@ BEGIN # single instance my $desc = $description_strings[$sidx]; + my $hex = sprintf("%X", $val); + + $desc =~ s/ -/-/g; # join words + $desc =~ s/-#/-${hex}/; # inline character-value if ($x_crunch) { my $cook = $desccooked[$sidx]; @@ -1436,18 +1455,18 @@ BEGIN " };\n"; # lookup table - # + print OUT "\n". "static const struct charsetdesc {\n". - " uint32_t base;\n". - " uint32_t offset;\n". - " uint32_t count;\n". + " uint32_t base;\n". + " uint32_t offset;\n". + " uint32_t count;\n". "\n". "} x_${tablename}_lookup[] = {\n"; my ($last, $count, $offset) = (0, 0, 0); - foreach my $val (sort { $a <=> $b } keys %description_uchar) { + foreach my $val (sort { $a <=> $b } keys %description_index) { if (($last + 1) == $val) { ++$count; } else { @@ -1467,7 +1486,102 @@ BEGIN "};\n". "\n". "/*end*/\n"; + close(OUT); +} + + +# Function: DescriptionTable +# Generate description table. +# +# Parameters: +# none. +# +# Return: +# nothing. +# +sub +DictionaryTable($) #(tablename) +{ + my ($tablename) = @_; + + return if (! $x_crunch); + + print "generating ${tablename}.h ..\n"; + + # word dictionary by unicode-character + + for (my $sidx = 0; $sidx < scalar @description_strings; ++$sidx) { + my $desc = $description_strings[$sidx]; + my $uc = $description_unicode[$sidx]; + my $hex = sprintf("%X", $uc); + my @words = split(/[ ]+/, $desc); + + foreach my $word (@words) { + $word = uc($word); + $word =~ s/[-<>#]//g; # remove specials. + next if ($word eq ''); # empty. + next if ($word eq $hex); # filter character-value. + next if ($word =~ /\d/); # nuemric values. + + $description_words{$word} = () + if (! exists $description_words{$word}); + + push @{$description_words{$word}}, $uc; + } + } + + # export + + open(OUT, ">${tablename}.h") or + die "can't create '${tablename}.h' : $!"; + + print OUT + "/* -*- mode: c; tabs: 8; indent-width: 4; -*-\n". + " *\n". + " * -::- AN AUTO GENERATED FILE, DO NOT EDIT -::-\n". + " *\n". + " * Built: ${x_timestamp}\n". + " */\n". + "\n"; + + foreach my $word (sort keys %description_words) { + printf OUT + "static int32_t X_${word}[]%*s = { ", 24 - length($word), ""; + if (scalar @{$description_words{$word}} > 25) { + my $count = 0; + foreach my $uc (@{$description_words{$word}}) { + printf OUT "\n " + if (0 == ($count++ % 25)); + printf OUT "0x%x, ", $uc; + } + } else { + foreach my $uc (@{$description_words{$word}}) { + printf OUT "0x%x, ", $uc; + } + } + print OUT + "0 };\n"; + } + + printf OUT + "\n". + "static const struct charsetdict {\n". + " const char *word;\n". + " const int32_t *unicode;\n". + " uint32_t count;\n". + "\n". + "} x_${tablename}_lookup[] = {\n"; + + foreach my $word (sort keys %description_words) { + printf OUT + " { \"${word}\", X_${word}, %u },\n", scalar @{$description_words{$word}}; + } + + print OUT + "};\n". + "\n". + "/*end*/\n"; close(OUT); } @@ -1599,7 +1713,7 @@ BEGIN --warnings, -w enable warnings. - --crunch crunch description table. + --crunch crunch description and dictionary tables. --dynamic dynamic loader support. --labels generate verbose character descriptions/comments. @@ -1610,3 +1724,4 @@ BEGIN } #end + diff --git a/libchartable/makelocale.pl b/libchartable/makelocale.pl index 8639be2c..37a35b47 100644 --- a/libchartable/makelocale.pl +++ b/libchartable/makelocale.pl @@ -1,9 +1,9 @@ #!/usr/bin/perl -# $Id: makelocale.pl,v 1.9 2020/03/27 12:36:03 cvsuser Exp $ +# $Id: makelocale.pl,v 1.10 2022/03/21 14:59:58 cvsuser Exp $ # Character set locale table generation # -*- mode: perl; tabs: 8; indent-width: 4; -*- # -# Copyright (c) 2010 - 2020, Adam Young. +# Copyright (c) 2010 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. diff --git a/libchartable/utf8.c b/libchartable/utf8.c new file mode 100644 index 00000000..d941b09d --- /dev/null +++ b/libchartable/utf8.c @@ -0,0 +1,1412 @@ +// The latest version of this library is available on GitHub; +// https://github.com/sheredom/utf8.h + +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to + +#define __UTF8_SOURCE +#undef utf8_weak +#include "utf8.h" + +int utf8casecmp(const void *src1, const void *src2) { + utf8_int32_t src1_lwr_cp, src2_lwr_cp, src1_upr_cp, src2_upr_cp, src1_orig_cp, + src2_orig_cp; + + for (;;) { + src1 = utf8codepoint(src1, &src1_orig_cp); + src2 = utf8codepoint(src2, &src2_orig_cp); + + // lower the srcs if required + src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp); + src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp); + + // lower the srcs if required + src1_upr_cp = utf8uprcodepoint(src1_orig_cp); + src2_upr_cp = utf8uprcodepoint(src2_orig_cp); + + // check if the lowered codepoints match + if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { + return 0; + } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) { + continue; + } + + // if they don't match, then we return the difference between the characters + return src1_lwr_cp - src2_lwr_cp; + } +} + +void *utf8cat(void *utf8_restrict dst, const void *utf8_restrict src) { + char *d = (char *)dst; + const char *s = (const char *)src; + + // find the null terminating byte in dst + while ('\0' != *d) { + d++; + } + + // overwriting the null terminating byte in dst, append src byte-by-byte + while ('\0' != *s) { + *d++ = *s++; + } + + // write out a new null terminating byte into dst + *d = '\0'; + + return dst; +} + +void *utf8chr(const void *src, utf8_int32_t chr) { + char c[5] = {'\0', '\0', '\0', '\0', '\0'}; + + if (0 == chr) { + // being asked to return position of null terminating byte, so + // just run s to the end, and return! + const char *s = (const char *)src; + while ('\0' != *s) { + s++; + } + return (void *)s; + } else if (0 == ((utf8_int32_t)0xffffff80 & chr)) { + // 1-byte/7-bit ascii + // (0b0xxxxxxx) + c[0] = (char)chr; + } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { + // 2-byte/11-bit utf8 code point + // (0b110xxxxx 0b10xxxxxx) + c[0] = 0xc0 | (char)(chr >> 6); + c[1] = 0x80 | (char)(chr & 0x3f); + } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { + // 3-byte/16-bit utf8 code point + // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) + c[0] = 0xe0 | (char)(chr >> 12); + c[1] = 0x80 | (char)((chr >> 6) & 0x3f); + c[2] = 0x80 | (char)(chr & 0x3f); + } else { // if (0 == ((int)0xffe00000 & chr)) { + // 4-byte/21-bit utf8 code point + // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) + c[0] = 0xf0 | (char)(chr >> 18); + c[1] = 0x80 | (char)((chr >> 12) & 0x3f); + c[2] = 0x80 | (char)((chr >> 6) & 0x3f); + c[3] = 0x80 | (char)(chr & 0x3f); + } + + // we've made c into a 2 utf8 codepoint string, one for the chr we are + // seeking, another for the null terminating byte. Now use utf8str to + // search + return utf8str(src, c); +} + +int utf8cmp(const void *src1, const void *src2) { + const unsigned char *s1 = (const unsigned char *)src1; + const unsigned char *s2 = (const unsigned char *)src2; + + while (('\0' != *s1) || ('\0' != *s2)) { + if (*s1 < *s2) { + return -1; + } else if (*s1 > *s2) { + return 1; + } + + s1++; + s2++; + } + + // both utf8 strings matched + return 0; +} + +int utf8coll(const void *src1, const void *src2); + +void *utf8cpy(void *utf8_restrict dst, const void *utf8_restrict src) { + char *d = (char *)dst; + const char *s = (const char *)src; + + // overwriting anything previously in dst, write byte-by-byte + // from src + while ('\0' != *s) { + *d++ = *s++; + } + + // append null terminating byte + *d = '\0'; + + return dst; +} + +size_t utf8cspn(const void *src, const void *reject) { + const char *s = (const char *)src; + size_t chars = 0; + + while ('\0' != *s) { + const char *r = (const char *)reject; + size_t offset = 0; + + while ('\0' != *r) { + // checking that if *r is the start of a utf8 codepoint + // (it is not 0b10xxxxxx) and we have successfully matched + // a previous character (0 < offset) - we found a match + if ((0x80 != (0xc0 & *r)) && (0 < offset)) { + return chars; + } else { + if (*r == s[offset]) { + // part of a utf8 codepoint matched, so move our checking + // onwards to the next byte + offset++; + r++; + } else { + // r could be in the middle of an unmatching utf8 code point, + // so we need to march it on to the next character beginning, + + do { + r++; + } while (0x80 == (0xc0 & *r)); + + // reset offset too as we found a mismatch + offset = 0; + } + } + } + + // found a match at the end of *r, so didn't get a chance to test it + if (0 < offset) { + return chars; + } + + // the current utf8 codepoint in src did not match reject, but src + // could have been partway through a utf8 codepoint, so we need to + // march it onto the next utf8 codepoint starting byte + do { + s++; + } while ((0x80 == (0xc0 & *s))); + chars++; + } + + return chars; +} + +void *utf8dup(const void *src) { return utf8dup_ex(src, utf8_null, utf8_null); } + +void *utf8dup_ex(const void *src, void *(*alloc_func_ptr)(void *, size_t), + void *user_data) { + const char *s = (const char *)src; + char *n = utf8_null; + + // figure out how many bytes (including the terminator) we need to copy first + size_t bytes = utf8size(src); + + if (alloc_func_ptr) { + n = (char *)alloc_func_ptr(user_data, bytes); + } else { + n = (char *)malloc(bytes); + } + + if (utf8_null == n) { + // out of memory so we bail + return utf8_null; + } else { + bytes = 0; + + // copy src byte-by-byte into our new utf8 string + while ('\0' != s[bytes]) { + n[bytes] = s[bytes]; + bytes++; + } + + // append null terminating byte + n[bytes] = '\0'; + return n; + } +} + +void *utf8fry(const void *str); + +size_t utf8len(const void *str) { + return utf8nlen(str, SIZE_MAX); +} + +size_t utf8nlen(const void *str, size_t n) { + const unsigned char *s = (const unsigned char *)str; + const unsigned char *t = s; + size_t length = 0; + + while ((size_t) (s-t) < n && '\0' != *s) { + if (0xf0 == (0xf8 & *s)) { + // 4-byte utf8 code point (began with 0b11110xxx) + s += 4; + } else if (0xe0 == (0xf0 & *s)) { + // 3-byte utf8 code point (began with 0b1110xxxx) + s += 3; + } else if (0xc0 == (0xe0 & *s)) { + // 2-byte utf8 code point (began with 0b110xxxxx) + s += 2; + } else { // if (0x00 == (0x80 & *s)) { + // 1-byte ascii (began with 0b0xxxxxxx) + s += 1; + } + + // no matter the bytes we marched s forward by, it was + // only 1 utf8 codepoint + length++; + } + + if ((size_t) (s-t) > n) { + length--; + } + return length; +} + +int utf8ncasecmp(const void *src1, const void *src2, size_t n) { + utf8_int32_t src1_lwr_cp, src2_lwr_cp, src1_upr_cp, src2_upr_cp, src1_orig_cp, + src2_orig_cp; + + do { + const unsigned char *const s1 = (const unsigned char *)src1; + const unsigned char *const s2 = (const unsigned char *)src2; + + // first check that we have enough bytes left in n to contain an entire + // codepoint + if (0 == n) { + return 0; + } + + if ((1 == n) && ((0xc0 == (0xe0 & *s1)) || (0xc0 == (0xe0 & *s2)))) { + const utf8_int32_t c1 = (0xe0 & *s1); + const utf8_int32_t c2 = (0xe0 & *s2); + + if (c1 < c2) { + return c1 - c2; + } else { + return 0; + } + } + + if ((2 >= n) && ((0xe0 == (0xf0 & *s1)) || (0xe0 == (0xf0 & *s2)))) { + const utf8_int32_t c1 = (0xf0 & *s1); + const utf8_int32_t c2 = (0xf0 & *s2); + + if (c1 < c2) { + return c1 - c2; + } else { + return 0; + } + } + + if ((3 >= n) && ((0xf0 == (0xf8 & *s1)) || (0xf0 == (0xf8 & *s2)))) { + const utf8_int32_t c1 = (0xf8 & *s1); + const utf8_int32_t c2 = (0xf8 & *s2); + + if (c1 < c2) { + return c1 - c2; + } else { + return 0; + } + } + + src1 = utf8codepoint(src1, &src1_orig_cp); + src2 = utf8codepoint(src2, &src2_orig_cp); + n -= utf8codepointsize(src1_orig_cp); + + src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp); + src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp); + + src1_upr_cp = utf8uprcodepoint(src1_orig_cp); + src2_upr_cp = utf8uprcodepoint(src2_orig_cp); + + // check if the lowered codepoints match + if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { + return 0; + } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) { + continue; + } + + // if they don't match, then we return the difference between the characters + return src1_lwr_cp - src2_lwr_cp; + } while (0 < n); + + // both utf8 strings matched + return 0; +} + +void *utf8ncat(void *utf8_restrict dst, const void *utf8_restrict src, + size_t n) { + char *d = (char *)dst; + const char *s = (const char *)src; + + // find the null terminating byte in dst + while ('\0' != *d) { + d++; + } + + // overwriting the null terminating byte in dst, append src byte-by-byte + // stopping if we run out of space + do { + *d++ = *s++; + } while (('\0' != *s) && (0 != --n)); + + // write out a new null terminating byte into dst + *d = '\0'; + + return dst; +} + +int utf8ncmp(const void *src1, const void *src2, size_t n) { + const unsigned char *s1 = (const unsigned char *)src1; + const unsigned char *s2 = (const unsigned char *)src2; + + while ((0 != n--) && (('\0' != *s1) || ('\0' != *s2))) { + if (*s1 < *s2) { + return -1; + } else if (*s1 > *s2) { + return 1; + } + + s1++; + s2++; + } + + // both utf8 strings matched + return 0; +} + +void *utf8ncpy(void *utf8_restrict dst, const void *utf8_restrict src, + size_t n) { + char *d = (char *)dst; + const char *s = (const char *)src; + size_t index, check_index; + + // overwriting anything previously in dst, write byte-by-byte + // from src + for (index = 0; index < n; index++) { + d[index] = s[index]; + if ('\0' == s[index]) { + break; + } + } + + for ( check_index = index - 1; check_index > 0 && 0x80 == (0xc0 & d[check_index]); check_index--) { + // just moving the index + } + + if (check_index < index && (index - check_index) < utf8codepointsize(d[check_index])) { + index = check_index; + } + + // append null terminating byte + for (; index < n; index++) { + d[index] = 0; + } + + return dst; +} + +void *utf8ndup(const void *src, size_t n) { + return utf8ndup_ex(src, n, utf8_null, utf8_null); +} + +void *utf8ndup_ex(const void *src, size_t n, + void *(*alloc_func_ptr)(void *, size_t), void *user_data) { + const char *s = (const char *)src; + char *c = utf8_null; + size_t bytes = 0; + + // Find the end of the string or stop when n is reached + while ('\0' != s[bytes] && bytes < n) { + bytes++; + } + + // In case bytes is actually less than n, we need to set it + // to be used later in the copy byte by byte. + n = bytes; + + if (alloc_func_ptr) { + c = (char *)alloc_func_ptr(user_data, bytes + 1); + } else { + c = (char *)malloc(bytes + 1); + } + + if (utf8_null == c) { + // out of memory so we bail + return utf8_null; + } + + bytes = 0; + + // copy src byte-by-byte into our new utf8 string + while ('\0' != s[bytes] && bytes < n) { + c[bytes] = s[bytes]; + bytes++; + } + + // append null terminating byte + c[bytes] = '\0'; + return c; +} + +void *utf8rchr(const void *src, int chr) { + const char *s = (const char *)src; + const char *match = utf8_null; + char c[5] = {'\0', '\0', '\0', '\0', '\0'}; + + if (0 == chr) { + // being asked to return position of null terminating byte, so + // just run s to the end, and return! + while ('\0' != *s) { + s++; + } + return (void *)s; + } else if (0 == ((int)0xffffff80 & chr)) { + // 1-byte/7-bit ascii + // (0b0xxxxxxx) + c[0] = (char)chr; + } else if (0 == ((int)0xfffff800 & chr)) { + // 2-byte/11-bit utf8 code point + // (0b110xxxxx 0b10xxxxxx) + c[0] = 0xc0 | (char)(chr >> 6); + c[1] = 0x80 | (char)(chr & 0x3f); + } else if (0 == ((int)0xffff0000 & chr)) { + // 3-byte/16-bit utf8 code point + // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) + c[0] = 0xe0 | (char)(chr >> 12); + c[1] = 0x80 | (char)((chr >> 6) & 0x3f); + c[2] = 0x80 | (char)(chr & 0x3f); + } else { // if (0 == ((int)0xffe00000 & chr)) { + // 4-byte/21-bit utf8 code point + // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) + c[0] = 0xf0 | (char)(chr >> 18); + c[1] = 0x80 | (char)((chr >> 12) & 0x3f); + c[2] = 0x80 | (char)((chr >> 6) & 0x3f); + c[3] = 0x80 | (char)(chr & 0x3f); + } + + // we've created a 2 utf8 codepoint string in c that is + // the utf8 character asked for by chr, and a null + // terminating byte + + while ('\0' != *s) { + size_t offset = 0; + + while (s[offset] == c[offset]) { + offset++; + } + + if ('\0' == c[offset]) { + // we found a matching utf8 code point + match = s; + s += offset; + } else { + s += offset; + + // need to march s along to next utf8 codepoint start + // (the next byte that doesn't match 0b10xxxxxx) + if ('\0' != *s) { + do { + s++; + } while (0x80 == (0xc0 & *s)); + } + } + } + + // return the last match we found (or 0 if no match was found) + return (void *)match; +} + +void *utf8pbrk(const void *str, const void *accept) { + const char *s = (const char *)str; + + while ('\0' != *s) { + const char *a = (const char *)accept; + size_t offset = 0; + + while ('\0' != *a) { + // checking that if *a is the start of a utf8 codepoint + // (it is not 0b10xxxxxx) and we have successfully matched + // a previous character (0 < offset) - we found a match + if ((0x80 != (0xc0 & *a)) && (0 < offset)) { + return (void *)s; + } else { + if (*a == s[offset]) { + // part of a utf8 codepoint matched, so move our checking + // onwards to the next byte + offset++; + a++; + } else { + // r could be in the middle of an unmatching utf8 code point, + // so we need to march it on to the next character beginning, + + do { + a++; + } while (0x80 == (0xc0 & *a)); + + // reset offset too as we found a mismatch + offset = 0; + } + } + } + + // we found a match on the last utf8 codepoint + if (0 < offset) { + return (void *)s; + } + + // the current utf8 codepoint in src did not match accept, but src + // could have been partway through a utf8 codepoint, so we need to + // march it onto the next utf8 codepoint starting byte + do { + s++; + } while ((0x80 == (0xc0 & *s))); + } + + return utf8_null; +} + +size_t utf8size(const void *str) { + return utf8size_lazy(str) + 1; +} + +size_t utf8size_lazy(const void *str) { + return utf8nsize_lazy(str, SIZE_MAX); +} + +size_t utf8nsize_lazy(const void *str, size_t n) { + const char *s = (const char *)str; + size_t size = 0; + while (size < n && '\0' != s[size]) { + size++; + } + return size; +} + +size_t utf8spn(const void *src, const void *accept) { + const char *s = (const char *)src; + size_t chars = 0; + + while ('\0' != *s) { + const char *a = (const char *)accept; + size_t offset = 0; + + while ('\0' != *a) { + // checking that if *r is the start of a utf8 codepoint + // (it is not 0b10xxxxxx) and we have successfully matched + // a previous character (0 < offset) - we found a match + if ((0x80 != (0xc0 & *a)) && (0 < offset)) { + // found a match, so increment the number of utf8 codepoints + // that have matched and stop checking whether any other utf8 + // codepoints in a match + chars++; + s += offset; + offset = 0; + break; + } else { + if (*a == s[offset]) { + offset++; + a++; + } else { + // a could be in the middle of an unmatching utf8 codepoint, + // so we need to march it on to the next character beginning, + do { + a++; + } while (0x80 == (0xc0 & *a)); + + // reset offset too as we found a mismatch + offset = 0; + } + } + } + + // found a match at the end of *a, so didn't get a chance to test it + if (0 < offset) { + chars++; + s += offset; + continue; + } + + // if a got to its terminating null byte, then we didn't find a match. + // Return the current number of matched utf8 codepoints + if ('\0' == *a) { + return chars; + } + } + + return chars; +} + +void *utf8str(const void *haystack, const void *needle) { + const char *h = (const char *)haystack; + utf8_int32_t throwaway_codepoint; + + // if needle has no utf8 codepoints before the null terminating + // byte then return haystack + if ('\0' == *((const char *)needle)) { + return (void *)haystack; + } + + while ('\0' != *h) { + const char *maybeMatch = h; + const char *n = (const char *)needle; + + while (*h == *n && (*h != '\0' && *n != '\0')) { + n++; + h++; + } + + if ('\0' == *n) { + // we found the whole utf8 string for needle in haystack at + // maybeMatch, so return it + return (void *)maybeMatch; + } else { + // h could be in the middle of an unmatching utf8 codepoint, + // so we need to march it on to the next character beginning + // starting from the current character + h = (const char *)utf8codepoint(maybeMatch, &throwaway_codepoint); + } + } + + // no match + return utf8_null; +} + +void *utf8casestr(const void *haystack, const void *needle) { + const void *h = haystack; + + // if needle has no utf8 codepoints before the null terminating + // byte then return haystack + if ('\0' == *((const char *)needle)) { + return (void *)haystack; + } + + for (;;) { + const void *maybeMatch = h; + const void *n = needle; + utf8_int32_t h_cp, n_cp; + + // Get the next code point and track it + const void *nextH = h = utf8codepoint(h, &h_cp); + n = utf8codepoint(n, &n_cp); + + while ((0 != h_cp) && (0 != n_cp)) { + h_cp = utf8lwrcodepoint(h_cp); + n_cp = utf8lwrcodepoint(n_cp); + + // if we find a mismatch, bail out! + if (h_cp != n_cp) { + break; + } + + h = utf8codepoint(h, &h_cp); + n = utf8codepoint(n, &n_cp); + } + + if (0 == n_cp) { + // we found the whole utf8 string for needle in haystack at + // maybeMatch, so return it + return (void *)maybeMatch; + } + + if (0 == h_cp) { + // no match + return utf8_null; + } + + // Roll back to the next code point in the haystack to test + h = nextH; + } +} + +void *utf8valid(const void *str) { + return utf8nvalid(str, SIZE_MAX); +} + +void *utf8nvalid(const void *str, size_t n) { + const char *s = (const char *)str; + const char *t = s; + size_t consumed, remained; + + while ((void) (consumed = (size_t) (s-t)), consumed < n && '\0' != *s) { + remained = n - consumed; + + if (0xf0 == (0xf8 & *s)) { + // ensure that there's 4 bytes or more remained + if (remained < 4) { + return (void *)s; + } + + // ensure each of the 3 following bytes in this 4-byte + // utf8 codepoint began with 0b10xxxxxx + if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2])) || + (0x80 != (0xc0 & s[3]))) { + return (void *)s; + } + + // ensure that our utf8 codepoint ended after 4 bytes + if (0x80 == (0xc0 & s[4])) { + return (void *)s; + } + + // ensure that the top 5 bits of this 4-byte utf8 + // codepoint were not 0, as then we could have used + // one of the smaller encodings + if ((0 == (0x07 & s[0])) && (0 == (0x30 & s[1]))) { + return (void *)s; + } + + // 4-byte utf8 code point (began with 0b11110xxx) + s += 4; + } else if (0xe0 == (0xf0 & *s)) { + // ensure that there's 3 bytes or more remained + if (remained < 3) { + return (void *)s; + } + + // ensure each of the 2 following bytes in this 3-byte + // utf8 codepoint began with 0b10xxxxxx + if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2]))) { + return (void *)s; + } + + // ensure that our utf8 codepoint ended after 3 bytes + if (0x80 == (0xc0 & s[3])) { + return (void *)s; + } + + // ensure that the top 5 bits of this 3-byte utf8 + // codepoint were not 0, as then we could have used + // one of the smaller encodings + if ((0 == (0x0f & s[0])) && (0 == (0x20 & s[1]))) { + return (void *)s; + } + + // 3-byte utf8 code point (began with 0b1110xxxx) + s += 3; + } else if (0xc0 == (0xe0 & *s)) { + // ensure that there's 2 bytes or more remained + if (remained < 2) { + return (void *)s; + } + + // ensure the 1 following byte in this 2-byte + // utf8 codepoint began with 0b10xxxxxx + if (0x80 != (0xc0 & s[1])) { + return (void *)s; + } + + // ensure that our utf8 codepoint ended after 2 bytes + if (0x80 == (0xc0 & s[2])) { + return (void *)s; + } + + // ensure that the top 4 bits of this 2-byte utf8 + // codepoint were not 0, as then we could have used + // one of the smaller encodings + if (0 == (0x1e & s[0])) { + return (void *)s; + } + + // 2-byte utf8 code point (began with 0b110xxxxx) + s += 2; + } else if (0x00 == (0x80 & *s)) { + // 1-byte ascii (began with 0b0xxxxxxx) + s += 1; + } else { + // we have an invalid 0b1xxxxxxx utf8 code point entry + return (void *)s; + } + } + + return utf8_null; +} + +int utf8makevalid(void *str, const utf8_int32_t replacement) { + char *read = (char *)str; + char *write = read; + const char r = (char)replacement; + utf8_int32_t codepoint; + + if (replacement > 0x7f) { + return -1; + } + + while ('\0' != *read) { + if (0xf0 == (0xf8 & *read)) { + // ensure each of the 3 following bytes in this 4-byte + // utf8 codepoint began with 0b10xxxxxx + if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2])) || + (0x80 != (0xc0 & read[3]))) { + *write++ = r; + read++; + continue; + } + + // 4-byte utf8 code point (began with 0b11110xxx) + read = (char *)utf8codepoint(read, &codepoint); + write = (char *)utf8catcodepoint(write, codepoint, 4); + } else if (0xe0 == (0xf0 & *read)) { + // ensure each of the 2 following bytes in this 3-byte + // utf8 codepoint began with 0b10xxxxxx + if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2]))) { + *write++ = r; + read++; + continue; + } + + // 3-byte utf8 code point (began with 0b1110xxxx) + read = (char *)utf8codepoint(read, &codepoint); + write = (char *)utf8catcodepoint(write, codepoint, 3); + } else if (0xc0 == (0xe0 & *read)) { + // ensure the 1 following byte in this 2-byte + // utf8 codepoint began with 0b10xxxxxx + if (0x80 != (0xc0 & read[1])) { + *write++ = r; + read++; + continue; + } + + // 2-byte utf8 code point (began with 0b110xxxxx) + read = (char *)utf8codepoint(read, &codepoint); + write = (char *)utf8catcodepoint(write, codepoint, 2); + } else if (0x00 == (0x80 & *read)) { + // 1-byte ascii (began with 0b0xxxxxxx) + read = (char *)utf8codepoint(read, &codepoint); + write = (char *)utf8catcodepoint(write, codepoint, 1); + } else { + // if we got here then we've got a dangling continuation (0b10xxxxxx) + *write++ = r; + read++; + continue; + } + } + + *write = '\0'; + + return 0; +} + +void *utf8codepoint(const void *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint) { + const char *s = (const char *)str; + + if (0xf0 == (0xf8 & s[0])) { + // 4 byte utf8 codepoint + *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | + ((0x3f & s[2]) << 6) | (0x3f & s[3]); + s += 4; + } else if (0xe0 == (0xf0 & s[0])) { + // 3 byte utf8 codepoint + *out_codepoint = + ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); + s += 3; + } else if (0xc0 == (0xe0 & s[0])) { + // 2 byte utf8 codepoint + *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); + s += 2; + } else { + // 1 byte utf8 codepoint otherwise + *out_codepoint = s[0]; + s += 1; + } + + return (void *)s; +} + +size_t utf8codepointcalcsize(const void *str) { + const char *s = (const char *)str; + + if (0xf0 == (0xf8 & s[0])) { + // 4 byte utf8 codepoint + return 4; + } else if (0xe0 == (0xf0 & s[0])) { + // 3 byte utf8 codepoint + return 3; + } else if (0xc0 == (0xe0 & s[0])) { + // 2 byte utf8 codepoint + return 2; + } + + // 1 byte utf8 codepoint otherwise + return 1; +} + +size_t utf8codepointsize(utf8_int32_t chr) { + if (0 == ((utf8_int32_t)0xffffff80 & chr)) { + return 1; + } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { + return 2; + } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { + return 3; + } else { // if (0 == ((int)0xffe00000 & chr)) { + return 4; + } +} + +void *utf8catcodepoint(void *str, utf8_int32_t chr, size_t n) { + char *s = (char *)str; + + if (0 == ((utf8_int32_t)0xffffff80 & chr)) { + // 1-byte/7-bit ascii + // (0b0xxxxxxx) + if (n < 1) { + return utf8_null; + } + s[0] = (char)chr; + s += 1; + } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { + // 2-byte/11-bit utf8 code point + // (0b110xxxxx 0b10xxxxxx) + if (n < 2) { + return utf8_null; + } + s[0] = 0xc0 | (char)((chr >> 6) & 0x1f); + s[1] = 0x80 | (char)(chr & 0x3f); + s += 2; + } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { + // 3-byte/16-bit utf8 code point + // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) + if (n < 3) { + return utf8_null; + } + s[0] = 0xe0 | (char)((chr >> 12) & 0x0f); + s[1] = 0x80 | (char)((chr >> 6) & 0x3f); + s[2] = 0x80 | (char)(chr & 0x3f); + s += 3; + } else { // if (0 == ((int)0xffe00000 & chr)) { + // 4-byte/21-bit utf8 code point + // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) + if (n < 4) { + return utf8_null; + } + s[0] = 0xf0 | (char)((chr >> 18) & 0x07); + s[1] = 0x80 | (char)((chr >> 12) & 0x3f); + s[2] = 0x80 | (char)((chr >> 6) & 0x3f); + s[3] = 0x80 | (char)(chr & 0x3f); + s += 4; + } + + return s; +} + +int utf8islower(utf8_int32_t chr) { return chr != utf8uprcodepoint(chr); } + +int utf8isupper(utf8_int32_t chr) { return chr != utf8lwrcodepoint(chr); } + +void utf8lwr(void *utf8_restrict str) { + void *p, *pn; + utf8_int32_t cp; + + p = (char *)str; + pn = utf8codepoint(p, &cp); + + while (cp != 0) { + const utf8_int32_t lwr_cp = utf8lwrcodepoint(cp); + const size_t size = utf8codepointsize(lwr_cp); + + if (lwr_cp != cp) { + utf8catcodepoint(p, lwr_cp, size); + } + + p = pn; + pn = utf8codepoint(p, &cp); + } +} + +void utf8upr(void *utf8_restrict str) { + void *p, *pn; + utf8_int32_t cp; + + p = (char *)str; + pn = utf8codepoint(p, &cp); + + while (cp != 0) { + const utf8_int32_t lwr_cp = utf8uprcodepoint(cp); + const size_t size = utf8codepointsize(lwr_cp); + + if (lwr_cp != cp) { + utf8catcodepoint(p, lwr_cp, size); + } + + p = pn; + pn = utf8codepoint(p, &cp); + } +} + +utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { + if (((0x0041 <= cp) && (0x005a >= cp)) || + ((0x00c0 <= cp) && (0x00d6 >= cp)) || + ((0x00d8 <= cp) && (0x00de >= cp)) || + ((0x0391 <= cp) && (0x03a1 >= cp)) || + ((0x03a3 <= cp) && (0x03ab >= cp)) || + ((0x0410 <= cp) && (0x042f >= cp))) { + cp += 32; + } else if ((0x0400 <= cp) && (0x040f >= cp)) { + cp += 80; + } else if (((0x0100 <= cp) && (0x012f >= cp)) || + ((0x0132 <= cp) && (0x0137 >= cp)) || + ((0x014a <= cp) && (0x0177 >= cp)) || + ((0x0182 <= cp) && (0x0185 >= cp)) || + ((0x01a0 <= cp) && (0x01a5 >= cp)) || + ((0x01de <= cp) && (0x01ef >= cp)) || + ((0x01f8 <= cp) && (0x021f >= cp)) || + ((0x0222 <= cp) && (0x0233 >= cp)) || + ((0x0246 <= cp) && (0x024f >= cp)) || + ((0x03d8 <= cp) && (0x03ef >= cp)) || + ((0x0460 <= cp) && (0x0481 >= cp)) || + ((0x048a <= cp) && (0x04ff >= cp))) { + cp |= 0x1; + } else if (((0x0139 <= cp) && (0x0148 >= cp)) || + ((0x0179 <= cp) && (0x017e >= cp)) || + ((0x01af <= cp) && (0x01b0 >= cp)) || + ((0x01b3 <= cp) && (0x01b6 >= cp)) || + ((0x01cd <= cp) && (0x01dc >= cp))) { + cp += 1; + cp &= ~0x1; + } else { + switch (cp) { + default: + break; + case 0x0178: + cp = 0x00ff; + break; + case 0x0243: + cp = 0x0180; + break; + case 0x018e: + cp = 0x01dd; + break; + case 0x023d: + cp = 0x019a; + break; + case 0x0220: + cp = 0x019e; + break; + case 0x01b7: + cp = 0x0292; + break; + case 0x01c4: + cp = 0x01c6; + break; + case 0x01c7: + cp = 0x01c9; + break; + case 0x01ca: + cp = 0x01cc; + break; + case 0x01f1: + cp = 0x01f3; + break; + case 0x01f7: + cp = 0x01bf; + break; + case 0x0187: + cp = 0x0188; + break; + case 0x018b: + cp = 0x018c; + break; + case 0x0191: + cp = 0x0192; + break; + case 0x0198: + cp = 0x0199; + break; + case 0x01a7: + cp = 0x01a8; + break; + case 0x01ac: + cp = 0x01ad; + break; + case 0x01af: + cp = 0x01b0; + break; + case 0x01b8: + cp = 0x01b9; + break; + case 0x01bc: + cp = 0x01bd; + break; + case 0x01f4: + cp = 0x01f5; + break; + case 0x023b: + cp = 0x023c; + break; + case 0x0241: + cp = 0x0242; + break; + case 0x03fd: + cp = 0x037b; + break; + case 0x03fe: + cp = 0x037c; + break; + case 0x03ff: + cp = 0x037d; + break; + case 0x037f: + cp = 0x03f3; + break; + case 0x0386: + cp = 0x03ac; + break; + case 0x0388: + cp = 0x03ad; + break; + case 0x0389: + cp = 0x03ae; + break; + case 0x038a: + cp = 0x03af; + break; + case 0x038c: + cp = 0x03cc; + break; + case 0x038e: + cp = 0x03cd; + break; + case 0x038f: + cp = 0x03ce; + break; + case 0x0370: + cp = 0x0371; + break; + case 0x0372: + cp = 0x0373; + break; + case 0x0376: + cp = 0x0377; + break; + case 0x03f4: + cp = 0x03b8; + break; + case 0x03cf: + cp = 0x03d7; + break; + case 0x03f9: + cp = 0x03f2; + break; + case 0x03f7: + cp = 0x03f8; + break; + case 0x03fa: + cp = 0x03fb; + break; + } + } + + return cp; +} + +utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { + if (((0x0061 <= cp) && (0x007a >= cp)) || + ((0x00e0 <= cp) && (0x00f6 >= cp)) || + ((0x00f8 <= cp) && (0x00fe >= cp)) || + ((0x03b1 <= cp) && (0x03c1 >= cp)) || + ((0x03c3 <= cp) && (0x03cb >= cp)) || + ((0x0430 <= cp) && (0x044f >= cp))) { + cp -= 32; + } else if ((0x0450 <= cp) && (0x045f >= cp)) { + cp -= 80; + } else if (((0x0100 <= cp) && (0x012f >= cp)) || + ((0x0132 <= cp) && (0x0137 >= cp)) || + ((0x014a <= cp) && (0x0177 >= cp)) || + ((0x0182 <= cp) && (0x0185 >= cp)) || + ((0x01a0 <= cp) && (0x01a5 >= cp)) || + ((0x01de <= cp) && (0x01ef >= cp)) || + ((0x01f8 <= cp) && (0x021f >= cp)) || + ((0x0222 <= cp) && (0x0233 >= cp)) || + ((0x0246 <= cp) && (0x024f >= cp)) || + ((0x03d8 <= cp) && (0x03ef >= cp)) || + ((0x0460 <= cp) && (0x0481 >= cp)) || + ((0x048a <= cp) && (0x04ff >= cp))) { + cp &= ~0x1; + } else if (((0x0139 <= cp) && (0x0148 >= cp)) || + ((0x0179 <= cp) && (0x017e >= cp)) || + ((0x01af <= cp) && (0x01b0 >= cp)) || + ((0x01b3 <= cp) && (0x01b6 >= cp)) || + ((0x01cd <= cp) && (0x01dc >= cp))) { + cp -= 1; + cp |= 0x1; + } else { + switch (cp) { + default: + break; + case 0x00ff: + cp = 0x0178; + break; + case 0x0180: + cp = 0x0243; + break; + case 0x01dd: + cp = 0x018e; + break; + case 0x019a: + cp = 0x023d; + break; + case 0x019e: + cp = 0x0220; + break; + case 0x0292: + cp = 0x01b7; + break; + case 0x01c6: + cp = 0x01c4; + break; + case 0x01c9: + cp = 0x01c7; + break; + case 0x01cc: + cp = 0x01ca; + break; + case 0x01f3: + cp = 0x01f1; + break; + case 0x01bf: + cp = 0x01f7; + break; + case 0x0188: + cp = 0x0187; + break; + case 0x018c: + cp = 0x018b; + break; + case 0x0192: + cp = 0x0191; + break; + case 0x0199: + cp = 0x0198; + break; + case 0x01a8: + cp = 0x01a7; + break; + case 0x01ad: + cp = 0x01ac; + break; + case 0x01b0: + cp = 0x01af; + break; + case 0x01b9: + cp = 0x01b8; + break; + case 0x01bd: + cp = 0x01bc; + break; + case 0x01f5: + cp = 0x01f4; + break; + case 0x023c: + cp = 0x023b; + break; + case 0x0242: + cp = 0x0241; + break; + case 0x037b: + cp = 0x03fd; + break; + case 0x037c: + cp = 0x03fe; + break; + case 0x037d: + cp = 0x03ff; + break; + case 0x03f3: + cp = 0x037f; + break; + case 0x03ac: + cp = 0x0386; + break; + case 0x03ad: + cp = 0x0388; + break; + case 0x03ae: + cp = 0x0389; + break; + case 0x03af: + cp = 0x038a; + break; + case 0x03cc: + cp = 0x038c; + break; + case 0x03cd: + cp = 0x038e; + break; + case 0x03ce: + cp = 0x038f; + break; + case 0x0371: + cp = 0x0370; + break; + case 0x0373: + cp = 0x0372; + break; + case 0x0377: + cp = 0x0376; + break; + case 0x03d1: + cp = 0x0398; + break; + case 0x03d7: + cp = 0x03cf; + break; + case 0x03f2: + cp = 0x03f9; + break; + case 0x03f8: + cp = 0x03f7; + break; + case 0x03fb: + cp = 0x03fa; + break; + } + } + + return cp; +} + +void *utf8rcodepoint(const void *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint) { + const char *s = (const char *)str; + + if (0xf0 == (0xf8 & s[0])) { + // 4 byte utf8 codepoint + *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | + ((0x3f & s[2]) << 6) | (0x3f & s[3]); + } else if (0xe0 == (0xf0 & s[0])) { + // 3 byte utf8 codepoint + *out_codepoint = + ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); + } else if (0xc0 == (0xe0 & s[0])) { + // 2 byte utf8 codepoint + *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); + } else { + // 1 byte utf8 codepoint otherwise + *out_codepoint = s[0]; + } + + do { + s--; + } while ((0 != (0x80 & s[0])) && (0x80 == (0xc0 & s[0]))); + + return (void *)s; +} + +/*end*/ diff --git a/libchartable/utf8.h b/libchartable/utf8.h new file mode 100644 index 00000000..558dfebf --- /dev/null +++ b/libchartable/utf8.h @@ -0,0 +1,277 @@ +// The latest version of this library is available on GitHub; +// https://github.com/sheredom/utf8.h + +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// For more information, please refer to + +#ifndef SHEREDOM_UTF8_H_INCLUDED +#define SHEREDOM_UTF8_H_INCLUDED + +#if defined(_MSC_VER) +#pragma warning(push) + +/* disable warning: no function prototype given: converting '()' to '(void)' */ +#pragma warning(disable : 4255) + +/* disable warning: '__cplusplus' is not defined as a preprocessor macro, + * replacing with '0' for '#if/#elif' */ +#pragma warning(disable : 4668) + +/* disable warning: bytes padding added after construct */ +#pragma warning(disable : 4820) +#endif + +#include +#include + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1920) +typedef __int32 utf8_int32_t; +#else +#include +typedef int32_t utf8_int32_t; +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wcast-qual" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) || defined(__WATCOMC__) +#define utf8_nonnull +#define utf8_pure +#define utf8_restrict __restrict +#define utf8_weak extern /*__inline*/ +#elif defined(__clang__) || defined(__GNUC__) +#define utf8_nonnull __attribute__((nonnull)) +#define utf8_pure __attribute__((pure)) +#define utf8_restrict __restrict__ +#define utf8_weak extern /*__attribute__((weak))*/ +#else +#error Non clang, non gcc, non MSVC compiler found! +#endif + +#ifdef __cplusplus +#define utf8_null NULL +#else +#define utf8_null 0 +#endif + +// Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > +// src2 respectively, case insensitive. +utf8_nonnull utf8_pure utf8_weak int utf8casecmp(const void *src1, + const void *src2); + +// Append the utf8 string src onto the utf8 string dst. +utf8_nonnull utf8_weak void *utf8cat(void *utf8_restrict dst, + const void *utf8_restrict src); + +// Find the first match of the utf8 codepoint chr in the utf8 string src. +utf8_nonnull utf8_pure utf8_weak void *utf8chr(const void *src, + utf8_int32_t chr); + +// Return less than 0, 0, greater than 0 if src1 < src2, +// src1 == src2, src1 > src2 respectively. +utf8_nonnull utf8_pure utf8_weak int utf8cmp(const void *src1, + const void *src2); + +// Copy the utf8 string src onto the memory allocated in dst. +utf8_nonnull utf8_weak void *utf8cpy(void *utf8_restrict dst, + const void *utf8_restrict src); + +// Number of utf8 codepoints in the utf8 string src that consists entirely +// of utf8 codepoints not from the utf8 string reject. +utf8_nonnull utf8_pure utf8_weak size_t utf8cspn(const void *src, + const void *reject); + +// Duplicate the utf8 string src by getting its size, malloc'ing a new buffer +// copying over the data, and returning that. Or 0 if malloc failed. +utf8_weak void *utf8dup(const void *src); + +// Number of utf8 codepoints in the utf8 string str, +// excluding the null terminating byte. +utf8_nonnull utf8_pure utf8_weak size_t utf8len(const void *str); + +// Similar to utf8len, except that only at most n bytes of src are looked. +utf8_nonnull utf8_pure utf8_weak size_t utf8nlen(const void *str, size_t n); + +// Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > +// src2 respectively, case insensitive. Checking at most n bytes of each utf8 +// string. +utf8_nonnull utf8_pure utf8_weak int utf8ncasecmp(const void *src1, + const void *src2, size_t n); + +// Append the utf8 string src onto the utf8 string dst, +// writing at most n+1 bytes. Can produce an invalid utf8 +// string if n falls partway through a utf8 codepoint. +utf8_nonnull utf8_weak void *utf8ncat(void *utf8_restrict dst, + const void *utf8_restrict src, size_t n); + +// Return less than 0, 0, greater than 0 if src1 < src2, +// src1 == src2, src1 > src2 respectively. Checking at most n +// bytes of each utf8 string. +utf8_nonnull utf8_pure utf8_weak int utf8ncmp(const void *src1, + const void *src2, size_t n); + +// Copy the utf8 string src onto the memory allocated in dst. +// Copies at most n bytes. If n falls partway through a utf8 +// codepoint, or if dst doesn't have enough room for a null +// terminator, the final string will be cut short to preserve +// utf8 validity. + +utf8_nonnull utf8_weak void *utf8ncpy(void *utf8_restrict dst, + const void *utf8_restrict src, size_t n); + +// Similar to utf8dup, except that at most n bytes of src are copied. If src is +// longer than n, only n bytes are copied and a null byte is added. +// +// Returns a new string if successful, 0 otherwise +utf8_weak void *utf8ndup(const void *src, size_t n); + +// Locates the first occurrence in the utf8 string str of any byte in the +// utf8 string accept, or 0 if no match was found. +utf8_nonnull utf8_pure utf8_weak void *utf8pbrk(const void *str, + const void *accept); + +// Find the last match of the utf8 codepoint chr in the utf8 string src. +utf8_nonnull utf8_pure utf8_weak void *utf8rchr(const void *src, int chr); + +// Number of bytes in the utf8 string str, +// including the null terminating byte. +utf8_nonnull utf8_pure utf8_weak size_t utf8size(const void *str); + +// Similar to utf8size, except that the null terminating byte is excluded. +utf8_nonnull utf8_pure utf8_weak size_t utf8size_lazy(const void *str); + +// Similar to utf8size, except that only at most n bytes of src are looked and +// the null terminating byte is excluded. +utf8_nonnull utf8_pure utf8_weak size_t utf8nsize_lazy(const void *str, size_t n); + +// Number of utf8 codepoints in the utf8 string src that consists entirely +// of utf8 codepoints from the utf8 string accept. +utf8_nonnull utf8_pure utf8_weak size_t utf8spn(const void *src, + const void *accept); + +// The position of the utf8 string needle in the utf8 string haystack. +utf8_nonnull utf8_pure utf8_weak void *utf8str(const void *haystack, + const void *needle); + +// The position of the utf8 string needle in the utf8 string haystack, case +// insensitive. +utf8_nonnull utf8_pure utf8_weak void *utf8casestr(const void *haystack, + const void *needle); + +// Return 0 on success, or the position of the invalid +// utf8 codepoint on failure. +utf8_nonnull utf8_pure utf8_weak void *utf8valid(const void *str); + +// Similar to utf8valid, except that only at most n bytes of src are looked. +utf8_nonnull utf8_pure utf8_weak void *utf8nvalid(const void *str, size_t n); + +// Given a null-terminated string, makes the string valid by replacing invalid +// codepoints with a 1-byte replacement. Returns 0 on success. +utf8_nonnull utf8_weak int utf8makevalid(void *str, + const utf8_int32_t replacement); + +// Sets out_codepoint to the current utf8 codepoint in str, and returns the +// address of the next utf8 codepoint after the current one in str. +utf8_nonnull utf8_weak void * +utf8codepoint(const void *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint); + +// Calculates the size of the next utf8 codepoint in str. +utf8_nonnull utf8_weak size_t utf8codepointcalcsize(const void *str); + +// Returns the size of the given codepoint in bytes. +utf8_weak size_t utf8codepointsize(utf8_int32_t chr); + +// Write a codepoint to the given string, and return the address to the next +// place after the written codepoint. Pass how many bytes left in the buffer to +// n. If there is not enough space for the codepoint, this function returns +// null. +utf8_nonnull utf8_weak void *utf8catcodepoint(void *str, utf8_int32_t chr, + size_t n); + +// Returns 1 if the given character is lowercase, or 0 if it is not. +utf8_weak int utf8islower(utf8_int32_t chr); + +// Returns 1 if the given character is uppercase, or 0 if it is not. +utf8_weak int utf8isupper(utf8_int32_t chr); + +// Transform the given string into all lowercase codepoints. +utf8_nonnull utf8_weak void utf8lwr(void *utf8_restrict str); + +// Transform the given string into all uppercase codepoints. +utf8_nonnull utf8_weak void utf8upr(void *utf8_restrict str); + +// Make a codepoint lower case if possible. +utf8_weak utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp); + +// Make a codepoint upper case if possible. +utf8_weak utf8_int32_t utf8uprcodepoint(utf8_int32_t cp); + +// Sets out_codepoint to the current utf8 codepoint in str, and returns the +// address of the previous utf8 codepoint before the current one in str. +utf8_nonnull utf8_weak void * +utf8rcodepoint(const void *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint); + +// Duplicate the utf8 string src by getting its size, calling alloc_func_ptr to +// copy over data to a new buffer, and returning that. Or 0 if alloc_func_ptr +// returned null. +utf8_weak void *utf8dup_ex(const void *src, + void *(*alloc_func_ptr)(void *, size_t), + void *user_data); + +// Similar to utf8dup, except that at most n bytes of src are copied. If src is +// longer than n, only n bytes are copied and a null byte is added. +// +// Returns a new string if successful, 0 otherwise. +utf8_weak void *utf8ndup_ex(const void *src, size_t n, + void *(*alloc_func_ptr)(void *, size_t), + void *user_data); + +#if !defined(__UTF8_SOURCE) +#undef utf8_restrict +#undef utf8_null +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif // SHEREDOM_UTF8_H_INCLUDED diff --git a/libcharudet/.cvsignore b/libcharudet/.cvsignore index f3c7a7c5..d718f179 100644 --- a/libcharudet/.cvsignore +++ b/libcharudet/.cvsignore @@ -1 +1,3 @@ Makefile +*.err + diff --git a/libcharudet/libcharudet.cpp b/libcharudet/libcharudet.cpp index 002b4f4d..bdc79b7f 100644 --- a/libcharudet/libcharudet.cpp +++ b/libcharudet/libcharudet.cpp @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_libchardet_cpp,"$Id: libcharudet.cpp,v 1.6 2018/10/04 14:43:24 cvsuser Exp $") +__CIDENT_RCSID(cr_libchardet_cpp,"$Id: libcharudet.cpp,v 1.7 2022/03/21 15:12:12 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: libcharudet.cpp,v 1.6 2018/10/04 14:43:24 cvsuser Exp $ +/* $Id: libcharudet.cpp,v 1.7 2022/03/21 15:12:12 cvsuser Exp $ * * libchardet interface. * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libduktape/.cvsignore b/libduktape/.cvsignore index 74125502..d8929d3e 100644 --- a/libduktape/.cvsignore +++ b/libduktape/.cvsignore @@ -1,2 +1,3 @@ -Makefile +Makefile +*.err version.h diff --git a/libllist/.cvsignore b/libllist/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/libllist/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/libllist/Makefile.in b/libllist/Makefile.in index a302e738..f2172fe4 100644 --- a/libllist/Makefile.in +++ b/libllist/Makefile.in @@ -1,9 +1,9 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.15 2020/06/18 20:35:17 cvsuser Exp $ +# $Id: Makefile.in,v 1.16 2022/03/21 15:13:03 cvsuser Exp $ # libllist makefile. # # -# Copyright (c) 1998 - 2020, Adam Young. +# Copyright (c) 1998 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. diff --git a/libllist/llalloc.c b/libllist/llalloc.c index 86b38ec4..68a04464 100644 --- a/libllist/llalloc.c +++ b/libllist/llalloc.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_alloc_c,"$Id: llalloc.c,v 1.11 2018/10/01 22:13:55 cvsuser Exp $") +__CIDENT_RCSID(cr_alloc_c,"$Id: llalloc.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llalloc.c,v 1.11 2018/10/01 22:13:55 cvsuser Exp $ +/* $Id: llalloc.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llappend.c b/libllist/llappend.c index c1ad1087..32a97125 100644 --- a/libllist/llappend.c +++ b/libllist/llappend.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_append_c,"$Id: llappend.c,v 1.11 2018/10/01 22:13:55 cvsuser Exp $") +__CIDENT_RCSID(cr_append_c,"$Id: llappend.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llappend.c,v 1.11 2018/10/01 22:13:55 cvsuser Exp $ +/* $Id: llappend.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llclear.c b/libllist/llclear.c index 2eca7203..a6339772 100644 --- a/libllist/llclear.c +++ b/libllist/llclear.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_clear_c,"$Id: llclear.c,v 1.13 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_clear_c,"$Id: llclear.c,v 1.14 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llclear.c,v 1.13 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llclear.c,v 1.14 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/lldelete.c b/libllist/lldelete.c index 04439563..c6444976 100644 --- a/libllist/lldelete.c +++ b/libllist/lldelete.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_delete_c,"$Id: lldelete.c,v 1.12 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_delete_c,"$Id: lldelete.c,v 1.13 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: lldelete.c,v 1.12 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: lldelete.c,v 1.13 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llelem.c b/libllist/llelem.c index 870e8c8a..bced7bc3 100644 --- a/libllist/llelem.c +++ b/libllist/llelem.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_elem_c,"$Id: llelem.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_elem_c,"$Id: llelem.c,v 1.11 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llelem.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llelem.c,v 1.11 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llfirst.c b/libllist/llfirst.c index 4736c662..d5fd06de 100644 --- a/libllist/llfirst.c +++ b/libllist/llfirst.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_first_c,"$Id: llfirst.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_first_c,"$Id: llfirst.c,v 1.11 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llfirst.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llfirst.c,v 1.11 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llfree.c b/libllist/llfree.c index cc63d625..d22f0a79 100644 --- a/libllist/llfree.c +++ b/libllist/llfree.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_free_c,"$Id: llfree.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_free_c,"$Id: llfree.c,v 1.11 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llfree.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llfree.c,v 1.11 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llheaders.h b/libllist/llheaders.h index f47531f8..082369b9 100644 --- a/libllist/llheaders.h +++ b/libllist/llheaders.h @@ -1,16 +1,16 @@ #ifndef GR_LLHEADERS_H_INCLUDED #define GR_LLHEADERS_H_INCLUDED #include -__CIDENT_RCSID(cr_llheaders_h,"$Id: llheaders.h,v 1.8 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_llheaders_h,"$Id: llheaders.h,v 1.9 2022/03/21 15:13:03 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* -*- indent-width: 2; -*- */ -/* $Id: llheaders.h,v 1.8 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llheaders.h,v 1.9 2022/03/21 15:13:03 cvsuser Exp $ * * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llhook.c b/libllist/llhook.c index 3a4356ea..bd180835 100644 --- a/libllist/llhook.c +++ b/libllist/llhook.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_hook_c,"$Id: llhook.c,v 1.11 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_hook_c,"$Id: llhook.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llhook.c,v 1.11 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llhook.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llinit.c b/libllist/llinit.c index 35862cb8..02a14c8b 100644 --- a/libllist/llinit.c +++ b/libllist/llinit.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_init_c,"$Id: llinit.c,v 1.11 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_init_c,"$Id: llinit.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llinit.c,v 1.11 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llinit.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llinsert.c b/libllist/llinsert.c index b983386c..55b15178 100644 --- a/libllist/llinsert.c +++ b/libllist/llinsert.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_insert_c,"$Id: llinsert.c,v 1.13 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_insert_c,"$Id: llinsert.c,v 1.14 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llinsert.c,v 1.13 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llinsert.c,v 1.14 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/lllast.c b/libllist/lllast.c index 13cee9f2..d68230f7 100644 --- a/libllist/lllast.c +++ b/libllist/lllast.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_last_c,"$Id: lllast.c,v 1.8 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_last_c,"$Id: lllast.c,v 1.9 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: lllast.c,v 1.8 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: lllast.c,v 1.9 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/lllength.c b/libllist/lllength.c index 2e3dec74..c7837abe 100644 --- a/libllist/lllength.c +++ b/libllist/lllength.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_length_c,"$Id: lllength.c,v 1.8 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_length_c,"$Id: lllength.c,v 1.9 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: lllength.c,v 1.8 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: lllength.c,v 1.9 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/lllook.c b/libllist/lllook.c index 1f7a9366..fe339d77 100644 --- a/libllist/lllook.c +++ b/libllist/lllook.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_look_c,"$Id: lllook.c,v 1.11 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_look_c,"$Id: lllook.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: lllook.c,v 1.11 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: lllook.c,v 1.12 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llmagic.c b/libllist/llmagic.c index afd4c81c..6a6c4ee7 100644 --- a/libllist/llmagic.c +++ b/libllist/llmagic.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_magic_c,"$Id: llmagic.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_magic_c,"$Id: llmagic.c,v 1.11 2022/03/21 15:13:03 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llmagic.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llmagic.c,v 1.11 2022/03/21 15:13:03 cvsuser Exp $ * Linked list management module. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llnext.c b/libllist/llnext.c index 5be1d752..450c5678 100644 --- a/libllist/llnext.c +++ b/libllist/llnext.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_next_c,"$Id: llnext.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_next_c,"$Id: llnext.c,v 1.11 2022/03/21 15:13:04 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llnext.c,v 1.10 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llnext.c,v 1.11 2022/03/21 15:13:04 cvsuser Exp $ * Linked list management module. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llprev.c b/libllist/llprev.c index 022bda78..e498aa0e 100644 --- a/libllist/llprev.c +++ b/libllist/llprev.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_prev_c,"$Id: llprev.c,v 1.12 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_prev_c,"$Id: llprev.c,v 1.13 2022/03/21 15:13:04 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llprev.c,v 1.12 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llprev.c,v 1.13 2022/03/21 15:13:04 cvsuser Exp $ * Linked list management module. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llpush.c b/libllist/llpush.c index 1138b4ea..513aec86 100644 --- a/libllist/llpush.c +++ b/libllist/llpush.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_push_c,"$Id: llpush.c,v 1.12 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_push_c,"$Id: llpush.c,v 1.13 2022/03/21 15:13:04 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llpush.c,v 1.12 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llpush.c,v 1.13 2022/03/21 15:13:04 cvsuser Exp $ * Linked list management module. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llremove.c b/libllist/llremove.c index 7c22bd3c..9279a06c 100644 --- a/libllist/llremove.c +++ b/libllist/llremove.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_remove_c,"$Id: llremove.c,v 1.11 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_remove_c,"$Id: llremove.c,v 1.12 2022/03/21 15:13:04 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llremove.c,v 1.11 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llremove.c,v 1.12 2022/03/21 15:13:04 cvsuser Exp $ * Linked list management module. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libllist/llunhook.c b/libllist/llunhook.c index b4999389..19671814 100644 --- a/libllist/llunhook.c +++ b/libllist/llunhook.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_unhook_c,"$Id: llunhook.c,v 1.12 2018/10/01 22:13:56 cvsuser Exp $") +__CIDENT_RCSID(cr_unhook_c,"$Id: llunhook.c,v 1.13 2022/03/21 15:13:04 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: llunhook.c,v 1.12 2018/10/01 22:13:56 cvsuser Exp $ +/* $Id: llunhook.c,v 1.13 2022/03/21 15:13:04 cvsuser Exp $ * Linked list management module. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libmalloc/.cvsignore b/libmalloc/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/libmalloc/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/libmisc/.cvsignore b/libmisc/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/libmisc/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/libmisc/edtrace.c b/libmisc/edtrace.c index 18a1ac93..7fd1d080 100644 --- a/libmisc/edtrace.c +++ b/libmisc/edtrace.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_edtrace_c,"$Id: edtrace.c,v 1.43 2020/06/18 13:13:45 cvsuser Exp $") +__CIDENT_RCSID(gr_edtrace_c,"$Id: edtrace.c,v 1.44 2021/07/05 15:01:28 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: edtrace.c,v 1.43 2020/06/18 13:13:45 cvsuser Exp $ +/* $Id: edtrace.c,v 1.44 2021/07/05 15:01:28 cvsuser Exp $ * Simple diagnostic trace. * * @@ -340,7 +340,7 @@ trace_str(const char *str) const char * c_string(const char *str) { - static char buf[1024]; /* MAGIC */ + static char buf[4 * 1024]; /* MAGIC */ const char *endbp = (buf + (sizeof(buf) - 10)); register char *bp = buf; char c; diff --git a/libonigrx/.cvsignore b/libonigrx/.cvsignore new file mode 100644 index 00000000..97c747fe --- /dev/null +++ b/libonigrx/.cvsignore @@ -0,0 +1,7 @@ +Makefile +*.err +.unpacked.* +onig-5.9.4 +onig-5.9.5 +onig-6.9.6 + diff --git a/libonigrx/.gitignore b/libonigrx/.gitignore index dfc80a88..9dc574b2 100644 --- a/libonigrx/.gitignore +++ b/libonigrx/.gitignore @@ -1,2 +1,4 @@ onig-5.9.4/ -onig-5.9.5/ \ No newline at end of file +onig-5.9.5/ +onig-6.9.6/ +.unpacked.* diff --git a/libsplay/.cvsignore b/libsplay/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/libsplay/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/libsplay/spblk.c b/libsplay/spblk.c index 54f8ec22..4117a3e3 100644 --- a/libsplay/spblk.c +++ b/libsplay/spblk.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spblk_c,"$Id: spblk.c,v 1.15 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_spblk_c,"$Id: spblk.c,v 1.16 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spblk.c,v 1.15 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: spblk.c,v 1.16 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spdeq.c b/libsplay/spdeq.c index e89a4647..2610ff09 100644 --- a/libsplay/spdeq.c +++ b/libsplay/spdeq.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spdeq_c,"$Id: spdeq.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_spdeq_c,"$Id: spdeq.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spdeq.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: spdeq.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spempty.c b/libsplay/spempty.c index 9bc548dc..e0a5a563 100644 --- a/libsplay/spempty.c +++ b/libsplay/spempty.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spempty_c,"$Id: spempty.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_spempty_c,"$Id: spempty.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spempty.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: spempty.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spenq.c b/libsplay/spenq.c index 628c120d..a9312f4c 100644 --- a/libsplay/spenq.c +++ b/libsplay/spenq.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spenq_c,"$Id: spenq.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_spenq_c,"$Id: spenq.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spenq.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: spenq.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spflat.c b/libsplay/spflat.c index 8f17894f..8bcebf25 100644 --- a/libsplay/spflat.c +++ b/libsplay/spflat.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spflat_c,"$Id: spflat.c,v 1.15 2020/04/11 20:01:27 cvsuser Exp $") +__CIDENT_RCSID(cr_spflat_c,"$Id: spflat.c,v 1.16 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spflat.c,v 1.15 2020/04/11 20:01:27 cvsuser Exp $ +/* $Id: spflat.c,v 1.16 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/sphead.c b/libsplay/sphead.c index 5cf5bc8f..2885e1a9 100644 --- a/libsplay/sphead.c +++ b/libsplay/sphead.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_sphead_c,"$Id: sphead.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_sphead_c,"$Id: sphead.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: sphead.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: sphead.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spheaders.h b/libsplay/spheaders.h index 4c1d0e85..956c7319 100644 --- a/libsplay/spheaders.h +++ b/libsplay/spheaders.h @@ -1,15 +1,15 @@ #ifndef GR_SPHEADERS_H_INCLUDED #define GR_SPHEADERS_H_INCLUDED #include -__CIDENT_RCSID(cr_spheaders_h,"$Id: spheaders.h,v 1.11 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_spheaders_h,"$Id: spheaders.h,v 1.12 2022/03/21 15:17:20 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spheaders.h,v 1.11 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: spheaders.h,v 1.12 2022/03/21 15:17:20 cvsuser Exp $ * splay library * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spinit.c b/libsplay/spinit.c index c206de90..7ca6459c 100644 --- a/libsplay/spinit.c +++ b/libsplay/spinit.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(cr_spinit_c,"$Id: spinit.c,v 1.15 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_spinit_c,"$Id: spinit.c,v 1.16 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spinit.c,v 1.15 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: spinit.c,v 1.16 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * The basic splay tree algorithms were originally presented in: @@ -12,7 +12,7 @@ __CIDENT_RCSID(cr_spinit_c,"$Id: spinit.c,v 1.15 2018/10/01 22:14:55 cvsuser Exp * of Computing (Boston, Apr 1983) 235-245. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/splay.c b/libsplay/splay.c index e2db75a3..b0b02b4e 100644 --- a/libsplay/splay.c +++ b/libsplay/splay.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(cr_splay_c,"$Id: splay.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_splay_c,"$Id: splay.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: splay.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: splay.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * The basic splay tree algorithms were originally presented in: @@ -12,7 +12,7 @@ __CIDENT_RCSID(cr_splay_c,"$Id: splay.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $ * of Computing (Boston, Apr 1983) 235-245. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/splookup.c b/libsplay/splookup.c index 4a7f5e4c..3a0d9146 100644 --- a/libsplay/splookup.c +++ b/libsplay/splookup.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_splookup_c,"$Id: splookup.c,v 1.14 2020/04/11 20:01:27 cvsuser Exp $") +__CIDENT_RCSID(cr_splookup_c,"$Id: splookup.c,v 1.15 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: splookup.c,v 1.14 2020/04/11 20:01:27 cvsuser Exp $ +/* $Id: splookup.c,v 1.15 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spplook.c b/libsplay/spplook.c index b882a494..c0f9497a 100644 --- a/libsplay/spplook.c +++ b/libsplay/spplook.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spplook_c,"$Id: spplook.c,v 1.18 2020/04/20 23:08:07 cvsuser Exp $") +__CIDENT_RCSID(cr_spplook_c,"$Id: spplook.c,v 1.19 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spplook.c,v 1.18 2020/04/20 23:08:07 cvsuser Exp $ +/* $Id: spplook.c,v 1.19 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -128,4 +128,4 @@ cmp_ambiguous( return ret; } -/*end*/ \ No newline at end of file +/*end*/ diff --git a/libsplay/spsize.c b/libsplay/spsize.c index 73dde157..46f27a19 100644 --- a/libsplay/spsize.c +++ b/libsplay/spsize.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spsize_c,"$Id: spsize.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_spsize_c,"$Id: spsize.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spsize.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: spsize.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spstats.c b/libsplay/spstats.c index bb5eb485..efab4be7 100644 --- a/libsplay/spstats.c +++ b/libsplay/spstats.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spstats_c,"$Id: spstats.c,v 1.14 2020/04/20 23:08:07 cvsuser Exp $") +__CIDENT_RCSID(cr_spstats_c,"$Id: spstats.c,v 1.15 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spstats.c,v 1.14 2020/04/20 23:08:07 cvsuser Exp $ +/* $Id: spstats.c,v 1.15 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/sptest.c b/libsplay/sptest.c index b0e676fa..25ae7630 100644 --- a/libsplay/sptest.c +++ b/libsplay/sptest.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_sptest_c,"$Id: sptest.c,v 1.9 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_sptest_c,"$Id: sptest.c,v 1.10 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: sptest.c,v 1.9 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: sptest.c,v 1.10 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/sptree.c b/libsplay/sptree.c index 54265b72..7b481f42 100644 --- a/libsplay/sptree.c +++ b/libsplay/sptree.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_sptree_c,"$Id: sptree.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_sptree_c,"$Id: sptree.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: sptree.c,v 1.13 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: sptree.c,v 1.14 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/sputil.c b/libsplay/sputil.c index 0a83a9ca..8c9c29d6 100644 --- a/libsplay/sputil.c +++ b/libsplay/sputil.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_sputil_c,"$Id: sputil.c,v 1.10 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_sputil_c,"$Id: sputil.c,v 1.11 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: sputil.c,v 1.10 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: sputil.c,v 1.11 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spwalk.c b/libsplay/spwalk.c index dd12e8df..2146c03e 100644 --- a/libsplay/spwalk.c +++ b/libsplay/spwalk.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spwalk_c,"$Id: spwalk.c,v 1.14 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_spwalk_c,"$Id: spwalk.c,v 1.15 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spwalk.c,v 1.14 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: spwalk.c,v 1.15 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libsplay/spzap.c b/libsplay/spzap.c index 86a90575..a5b169a7 100644 --- a/libsplay/spzap.c +++ b/libsplay/spzap.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(cr_spzap_c,"$Id: spzap.c,v 1.6 2018/10/01 22:14:55 cvsuser Exp $") +__CIDENT_RCSID(cr_spzap_c,"$Id: spzap.c,v 1.7 2022/03/21 15:17:20 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: spzap.c,v 1.6 2018/10/01 22:14:55 cvsuser Exp $ +/* $Id: spzap.c,v 1.7 2022/03/21 15:17:20 cvsuser Exp $ * libsplay version 2.0 - SPLAY tree implementation. * * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libteken/.cvsignore b/libteken/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/libteken/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/libterm/.cvsignore b/libterm/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/libterm/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/libtre/.cvsignore b/libtre/.cvsignore index f2c9b22d..cb31246f 100644 --- a/libtre/.cvsignore +++ b/libtre/.cvsignore @@ -1,4 +1,6 @@ -tre-master/ +Makefile +*.err +tre-master tre-config.h tre.h - +.unpacked.* diff --git a/libtre/.gitignore b/libtre/.gitignore index f2c9b22d..67b0eaf0 100644 --- a/libtre/.gitignore +++ b/libtre/.gitignore @@ -1,4 +1,5 @@ tre-master/ tre-config.h tre.h +.unpacked.* diff --git a/libvfs/.cvsignore b/libvfs/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/libvfs/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/libvfs/Makefile.in b/libvfs/Makefile.in index 3b3db417..675e5d20 100644 --- a/libvfs/Makefile.in +++ b/libvfs/Makefile.in @@ -1,9 +1,9 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.11 2020/06/18 20:35:17 cvsuser Exp $ +# $Id: Makefile.in,v 1.12 2022/03/21 14:27:22 cvsuser Exp $ # libvfs makefile. # # -# Copyright (c) 1998 - 2020, Adam Young. +# Copyright (c) 1998 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. diff --git a/libvfs/vfs.c b/libvfs/vfs.c index 07bce7fd..4a810c1d 100644 --- a/libvfs/vfs.c +++ b/libvfs/vfs.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_c,"$Id: vfs.c,v 1.14 2020/04/14 23:13:32 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_c,"$Id: vfs.c,v 1.15 2022/03/21 14:27:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs.c,v 1.14 2020/04/14 23:13:32 cvsuser Exp $ +/* $Id: vfs.c,v 1.15 2022/03/21 14:27:22 cvsuser Exp $ * Virtual file system interface. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs.h b/libvfs/vfs.h index f89d143c..0b7a6d39 100644 --- a/libvfs/vfs.h +++ b/libvfs/vfs.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_H_INCLUDED #define GR_VFS_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_h,"$Id: vfs.h,v 1.15 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_h,"$Id: vfs.h,v 1.16 2022/03/21 14:27:22 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs.h,v 1.15 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs.h,v 1.16 2022/03/21 14:27:22 cvsuser Exp $ * Virtial File System Interface. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_archive.c b/libvfs/vfs_archive.c index 843e1bef..cf4ac2a2 100644 --- a/libvfs/vfs_archive.c +++ b/libvfs/vfs_archive.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_archive_c,"$Id: vfs_archive.c,v 1.20 2020/04/14 23:13:32 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_archive_c,"$Id: vfs_archive.c,v 1.21 2022/03/21 14:27:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_archive.c,v 1.20 2020/04/14 23:13:32 cvsuser Exp $ +/* $Id: vfs_archive.c,v 1.21 2022/03/21 14:27:22 cvsuser Exp $ * Virtual file system interface - libarchive driver. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_base.c b/libvfs/vfs_base.c index 9baadd4c..8babc740 100644 --- a/libvfs/vfs_base.c +++ b/libvfs/vfs_base.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_base_c,"$Id: vfs_base.c,v 1.24 2020/06/18 13:17:29 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_base_c,"$Id: vfs_base.c,v 1.25 2022/03/21 14:27:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_base.c,v 1.24 2020/06/18 13:17:29 cvsuser Exp $ +/* $Id: vfs_base.c,v 1.25 2022/03/21 14:27:22 cvsuser Exp $ * Virtual file system interface - base implementation. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_cache.c b/libvfs/vfs_cache.c index cdfd64f0..bc0f751e 100644 --- a/libvfs/vfs_cache.c +++ b/libvfs/vfs_cache.c @@ -1,8 +1,8 @@ #include -__CIDENT_RCSID(gr_vfs_cache_c,"$Id: vfs_cache.c,v 1.13 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_cache_c,"$Id: vfs_cache.c,v 1.14 2022/03/21 14:27:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_cache.c,v 1.13 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_cache.c,v 1.14 2022/03/21 14:27:22 cvsuser Exp $ * Virtual file system interface - name cache * * Names found by directory scans are retained in a cache for future reference. @@ -12,7 +12,7 @@ __CIDENT_RCSID(gr_vfs_cache_c,"$Id: vfs_cache.c,v 1.13 2019/03/15 23:23:01 cvsus * refers to the directory containing name. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -102,7 +102,7 @@ vfs_cache_lookup(struct vfs_cache *cache, const char *abspath, unsigned abslen) if (abslen) { struct vfs_node find = {0}; cacherb_t *rb = &cache->c_tree; - + find.v_magic = VNODE_MAGIC; find.v_cache = cache; find.v_cachehash = vfs_name_hash(abspath, abslen); diff --git a/libvfs/vfs_cache.h b/libvfs/vfs_cache.h index ca021a5d..7d7606d7 100644 --- a/libvfs/vfs_cache.h +++ b/libvfs/vfs_cache.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_CACHE_H_INCLUDED #define GR_VFS_CACHE_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_cache_h,"$Id: vfs_cache.h,v 1.10 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_cache_h,"$Id: vfs_cache.h,v 1.11 2022/03/21 14:27:22 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_cache.h,v 1.10 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_cache.h,v 1.11 2022/03/21 14:27:22 cvsuser Exp $ * Virtual File System Interface -- name cache. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_class.c b/libvfs/vfs_class.c index 93d05ce8..c043875a 100644 --- a/libvfs/vfs_class.c +++ b/libvfs/vfs_class.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_class_c,"$Id: vfs_class.c,v 1.12 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_class_c,"$Id: vfs_class.c,v 1.13 2022/03/21 14:27:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_class.c,v 1.12 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_class.c,v 1.13 2022/03/21 14:27:22 cvsuser Exp $ * Virtual file system - utility functions. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -73,13 +73,13 @@ vfs_class_shutdown(void) if (NULL != (vfs = TAILQ_FIRST(&x_instanceq))) { do { struct vfs_class *t_vfs = TAILQ_NEXT(vfs, v_node); - + if (vfs->v_prefix[0]) { vfs_class_delete(vfs); /* all but the root class */ } vfs = t_vfs; } while (vfs); - } + } } @@ -88,7 +88,7 @@ vfs_class_shutdown(void) * * Parameters; * desc - Description. - * prefix - Clas prefix associated virtual file-system + * prefix - Clas prefix associated virtual file-system * class, for examples ('ftp' and 'tar'). * impl - Implementation virtual operators. * @@ -106,7 +106,7 @@ vfs_class_new(const char *desc, const char *prefix, struct vfs_implementation *i assert(prefix); /* - * enforce basic rules, + * enforce basic rules, * length >= 3 (stop possible confusion with DOS/WIN32 drive specifications) and must * lead with an alpha and contain only trailing alpha-numeric characters. the only * exception is the root class which is representing using an empty prefix. @@ -116,12 +116,12 @@ vfs_class_new(const char *desc, const char *prefix, struct vfs_implementation *i * [a-z][a-z0-9]{2,} */ const char *t_prefix = prefix; - - if (prefixlength < 3 || !isalpha(*t_prefix)) { + + if (prefixlength < 3 || !isalpha(*t_prefix)) { errno = EINVAL; /* xxx[xxxx] */ return NULL; } - + while (*++t_prefix) { if (! isalnum(*t_prefix)) { errno = EINVAL; @@ -156,7 +156,7 @@ vfs_class_new(const char *desc, const char *prefix, struct vfs_implementation *i if (0 != (*impl->i_initialise)(vfs)) { /* * initialisation failure\ - * destroy c;ass + * destroy c;ass */ vfs->v_impl.i_shutdown = NULL; /* dont call shutdown */ vfs_class_delete(vfs); @@ -221,7 +221,7 @@ vfs_class_delete(struct vfs_class *vfs) { assert(vfs); assert(VINSTANCE_MAGIC == vfs->v_magic); - + VFS_TRACE(("\tvfs_class_delete('%s', '%s')\n", vfs->v_desc, vfs->v_prefix)) assert(0 == vfs->v_references); diff --git a/libvfs/vfs_class.h b/libvfs/vfs_class.h index 0f94a2ea..c6bc8eb6 100644 --- a/libvfs/vfs_class.h +++ b/libvfs/vfs_class.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_CLASS_H_INCLUDED #define GR_VFS_CLASS_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_class_h,"$Id: vfs_class.h,v 1.10 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_class_h,"$Id: vfs_class.h,v 1.11 2022/03/21 14:27:22 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_class.h,v 1.10 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_class.h,v 1.11 2022/03/21 14:27:22 cvsuser Exp $ * Virtual File System Interface -- filessytem class definitions. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_curl.c b/libvfs/vfs_curl.c index 13581386..79a700a1 100644 --- a/libvfs/vfs_curl.c +++ b/libvfs/vfs_curl.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_curl_c,"$Id: vfs_curl.c,v 1.14 2020/06/05 12:54:27 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_curl_c,"$Id: vfs_curl.c,v 1.15 2022/03/21 14:27:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_curl.c,v 1.14 2020/06/05 12:54:27 cvsuser Exp $ +/* $Id: vfs_curl.c,v 1.15 2022/03/21 14:27:22 cvsuser Exp $ * Virtual file system interface - libcurl driver. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_glob.c b/libvfs/vfs_glob.c index a3af7c42..d96d7b76 100644 --- a/libvfs/vfs_glob.c +++ b/libvfs/vfs_glob.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_glob_c,"$Id: vfs_glob.c,v 1.11 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_glob_c,"$Id: vfs_glob.c,v 1.12 2022/03/21 14:27:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_glob.c,v 1.11 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_glob.c,v 1.12 2022/03/21 14:27:22 cvsuser Exp $ * Virtual file system interface - glob implementation. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_glob.h b/libvfs/vfs_glob.h index 2f7fc556..87b22905 100644 --- a/libvfs/vfs_glob.h +++ b/libvfs/vfs_glob.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_GLOB_H_INCLUDED #define GR_VFS_GLOB_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_glob_h,"$Id: vfs_glob.h,v 1.8 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_glob_h,"$Id: vfs_glob.h,v 1.9 2022/03/21 14:27:22 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_glob.h,v 1.8 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_glob.h,v 1.9 2022/03/21 14:27:22 cvsuser Exp $ * Virtual file system interface - glob implementation. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -47,7 +47,7 @@ typedef struct { __CBEGIN_DECLS -extern int vfs_glob(const char *pattern, int flags, +extern int vfs_glob(const char *pattern, int flags, int (*errfunc)(const char *epath, int eerrno), vfs_glob_t *pglob); extern void vfs_globfree(vfs_glob_t *pglob); diff --git a/libvfs/vfs_handle.c b/libvfs/vfs_handle.c index 982ceadb..2cbf8a48 100644 --- a/libvfs/vfs_handle.c +++ b/libvfs/vfs_handle.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_handle_c,"$Id: vfs_handle.c,v 1.12 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_handle_c,"$Id: vfs_handle.c,v 1.13 2022/03/21 14:27:22 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_handle.c,v 1.12 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_handle.c,v 1.13 2022/03/21 14:27:22 cvsuser Exp $ * Virtual file system - file handle management. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -142,7 +142,7 @@ vfs_handle_get(int handle) * should address most sequental read/write operations. */ vhandle = x_handlecache; - + } else { /* * Lookup @@ -156,7 +156,7 @@ vfs_handle_get(int handle) return vhandle; } x_handlecache = vhandle; - } + } VFS_TRACE(("vfs_handle_get(%d) : NULL\n", handle)) return NULL; } diff --git a/libvfs/vfs_handle.h b/libvfs/vfs_handle.h index 2fac383a..a744f275 100644 --- a/libvfs/vfs_handle.h +++ b/libvfs/vfs_handle.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_HANDLE_H_INCLUDED #define GR_VFS_HANDLE_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_handle_h,"$Id: vfs_handle.h,v 1.11 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_handle_h,"$Id: vfs_handle.h,v 1.12 2022/03/21 14:27:22 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_handle.h,v 1.11 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_handle.h,v 1.12 2022/03/21 14:27:22 cvsuser Exp $ * Virtual File System Interface -- internal definitions. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_internal.h b/libvfs/vfs_internal.h index 158aacc1..99523405 100644 --- a/libvfs/vfs_internal.h +++ b/libvfs/vfs_internal.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_INTERNAL_H_INCLUDED #define GR_VFS_INTERNAL_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_internal_h,"$Id: vfs_internal.h,v 1.20 2020/06/20 01:59:53 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_internal_h,"$Id: vfs_internal.h,v 1.22 2022/03/21 14:27:23 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_internal.h,v 1.20 2020/06/20 01:59:53 cvsuser Exp $ +/* $Id: vfs_internal.h,v 1.22 2022/03/21 14:27:23 cvsuser Exp $ * Virtual File System Interface -- internal definitions. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -115,11 +115,9 @@ __CBEGIN_DECLS #define vfsio_write(_fd, _ob, _is) _write(_fd, _ob, _is) #define vfsio_lseek(_fd, _o, _w) _lseek(_fd, _o, _w) -#if !defined(vfsio_access) -#define vfsio_access(_fn, _m) _access(_fn, _m) -#endif -#define vfsio_chmod(_fn, _m) _chmod(_fn, _m) -#define vfsio_unlink(_fn) _unlink(_fn) +#define vfsio_access(_fn, _m) w32_access(_fn, _m) +#define vfsio_chmod(_fn, _m) w32_chmod(_fn, _m) +#define vfsio_unlink(_fn) w32_unlink(_fn) #if !defined(vfsio_mkdir) #define vfsio_mkdir(_dn, _m) _mkdir(_dn) diff --git a/libvfs/vfs_lookup.c b/libvfs/vfs_lookup.c index c17b56bc..a67ef143 100644 --- a/libvfs/vfs_lookup.c +++ b/libvfs/vfs_lookup.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_lookup_c,"$Id: vfs_lookup.c,v 1.13 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_lookup_c,"$Id: vfs_lookup.c,v 1.14 2022/03/21 14:27:23 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_lookup.c,v 1.13 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_lookup.c,v 1.14 2022/03/21 14:27:23 cvsuser Exp $ * Virtual file system interface - node management. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_lookup.h b/libvfs/vfs_lookup.h index 31b22940..1a9654ec 100644 --- a/libvfs/vfs_lookup.h +++ b/libvfs/vfs_lookup.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_LOOKUP_H_INCLUDED #define GR_VFS_LOOKUP_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_lookup_h,"$Id: vfs_lookup.h,v 1.10 2019/03/15 23:23:01 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_lookup_h,"$Id: vfs_lookup.h,v 1.11 2022/03/21 14:27:23 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_lookup.h,v 1.10 2019/03/15 23:23:01 cvsuser Exp $ +/* $Id: vfs_lookup.h,v 1.11 2022/03/21 14:27:23 cvsuser Exp $ * Virtual File System Interface -- lookup service. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -71,7 +71,7 @@ typedef struct vfs_lookup { char l_buffer[ VFS_MAXPATH+1 ]; } vfs_lookup_t; -extern struct vfs_node * vfs_lookup(struct vfs_mount *tree, const char *path, unsigned pathlen, +extern struct vfs_node * vfs_lookup(struct vfs_mount *tree, const char *path, unsigned pathlen, unsigned op, unsigned flags, struct vfs_lookup *lk); extern struct vfs_node * vfs_resolve(vfs_lookup_t *lk); diff --git a/libvfs/vfs_mount.c b/libvfs/vfs_mount.c index 7058eed4..75fbf384 100644 --- a/libvfs/vfs_mount.c +++ b/libvfs/vfs_mount.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_mount_c,"$Id: vfs_mount.c,v 1.16 2020/06/03 15:37:47 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_mount_c,"$Id: vfs_mount.c,v 1.17 2022/03/21 14:27:23 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_mount.c,v 1.16 2020/06/03 15:37:47 cvsuser Exp $ +/* $Id: vfs_mount.c,v 1.17 2022/03/21 14:27:23 cvsuser Exp $ * Virtual file system interface --- mount table management. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_mount.h b/libvfs/vfs_mount.h index 21a5d5ad..b2412d2f 100644 --- a/libvfs/vfs_mount.h +++ b/libvfs/vfs_mount.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_MOUNT_H_INCLUDED #define GR_VFS_MOUNT_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_mount_h,"$Id: vfs_mount.h,v 1.10 2019/03/15 23:23:02 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_mount_h,"$Id: vfs_mount.h,v 1.11 2022/03/21 14:27:23 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_mount.h,v 1.10 2019/03/15 23:23:02 cvsuser Exp $ +/* $Id: vfs_mount.h,v 1.11 2022/03/21 14:27:23 cvsuser Exp $ * Virtual File System Interface -- internal definitions. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_node.c b/libvfs/vfs_node.c index f3b81183..ffc56b6d 100644 --- a/libvfs/vfs_node.c +++ b/libvfs/vfs_node.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_node_c,"$Id: vfs_node.c,v 1.12 2019/03/15 23:23:02 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_node_c,"$Id: vfs_node.c,v 1.13 2022/03/21 14:27:23 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_node.c,v 1.12 2019/03/15 23:23:02 cvsuser Exp $ +/* $Id: vfs_node.c,v 1.13 2022/03/21 14:27:23 cvsuser Exp $ * Virtual file system interface - node management. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -78,7 +78,7 @@ vfs_node_new(unsigned type, const char *name, unsigned namlen, unsigned namhash, ++parent->v_childcount; ++parent->v_childedit; } - node->v_parent = parent; + node->v_parent = parent; return node; } @@ -125,7 +125,7 @@ vfs_node_destroy(struct vfs_node *node) if (NULL != (parent = node->v_parent)) { assert(VNODE_MAGIC == parent->v_magic); assert(parent->v_childcount); - + TAILQ_REMOVE(&parent->v_childlist, node, v_listnode); --parent->v_childcount; ++parent->v_childedit; @@ -155,7 +155,7 @@ vfs_node_type2str(unsigned type) case VNODE_REG: return "reg"; case VNODE_LNK: return "lnk"; case VNODE_BAD: return "bad"; - case VNODE_UNKNOWN: + case VNODE_UNKNOWN: return "Unknown"; } return ""; @@ -186,7 +186,7 @@ vfs_node_unlink(struct vfs_node *node) if (VNODE_DIR == node->v_type) { errno = EISDIR; /* can not unlink a directory */ return -1; - } + } assert(0 == node->v_childcount); assert(node->v_references); if (node->v_references <= 1) { /* allow references==0 */ @@ -227,7 +227,7 @@ vfs_node_first(struct vfs_node *node) */ struct vfs_node * vfs_node_next(struct vfs_node *node) -{ +{ assert(node); assert(VNODE_MAGIC == node->v_magic); return TAILQ_NEXT(node, v_listnode); diff --git a/libvfs/vfs_node.h b/libvfs/vfs_node.h index 681ca90f..5e2bd080 100644 --- a/libvfs/vfs_node.h +++ b/libvfs/vfs_node.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_NODE_H_INCLUDED #define GR_VFS_NODE_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_node_h,"$Id: vfs_node.h,v 1.10 2019/03/15 23:23:02 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_node_h,"$Id: vfs_node.h,v 1.11 2022/03/21 14:27:23 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_node.h,v 1.10 2019/03/15 23:23:02 cvsuser Exp $ +/* $Id: vfs_node.h,v 1.11 2022/03/21 14:27:23 cvsuser Exp $ * Virtual File System Interface -- node definitions. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -63,14 +63,14 @@ typedef struct vfs_node { unsigned v_childcount; unsigned v_childedit; /* edit count (inc on each ins/del) */ unsigned v_childseq; /* next child fileno */ - TAILQ_ENTRY(vfs_node) + TAILQ_ENTRY(vfs_node) v_listnode; /* list node */ struct vfs_cache * v_cache; /* cache (if any) */ unsigned v_cachelen; /* length of the name buffer */ unsigned v_cachehash; /* name hash */ const char * v_cachename; /* cache entry name */ RB_ENTRY(vfs_node) v_cachetree; /* name cache node */ - TAILQ_ENTRY(vfs_node) + TAILQ_ENTRY(vfs_node) v_cachelru; /* cache lru node */ unsigned v_flags; /* operational flags */ #define VNODE_FCACHED 0x0001 diff --git a/libvfs/vfs_stream.c b/libvfs/vfs_stream.c index d2f1a3f7..515c8dc9 100644 --- a/libvfs/vfs_stream.c +++ b/libvfs/vfs_stream.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_stream_c,"$Id: vfs_stream.c,v 1.13 2020/04/14 23:13:32 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_stream_c,"$Id: vfs_stream.c,v 1.14 2022/03/21 14:27:23 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_stream.c,v 1.13 2020/04/14 23:13:32 cvsuser Exp $ +/* $Id: vfs_stream.c,v 1.14 2022/03/21 14:27:23 cvsuser Exp $ * Virtual file system interface - streams. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libvfs/vfs_tree.c b/libvfs/vfs_tree.c index 80351722..9c664215 100644 --- a/libvfs/vfs_tree.c +++ b/libvfs/vfs_tree.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_tree_c,"$Id: vfs_tree.c,v 1.21 2020/06/18 13:18:07 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_tree_c,"$Id: vfs_tree.c,v 1.22 2022/03/21 14:27:23 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_tree.c,v 1.21 2020/06/18 13:18:07 cvsuser Exp $ +/* $Id: vfs_tree.c,v 1.22 2022/03/21 14:27:23 cvsuser Exp $ * Virtual file system interface - tree management. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -843,7 +843,7 @@ vfs_tree_vopen(struct vfs_mount *vmount, const char *path, int mode, int mask) mode &= ~O_CREAT; } } else { -#if defined(O_NOFOLLOW) && (O_NOFOLLOW) /* nonstandard */ +#if defined(O_NOFOLLOW) && (O_NOFOLLOW) /* nonstandard */ unsigned flags = ((mode & O_NOFOLLOW) ? 0 : LK_FFOLLOW) | LK_FNOCROSSMOUNT /*| LK_FLOCKLEAF*/; #else @@ -922,7 +922,7 @@ vfs_tree_vclose(struct vfs_handle *vhandle) } else { if (vhandle->h_ihandle >= 0) { - vfsio_close(vhandle->h_ihandle); + vfsio_close(vhandle->h_ihandle); vhandle->h_ihandle = -1; } } @@ -1054,7 +1054,7 @@ vfs_tree_vioctl(struct vfs_handle *vhandle, int op, void *data) } else { if (vhandle->h_ihandle >= 0) { #if defined(_WIN32) || defined(WIN32) || !defined(HAVE_IOCTL) - errno = EOPNOTSUPP; + errno = EOPNOTSUPP; ret = -1; #else ret = ioctl(vhandle->h_ihandle, op, data); diff --git a/libvfs/vfs_tree.h b/libvfs/vfs_tree.h index 99c586c5..6ab8b23d 100644 --- a/libvfs/vfs_tree.h +++ b/libvfs/vfs_tree.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_TREE_H_INCLUDED #define GR_VFS_TREE_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_tree_h,"$Id: vfs_tree.h,v 1.10 2019/03/15 23:23:02 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_tree_h,"$Id: vfs_tree.h,v 1.11 2022/03/21 14:27:23 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_tree.h,v 1.10 2019/03/15 23:23:02 cvsuser Exp $ +/* $Id: vfs_tree.h,v 1.11 2022/03/21 14:27:23 cvsuser Exp $ * Virtual File System Interface -- node tree definitions. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -76,7 +76,7 @@ struct vfs_treevops { int (* vop_seek)(struct vfs_tree *tree, struct vfs_handle *handle, off_t offset, int whence); int (* vop_ioctl)(struct vfs_tree *tree, struct vfs_handle *handle, int op, void *data); int (* vop_close)(struct vfs_tree *tree, struct vfs_handle *handle); - + int (* vop_localget)(struct vfs_tree *tree, struct vfs_node *node, int mode, int mask, int *fd); int (* vop_localput)(struct vfs_tree *tree, struct vfs_node *node, int changed); }; @@ -92,7 +92,7 @@ typedef struct vfs_tree { unsigned t_magic; /* structure magic */ struct vfs_mount * t_mount; /* owner/mount point */ struct vfs_treevops t_vops; /* tree interface operations */ - TAILQ_ENTRY(vfs_tree) + TAILQ_ENTRY(vfs_tree) t_nodelist; /* list node */ struct vfs_node * t_root; /* root node */ struct vfs_cache t_cache; /* node cache */ diff --git a/libvfs/vfs_util.c b/libvfs/vfs_util.c index 9c035648..c4e52616 100644 --- a/libvfs/vfs_util.c +++ b/libvfs/vfs_util.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_util_c,"$Id: vfs_util.c,v 1.20 2020/06/18 13:18:30 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_util_c,"$Id: vfs_util.c,v 1.21 2022/03/21 14:27:23 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_util.c,v 1.20 2020/06/18 13:18:30 cvsuser Exp $ +/* $Id: vfs_util.c,v 1.21 2022/03/21 14:27:23 cvsuser Exp $ * Virtual file system - utility functions. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -66,7 +66,7 @@ void vfs_init(void) { assert(VFS_VOPMAX == sizeof(struct vfs_implementation)/sizeof(void (*)())); - + VFS_TRACE(("vfs_init()\n")) vfs_tree_start(); vfs_class_start(); @@ -92,7 +92,7 @@ vfs_init(void) */ void vfs_shutdown(void) -{ +{ VFS_TRACE(("vfs_shutdown()\n")) /* x_root = NULL; */ /* include root */ vfs_mount_shutdown(); /* unmount 'all' virtual file-systems */ @@ -128,7 +128,7 @@ vfs_root(void) * Returns: * Address of root mount-point. */ -void +void vfs_trace(const char *fmt, ...) { va_list ap; @@ -298,12 +298,12 @@ vfs_tempnam(int *fd) * Returns: * Hash value. */ -unsigned +unsigned vfs_name_hash(const char *path, unsigned pathlen) { unsigned hash = (unsigned)-1; unsigned char ch; - + while (pathlen-- && (ch = (unsigned char)*path++) != 0) { if (! VFS_ISSEP(ch)) { /* ignore seperators */ hash = hash * 127 + tolower(ch); /* and case */ diff --git a/libvfs/vfs_vops.c b/libvfs/vfs_vops.c index d4e90e60..536b2949 100644 --- a/libvfs/vfs_vops.c +++ b/libvfs/vfs_vops.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_vfs_vops_c,"$Id: vfs_vops.c,v 1.11 2019/03/15 23:23:04 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_vops_c,"$Id: vfs_vops.c,v 1.12 2022/03/21 14:27:23 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_vops.c,v 1.11 2019/03/15 23:23:04 cvsuser Exp $ +/* $Id: vfs_vops.c,v 1.12 2022/03/21 14:27:23 cvsuser Exp $ * Virtual file system - virtual operators. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -134,7 +134,7 @@ vfs_vop_lookup(struct vfs_lookup *lk) if (vclass->v_impl.i_lookup) { ret = (*vclass->v_impl.i_lookup)(lk); } - + VFS_TRACE(("== %d\n", ret)) VFS_LEVELDEC() return ret; diff --git a/libvfs/vfs_vops.h b/libvfs/vfs_vops.h index 1e6d2607..4d076a2d 100644 --- a/libvfs/vfs_vops.h +++ b/libvfs/vfs_vops.h @@ -1,15 +1,15 @@ #ifndef GR_VFS_VOPS_H_INCLUDED #define GR_VFS_VOPS_H_INCLUDED #include -__CIDENT_RCSID(gr_vfs_vops_h,"$Id: vfs_vops.h,v 1.12 2019/03/15 23:23:04 cvsuser Exp $") +__CIDENT_RCSID(gr_vfs_vops_h,"$Id: vfs_vops.h,v 1.13 2022/03/21 14:27:23 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: vfs_vops.h,v 1.12 2019/03/15 23:23:04 cvsuser Exp $ +/* $Id: vfs_vops.h,v 1.13 2022/03/21 14:27:23 cvsuser Exp $ * Virtual File System Interface -- ops. * * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -89,7 +89,7 @@ struct vfs_mount; struct vfs_lookup; struct vfs_handle; struct vfs_node; -struct vfs_dir; +struct vfs_dir; struct vfs_dirent; struct vfs_implementation { diff --git a/libw32/.cvsignore b/libw32/.cvsignore index 1bc3cc2e..35a398f5 100644 --- a/libw32/.cvsignore +++ b/libw32/.cvsignore @@ -1 +1,7 @@ +util +ref* +Makefile w32config.h +package.h +update*.pl +*.err diff --git a/libw32/.gitignore b/libw32/.gitignore index 1bc3cc2e..3cbbb705 100644 --- a/libw32/.gitignore +++ b/libw32/.gitignore @@ -1 +1,7 @@ +util/ +ref*/ +Makefile w32config.h +package.h +update*.pl +*.err diff --git a/libw32/Makefile.in b/libw32/Makefile.in index e3032931..9fe4f4ab 100644 --- a/libw32/Makefile.in +++ b/libw32/Makefile.in @@ -1,9 +1,9 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.25 2020/06/20 01:29:20 cvsuser Exp $ +# $Id: Makefile.in,v 1.27 2022/03/21 14:29:39 cvsuser Exp $ # libwin32 makefile. # # -# Copyright (c) 1998 - 2020, Adam Young. +# Copyright (c) 2007, 2012 - 2022 Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. @@ -88,7 +88,7 @@ LDDEBUG= @LDDEBUG@ LDRELEASE= @LDRELEASE@ CINCLUDE= -I$(D_INC) @CINCLUDE@ -I. -CEXTRA= @DEFS@ +CEXTRA= -DUTF8FILENAMES=1 @DEFS@ ifeq ("$(BUILD_TYPE)","release") CFLAGS+= $(CRELEASE) $(CWARN) $(CINCLUDE) $(CEXTRA) $(XFLAGS) @@ -113,24 +113,32 @@ YFLAGS= -d W32LIB= $(D_LIB)/$(LP)w32_static$(A) W32DLL= $(D_LIB)/$(LP)w32.la -VERSION= 1.1.0 +VERSION= 1.2.0 VERSIONSPEC= $(subst .,:,$(VERSION)) CSOURCES=\ + w32_access.c \ w32_check.c \ w32_child.c \ + w32_chmod.c \ w32_chown.c \ w32_close.c \ w32_dir.c \ w32_dirent.c \ + w32_wdirent.c \ w32_dlfcn.c \ + w32_direntunc.c \ w32_domainname.c \ + w32_err.c \ w32_errno.c \ + w32_flock.c \ w32_fcntl.c \ w32_fsync.c \ w32_getcwd.c \ + w32_getcwdd.c \ w32_gethostname.c \ w32_getopt.c \ + w32_getopt_long.c \ w32_getrusage.c \ w32_getsubopt.c \ w32_getlocale.c \ @@ -153,7 +161,9 @@ CSOURCES=\ w32_progname.c \ w32_pwd.c \ w32_read.c \ + w32_readv.c \ w32_realpath.c \ + w32_rename.c \ w32_reparse.c \ w32_rwlock.c \ w32_select.c \ @@ -181,7 +191,8 @@ CSOURCES=\ w32_unlink.c \ w32_user.c \ w32_util.c \ - w32_write.c + w32_write.c \ + w32_writev.c LIBOBJS=\ $(addprefix $(D_OBJ)/,$(subst .c,$(O),$(CSOURCES))) @@ -197,7 +208,7 @@ endif OBJS= $(LIBOBJS) $(DLLOBJS) LIBS= $(W32LIB) $(W32DLL) TSKS= - +INSTALLED= ######################################################################################### # Rules @@ -216,6 +227,7 @@ $(W32LIB): $(D_OBJ)/.created $(LIBOBJS) $(AR) $(ARFLAGS) $@ $(LIBOBJS) $(RANLIB) $@ +INSTALLED+= $(D_BIN)/libw32.$(VERSION).dll $(W32DLL): CEXTRA += -DLIBW32_DYNAMIC -DLIBW32_LIBRARY $(W32DLL): DLLDEF = -export-symbols libw32.def $(W32DLL): $(DLLOBJS) @@ -229,7 +241,7 @@ $(D_OBJ)/.created: clean: @echo $(BUILD_TYPE) clean -@$(LIBTOOL) --mode=clean $(RM) $(W32DLL) $(DLLOBJS) >/dev/null 2>&1 - -@$(RM) $(RMFLAGS) $(BAK) $(W32LIB) $(CLEAN) $(XCLEAN) >/dev/null 2>&1 + -@$(RM) $(RMFLAGS) $(BAK) $(TSKS) $(INSTALLED) $(W32LIB) $(CLEAN) $(XCLEAN) >/dev/null 2>&1 -@$(RM) $(RMFLAGS) $(LIBOBJS) >/dev/null 2>&1 $(D_OBJ)/%$(O): %.c diff --git a/libw32/alloca.h b/libw32/alloca.h index c485af54..1845b276 100644 --- a/libw32/alloca.h +++ b/libw32/alloca.h @@ -1,14 +1,14 @@ #ifndef LIBW32_ALLOCA_H_INCLUDED #define LIBW32_ALLOCA_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_alloca_h,"$Id: alloca.h,v 1.7 2019/03/15 23:12:08 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_alloca_h,"$Id: alloca.h,v 1.8 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,13 +24,14 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ #include #endif /*LIBW32_ALLOCA_H_INCLUDED*/ + diff --git a/libw32/arpa/ftp.h b/libw32/arpa/ftp.h index 21862ab0..97757157 100644 --- a/libw32/arpa/ftp.h +++ b/libw32/arpa/ftp.h @@ -1,12 +1,12 @@ #ifndef LIBW32_ARPA_FTP_H_INCLUDED #define LIBW32_ARPA_FTP_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_arpa_ftp_h,"$Id: ftp.h,v 1.7 2018/09/30 23:32:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_arpa_ftp_h,"$Id: ftp.h,v 1.8 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2017, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/arpa/inet.h b/libw32/arpa/inet.h index 9576811c..6fdf9404 100644 --- a/libw32/arpa/inet.h +++ b/libw32/arpa/inet.h @@ -1,12 +1,12 @@ #ifndef GR_INET_H_INCLUDED #define GR_INET_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_arpa_inet_h,"$Id: inet.h,v 1.5 2017/01/29 02:22:52 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_arpa_inet_h,"$Id: inet.h,v 1.6 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2017, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/arpa/telnet.h b/libw32/arpa/telnet.h index 3b43ec19..f820bd7d 100644 --- a/libw32/arpa/telnet.h +++ b/libw32/arpa/telnet.h @@ -1,13 +1,13 @@ #ifndef LIBW32_ARPA_TELNET_H_INCLUDED #define LIBW32_ARPA_TELNET_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_arpa_telnet_h,"$Id: telnet.h,v 1.6 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_arpa_telnet_h,"$Id: telnet.h,v 1.7 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ -/* $Id: telnet.h,v 1.6 2018/09/29 02:25:24 cvsuser Exp $ */ +/* $Id: telnet.h,v 1.7 2022/03/21 14:29:42 cvsuser Exp $ */ /* - * Copyright (c) 1998 - 2017, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -55,7 +55,6 @@ __CPRAGMA_ONCE * @(#)telnet.h 8.2 (Berkeley) 12/15/93 */ - /* * Definitions for the TELNET protocol. */ diff --git a/libw32/config.h b/libw32/config.h index c5e576b8..5d73912e 100644 --- a/libw32/config.h +++ b/libw32/config.h @@ -1,14 +1,14 @@ #ifndef LIBW32_CONFIG_H_INCLUDED #define LIBW32_CONFIG_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_config_h,"$Id: config.h,v 1.4 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_config_h,"$Id: config.h,v 1.5 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ diff --git a/libw32/dirent.h b/libw32/dirent.h index abb579f7..55f69937 100644 --- a/libw32/dirent.h +++ b/libw32/dirent.h @@ -1,14 +1,14 @@ #ifndef LIBW32_DIRENT_H_INCLUDED #define LIBW32_DIRENT_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_dirent_h,"$Id: dirent.h,v 1.18 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_dirent_h,"$Id: dirent.h,v 1.20 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -38,15 +38,44 @@ __CPRAGMA_ONCE #if !defined(MAXPATHLEN) #define MAXPATHLEN 1024 /* PATH_MAX */ #endif -#if !defined(MAXNAMLEN) -#define MAXNAMLEN 1024 /* PATH_MAX */ -#endif + +/* + * Notes: d_name field + * + * The dirent structure definition shown above is taken from the Unix headers, + * and shows the d_name field with a fixed size. + * + * Warning: applications should avoid any dependence on the size of the d_name field. + * POSIX defines it as char d_name[], a character array of unspecified size, + * with at most NAME_MAX characters preceding the terminating null byte ('\0'). + * + * POSIX.1 explicitly notes that this field should not be used as an lvalue. + * The standard also notes that the use of sizeof(d_name) is incorrect; + * use strlen(d_name) instead. + * + * On some systems, this field is defined as char d_name[1]. By implication, + * the use sizeof(struct dirent) to capture the size of the record including + * the size of d_name is also incorrect. + */ struct dirent { #define d_ino d_fileno /* Backward compatibility */ unsigned long d_fileno; /* File number directory */ - unsigned short d_reclen; /* Length of this record */ - unsigned short d_namlen; /* Length of string in d_name */ + unsigned short d_reclen; /* Length of this record, in bytes */ + unsigned short d_namlen; /* Length of string in d_name, excluding terminating null; in characters. */ + +#ifndef _DIRENT_HAVE_D_RECLEN +#define _DIRENT_HAVE_D_RECLEN /* BSD extension */ +#endif +#ifndef _DIRENT_HAVE_D_NAMLEN +#define _DIRENT_HAVE_D_NAMLEN /* BSD extension */ +#define _D_EXACT_NAMLEN(d) ((d)->d_namlen) +#define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN (d) + 1) +#endif +#ifndef _DIRENT_HAVE_D_TYPE +#define _DIRENT_HAVE_D_TYPE /* BSD extension */ +#endif + #if defined(_POSIX_SOURCE) && !defined(_DIRENT_SOURCE) time_t d_reserved1; time_t d_reserved2; @@ -57,26 +86,80 @@ struct dirent { time_t d_mtime; /* Modification time */ unsigned long d_size; /* File size */ unsigned long d_attr; /* File attributes */ -#endif /*_POSIX_SOURCE*/ - char d_name[ MAXNAMLEN+1 ]; +#endif /*_POSIX_SOURCE*/ + + unsigned char d_type; /* Type of the file, possibly unknown */ + +#define DT_UNKNOWN 0 // The type is unknown. Only some filesystems have full support to return the type of the file, others might always return this value. +#define DT_FIFO 1 // A named pipe, or FIFO. See FIFO Special Files. +#define DT_CHR 2 // A character device. +#define DT_DIR 4 // A directory. +#define DT_REG 8 // A regular file. +#define DT_LNK 10 // A symbolic link. +#define DT_SOCK 12 // A local-domain socket. +#define DT_BLK 14 // A block device. + +#define MAXNAMLEN 255 + char d_name[MAXNAMLEN + 1]; /* File name, NUL terminated */ +}; + + +struct _wdirent { + unsigned long d_fileno; /* File number directory */ + unsigned short d_reclen; /* Length of this record, in bytes */ + unsigned short d_namlen; /* Length of string in d_name, excluding terminating null; in characters. */ +#if defined(_POSIX_SOURCE) && !defined(_DIRENT_SOURCE) + time_t d_reserved1; + time_t d_reserved2; + unsigned long d_reserved3; + unsigned long d_reserved4; +#else + time_t d_ctime; /* Creation time */ + time_t d_mtime; /* Modification time */ + unsigned long d_size; /* File size */ + unsigned long d_attr; /* File attributes */ +#endif /*_POSIX_SOURCE*/ + unsigned char d_type; + wchar_t d_name[MAXNAMLEN + 1]; /* File name, NUL terminated */ }; #if defined(_POSIX_SOURCE) && !defined(_DIRENT_SOURCE) typedef void *DIR; +typedef void *_WDIR; + #else #if defined(_DIRENT_SOURCE) || defined(DEBUG) - /* _dirlist, - * linked list of directory entries only required within 'dirent.c'. + /* + * _dirlist -- linked list of directory entries only required within 'dirent.c'. */ struct _dirlist { time_t dl_ctime; time_t dl_mtime; + struct _dirlist *dl_next; unsigned long dl_size; unsigned long dl_size2; unsigned long dl_attr; - char * dl_entry; - struct _dirlist *dl_next; + unsigned short dl_namlen; /* length of buffer d_name, excluding nul; in characters */ + unsigned char dl_type; + char dl_name[1]; + // plus trailing name storage. + }; + + /* + * _wdirlist -- linked list of directory entries only required within 'wdirent.c'. + */ + struct _wdirlist { + time_t dl_ctime; + time_t dl_mtime; + struct _wdirlist *dl_next; + unsigned long dl_size; + unsigned long dl_size2; + unsigned long dl_attr; + unsigned short dl_namlen; /* length of buffer d_name, excluding nul; in characters */ + unsigned char dl_type; + wchar_t dl_name[1]; + // plus trailing name storage. }; #endif /*_DIRENT_SOURCE*/ @@ -85,7 +168,7 @@ typedef struct _dirdesc { int dd_id; /* Uniquely identify open dir */ long dd_loc; /* Offset in current buffer */ long dd_size; /* Amount of data returned by getdirentries */ - char * dd_buf; /* Data buffer */ + void * dd_buf; /* Data buffer */ int dd_len; /* Size of data buffer */ long dd_seek; /* Magic cookie returned by getdirentries */ void * dd_ddloc; /* Linked list of ddloc structs for telldir/seekdir */ @@ -95,8 +178,29 @@ typedef struct _dirdesc { unsigned long dd_flags; struct _dirlist * dd_contents; struct _dirlist * dd_current; + void * dd_handle; /* End of extensions */ } DIR; + +typedef struct _wdirdesc { + int dd_fd; /* File descriptor associated with directory */ + int dd_id; /* Uniquely identify open dir */ + long dd_loc; /* Offset in current buffer */ + long dd_size; /* Amount of data returned by getdirentries */ + void * dd_buf; /* Data buffer */ + int dd_len; /* Size of data buffer */ + long dd_seek; /* Magic cookie returned by getdirentries */ + void * dd_ddloc; /* Linked list of ddloc structs for telldir/seekdir */ + + /*extensions/internal*/ + unsigned long dd_magic; /* Structure magic */ + unsigned long dd_flags; + struct _wdirlist * dd_contents; + struct _wdirlist * dd_current; + void * dd_handle; +/* End of extensions */ +} _WDIR; + #endif /*_POSIX_SOURCE*/ #include @@ -104,12 +208,26 @@ typedef struct _dirdesc { __BEGIN_DECLS LIBW32_API DIR * opendir __P((const char *)); +LIBW32_API DIR * opendirA __P((const char *)); +LIBW32_API DIR * opendirW __P((const wchar_t *)); LIBW32_API int closedir __P((DIR *)); LIBW32_API struct dirent * readdir __P((DIR *)); LIBW32_API void rewinddir __P((DIR *)); + +LIBW32_API _WDIR * _wopendir __P((const wchar_t *)); +LIBW32_API int _wclosedir __P((_WDIR *)); +LIBW32_API struct _wdirent * _wreaddir __P((_WDIR *)); +LIBW32_API void _wrewinddir __P((_WDIR *)); + #ifndef _POSIX_SOURCE LIBW32_API void seekdir __P((DIR *, long)); LIBW32_API long telldir __P((DIR *)); +LIBW32_API int readdir_r __P((DIR *, struct dirent *, struct dirent **)); /*deprecated*/ + +LIBW32_API void _wseekdir __P((_WDIR *, long)); +LIBW32_API long _wtelldir __P((_WDIR *)); +LIBW32_API int _wreaddir_r __P((_WDIR *, struct _wdirent *, struct _wdirent **)); /*deprecated*/ + LIBW32_API int alphasort __P((const void *, const void *)); LIBW32_API int scandir __P((void)); LIBW32_API int getdirentries __P((int, char *, int, long *)); @@ -118,3 +236,4 @@ LIBW32_API int getdirentries __P((int, char *, int, long *)); __END_DECLS #endif /*LIBW32_DIRENT_H_INCLUDED*/ + diff --git a/libw32/dlfcn.h b/libw32/dlfcn.h index f7ddc9fc..b29ca2cf 100644 --- a/libw32/dlfcn.h +++ b/libw32/dlfcn.h @@ -1,14 +1,14 @@ #ifndef GR_DLFCN_H_INCLUDED #define GR_DLFCN_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_dlfcn_h,"$Id: dlfcn.h,v 1.8 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_dlfcn_h,"$Id: dlfcn.h,v 1.9 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * for windows + * for windows * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,14 +24,15 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ #include +#include __BEGIN_DECLS @@ -42,6 +43,8 @@ __BEGIN_DECLS #define RTLD_LOCAL 0x08 /* all symbols are not made available for relocation processing by other modules. */ LIBW32_API void * dlopen(const char *file, int mode); +LIBW32_API void * dlopenA(const char *file, int mode); +LIBW32_API void * dlopenW(const wchar_t *file, int mode); LIBW32_API void * dlsym(void *__restrict handle, const char *__restrict name); LIBW32_API int dlclose(void *handle); LIBW32_API char * dlerror(void); diff --git a/libw32/err.h b/libw32/err.h new file mode 100644 index 00000000..b4f657e0 --- /dev/null +++ b/libw32/err.h @@ -0,0 +1,56 @@ +#ifndef LIBW32_ERR_H_INCLUDED +#define LIBW32_ERR_H_INCLUDED +#include +__CIDENT_RCSID(gr_libw32_err_h,"$Id: err.h,v 1.3 2022/03/21 14:29:39 cvsuser Exp $") +__CPRAGMA_ONCE + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win + * + * Copyright (c) 1998 - 2022, Adam Young. + * All rights reserved. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + */ + +#include +#include + +__BEGIN_DECLS + +/* ": : \n", on stderr. */ +LIBW32_API void warn(const char *fmt, ...); +LIBW32_API void vwarn(const char *fmt, va_list ap); + +/* Likewise, but without ": " and the standard error string. */ +LIBW32_API void warnx(const char *fmt, ...); +LIBW32_API void vwarnx(const char *fmt, va_list ap); + +/* Like above, but the exits using 'eval' */ +LIBW32_API void err(int eval, const char *fmt, ...); +LIBW32_API void verr(int eval, const char *fmt, va_list ap); + +LIBW32_API void errx(int eval, const char *fmt, ...); +LIBW32_API void verrx(int eval, const char *fmt, va_list ap); + +__END_DECLS + +#endif /*WIN32_ERR_H_INCLUDED*/ diff --git a/libw32/getopt.h b/libw32/getopt.h index f4b52a42..ae1bd780 100644 --- a/libw32/getopt.h +++ b/libw32/getopt.h @@ -1,14 +1,14 @@ #ifndef LIBW32_GETOPT_H_INCLUDED #define LIBW32_GETOPT_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_getopt_h,"$Id: getopt.h,v 1.6 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_getopt_h,"$Id: getopt.h,v 1.9 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -61,6 +61,7 @@ struct option { LIBW32_API int getopt(int nargc, char * const *nargv, const char *options); LIBW32_API int getopt_long(int argvc, char * const *argv, const char *options, const struct option *long_options, int *idx); +LIBW32_API int getopt_long2(int argvc, char * const *argv, const char *options, const struct option *long_options, int *idx, char *buf, int buflen); __END_DECLS diff --git a/libw32/glob.h b/libw32/glob.h index 719ff5ce..e3188cb9 100644 --- a/libw32/glob.h +++ b/libw32/glob.h @@ -1,7 +1,7 @@ #ifndef GR_GLOB_H_INCLUDED #define GR_GLOB_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_glob_h,"$Id: glob.h,v 1.3 2018/10/11 01:46:31 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_glob_h,"$Id: glob.h,v 1.4 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ @@ -10,6 +10,8 @@ __CPRAGMA_ONCE * * This file is part of the GRIEF Editor. * + * This file is part of the GRIEF Editor. + * * The GRIEF Editor is free software: you can redistribute it * and/or modify it under the terms of the GRIEF Editor License. * @@ -21,10 +23,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Path name pattern matching diff --git a/libw32/gnuwin32_archive.h b/libw32/gnuwin32_archive.h index 886037a5..23826767 100644 --- a/libw32/gnuwin32_archive.h +++ b/libw32/gnuwin32_archive.h @@ -1,7 +1,7 @@ #ifndef GR_GNUWIN32_ARCHIVE_H_INCLUDED #define GR_GNUWIN32_ARCHIVE_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_gnuwin32_archive_h,"$Id: gnuwin32_archive.h,v 1.9 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_gnuwin32_archive_h,"$Id: gnuwin32_archive.h,v 1.10 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ @@ -22,10 +22,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ #endif /*GR_GNUWIN32_ARCHIVE_H_INCLUDED*/ diff --git a/libw32/gnuwin32_archive_entry.h b/libw32/gnuwin32_archive_entry.h index 08dbe1bb..c1386397 100644 --- a/libw32/gnuwin32_archive_entry.h +++ b/libw32/gnuwin32_archive_entry.h @@ -1,7 +1,7 @@ #ifndef GR_GNUWIN32_ARCHIVE_ENTRY_H_INCLUDED #define GR_GNUWIN32_ARCHIVE_ENTRY_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_gnuwin32_archive_entry_h,"$Id: gnuwin32_archive_entry.h,v 1.8 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_gnuwin32_archive_entry_h,"$Id: gnuwin32_archive_entry.h,v 1.9 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ @@ -22,10 +22,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ #endif /*GR_GNUWIN32_ARCHIVE_ENTRY_H_INCLUDED*/ diff --git a/libw32/gnuwin32_magic.h b/libw32/gnuwin32_magic.h index 30eb0114..d3a44ec7 100644 --- a/libw32/gnuwin32_magic.h +++ b/libw32/gnuwin32_magic.h @@ -1,7 +1,7 @@ #ifndef GR_GNUWIN32_MAGIC_H_INCLUDED #define GR_GNUWIN32_MAGIC_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_gnuwin32_magic_h,"$Id: gnuwin32_magic.h,v 1.8 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_gnuwin32_magic_h,"$Id: gnuwin32_magic.h,v 1.9 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ @@ -22,10 +22,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ #endif /*GR_GNUWIN32_MAGIC_H_INCLUDED*/ diff --git a/libw32/grp.h b/libw32/grp.h index 5eb9dc8d..c048b7d7 100644 --- a/libw32/grp.h +++ b/libw32/grp.h @@ -1,12 +1,14 @@ #ifndef LIBW32_GRP_H_INCLUDED #define LIBW32_GRP_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_grp_h,"$Id: grp.h,v 1.8 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_grp_h,"$Id: grp.h,v 1.11 2022/03/22 03:38:01 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2019, Adam Young. + * win32 implementation + * + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -22,17 +24,23 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ -#include +#include /* __BEGIN_DECLS, __PDECL */ +#include /* uid_t */ +#include /* size_t */ __BEGIN_DECLS +#if !defined(NGROUPS_MAX) +#define NGROUPS_MAX 32 +#endif + struct group { const char * gr_name; const char * gr_passwd; @@ -40,11 +48,19 @@ struct group { const char ** gr_mem; }; -LIBW32_API struct group *getgrent(void); LIBW32_API struct group *getgrgid(int); LIBW32_API struct group *getgrnam(const char *); + LIBW32_API void setgrent(void); +LIBW32_API struct group *getgrent(void); LIBW32_API void endgrent(void); +LIBW32_API int getgrent_r(struct group *grp, char *buf, size_t buflen, struct group **result); + +LIBW32_API int getgrgid_r(gid_t, struct group *, char *, size_t, struct group **); +LIBW32_API int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result); + +LIBW32_API int getgroups(int gidsetsize, gid_t grouplist[]); +LIBW32_API int setgroups(size_t size, const gid_t *gidset); __END_DECLS diff --git a/libw32/langinfo.h b/libw32/langinfo.h index 0ef375d7..b674f5ad 100644 --- a/libw32/langinfo.h +++ b/libw32/langinfo.h @@ -1,14 +1,14 @@ #ifndef LIBW32_LANGINFO_H_INCLUDED #define LIBW32_LANGINFO_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_langinfo_h,"$Id: langinfo.h,v 1.9 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_langinfo_h,"$Id: langinfo.h,v 1.11 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -37,6 +37,80 @@ __BEGIN_DECLS typedef enum { CODESET = 0 + +// To be defined/implemented as required +// +// D_T_FMT = 1, /* string for formatting date and time */ +// D_FMT = 2, /* date format string */ +// T_FMT = 3, /* time format string */ +// T_FMT_AMPM = 4, /* a.m. or p.m. time formatting string */ +// AM_STR = 5, /* Ante Meridian affix */ +// PM_STR = 6, /* Post Meridian affix */ +// +// DAY_1 = 7, /* week day names */ +// DAY_2 = 8, +// DAY_3 = 9, +// DAY_4 = 10, +// DAY_5 = 11, +// DAY_6 = 12, +// DAY_7 = 13, +// +// ABDAY_1 = 14, /* abbreviated week day names */ +// ABDAY_2 = 15, +// ABDAY_3 = 16, +// ABDAY_4 = 17, +// ABDAY_5 = 18, +// ABDAY_6 = 19, +// ABDAY_7 = 20, +// +// MON_1 = 21, /* month names */ +// MON_2 = 22, +// MON_3 = 23, +// MON_4 = 24, +// MON_5 = 25, +// MON_6 = 26, +// MON_7 = 27, +// MON_8 = 28, +// MON_9 = 29, +// MON_10 = 30, +// MON_11 = 31, +// MON_12 = 32, +// +// ABMON_1 = 33, /* abbreviated month names */ +// ABMON_2 = 34, +// ABMON_3 = 35, +// ABMON_4 = 36, +// ABMON_5 = 37, +// ABMON_6 = 38, +// ABMON_7 = 39, +// ABMON_8 = 40, +// ABMON_9 = 41, +// ABMON_10 = 42, +// ABMON_11 = 43, +// ABMON_12 = 44, +// +// ERA = 45, /* era description segments */ +// ERA_D_FMT = 46, /* era date format string */ +// ERA_D_T_FMT = 47, /* era date and time format string */ +// ERA_T_FMT = 48, /* era time format string */ +// ALT_DIGITS = 49, /* alternative symbols for digits */ +// +// RADIXCHAR = 50, /* radix char */ +// THOUSEP = 51, /* separator for thousands */ +// +// YESEXPR = 52, /* affirmative response expression */ +// NOEXPR = 53, /* negative response expression */ +// +// #if !defined(_ANSI_SOURCE) +// YESSTR = 54, /* affirmative response for yes/no queries */ +// NOSTR = 55, /* negative response for yes/no queries */ +// #endif +// +// CRNCYSTR = 56, /* currency symbol */ +// +// #if !defined(_ANSI_SOURCE) +// D_MD_ORDER = 57 /* month/day order (local extension) */ +// #endif } nl_item; diff --git a/libw32/libgen.h b/libw32/libgen.h index 4e4fa9f2..df6b107d 100644 --- a/libw32/libgen.h +++ b/libw32/libgen.h @@ -1,14 +1,14 @@ #ifndef LIBW32_LIBGEN_H_INCLUDED #define LIBW32_LIBGEN_H_INCLUDED #include -__CIDENT_RCSID(gr_libgen_h,"$Id: libgen.h,v 1.2 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libgen_h,"$Id: libgen.h,v 1.3 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 implementation * - * Copyright (c) 2007, 2012 - 2019 Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -23,10 +23,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ diff --git a/libw32/libw32.h b/libw32/libw32.h index 775d7f7b..3dd8a2fe 100644 --- a/libw32/libw32.h +++ b/libw32/libw32.h @@ -1,10 +1,10 @@ -#ifndef LIBW32_WIN32_H_INCLUDED -#define LIBW32_WIN32_H_INCLUDED +#ifndef LIBW32_LIBW32_H_INCLUDED +#define LIBW32_LIBW32_H_INCLUDED /* -*- mode: c; indent-width: 4; -*- */ /* * win32 public interface * - * Copyright (c) 2007, 2012 - 2019 Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -19,10 +19,10 @@ * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -32,6 +32,7 @@ #include #include #include +#include #include #endif /*LIBW32_WIN32_H_INCLUDED*/ diff --git a/libw32/libw32.rc b/libw32/libw32.rc index 93dbef7c..d5c47c07 100644 --- a/libw32/libw32.rc +++ b/libw32/libw32.rc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 - 2020 Adam Young. + * Copyright (c) 2016 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -54,7 +54,7 @@ BEGIN VALUE "InternalName", "libwin32.dll\0" VALUE "LegalCopyright", - "Copyright (c) 2007 - 2020 Adam Young\0" + "Copyright (c) 2007 - 2022 Adam Young\0" VALUE "OriginalFilename", "libwin32." LIBW32_VERSION ".dll\0" diff --git a/libw32/libw32_version.h b/libw32/libw32_version.h index 753fb8b6..a6cd10a7 100644 --- a/libw32/libw32_version.h +++ b/libw32/libw32_version.h @@ -1,7 +1,7 @@ #ifndef LIBW32_VERSION_H_INCLUDED #define LIBW32_VERSION_H_INCLUDED /* - * Copyright (c) 2016 - 2019 Adam Young. + * Copyright (c) 2016 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -16,16 +16,16 @@ * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ -#define LIBW32_VERSION "1.1.0" +#define LIBW32_VERSION "1.2.0" #define LIBW32_VER_MAJOR 1 -#define LIBW32_VER_MINOR 1 +#define LIBW32_VER_MINOR 2 #define LIBW32_VER_REVISION 0 #endif /*LIBW32_VERSION_H_INCLUDED*/ diff --git a/libw32/netdb.h b/libw32/netdb.h index a5a07260..e56416b6 100644 --- a/libw32/netdb.h +++ b/libw32/netdb.h @@ -1,14 +1,14 @@ #ifndef LIBW32_NETDB_H_INCLUDED #define LIBW32_NETDB_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_netdb_h,"$Id: netdb.h,v 1.11 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_netdb_h,"$Id: netdb.h,v 1.12 2022/03/21 14:29:39 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ diff --git a/libw32/netinet/in.h b/libw32/netinet/in.h index 1ff129f0..d2869e24 100644 --- a/libw32/netinet/in.h +++ b/libw32/netinet/in.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_IN_H_INCLUDED #define LIBW32_SYS_IN_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_netinet_in_h,"$Id: in.h,v 1.7 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_netinet_in_h,"$Id: in.h,v 1.8 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * netinet/in.h * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/netinet/tcp.h b/libw32/netinet/tcp.h index 4efab364..077fd37c 100644 --- a/libw32/netinet/tcp.h +++ b/libw32/netinet/tcp.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_TCP_H_INCLUDED #define LIBW32_SYS_TCP_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_netinet_tcp_h,"$Id: tcp.h,v 1.6 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_netinet_tcp_h,"$Id: tcp.h,v 1.7 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * netinet/tcp.h * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/notice_c.txt b/libw32/notice_c.txt index d8402837..8cea47b9 100644 --- a/libw32/notice_c.txt +++ b/libw32/notice_c.txt @@ -1,4 +1,4 @@ - * Copyright (c) 1998 - 2014, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -6,10 +6,10 @@ * The GRIEF Editor is free software: you can redistribute it * and/or modify it under the terms of the GRIEF Editor License. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from diff --git a/libw32/notice_h.txt b/libw32/notice_h.txt index 734d5f51..74f9a25b 100644 --- a/libw32/notice_h.txt +++ b/libw32/notice_h.txt @@ -1,4 +1,4 @@ - * Copyright (c) 1998 - 2014, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the Grief Editor. @@ -6,10 +6,10 @@ * The Grief Editor is free software: you can redistribute it * and/or modify it under the terms of the Grief Editor License. * - * The Grief Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== diff --git a/libw32/notice_x.txt b/libw32/notice_x.txt index 36df51fb..8598d871 100644 --- a/libw32/notice_x.txt +++ b/libw32/notice_x.txt @@ -1,4 +1,4 @@ - * Copyright (c) 2014, Grief Author(s). + * Copyright (c) 2014 - 2022, Grief Author(s). * All rights reserved. * * This file is part of the Grief Editor. diff --git a/libw32/poll.h b/libw32/poll.h index d3162bc9..18c12674 100644 --- a/libw32/poll.h +++ b/libw32/poll.h @@ -1,14 +1,14 @@ #ifndef LIBW32_POLL_H_INCLUDED #define LIBW32_POLL_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_poll_h,"$Id: poll.h,v 1.10 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_poll_h,"$Id: poll.h,v 1.11 2022/03/21 14:29:40 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ diff --git a/libw32/pwd.h b/libw32/pwd.h index f81e2d78..16d76bc0 100644 --- a/libw32/pwd.h +++ b/libw32/pwd.h @@ -1,12 +1,12 @@ #ifndef LIBW32_PWD_H_INCLUDED #define LIBW32_PWD_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_pwd_h,"$Id: pwd.h,v 1.7 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_pwd_h,"$Id: pwd.h,v 1.10 2022/03/22 03:38:01 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -22,20 +22,22 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ -#include +#include /* __BEGIN_DECLS, __PDECL */ +#include /* uid_t */ +#include /* size_t */ __BEGIN_DECLS /* * The header shall provide a definition for struct passwd, - * which shall include at least the following members: + * which shall include at least the following members: * * char *pw_name User's login name. * uid_t pw_uid Numerical user ID. @@ -58,14 +60,16 @@ struct passwd { int pw_audflg; }; -LIBW32_API struct passwd *getpwent(void); LIBW32_API struct passwd *getpwuid(int); LIBW32_API struct passwd *getpwnam(const char *); + LIBW32_API void setpwent(void); +LIBW32_API struct passwd *getpwent(void); LIBW32_API void endpwent(void); +LIBW32_API int getpwent_r(struct passwd *, char *, size_t, struct passwd **); -//LIBW32_API int getpwnam_r(const char *, struct passwd *, char *, size_t, struct passwd **); -//LIBW32_API int getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **); +LIBW32_API int getpwnam_r(const char *, struct passwd *, char *, size_t, struct passwd **); +LIBW32_API int getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **); __END_DECLS diff --git a/libw32/sys/cdefs.h b/libw32/sys/cdefs.h index 4a700679..57ec008b 100644 --- a/libw32/sys/cdefs.h +++ b/libw32/sys/cdefs.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_CDEFS_H_INCLUDED #define LIBW32_SYS_CDEFS_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_cdefs_h,"$Id: cdefs.h,v 1.15 2018/09/30 23:24:13 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_cdefs_h,"$Id: cdefs.h,v 1.16 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- * * win32 declaration helpers * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -34,7 +34,7 @@ __CPRAGMA_ONCE #pragma warning(disable:4115) /* forward reference of struct * */ #endif -/* +/* * Library binding. */ #if !defined(LIBW32_API) @@ -64,7 +64,7 @@ __CPRAGMA_ONCE #endif //!LIBW32_API -/* +/* * Binding: * * Usage: diff --git a/libw32/sys/endian.h b/libw32/sys/endian.h index 03b148c7..8db4e52f 100644 --- a/libw32/sys/endian.h +++ b/libw32/sys/endian.h @@ -1,14 +1,14 @@ #ifndef GR_ENDIAN_H_INCLUDED #define GR_ENDIAN_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_endian_h,"$Id: endian.h,v 1.9 2018/10/01 00:00:05 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_endian_h,"$Id: endian.h,v 1.10 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- * * win32 implementation * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/file.h b/libw32/sys/file.h new file mode 100644 index 00000000..621d2974 --- /dev/null +++ b/libw32/sys/file.h @@ -0,0 +1,39 @@ +#ifndef LIBW32_SYS_FILE_H_INCLUDED +#define LIBW32_SYS_FILE_H_INCLUDED +#include +__CIDENT_RCSID(gr_libw32_sys_file_h,"$Id: file.h,v 1.2 2022/03/21 14:29:42 cvsuser Exp $") +__CPRAGMA_ONCE + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 sys/file.h + * + * Copyright (c) 2020 - 2022, Adam Young. + * All rights reserved. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * The GRIEF Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License for more details. + * ==end== + */ + +#include + +#define LOCK_SH 0x01 +#define LOCK_EX 0x02 +#define LOCK_NB 0x04 +#define LOCK_UN 0x08 + +__BEGIN_DECLS + +LIBW32_API int w32_flock(int fd, int operation); + +__END_DECLS + +#endif /*LIBW32_SYS_FILE_H_INCLUDED*/ diff --git a/libw32/sys/ioctl.h b/libw32/sys/ioctl.h index 3511ea13..cbcdebb9 100644 --- a/libw32/sys/ioctl.h +++ b/libw32/sys/ioctl.h @@ -1,12 +1,12 @@ #ifndef LIBW32_SYS_IOCTL_H_INCLUDED #define LIBW32_SYS_IOCTL_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_ioctl_h,"$Id: ioctl.h,v 1.8 2018/10/01 16:44:41 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_ioctl_h,"$Id: ioctl.h,v 1.9 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 2012 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/mman.h b/libw32/sys/mman.h index 34b54b84..c02f9f9b 100644 --- a/libw32/sys/mman.h +++ b/libw32/sys/mman.h @@ -1,13 +1,13 @@ #ifndef LIBW32_SYS_MMAN_H_INCLUDED #define LIBW32_SYS_MMAN_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_mman_h,"$Id: mman.h,v 1.10 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_mman_h,"$Id: mman.h,v 1.11 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 mmap implementation - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/mount.h b/libw32/sys/mount.h index c7c07921..d1540ff4 100644 --- a/libw32/sys/mount.h +++ b/libw32/sys/mount.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_MOUNT_H_INCLUDED #define LIBW32_SYS_MOUNT_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_mount_h,"$Id: mount.h,v 1.9 2018/10/11 01:49:01 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_mount_h,"$Id: mount.h,v 1.10 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 mount() implementation * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/pack0.h b/libw32/sys/pack0.h index 299fa247..988678c0 100644 --- a/libw32/sys/pack0.h +++ b/libw32/sys/pack0.h @@ -1,10 +1,10 @@ /* -*- mode: c; indent-width: 4; -*- - * $Id: pack0.h,v 1.7 2018/09/29 02:25:24 cvsuser Exp $ + * $Id: pack0.h,v 1.8 2022/03/21 14:29:43 cvsuser Exp $ * ==noguard== * * win32 declaration helpers * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/pack1.h b/libw32/sys/pack1.h index 4481389d..1a574d1b 100644 --- a/libw32/sys/pack1.h +++ b/libw32/sys/pack1.h @@ -1,10 +1,10 @@ /* -*- mode: c; indent-width: 4; -*- - * $Id: pack1.h,v 1.7 2018/09/29 02:25:24 cvsuser Exp $ + * $Id: pack1.h,v 1.8 2022/03/21 14:29:43 cvsuser Exp $ * ==noguard== * * win32 declaration helpers * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/param.h b/libw32/sys/param.h index 1101112a..e0b0fbd0 100644 --- a/libw32/sys/param.h +++ b/libw32/sys/param.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_PARAM_H_INCLUDED #define LIBW32_SYS_PARAM_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_param_h,"$Id: param.h,v 1.13 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_param_h,"$Id: param.h,v 1.14 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/poll.h b/libw32/sys/poll.h index da1b672b..66f3b304 100644 --- a/libw32/sys/poll.h +++ b/libw32/sys/poll.h @@ -1,12 +1,12 @@ #ifndef LIBW32_SYS_POLL_H_INCLUDED #define LIBW32_SYS_POLL_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_poll_h,"$Id: poll.h,v 1.1 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_poll_h,"$Id: poll.h,v 1.2 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/queue.h b/libw32/sys/queue.h index 0b79a285..f66a22df 100644 --- a/libw32/sys/queue.h +++ b/libw32/sys/queue.h @@ -1,12 +1,12 @@ #ifndef GR_QUEUE_H_INCLUDED #define GR_QUEUE_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_queue_h,"$Id: queue.h,v 1.7 2018/10/01 00:00:05 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_queue_h,"$Id: queue.h,v 1.8 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/resource.h b/libw32/sys/resource.h index 1e8212bf..71fd70a1 100644 --- a/libw32/sys/resource.h +++ b/libw32/sys/resource.h @@ -6,7 +6,7 @@ __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 2020, Adam Young. + * Copyright (c) 2020 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/rwlock.h b/libw32/sys/rwlock.h index 57d55780..a27485ff 100644 --- a/libw32/sys/rwlock.h +++ b/libw32/sys/rwlock.h @@ -1,14 +1,14 @@ #ifndef GR_SYS_RWLOCK_H_INCLUDED #define GR_SYS_RWLOCK_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_rwlock_h,"$Id: rwlock.h,v 1.8 2018/10/12 00:30:31 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_rwlock_h,"$Id: rwlock.h,v 1.9 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 implementation * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/select.h b/libw32/sys/select.h index fefb39e1..542bd978 100644 --- a/libw32/sys/select.h +++ b/libw32/sys/select.h @@ -1,12 +1,12 @@ #ifndef LIBW32_SYS_SELECT_H_INCLUDED #define LIBW32_SYS_SELECT_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_select_h,"$Id: select.h,v 1.7 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_select_h,"$Id: select.h,v 1.8 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/socket.h b/libw32/sys/socket.h index 1d83d997..2faaa474 100644 --- a/libw32/sys/socket.h +++ b/libw32/sys/socket.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_SOCKET_H_INCLUDED #define LIBW32_SYS_SOCKET_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_socket_h,"$Id: socket.h,v 1.13 2020/06/06 00:37:32 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_socket_h,"$Id: socket.h,v 1.15 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -34,6 +34,16 @@ LIBW32_API extern int w32_h_errno; struct pollfd; +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + size_t msg_iovlen; + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +}; + LIBW32_API int w32_sockinit(void); LIBW32_API int w32_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res); @@ -57,7 +67,7 @@ LIBW32_API int w32_getpeername_fd(int fd, struct sockaddr *name, sockle LIBW32_API int w32_getpeername_native(int fd, struct sockaddr *name, socklen_t *namelen); LIBW32_API int w32_getsockname_fd(int fd, struct sockaddr *name, socklen_t *namelen); LIBW32_API int w32_getsockname_native(int fd, struct sockaddr *name, socklen_t *namelen); -LIBW32_API int w32_ioctlsocket(int fd, long cmd, int *argp); +LIBW32_API int w32_ioctlsocket_fd(int fd, long cmd, int *argp); LIBW32_API int w32_ioctlsocket_native(int fd, long cmd, int *argp); LIBW32_API int w32_bind_fd(int fd, const struct sockaddr *name, socklen_t namelen); LIBW32_API int w32_bind_native(int fd, const struct sockaddr *name, socklen_t namelen); @@ -69,10 +79,16 @@ LIBW32_API int w32_send_fd(int fd, const void *buf, size_t len, int fla LIBW32_API int w32_send_native(int fd, const void *buf, size_t len, int flags); LIBW32_API int w32_sendto_fd(int fd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); LIBW32_API int w32_sendto_native(int fd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +LIBW32_API int w32_sendmsg_fd(int fd, const struct msghdr *message, int flags); +LIBW32_API int w32_sendmsg_native(int fd, const struct msghdr *message, int flags); LIBW32_API int w32_recv_fd(int fd, char *buf, int len, int flags); LIBW32_API int w32_recv_native(int fd, char *buf, int len, int flags); LIBW32_API int w32_recvfrom_fd(int fd, char *buf, int len, int flags, struct sockaddr *from_addr, int *fromlen); LIBW32_API int w32_recvfrom_native(int fd, char *buf, int len, int flags, struct sockaddr *from_addr, int *fromlen); +LIBW32_API int w32_shutdown_fd(int fd, int flags); +LIBW32_API int w32_shutdown_native(int fd, int flags); +LIBW32_API int w32_sockblockingmode_fd(int fd, int enabled); +LIBW32_API int w32_sockblockingmode_native(int fd, int enabled); LIBW32_API int w32_sockwrite_fd(int fd, const void *buffer, unsigned int cnt); LIBW32_API int w32_sockwrite_native(int fd, const void *buffer, unsigned int cnt); LIBW32_API int w32_sockread_fd(int fd, void *buf, unsigned int nbyte); @@ -91,10 +107,26 @@ LIBW32_API int w32_socketpair_native(int af, int type, int proto, int s LIBW32_API int w32_poll_fd(struct pollfd *fds, int cnt, int timeout); LIBW32_API int w32_poll_native(struct pollfd *fds, int cnt, int timeout); + +/* + * Compile time bindings + */ +#if defined(LIBW32_SOCKET_MAP_FD) +#if !defined(WIN32_SOCKET_MAP_FD) +#define WIN32_SOCKET_MAP_FD 1 +#endif +#endif +#if defined(LIBW32_SOCKET_MAP_NATIVE) +#if !defined(WIN32_SOCKET_MAP_NATIVE) +#define WIN32_SOCKET_MAP_NATIVE 1 +#endif +#endif + #if defined(WIN32_SOCKET_MAP_FD) && defined(WIN32_SOCKET_MAP_NATIVE) -#error both WIN32_SOCKET_MAP_FD and WIN32_SOCKET_MAP_NATIVE enabled ... +#error WIN32_SOCKET_MAP_FD and WIN32_SOCKET_MAP_NATIVE are mutually exclusive #endif + #if defined(WIN32_SOCKET_MAP_FD) || defined(WIN32_SOCKET_MAP_NATIVE) /* * Socket interface, generic functions. @@ -142,16 +174,21 @@ LIBW32_API int w32_poll_native(struct pollfd *fds, int cnt, int timeout #define poll(a,b,c) w32_poll_fd(a,b,c) #define send(a,b,c,d) w32_send_fd(a,b,c,d) #define sendto(a,b,c,d,e) w32_sendto_fd(a,b,c,d,e) +#define sendmsg(a,b,c) w32_sendmsg_fd(a,b,c) #define recv(a,b,c,d) w32_recv_fd(a,b,c,d) #define recvfrom(a,b,c,d,e,f) w32_recvfrom_fd(a,b,c,d,e,f) #define shutdown(a,b) w32_shutdown_fd(a,b) #if !defined(LIBW32_SYS_POLL_H_INCLUDED) #define poll(a,b,c) w32_poll_fd(a,b,c) #endif + +#define sockblockingmode(a,b) w32_sockblockingmode_fd(a,b) #define sockread(a,b,c) w32_sockread_fd(a,b,c) #define sockwrite(a,b,c) w32_sockwrite_fd(a,b,c) #define sockclose(a) w32_sockclose_fd(a) +#define socketpair(a,b,c,d) w32_socketpair_fd(a,b,c,d) + #elif defined(WIN32_SOCKET_MAP_NATIVE) /* * Socket interface, native sockets. @@ -169,16 +206,21 @@ LIBW32_API int w32_poll_native(struct pollfd *fds, int cnt, int timeout #define poll(a,b,c) w32_poll_native(a,b,c) #define send(a,b,c,d) w32_send_native(a,b,c,d) #define sendto(a,b,c,d,e) w32_sendto_native(a,b,c,d,e) +#define sendmsg(a,b,c) w32_sendmsg_native(a,b,c) #define recv(a,b,c,d) w32_recv_native(a,b,c,d) #define recvfrom(a,b,c,d,e,f) w32_recvfrom_native(a,b,c,d,e,f) #define shutdown(a,b) w32_shutdown_native(a,b) #if !defined(LIBW32_SYS_POLL_H_INCLUDED) #define poll(a,b,c) w32_poll_native(a,b,c) #endif /*SOCKET_MAPCALLS*/ + +#define sockblockingmode(a,b) w32_sockblockingmode_native(a,b) #define sockread(a,b,c) w32_sockread_native(a,b,c) #define sockwrite(a,b,c) w32_sockwrite_native(a,b,c) #define sockclose(a) w32_sockclose_native(a) +#define socketpair(a,b,c,d) w32_socketpair_native(a,b,c,d) + #endif /*WIN32_SOCKET_MAP_FD|NATIVE*/ __END_DECLS diff --git a/libw32/sys/statfs.h b/libw32/sys/statfs.h index da378ef8..37d52ec1 100644 --- a/libw32/sys/statfs.h +++ b/libw32/sys/statfs.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_STATFS_H_INCLUDED #define LIBW32_SYS_STATFS_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_statfs_h,"$Id: statfs.h,v 1.7 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_statfs_h,"$Id: statfs.h,v 1.10 2022/03/22 08:05:09 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 [f]statfs implementation * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 2012 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -26,6 +26,7 @@ __CPRAGMA_ONCE #include #include #include +#include #define FS_MAGIC 0x11954 /* Taken from HP-UX */ @@ -57,8 +58,10 @@ struct statfs { __BEGIN_DECLS -LIBW32_API int statfs(const char *, struct statfs *); -LIBW32_API int fstatfs(int, struct statfs *); +LIBW32_API int statfs(const char *path, struct statfs *buf); +LIBW32_API int statfsA(const char *path, struct statfs *buf); +LIBW32_API int statfsW(const wchar_t *path, struct statfs *buf); +LIBW32_API int fstatfs(int fd, struct statfs *buf); __END_DECLS diff --git a/libw32/sys/statvfs.h b/libw32/sys/statvfs.h index 9b6be43a..4bde0b3b 100644 --- a/libw32/sys/statvfs.h +++ b/libw32/sys/statvfs.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_STATVFS_H #define LIBW32_SYS_STATVFS_H #include -__CIDENT_RCSID(gr_libw32_sys_statvfs_h,"$Id: statvfs.h,v 1.8 2018/10/11 01:49:01 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_statvfs_h,"$Id: statvfs.h,v 1.9 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 [f]statvfs implementation * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/time.h b/libw32/sys/time.h index 10c22d03..37c781d9 100644 --- a/libw32/sys/time.h +++ b/libw32/sys/time.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_TIME_H #define LIBW32_SYS_TIME_H #include -__CIDENT_RCSID(gr_libw32_sys_time_h,"$Id: time.h,v 1.13 2020/06/18 20:35:18 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_time_h,"$Id: time.h,v 1.14 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 sys/time.h implementation. * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/uio.h b/libw32/sys/uio.h index a5cc5689..99d0a63a 100644 --- a/libw32/sys/uio.h +++ b/libw32/sys/uio.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_UIO_H_INCLUDED #define LIBW32_SYS_UIO_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_uio_h,"$Id: uio.h,v 1.8 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_uio_h,"$Id: uio.h,v 1.10 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 sys/uio.h * - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -16,10 +16,10 @@ __CPRAGMA_ONCE * The GRIEF Editor is free software: you can redistribute it * and/or modify it under the terms of the GRIEF Editor License. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -33,14 +33,18 @@ __CPRAGMA_ONCE __BEGIN_DECLS -typedef struct iovec { +struct iovec { void * iov_base; int iov_len; -} iovec_t; +}; -LIBW32_API size_t readv(int, const struct iovec *, int); -LIBW32_API size_t writev(int, const struct iovec *, int); +LIBW32_API int /*ssize_t*/ readv(int, const struct iovec *, int); +LIBW32_API int /*ssize_t*/ writev(int, const struct iovec *, int); +// LIBW32_API ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); +// LIBW32_API ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); +// LIBW32_API ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags); +// LIBW32_API ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags); __END_DECLS #endif /*LIBW32_SYS_UIO_H_INCLUDED */ diff --git a/libw32/sys/utsname.h b/libw32/sys/utsname.h index bc2dea3b..0cb294cc 100644 --- a/libw32/sys/utsname.h +++ b/libw32/sys/utsname.h @@ -1,12 +1,12 @@ #ifndef LIBW32_SYS_UTSNAME_H_INCLUDED #define LIBW32_SYS_UTSNAME_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_utsname_h,"$Id: utsname.h,v 1.8 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_utsname_h,"$Id: utsname.h,v 1.9 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2018, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/utypes.h b/libw32/sys/utypes.h index 6dcaccc6..a2fa4e27 100644 --- a/libw32/sys/utypes.h +++ b/libw32/sys/utypes.h @@ -1,14 +1,14 @@ #ifndef LIBW32_SYS_UTYPES_H_INCLUDED #define LIBW32_SYS_UTYPES_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_sys_utypes_h,"$Id: utypes.h,v 1.28 2021/04/07 16:15:41 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_utypes_h,"$Id: utypes.h,v 1.30 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 unix types * - * Copyright (c) 1998 - 2021, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,23 +24,6 @@ __CPRAGMA_ONCE */ #if defined(_MSC_VER) -#if (_MSC_VER != 1200) /* MSVC 6 */ -#if (_MSC_VER != 1400) /* MSVC 8/2005 */ -#if (_MSC_VER != 1500) /* MSVC 9/2008 */ -#if (_MSC_VER != 1600) /* MSVC 10/2010 */ -#if (_MSC_VER != 1900) /* MSVC 19/2015 */ -#if (_MSC_VER < 1910 || _MSC_VER > 1916) /* MSVC 19.10 .. 16/2017 */ -#if (_MSC_VER > 1928) /* MSVC 19.20 / 2019.08 */ -#error utypes.h: untested MSVC Version (2005 -- 2019.08) only ... - //see: https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B -#endif //2019 -#endif //2017 -#endif //2015 -#endif //2010 -#endif //2008 -#endif //2005 -#endif //_MSC_VER - #pragma warning(disable:4115) #elif defined(__WATCOMC__) diff --git a/libw32/sys/vfs.h b/libw32/sys/vfs.h index aed10fb7..5e44d707 100644 --- a/libw32/sys/vfs.h +++ b/libw32/sys/vfs.h @@ -1,12 +1,12 @@ #ifndef LIBW32_SYS_VFS_H #define LIBW32_SYS_VFS_H #include -__CIDENT_RCSID(gr_libw32_sys_vfs_h,"$Id: vfs.h,v 1.7 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_vfs_h,"$Id: vfs.h,v 1.8 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 2012 - 2018, Adam Young. + * Copyright (c) 2012 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/sys/wait.h b/libw32/sys/wait.h index a99ae0db..ee898212 100644 --- a/libw32/sys/wait.h +++ b/libw32/sys/wait.h @@ -1,12 +1,12 @@ #ifndef LIBW32_SYS_WAIT_H #define LIBW32_SYS_WAIT_H #include -__CIDENT_RCSID(gr_libw32_sys_wait_h,"$Id: wait.h,v 1.7 2018/09/29 02:25:24 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_sys_wait_h,"$Id: wait.h,v 1.8 2022/03/21 14:29:43 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 2012 - 2018 Adam Young. + * Copyright (c) 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. diff --git a/libw32/unistd.h b/libw32/unistd.h index 3497516f..42705158 100644 --- a/libw32/unistd.h +++ b/libw32/unistd.h @@ -1,14 +1,14 @@ #ifndef LIBW32_UNISTD_H_INCLUDED #define LIBW32_UNISTD_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_unistd_h,"$Id: unistd.h,v 1.51 2021/04/07 16:15:41 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_unistd_h,"$Id: unistd.h,v 1.55 2022/03/21 14:29:40 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 header (_MSC_VER, __WATCOMC__ and __MINGW32__) * - * Copyright (c) 1998 - 2021, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -38,10 +38,12 @@ __CPRAGMA_ONCE #if (_MSC_VER != 1500) /* MSVC 9/2008 */ #if (_MSC_VER != 1600) /* MSVC 10/2010 */ #if (_MSC_VER != 1900) /* MSVC 19/2015 */ -#if (_MSC_VER < 1910 || _MSC_VER > 1916) /* MSVC 19.10 .. 16/2017 */ -#if (_MSC_VER > 1928) /* MSVC 19.20 / 2019.08 */ -#error unistd.h: untested MSVC Version (2005 -- 2019.08) only ... +#if (_MSC_VER < 1910 || _MSC_VER > 1916) /* MSVC 2017: 19.10 .. 16 */ +#if (_MSC_VER > 1929) /* MSVC 2019: 19.20 .. 29 */ +#if (_MSC_VER > 1931) /* MSVC 2022: 19.30 .. 31 */ +#error unistd.h: untested MSVC Version (2005 -- 2019.31) //see: https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B +#endif //2022 #endif //2019 #endif //2017 #endif //2015 @@ -137,6 +139,22 @@ __CPRAGMA_ONCE __BEGIN_DECLS /*limits*/ +// Starting in Windows 10, version 1607, MAX_PATH(255) limitations have been removed from +// common Win32 file and directory functions. However, you must opt-in to the new behavior. +// +// To enable the new long path behavior, both of the following conditions must be met: +// +// Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled +// +// The (Type: REG_DWORD) registry key (above) must exist and be set to 1. The key's value +// will be cached by the system (per process) after the first call to an affected Win32 file +// or directory function (see below for the list of functions). The registry key will not be +// reloaded during the lifetime of the process. In order for all apps on the system to recognize +// the value of the key, a reboot might be required because some processes may have started +// before the key was set. +// +// Note: The application manifest must also include the longPathAware element. +// #define WIN32_PATH_MAX 1024 #define WIN32_LINK_DEPTH 8 @@ -440,7 +458,10 @@ LIBW32_API size_t strnlen(const char *s, size_t maxlen); /* */ LIBW32_API int gettimeofday (struct timeval *tv, struct timezone *tz); + LIBW32_API int w32_utime (const char *path, const struct utimbuf *times); +LIBW32_API int w32_utimeA (const char *path, const struct utimbuf *times); +LIBW32_API int w32_utimeW (const wchar_t *path, const struct utimbuf *times); #if defined(WIN32_UNISTD_MAP) #if !defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) @@ -458,7 +479,10 @@ LIBW32_API const char * getlogin (void); LIBW32_API int getlogin_r (char *name, size_t namesize); LIBW32_API void setprogname (const char *name); +LIBW32_API void setprognameW (const wchar_t *name); LIBW32_API const char * getprogname (void); +LIBW32_API const char * getprognameA (void); +LIBW32_API const wchar_t * getprognameW (void); LIBW32_API int issetugid (void); @@ -489,16 +513,40 @@ LIBW32_API size_t w32_strftime (char *buf, size_t buflen, const char *fmt, #endif /*WIN32_UNISTD_MAP*/ /* i/o */ +LIBW32_API int w32_utf8filenames_enable (void); + LIBW32_API int w32_open (const char *path, int, ...); +LIBW32_API int w32_openA (const char *path, int, int); +LIBW32_API int w32_openW (const wchar_t *path, int, int); LIBW32_API int w32_stat (const char *path, struct stat *sb); +LIBW32_API int w32_statA (const char *path, struct stat *sb); +LIBW32_API int w32_statW (const wchar_t *path, struct stat *sb); LIBW32_API int w32_lstat (const char *path, struct stat *sb); +LIBW32_API int w32_lstatA (const char *path, struct stat *sb); +LIBW32_API int w32_lstatW (const wchar_t *path, struct stat *sb); LIBW32_API int w32_fstat (int fd, struct stat *sb); +LIBW32_API int w32_fstatA (int fd, struct stat *sb); +LIBW32_API int w32_fstatW (int fd, struct stat *sb); LIBW32_API int w32_read (int fd, void *buffer, size_t cnt); LIBW32_API int w32_write (int fd, const void *buffer, size_t cnt); LIBW32_API int w32_close (int fd); LIBW32_API const char * w32_strerror (int errnum); + LIBW32_API int w32_link (const char *from, const char *to); +LIBW32_API int w32_linkA (const char *from, const char *to); +LIBW32_API int w32_linkW (const wchar_t *from, const wchar_t *to); + LIBW32_API int w32_unlink (const char *fname); +LIBW32_API int w32_unlinkA (const char *fname); +LIBW32_API int w32_unlinkW (const wchar_t *fname); + +LIBW32_API int w32_access (const char *fname, int mode); +LIBW32_API int w32_accessA (const char *fname, int mode); +LIBW32_API int w32_accessW (const wchar_t *fname, int mode); + +LIBW32_API int w32_rename (const char *ofile, const char *nfile); +LIBW32_API int w32_renameA (const char *ofile, const char *nfile); +LIBW32_API int w32_renameW (const wchar_t *ofile, const wchar_t *nfile); LIBW32_API ssize_t pread (int fildes, void *buf, size_t nbyte, off_t offset); LIBW32_API ssize_t pwrite (int fildes, const void *buf, size_t nbyte, off_t offset); @@ -513,6 +561,8 @@ LIBW32_API ssize_t pwrite (int fildes, const void *buf, size_t nbyte, off_t #define close(a) w32_close(a) #define link(f,t) w32_link(f,t) #define unlink(p) w32_unlink(p) +#define access(p,m) w32_access(p, m) +#define rename(a,b) w32_rename(a,b) #endif /*WIN32_UNISTD_MAP*/ #if defined(WIN32_UNISTD_MAP) || \ @@ -521,11 +571,25 @@ LIBW32_API ssize_t pwrite (int fildes, const void *buf, size_t nbyte, off_t //#define g_strerror(a) w32_strerror(a) /* must also replace libglib version */ #endif -LIBW32_API int w32_mkdir (const char *fname, int mode); -LIBW32_API int w32_chdir (const char *fname); -LIBW32_API int w32_rmdir (const char *fname); +LIBW32_API int w32_mkdir (const char *path, int mode); +LIBW32_API int w32_mkdirA (const char *path, int mode); +LIBW32_API int w32_mkdirW (const wchar_t *path, int mode); + +LIBW32_API int w32_chdir (const char *path); +LIBW32_API int w32_chdirA (const char *path); +LIBW32_API int w32_chdirW (const wchar_t *path); + +LIBW32_API int w32_rmdir (const char *path); +LIBW32_API int w32_rmdirA (const char *path); +LIBW32_API int w32_rmdirW (const wchar_t *path); + LIBW32_API char * w32_getcwd (char *path, int size); +LIBW32_API char * w32_getcwdA (char *path, int size); +LIBW32_API wchar_t * w32_getcwdW (wchar_t *path, int size); + LIBW32_API char * w32_getcwdd (char drive, char *path, int size); +LIBW32_API char * w32_getcwddA (char drive, char *path, int size); +LIBW32_API wchar_t * w32_getcwddW (char drive, wchar_t *path, int size); #if defined(WIN32_UNISTD_MAP) #define mkdir(d,m) w32_mkdir(d, m) @@ -544,20 +608,43 @@ LIBW32_API char * w32_getcwdd (char drive, char *path, int size); #endif /*_MSC_VER*/ #endif /*WIN32_UNISTD_MAP*/ -LIBW32_API int w32_mkstemp(char *path); +LIBW32_API int w32_mkstemp (char *path); +LIBW32_API int w32_mkstempA (char *path); +LIBW32_API int w32_mkstempW (wchar_t *path); #if defined(_MSC_VER) LIBW32_API int mkstemp (char *path); #endif + +LIBW32_API int w32_mkstemps (char *path, int suffixlen); +LIBW32_API int w32_mkstempsA (char *path, int suffixlen); +LIBW32_API int w32_mkstempsW (wchar_t *path, int suffixlen); + LIBW32_API int w32_mkstempx (char *path); +LIBW32_API int w32_mkstempxA (char *path); +LIBW32_API int w32_mkstempxW (wchar_t *path); + +LIBW32_API char * w32_mkdtemp (char *path); +LIBW32_API char * w32_mkdtempA (char *path); +LIBW32_API wchar_t * w32_mkdtempW (wchar_t *path); + +LIBW32_API char * w32_mkdtemps (char *path, int suffixlen); +LIBW32_API char * w32_mkdtempsA (char *path, int suffixlen); +LIBW32_API wchar_t * w32_mkdtempsW (wchar_t *path, int suffixlen); LIBW32_API int ftruncate (int fildes, off_t size); LIBW32_API int truncate (const char *path, off_t length); +LIBW32_API int truncateA (const char *path, off_t length); +LIBW32_API int truncateW (const wchar_t *path, off_t length); LIBW32_API int w32_readlink (const char *path, char *name, int sz); +LIBW32_API int w32_readlinkA (const char *path, char *name, int sz); +LIBW32_API int w32_readlinkW (const wchar_t *path, wchar_t *name, int sz); LIBW32_API int w32_symlink (const char *from, const char *to); LIBW32_API char * w32_realpath (const char *path, char *resolved_path /*PATH_MAX*/); LIBW32_API char * w32_realpath2 (const char *path, char *resolved_path, int maxlen); +LIBW32_API char * w32_realpathA (const char *path, char *resolved_path, int maxlen); +LIBW32_API wchar_t * w32_realpathW (const wchar_t *path, wchar_t *resolved_path, int maxlen); #if defined(WIN32_UNISTD_MAP) #define readlink(__path,__name, __sz) \ @@ -566,8 +653,22 @@ LIBW32_API char * w32_realpath2 (const char *path, char *resolved_path, in w32_symlink (__from, __to) #endif -LIBW32_API int chown (const char *, uid_t, gid_t); +LIBW32_API int w32_chmod (const char *, mode_t); +LIBW32_API int w32_chmodA (const char *, mode_t); +LIBW32_API int w32_chmodW (const wchar_t *, mode_t); + +#if defined(WIN32_UNISTD_MAP) +#define chmod(__path,__mode) \ + w32_chmod (__path, __mode) +#endif + +LIBW32_API int chown (const char *path, uid_t uid, gid_t gid); +LIBW32_API int chownA (const char *path, uid_t uid, gid_t gid); +LIBW32_API int chownW (const wchar_t *path, uid_t uid, gid_t gid); + LIBW32_API int mknod (const char *path, int mode, int dev); +LIBW32_API int mknodA (const char *path, int mode, int dev); +LIBW32_API int mknodW (const wchar_t *path, int mode, int dev); #if !defined(F_GETFL) #define F_GETFL 1 diff --git a/libw32/w32_access.c b/libw32/w32_access.c new file mode 100644 index 00000000..f96e9284 --- /dev/null +++ b/libw32/w32_access.c @@ -0,0 +1,150 @@ +#include +__CIDENT_RCSID(gr_w32_access_c,"$Id: w32_access.c,v 1.2 2022/03/21 14:29:40 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win2 access() system calls + * + * Copyright (c) 2022 Adam Young. + * All rights reserved. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + * + * Notice: Portions of this text are reprinted and reproduced in electronic form. from + * IEEE Portable Operating System Interface (POSIX), for reference only. Copyright (C) + * 2001-2003 by the Institute of. Electrical and Electronics Engineers, Inc and The Open + * Group. Copyright remains with the authors and the original Standard can be obtained + * online at http://www.opengroup.org/unix/online.html. + * ==extra== + */ + +#include "win32_internal.h" +#include + +/* +// NAME +// access - determine accessibility of a file. +// +// SYNOPSIS +// #include +// +// int access(const char *path, int amode); +// +// DESCRIPTION +// The access() function shall check the file named by the pathname pointed +// to by the path argument for accessibility according to the bit pattern +// contained in amode, using the real user ID in place of the effective user +// ID and the real group ID in place of the effective group ID. +// +// The value of amode is either the bitwise-inclusive OR of the access +// permissions to be checked (R_OK, W_OK, X_OK) or the existence test (F_OK). +// +// If any access permissions are checked, each shall be checked individually, +// as described in the Base Definitions volume of IEEE Std 1003.1-2001, +// Chapter 3, Definitions. If the process has appropriate privileges, +// an implementation may indicate success for X_OK even if none of the +// execute file permission bits are set. +// +// RETURN VALUE +// If the requested access is permitted, access() succeeds and shall +// return 0; otherwise, -1 shall be returned and errno shall be set to +// indicate the error. +// +// ERRORS +// The access() function shall fail if: +// +// [EACCES] +// Permission bits of the file mode do not permit the requested access, +// or search permission is denied on a component of the path prefix. +// +// [ELOOP] +// A loop exists in symbolic links encountered during resolution of +// the path argument. +// +// [ENAMETOOLONG] +// The length of the path argument exceeds {PATH_MAX} or a pathname +// component is longer than {NAME_MAX}. +// +// [ENOENT] +// A component of path does not name an existing file or path is an +// empty string. +// +// [ENOTDIR] +// A component of the path prefix is not a directory. +// +// [EROFS] +// Write access is requested for a file on a read-only file system. +// +// The access() function may fail if: +// +// [EINVAL] +// The value of the amode argument is invalid. +// +// [ELOOP] +// More than {SYMLOOP_MAX} symbolic links were encountered during +// resolution of the path argument. +// +// [ENAMETOOLONG] +// As a result of encountering a symbolic link in resolution of the +// path argument, the length of the substituted pathname string +// exceeded {PATH_MAX}. +// +// [ETXTBSY] +// Write access is requested for a pure procedure (shared text) +// file that is being executed. +*/ +int +w32_access(const char *path, int amode) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return w32_accessW(wpath, amode); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_accessA(path, amode); +} + + +int +w32_accessA(const char *path, int amode) +{ + return _access(path, amode); +} + + +int +w32_accessW(const wchar_t *path, int amode) +{ + return _waccess(path, amode); +} + +/*end*/ diff --git a/libw32/w32_check.c b/libw32/w32_check.c index e4b53a1c..507dd4dd 100644 --- a/libw32/w32_check.c +++ b/libw32/w32_check.c @@ -1,12 +1,12 @@ #include -__CIDENT_RCSID(gr_w32_check_c,"$Id: w32_check.c,v 1.18 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_check_c,"$Id: w32_check.c,v 1.20 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 system io functionality * Note: NOT CALLED -- purely a compile time check of the mode namespace * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -22,10 +22,10 @@ __CIDENT_RCSID(gr_w32_check_c,"$Id: w32_check.c,v 1.18 2019/03/15 23:12:09 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -36,8 +36,11 @@ __CIDENT_RCSID(gr_w32_check_c,"$Id: w32_check.c,v 1.18 2019/03/15 23:12:09 cvsus * ==extra== */ +#ifndef _WIN32 +#error _WIN32 undefined +#endif #ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 /* enable xp+ features */ +#define _WIN32_WINNT 0x0501 /* enable xp+ features */ #endif #include "w32config.h" @@ -171,4 +174,3 @@ __w32_check_attr(mode_t mode) } /*end*/ - diff --git a/libw32/w32_child.c b/libw32/w32_child.c index 58be1414..eff9ff0c 100644 --- a/libw32/w32_child.c +++ b/libw32/w32_child.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_child_c,"$Id: w32_child.c,v 1.15 2020/06/18 13:19:39 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_child_c,"$Id: w32_child.c,v 1.16 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 sub-process support * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,15 +21,16 @@ __CIDENT_RCSID(gr_w32_child_c,"$Id: w32_child.c,v 1.15 2020/06/18 13:19:39 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ #include "win32_internal.h" #include "win32_child.h" +#include "win32_misc.h" #include #include @@ -60,16 +61,32 @@ typedef struct { } Redirect_t; static int cmdis(const char *shell, int slen, const char *cmd); +static int cmdisW(const wchar_t *shell, int slen, const wchar_t *cmd); +static int TOLOWER(wchar_t ch); static BOOL SendCloseMessage(HANDLE hProc); static BOOL WASNOT_ENOENT(void); -static int BuildVectors(win32_spawn_t *args, char **argblk, char **envblk); -static char * Getpath(const char *src, char *dst, unsigned maxlen); -static const char * Getenv(const char *const *envp, const char *val); -static HANDLE ExecChild(win32_spawn_t *args, +static int BuildVectorsA(win32_spawn_t *args, char **argblk, char **envblk); +static char * BuildArgA(const char *cmd, const char **argv); +static char * BuildEnvA(const char **envv); +static int BuildVectorsW(win32_spawnw_t *args, wchar_t **argblk, wchar_t **envblk); +static wchar_t * BuildArgW(const wchar_t *cmd, const wchar_t **argv); +static wchar_t * BuildEnvW(const wchar_t **envv); + +static const char * GetpathA(const char *src, char *dst, unsigned maxlen); +static const wchar_t * GetpathW(const wchar_t *src, wchar_t *dst, unsigned maxlen); + +static const char * GetenvA(const char *const *envp, const char *val); +static const wchar_t * GetenvW(const wchar_t *const *envp, const wchar_t *val); + +static HANDLE ExecChildA(win32_spawn_t *args, const char *arg0, char *argv, char *envp, STARTUPINFOA *si, PROCESS_INFORMATION *pi); -static void DisplayError(HANDLE hOutput, const char *pszAPI, const char *args); +static HANDLE ExecChildW(win32_spawnw_t *args, + const wchar_t *arg0, wchar_t *argv, wchar_t *envp, STARTUPINFOW *si, PROCESS_INFORMATION *pi); + +static void DisplayErrorA(HANDLE hOutput, const char *pszAPI, const char *args); +static void DisplayErrorW(HANDLE hOutput, const wchar_t *pszAPI, const wchar_t *args); static void InternalError(const char *pszAPI); @@ -510,6 +527,24 @@ SendCloseMessage(HANDLE hProc) */ LIBW32_API int w32_iscommand(const char *shell) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wshell[WIN32_PATH_MAX]; + + if (w32_utf2wc(shell, wshell, _countof(wshell)) > 0) { + return w32_iscommandW(wshell); + } + return -1; + } +#endif //UTF8FILENAMES + + return w32_iscommandA(shell); +} + + +LIBW32_API int +w32_iscommandA(const char *shell) { const int slen = (int)strlen(shell); @@ -524,6 +559,23 @@ w32_iscommand(const char *shell) } + +LIBW32_API int +w32_iscommandW(const wchar_t *shell) +{ + const int slen = (int)wcslen(shell); + + if (cmdisW(shell, slen, L"cmd") || + cmdisW(shell, slen, L"cmd.exe") || + cmdisW(shell, slen, L"command") || + cmdisW(shell, slen, L"command.com") || + cmdisW(shell, slen, L"command.exe")) { + return TRUE; + } + return FALSE; +} + + static int cmdis(const char *shell, int slen, const char *cmd) { @@ -531,7 +583,22 @@ cmdis(const char *shell, int slen, const char *cmd) const char *p = shell + slen - clen; if (slen == clen || (slen > clen && (p[-1] == '\\' || p[-1] == '/'))) { - if (_stricmp(p, cmd) == 0) { + if (0 == _stricmp(p, cmd)) { + return TRUE; + } + } + return FALSE; +} + + +static int +cmdisW(const wchar_t *shell, int slen, const wchar_t *cmd) +{ + const int clen = (int)wcslen(cmd); + const wchar_t *p = shell + slen - clen; + + if (slen == clen || (slen > clen && (p[-1] == '\\' || p[-1] == '/'))) { + if (0 == _wcsicmp(p, cmd)) { return TRUE; } } @@ -539,36 +606,49 @@ cmdis(const char *shell, int slen, const char *cmd) } + /* * w32_child_exec --- - * Setup a STARTUPINFO structure and launches redirected child using + * Setup a STARTUPINFO structure and launches a redirected child using * the specified stdin/stdout and stderr handles. * - * This is a low level interface and expects the caller has setup the - * calling environment. + * A low level interface that expects the caller has setup the calling environment. */ LIBW32_API HANDLE -w32_child_exec( - struct win32_spawn *args, HANDLE hStdIn, HANDLE hStdOut, HANDLE hStdErr) +w32_child_execA( + win32_spawn_t *args, HANDLE hStdIn, HANDLE hStdOut, HANDLE hStdErr) { PROCESS_INFORMATION pi = {0}; STARTUPINFOA si = {0}; + char *argblk = NULL; + char *envblk = NULL; HANDLE hProc = 0; - char *argblk; - char *envblk; - /* - * Set up the start up info struct + /* + * Build env and command line. + */ + if (NULL == args || (NULL == args->cmd && NULL == args->argv)) { + errno = EINVAL; + return 0; + } + + if (! BuildVectorsA(args, &argblk, &envblk) != 0) { + InternalError("BuildVector"); + return 0; + } + + /* + * Set up the start up info struct * USESTDHANDLES, - * The hStdInput, hStdOutput, and hStdError members contain additional information. + * hStdInput, hStdOutput, and hStdError members contain additional information. * - * If this flag is specified when calling one of the process creation functions, - * the handles must be inheritable and the function's bInheritHandles parameter + * If this flag is specified when calling one of the process creation functions, + * the handles must be inheritable and the function's bInheritHandles parameter * must be set to TRUE. For more information; */ (void) memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); - si.wShowWindow = SW_HIDE; //SW_NORMAL, SW_SHOWMINIMIZED + si.wShowWindow = ((args->flags & W32_SWHIDE) ? SW_HIDE : SW_SHOW); si.hStdInput = hStdIn; si.hStdOutput = hStdOut; si.hStdError = hStdErr; @@ -580,40 +660,41 @@ w32_child_exec( si.dwFlags = STARTF_USESTDHANDLES; si.dwFlags |= STARTF_USESHOWWINDOW; - /* - * Build env and command line. - */ - if (BuildVectors(args, &argblk, &envblk) != 0) { - InternalError("building arg and env"); - } - - /* - * Launch the process that you want to redirect. + /* + * Launch the process that you want to redirect, as lpApplicationName is NULL, search path is: + * + * o The directory from which the application loaded. + * o The current directory for the parent process. + * o The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. + * o The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System. + * o The Windows directory. Use the GetWindowsDirectory function to get the path of this directory. + * o The directories that are listed in the PATH environment variable. */ - if (0 == (hProc = ExecChild(args, NULL, argblk, envblk, &si, &pi))) { - const char *path, *cmd = - (args->argv ? args->argv[0] : args->cmd); + if (0 == (hProc = ExecChildA(args, NULL, argblk, envblk, &si, &pi))) { + const char *path, *cmd = (args->argv ? args->argv[0] : args->cmd); char *pfin, *buf = NULL; - // Complete if, - // Error != ERROR_FILE_NOT_FOUND - // arg0 contains a '/'. - // or PATH is NULL + // Complete if either: + // + // o Error != ERROR_FILE_NOT_FOUND + // o arg0 contains a '/'. + // o PATH is NULL // if (WASNOT_ENOENT() || strchr(cmd, XSLASHCHAR) != NULL || - NULL == (path = Getenv(args->envp, "PATH"))) { + NULL == (path = GetenvA(args->envv, "PATH"))) { goto done; } - if ((buf = calloc(_MAX_PATH + 1, 1)) == (const char *)NULL) { + if ((buf = calloc(_MAX_PATH + 1, sizeof(char))) == (const char *)NULL) { goto done; } - while (NULL != (path = Getpath(path, buf, _MAX_PATH-1)) && (*buf)) { + while (NULL != (path = GetpathA(path, buf, _MAX_PATH - 1)) && (*buf)) { /* If necessary, append a SLASH */ pfin = buf + strlen(buf) - 1; - if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR) - (void) strcat(buf, SLASH); + if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR) { + strcat(buf, SLASH); + } /* Check length */ if (strlen(buf) + strlen(cmd) < _MAX_PATH) { @@ -622,19 +703,137 @@ w32_child_exec( break; } - // Try spawning it. if successful, or if errno comes back - // with a value other than ENOENT and the pathname is not - // a UNC name, return to the caller. + // If successful, or if errno comes back with a value other than ENOENT + // and the pathname is not a UNC name, return to the caller. // - if ((hProc = ExecChild(args, buf, argblk, envblk, &si, &pi)) != 0 || + if ((hProc = ExecChildA(args, buf, argblk, envblk, &si, &pi)) != 0 || ((WASNOT_ENOENT()) && (!ISSLASH(*buf) || !ISSLASH(*(buf+1))))) { break; } } -done:; if (buf != NULL) { - free(buf); +done:; free(buf); + } + + /* Close any unnecessary handles. */ + if (hProc) { // success + if (! CloseHandle(pi.hThread)) { + InternalError("CloseHandle (thread)"); + } + } + + free(argblk); + free(envblk); + return hProc; +} + + +/* + * w32_child_execW --- + * Setup a STARTUPINFO structure and launches a redirected child using + * the specified stdin/stdout and stderr handles. + * + * A low level interface that expects the caller has setup the calling environment. + */ +LIBW32_API HANDLE +w32_child_execW( + win32_spawnw_t *args, HANDLE hStdIn, HANDLE hStdOut, HANDLE hStdErr) +{ + PROCESS_INFORMATION pi = {0}; + STARTUPINFOW si = {0}; + wchar_t *argblk = NULL; + wchar_t *envblk = NULL; + HANDLE hProc = 0; + + /* + * Build env and command line. + */ + if (NULL == args || (NULL == args->cmd && NULL == args->argv)) { + errno = EINVAL; + return 0; + } + + if (! BuildVectorsW(args, &argblk, &envblk)) { + InternalError("building arg and env"); + return 0; + } + + /* + * Set up the start up info struct + * USESTDHANDLES, + * hStdInput, hStdOutput, and hStdError members contain additional information. + * + * If this flag is specified when calling one of the process creation functions, + * the handles must be inheritable and the function's bInheritHandles parameter + * must be set to TRUE. For more information; + */ + (void) memset(&si, 0, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.wShowWindow = ((args->flags & W32_SWHIDE) ? SW_HIDE : SW_SHOW); + si.hStdInput = hStdIn; + si.hStdOutput = hStdOut; + si.hStdError = hStdErr; + + if (hStdIn) { DWORD flags; assert(GetHandleInformation(hStdIn, &flags) && (HANDLE_FLAG_INHERIT & flags)); } + if (hStdOut) { DWORD flags; assert(GetHandleInformation(hStdOut, &flags) && (HANDLE_FLAG_INHERIT & flags)); } + if (hStdErr) { DWORD flags; assert(GetHandleInformation(hStdErr, &flags) && (HANDLE_FLAG_INHERIT & flags)); } + + si.dwFlags = STARTF_USESTDHANDLES; + si.dwFlags |= STARTF_USESHOWWINDOW; + + /* + * Launch the process that you want to redirect, as lpApplicationName is NULL, search path is: + * + * o The directory from which the application loaded. + * o The current directory for the parent process. + * o The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. + * o The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System. + * o The Windows directory. Use the GetWindowsDirectory function to get the path of this directory. + * o The directories that are listed in the PATH environment variable. + */ + if (0 == (hProc = ExecChildW(args, NULL, argblk, envblk, &si, &pi))) { + const wchar_t *path, *cmd = (args->argv ? args->argv[0] : args->cmd); + wchar_t *pfin, *buf = NULL; + + // Complete if either: + // + // o Error != ERROR_FILE_NOT_FOUND + // o arg0 contains a '/'. + // o PATH is NULL + // + if (WASNOT_ENOENT() || wcschr(cmd, XSLASHCHAR) != NULL || + NULL == (path = GetenvW(args->envv, L"PATH"))) { + goto done; + } + + if ((buf = calloc(_MAX_PATH + 1, sizeof(wchar_t))) == (const wchar_t *)NULL) { + goto done; } + + while (NULL != (path = GetpathW(path, buf, _MAX_PATH - 1)) && (*buf)) { + /* If necessary, append a SLASH */ + pfin = buf + wcslen(buf) - 1; + if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR) { + wcscat(buf, LSLASH); + } + + /* Check length */ + if (wcslen(buf) + wcslen(cmd) < _MAX_PATH) { + wcscat(buf, cmd); + } else { + break; + } + + // If successful, or if errno comes back with a value other than ENOENT + // and the pathname is not a UNC name, return to the caller. + // + if ((hProc = ExecChildW(args, buf, argblk, envblk, &si, &pi)) != 0 || + ((WASNOT_ENOENT()) && (!ISSLASH(*buf) || !ISSLASH(*(buf+1))))) { + break; + } + } + +done:; free(buf); } /* Close any unnecessary handles. */ @@ -651,11 +850,12 @@ done:; if (buf != NULL) { static HANDLE -ExecChild(win32_spawn_t *args, +ExecChildA(win32_spawn_t *args, const char *arg0, char *argv, char *envp, STARTUPINFOA *si, PROCESS_INFORMATION *pi) { HANDLE hProc = 0; + args->_dwFlags &= ~CREATE_UNICODE_ENVIRONMENT; if (CreateProcessA( arg0, argv, // [in] application name/args. NULL, NULL, // [in] SD's. @@ -668,8 +868,34 @@ ExecChild(win32_spawn_t *args, args->_dwProcessId = pi->dwProcessId; hProc = pi->hProcess; - } else if (WASNOT_ENOENT()) { // XXX, current or hStdError ?? - DisplayError(GetStdHandle(STD_OUTPUT_HANDLE), "CreateProcess", argv); + } else if (WASNOT_ENOENT()) { + DisplayErrorA(GetStdHandle(STD_OUTPUT_HANDLE), "CreateProcess", arg0); + } + return hProc; +} + + +static HANDLE +ExecChildW(win32_spawnw_t *args, + const wchar_t *arg0, wchar_t *argv, wchar_t *envp, STARTUPINFOW *si, PROCESS_INFORMATION *pi) +{ + HANDLE hProc = 0; + + if (envp) args->_dwFlags |= CREATE_UNICODE_ENVIRONMENT; + if (CreateProcessW( + arg0, argv, // [in] application name/args. + NULL, NULL, // [in] SD's. + TRUE, // [in] handle inheritance options. + args->_dwFlags, // [in] creation flags. + envp, // [in] new envirnoment. + args->dir, // [in] working directory. + si, // [in] startup information. + pi)) { // [out] process information. + args->_dwProcessId = pi->dwProcessId; + hProc = pi->hProcess; + + } else if (WASNOT_ENOENT()) { + DisplayErrorW(GetStdHandle(STD_OUTPUT_HANDLE), L"CreateProcess", arg0); } return hProc; } @@ -713,7 +939,7 @@ WASNOT_ENOENT(void) LIBW32_API BOOL w32_child_wait(HANDLE hProc, int *status, int nowait) { - DWORD dwStatus, rc; + DWORD dwStatus = 0, rc; BOOL ret = FALSE; /* @@ -726,7 +952,13 @@ w32_child_wait(HANDLE hProc, int *status, int nowait) errno = ECHILD; /* - * Wait for child process, then fetch its exit code + * Verify handle. + */ + } else if (0 == GetExitCodeProcess(hProc, (LPDWORD)&dwStatus)) { + errno = ECHILD; + + /* + * Wait for child process, then fetch its exit code. */ } else if ((rc = WaitForSingleObject(hProc, (nowait ? 0 : INFINITE))) == WAIT_OBJECT_0 && GetExitCodeProcess(hProc, (LPDWORD)&dwStatus)) { @@ -734,12 +966,21 @@ w32_child_wait(HANDLE hProc, int *status, int nowait) * Normal termination: lo-byte = 0, hi-byte = child exit code. * Abnormal termination: lo-byte = term status, hi-byte = 0. */ + if (STILL_ACTIVE == dwStatus) { // should occur yet! + unsigned delay = 0; + do { + Sleep(100); // 10 * 100ms - 1 second + if (GetExitCodeProcess(hProc, (LPDWORD)&dwStatus) && STILL_ACTIVE != dwStatus) { + break; //done + } + } while (++delay < 10); + } CloseHandle(hProc); // process complete if (status) { if (0 == (dwStatus & 0xff)) { - *status = (int)dwStatus >> 8; + *status = (int)(dwStatus >> 8); } else { - *status = (int)dwStatus; + *status = (int)(dwStatus & 0xff); } } ret = TRUE; @@ -755,122 +996,291 @@ w32_child_wait(HANDLE hProc, int *status, int nowait) /* - * BuildVectors --- build up command line/environ vectors. + * BuildVectorsA --- build up command line/environ vectors. * * Set up the block forms of the environment and the command line. If "envp" is * null, "_environ" is used instead. File handle info is passed in the environment * if _fileinfo is !0. */ + static int -BuildVectors(win32_spawn_t *args, char **argblk, char **envblk) +BuildVectorsA(win32_spawn_t *args, char **argblk, char **envblk) +{ + *envblk = NULL; + + if (NULL == (*argblk = BuildArgA(args->cmd, args->argv))) { + return FALSE; + } + + if (args->envv) { + if (NULL == (*envblk = BuildEnvA(args->envv))) { + free(*argblk); + *argblk = NULL; + return FALSE; + } + } + + return TRUE; +} + + + +static char * +BuildArgA(const char *cmd, const char **argv) +{ + const char * const *vp; + char *ret; + int len; + + /* + * Allocate space for environment strings, count the number of bytes + * in the environment strings including nulls between strings + */ + if (cmd) { + len = (int)strlen(cmd) + 1 /*nul*/; + assert(NULL == argv); + } else { + for (vp = argv, len = 2 /*quotes*/ + 2 /*delim*/; *vp; len += (int)strlen(*vp++) + 1 /*nul*/) + /**/; + } + + if (len > (32 * 1024 * sizeof(char))) { + errno = E2BIG; // command line too long >32k. + return NULL; + } + + if (NULL == (ret = (char *)calloc(len * sizeof(char), 1))) { + return NULL; + } + + /* + * Build the command line by concatenating the argument strings + * with spaces between, and two null bytes at the end. + */ + if (cmd) { + strcpy(ret, cmd); + + } else { + char *cursor = ret; + + vp = argv; + for (len = 0; *vp; ++len) { + const char *arg = *vp++; + int quote = FALSE; + + if (0 == len && *arg != '"' && strchr(arg, ' ')) { + quote = TRUE; // quote, contains space. + } + + if (quote) *cursor++ = '"'; + if (0 == len) { + while (*arg) { // convert slashs within arg0. + *cursor++ = ('/' == *arg ? '\\' : *arg); + ++arg; + } + } else { + strcpy(cursor, arg); + cursor += strlen(arg); + } + if (quote) *cursor++ = '"'; + + *cursor++ = ' '; // space delimiter. + } + + cursor[-1] = '\0'; // remove extra delimiter. + *cursor = '\0'; // terminator. + } + + return ret; +} + + +static char * +BuildEnvA(const char **envv) { + /* + * Set up the block forms of the environment and the command line. + * If "envv" is null, "_environ" is used instead. + */ const char **envp = #if defined(__WATCOMC__) - (args->envp ? args->envp : (const char **)environ); + (envv ? envv : (const char **)environ); #else - (args->envp ? args->envp : (const char **)_environ); + (envv ? envv : (const char **)_environ); #endif const char * const *vp; - int tmp; - char *cptr; + char *ret, *cursor; + int len; /* - * Allocate space for command line string. tmp counts the number of - * bytes in the command line string including spaces between arguments - * plus two charcater for possible quoting. + * Allocate space for environment strings, count the number of bytes + * in the environment strings including nulls between strings */ - if (args->cmd) { - tmp = (int)strlen(args->cmd) + 1; - } else { - for (vp = args->argv, tmp = 2+2; *vp; tmp += (int)strlen(*vp++) + 1) - /**/; + for (vp = envp, len = 2 /*padding*/; *vp; len += (int)strlen(*vp++) + 1 /*nul*/) + /**/; + + if (NULL == (ret = (char *)calloc(len * sizeof(char), 1))) { + return NULL; } - if (tmp > 32767) { - errno = E2BIG; // command line too long >32k - return -1; + /* + * Build the environment block by concatenating the environment + * strings with nulls between and two null bytes at the end + */ + for (cursor = ret, vp = envp, len = 0; *vp; ++len, ++vp) { + const int slen = strlen(*vp) + 1 /*nul*/; + memcpy(cursor, *vp, slen * sizeof(char)); + cursor += slen; } - /* Allocate space for the command line plus 2 null bytes */ - if ((*argblk = calloc(tmp * sizeof(char), 1)) == NULL) { - *envblk = NULL; - return -1; + if (cursor == ret) *cursor++ = '\0'; + *cursor = '\0'; // final terminator. + + return ret; +} + + +/* + * BuildVectorsW --- build up command line/environ vectors. + * + * Set up the block forms of the environment and the command line. If "envp" is + * null, "_wenviron" is used instead. File handle info is passed in the environment + * if _fileinfo is !0. + */ + +static int +BuildVectorsW(win32_spawnw_t *args, wchar_t **argblk, wchar_t **envblk) +{ + *envblk = NULL; + + if (NULL == (*argblk = BuildArgW(args->cmd, args->argv))) { + return FALSE; } + if (args->envv) { + if (NULL == (*envblk = BuildEnvW(args->envv))) { + free(*argblk); + *argblk = NULL; + return FALSE; + } + } + + return TRUE; +} + + +static wchar_t * +BuildArgW(const wchar_t *cmd, const wchar_t **argv) +{ + const wchar_t * const *vp; + wchar_t *ret; + int len; + /* - * Allocate space for environment strings tmp counts the number of bytes + * Allocate space for environment strings, count the number of bytes * in the environment strings including nulls between strings */ - for (vp = envp, tmp = 2; *vp; tmp += (int)strlen(*vp++) + 1) - /**/; + if (cmd) { + len = (int)wcslen(cmd) + 1 /*nul*/; + assert(NULL == argv); + } else { + for (vp = argv, len = 2 /*quotes*/ + 2 /*delim*/; *vp; len += (int)wcslen(*vp++) + 1 /*nul*/) + /**/; + } - /* Allocate space for the environment strings plus extra null byte */ - if (NULL == (*envblk = calloc(tmp * sizeof(char), 1))) { - free(*argblk); - *argblk = NULL; - return -1; + if (len > (32 * 1024 * sizeof(wchar_t))) { + errno = E2BIG; // command line too long >32k. + return NULL; + } + + if (NULL == (ret = (wchar_t *)calloc(len * sizeof(wchar_t), 1))) { + return NULL; } /* * Build the command line by concatenating the argument strings * with spaces between, and two null bytes at the end. */ - cptr = *argblk; - - if (args->cmd) { - strcpy(cptr, args->cmd); - cptr += strlen(args->cmd); + if (cmd) { + wcscpy(ret, cmd); } else { - vp = args->argv; - for (tmp = 0; *vp; ++tmp) { - const char *arg = *vp++; + wchar_t *cursor = ret; + + vp = argv; + for (len = 0; *vp; ++len) { + const wchar_t *arg = *vp++; int quote = FALSE; - if (0 == tmp && *arg != '"' && strchr(arg, ' ')) { - ++quote; // quote, contains space + if (0 == len && *arg != '"' && wcschr(arg, ' ')) { + quote = TRUE; // quote, contains space. } - if (quote) *cptr++ = '"'; - if (0 == tmp) { - while (*arg) { // convert slashs within arg0 - *cptr++ = ('/' == *arg ? '\\' : *arg); + if (quote) *cursor++ = '"'; + if (0 == len) { + while (*arg) { // convert slashs within arg0. + *cursor++ = ('/' == *arg ? '\\' : *arg); ++arg; } } else { - strcpy(cptr, arg); - cptr += strlen(arg); + wcscpy(cursor, arg); + cursor += wcslen(arg); } - if (quote) *cptr++ = '"'; + if (quote) *cursor++ = '"'; - *cptr++ = ' '; + *cursor++ = ' '; // space delimiter. } - *cptr = cptr[-1] = '\0'; // remove extra blank + + cursor[-1] = '\0'; // remove extra delimiter. + *cursor = '\0'; // terminator. } + return ret; +} + +static wchar_t * +BuildEnvW(const wchar_t **envv) +{ /* - * Build the environment block by concatenating the environment - * strings with nulls between and two null bytes at the end + * Set up the block forms of the environment and the command line. + * If "envv" is null, "_environ" is used instead. */ - cptr = *envblk; - vp = envp; + const wchar_t **envp = +#if defined(__WATCOMC__) + (envv ? envv : (const wchar_t **)_wenviron); +#else + (envv ? envv : (const wchar_t **)_wenviron); +#endif + const wchar_t * const *vp; + wchar_t *ret, *cursor; + int len; + + /* + * Allocate space for environment strings, count the number of bytes + * in the environment strings including nulls between strings + */ + for (vp = envp, len = 2 /*padding*/; *vp; len += (int)wcslen(*vp++) + 1 /*nul*/) + /**/; - for (tmp = 0; *vp; ++tmp) { - (void) strcpy(cptr, *vp); - cptr += strlen(*vp++) + 1; + if (NULL == (ret = (wchar_t *)calloc(len * sizeof(wchar_t), 1))) { + return NULL; } /* - * Empty environment block ... this requires two nulls. + * Build the environment block by concatenating the environment + * strings with nulls between and two null bytes at the end */ - if (cptr != NULL) { - if (cptr == *envblk) { - *cptr++ = '\0'; - } - *cptr = '\0'; // Extra \0 terminates + for (cursor = ret, vp = envp, len = 0; *vp; ++len, ++vp) { + const int slen = wcslen(*vp) + 1 /*nul*/; + memcpy(cursor, *vp, slen * sizeof(wchar_t)); + cursor += slen; } - return 0; + + if (cursor == ret) *cursor++ = '\0'; + *cursor = '\0'; // final terminator. + + return ret; } @@ -889,8 +1299,8 @@ BuildVectors(win32_spawn_t *args, char **argblk, char **envblk) * * PATH=C:\BIN;"D:\CRT\TOOLS;B1";C:\BINP */ -static char * -Getpath(const char *src, char *dst, unsigned maxlen) +static const char * +GetpathA(const char *src, char *dst, unsigned maxlen) { const char *save_src; @@ -946,12 +1356,73 @@ Getpath(const char *src, char *dst, unsigned maxlen) */ appendnull: *dst = '\0'; - return((save_src != src) ? (char *)src : NULL); + return((save_src != src) ? (const char *)src : NULL); +} + + +static const wchar_t * +GetpathW(const wchar_t *src, wchar_t *dst, unsigned maxlen) +{ + const wchar_t *save_src; + + /* Strip off leading semi colons */ + while (*src == ';') { + ++src; + } + + /* Save original src pointer */ + save_src = src; + + /* Decrement maxlen to allow for the terminating _T('\0') */ + if (--maxlen == 0) { + goto appendnull; + } + + /* Get the next path in src string */ + while (*src && (*src != ';')) { + if (*src != '"') { // check for quote char + *dst++ = *src++; + if (--maxlen == 0) { + save_src = src; // ensure NULL return + goto appendnull; + } + + } else { // quoted + /* Copy all chars until we hit the final quote or the EOS */ + src++; // skip over opening quote + while (*src && (*src != '"')) { + *dst++ = *src++; + if ( --maxlen == 0 ) { + save_src = src; // ensure NULL return + goto appendnull; + } + } + + if (*src) { + src++; // skip over closing quote + } + } + } + + /* + * If we copied something and stopped because of a ';', skip ';' + * before returning + */ + while (*src == ';') { + ++src; + } + + /* + * Store a terminating null. + */ +appendnull: + *dst = '\0'; + return ((save_src != src) ? (const wchar_t *)src : NULL); } static const char * -Getenv(const char *const *envp, const char *val) +GetenvA(const char *const *envp, const char *val) { const char *p = NULL; @@ -965,7 +1436,7 @@ Getenv(const char *const *envp, const char *val) p = *envp + len + 1; break; } - envp++; + ++envp; } } @@ -977,39 +1448,72 @@ Getenv(const char *const *envp, const char *val) } +static const wchar_t * +GetenvW(const wchar_t *const *envp, const wchar_t *val) +{ + const wchar_t *p = NULL; + + if (envp) { // Search local path + size_t len; + + len = wcslen(val); + while (*envp) { + if (wcslen(*envp) > len && *(*envp + len) == '=' && + wcsncmp(*envp, val, len) == 0) { + p = *envp + len + 1; + break; + } + ++envp; + } + } + + if (p == (const wchar_t *)NULL) { // Global path + p = _wgetenv(val); + } + + return (p); +} + + /* * WaiInternalError --- * Displays the error number and corresponding message. */ static void -DisplayError( - HANDLE hOutput, const char *pszAPI, const char *args) +DisplayErrorA( + HANDLE hOutput, const char *msg, const char *cmd) { const DWORD rc = GetLastError(); - LPVOID lpvMessageBuffer; - char szPrintBuffer[512]; - DWORD nCharsWritten; + char t_rcbuffer[512], buffer[1024]; + const char *rcmsg = w32_vsyserrorA(rc, t_rcbuffer, sizeof(t_rcbuffer), cmd, NULL); + int len; - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPSTR)&lpvMessageBuffer, 0, NULL); + len = _snprintf(buffer, sizeof(buffer), + "Internal Error: %s = %u (%s).\n", msg, (unsigned)rc, rcmsg); + WriteConsoleA(hOutput, buffer, len, NULL, NULL); +} - _snprintf(szPrintBuffer, sizeof(szPrintBuffer), - "Internal Error: %s = %d (%s).\n%s%s", pszAPI, rc, (char *)lpvMessageBuffer, - args ? args : "", args ? "\n" : "" ); - szPrintBuffer[sizeof(szPrintBuffer) - 1] = 0; - WriteConsoleA(hOutput, szPrintBuffer, lstrlenA(szPrintBuffer), &nCharsWritten, NULL); - LocalFree(lpvMessageBuffer); +static void +DisplayErrorW( + HANDLE hOutput, const wchar_t *msg, const wchar_t *cmd) +{ + const DWORD rc = GetLastError(); + wchar_t t_rcbuffer[512], buffer[1024]; + const wchar_t *rcmsg = w32_vsyserrorW(rc, t_rcbuffer, _countof(t_rcbuffer), cmd, NULL); + int len; + + len = _snwprintf(buffer, _countof(buffer), + L"Internal Error: %s = %u (%s).\n", msg, (unsigned)rc, rcmsg); + WriteConsoleW(hOutput, buffer, len, NULL, NULL); } static void -InternalError( - const char *pszAPI) +InternalError(const char *pszAPI) { - DisplayError(GetStdHandle(STD_OUTPUT_HANDLE), pszAPI, NULL); + DisplayErrorA(GetStdHandle(STD_OUTPUT_HANDLE), pszAPI, NULL); ExitProcess(GetLastError()); } /*end*/ - diff --git a/libw32/w32_chmod.c b/libw32/w32_chmod.c new file mode 100644 index 00000000..9df20de0 --- /dev/null +++ b/libw32/w32_chmod.c @@ -0,0 +1,123 @@ +#include +__CIDENT_RCSID(gr_w32_chmod_c,"$Id: w32_chmod.c,v 1.2 2022/03/21 14:29:40 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 chmod() system calls. + * + * Copyright (c) 2020 - 2022 Adam Young. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + */ + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 /* enable xp+ features */ +#endif + +#include "win32_internal.h" +#include + + +/* +// NAME +// chmod +// +// SYNOPSIS +// #include +// +// int chmod(const char *pathname, mode_t mode); +// +// DESCRIPTION +// The chmod() and fchmod() system calls change a files mode bits. +// chmod() changes the mode of the file specified whose pathname is given +// in pathname, which is dereferenced if it is a symbolic link. +// +// The file mode consists of the file permission bits plus the set-user-ID, +// set-group-ID, and sticky bits) These system calls differ only in how the +// file is specified. +// +// ERRORS +// +// The chmod() function will fail if: +// +// [EACCES] +// Search permission is denied on a component of the path prefix. +// [ELOOP] +// Too many symbolic links were encountered in resolving path. +// [ENAMETOOLONG] +// The length of the path argument exceeds {PATH_MAX} or a pathname component is longer than {NAME_MAX}. +// [ENOTDIR] +// A component of the path prefix is not a directory. +// [ENOENT] +// A component of path does not name an existing file or path is an empty string. +// [EPERM] +// The effective user ID does not match the owner of the file and the process does not have appropriate privileges. +// [EROFS] +// The named file resides on a read-only file system. +// +// The chmod() function may fail if: +// +// [EINTR] +// A signal was caught during execution of the function. +// [EINVAL] +// The value of the mode argument is invalid. +// [ENAMETOOLONG] +// Pathname resolution of a symbolic link produced an intermediate result whose length exceeds {PATH_MAX}. +*/ + +LIBW32_API int +w32_chmod(const char *pathname, mode_t mode) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpathname[WIN32_PATH_MAX]; + + if (NULL == pathname) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(pathname, wpathname, _countof(wpathname)) > 0) { + return w32_chmodW(wpathname, mode); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_chmodA(pathname, mode); +} + + +LIBW32_API int +w32_chmodA(const char *pathname, mode_t mode) +{ +#undef chmod + return chmod(pathname, mode); +} + + +LIBW32_API int +w32_chmodW(const wchar_t *pathname, mode_t mode) +{ + return _wchmod(pathname, mode); +} + +/*end*/ diff --git a/libw32/w32_chown.c b/libw32/w32_chown.c index 310c5d2b..e269a88f 100644 --- a/libw32/w32_chown.c +++ b/libw32/w32_chown.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_chown_c,"$Id: w32_chown.c,v 1.12 2019/03/15 23:12:09 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_chown_c,"$Id: w32_chown.c,v 1.14 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 chown() system calls. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_chown_c,"$Id: w32_chown.c,v 1.12 2019/03/15 23:12:09 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -152,5 +152,24 @@ chown(const char *fname, uid_t uid, gid_t gid) return 0; } -/*end*/ +LIBW32_API int +chownA(const char *fname, uid_t uid, gid_t gid) +{ + __PUNUSED(fname); + __PUNUSED(uid); + __PUNUSED(gid); + return 0; +} + + +LIBW32_API int +chownW(const wchar_t *fname, uid_t uid, gid_t gid) +{ + __PUNUSED(fname); + __PUNUSED(uid); + __PUNUSED(gid); + return 0; +} + +/*end*/ diff --git a/libw32/w32_close.c b/libw32/w32_close.c index b9e6c1f4..482f0c83 100644 --- a/libw32/w32_close.c +++ b/libw32/w32_close.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_close_c,"$Id: w32_close.c,v 1.14 2019/03/15 23:12:10 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_close_c,"$Id: w32_close.c,v 1.15 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* - * win32 close() system calls + * win32 close() system calls. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_close_c,"$Id: w32_close.c,v 1.14 2019/03/15 23:12:10 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -180,5 +180,5 @@ w32_close(int fildes) } return ret; } -/*end*/ +/*end*/ diff --git a/libw32/w32_colors256.h b/libw32/w32_colors256.h index 75f3856f..7aae5ebd 100644 --- a/libw32/w32_colors256.h +++ b/libw32/w32_colors256.h @@ -1,7 +1,9 @@ +#ifndef LIBW32_W32_COLORS256_H_INCLUDED +#define LIBW32_W32_COLORS256_H_INCLUDED /* * RGB Colors -- win32 slang emulation. * - * Copyright (c) 2015 - 2019, Adam Young. + * Copyright (c) 2015 - 2022, Adam Young. * * This file is part of the GRIEF Editor. * @@ -16,10 +18,10 @@ * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -280,3 +282,5 @@ { 0xda, 0xda, 0xda }, /* 253 */ { 0xe4, 0xe4, 0xe4 }, /* 254 */ { 0xee, 0xee, 0xee }, /* 255 */ + +#endif /*LIBW32_W32_COLORS256_H_INCLUDED*/ diff --git a/libw32/w32_dir.c b/libw32/w32_dir.c index 1f088a00..ec450657 100644 --- a/libw32/w32_dir.c +++ b/libw32/w32_dir.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_dir_c,"$Id: w32_dir.c,v 1.12 2020/05/04 00:00:01 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_dir_c,"$Id: w32_dir.c,v 1.14 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* @@ -7,7 +7,7 @@ __CIDENT_RCSID(gr_w32_dir_c,"$Id: w32_dir.c,v 1.12 2020/05/04 00:00:01 cvsuser E * * mkdir, rmdir, chdir * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -23,10 +23,10 @@ __CIDENT_RCSID(gr_w32_dir_c,"$Id: w32_dir.c,v 1.12 2020/05/04 00:00:01 cvsuser E * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -42,8 +42,10 @@ __CIDENT_RCSID(gr_w32_dir_c,"$Id: w32_dir.c,v 1.12 2020/05/04 00:00:01 cvsuser E #include #include +#ifdef HAVE_WCHAR_H +#include +#endif #include - #include #if defined(_MSC_VER) @@ -51,9 +53,18 @@ __CIDENT_RCSID(gr_w32_dir_c,"$Id: w32_dir.c,v 1.12 2020/05/04 00:00:01 cvsuser E #pragma warning(disable : 4312) // type cast' : conversion from 'xxx' to 'xxx' of greater size #endif -const char * x_w32_cwdd[26]; /* current working directory, per drive */ +#include "win32_direct.h" + +int x_w32_cwdn = 0; /* current/last working drive number, A=1 etc */ +const char * x_w32_cwdd[26] = {0}; /* current working directory, per drive */ const char * x_w32_vfscwd = NULL; /* virtual UNC path, if any */ +static int set_root_directoryA(const char *path); +static int set_root_directoryW(const wchar_t *path); +static int set_vfs_directoryA(const char *path); +static int set_vfs_directoryW(const wchar_t *path); +static void cache_directory(void); + /* // NAME @@ -133,6 +144,31 @@ const char * x_w32_vfscwd = NULL; /* virtual UNC path, if any */ */ LIBW32_API int w32_mkdir(const char *path, int mode) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return w32_mkdirW(wpath, mode); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_mkdirA(path, mode); + +} + + +LIBW32_API int +w32_mkdirA(const char *path, int mode) { (void) mode; if (! CreateDirectoryA(path, NULL)) { @@ -142,6 +178,17 @@ w32_mkdir(const char *path, int mode) } +LIBW32_API int +w32_mkdirW(const wchar_t *path, int mode) +{ + (void) mode; + if (! CreateDirectoryW(path, NULL)) { + return w32_errno_set(); + } + return 0; +} + + /* // NAME // @@ -196,85 +243,286 @@ w32_mkdir(const char *path, int mode) // As a result of encountering a symbolic link in resolution of the path argument, // the length of the substituted pathname string exceeded { PATH_MAX}. */ + LIBW32_API int w32_chdir(const char *path) { - BOOL success; +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return w32_chdirW(wpath); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_chdirA(path); +} + + +LIBW32_API int +w32_chdirA(const char *path) +{ + BOOL success, isunc = FALSE; + int root; if (NULL == path || !*path) { errno = EINVAL; return -1; } - success = SetCurrentDirectoryA(path); + if ((root = set_root_directoryA(path)) >= -1) { + return root; + } + success = SetCurrentDirectoryA(path); if (! success) { // possible shortcut. char lnkbuf[WIN32_PATH_MAX]; - if (w32_shortcut_expand(path, lnkbuf, sizeof(lnkbuf), SHORTCUT_TRAILING|SHORTCUT_COMPONENT)) { + w32_errno_set(); + if (w32_lnkexpandA(path, lnkbuf, _countof(lnkbuf), SHORTCUT_TRAILING|SHORTCUT_COMPONENT)) { success = SetCurrentDirectoryA(lnkbuf); + if (! success) { + w32_errno_set(); + } else { + isunc = w32_unc_validA(lnkbuf); + } } + } else { + isunc = w32_unc_validA(path); } if (! success) { - int serverlen = w32_root_unc(path); + return set_vfs_directoryA(path); + } + + set_vfs_directoryA(NULL); + if (! isunc) cache_directory(); + + return 0; +} + + +LIBW32_API int +w32_chdirW(const wchar_t *path) +{ + BOOL success, isunc = FALSE; + int root; + + if (NULL == path || !*path) { + errno = EINVAL; + return -1; + } + + if ((root = set_root_directoryW(path)) >= -1) { + return root; + } + + success = SetCurrentDirectoryW(path); + if (! success) { // possible shortcut. + wchar_t lnkbuf[WIN32_PATH_MAX]; + + w32_errno_set(); + if (w32_lnkexpandW(path, lnkbuf, _countof(lnkbuf), SHORTCUT_TRAILING|SHORTCUT_COMPONENT)) { + success = SetCurrentDirectoryW(lnkbuf); + if (! success) { + w32_errno_set(); + } else { + isunc = w32_unc_validW(lnkbuf); + } + } + } else { + isunc = w32_unc_validW(path); + } + + if (! success) { + return set_vfs_directoryW(path); + } + + set_vfs_directoryW(NULL); + if (! isunc) cache_directory(); + + return 0; +} + + +static int +set_root_directoryA(const char *path) +{ + while (*path) { + if (! IS_PATH_SEP(*path)) { + return -2; // not root + } + ++path; + } + + /* + * chdir("/") behaviour is context specific, meaning goto root of current drive, + * mount point or current UNC. Normalisze this behaviour to root of current/last drive. + * Also see realpath() and related opendir() usage. + */ + { char npath[4]; + int driveno = w32_getdrive(); + + if (driveno <= 0) driveno = w32_getlastdrive(); + if (driveno <= 0) driveno = w32_getsystemdrive(); + if (driveno > 0) { + npath[0] = driveno + ('A' - 1); + npath[1] = ':'; + npath[2] = PATH_SEP; + npath[3] = 0; + return w32_chdirA(npath); + } + } + + errno = ENOTDIR; + return -1; +} + + +static int +set_root_directoryW(const wchar_t *path) +{ + while (*path) { + if (! IS_PATH_SEP(*path)) { + return -2; // not root + } + ++path; + } + + /* + * Generic chdir("/") behaviour is context specific, meaning goto root of current drive, + * mount point or current UNC. Normalisze this behaviour to root of current/last drive. + * Also see realpath() and related opendir() usage. + */ + { wchar_t npath[4]; + int driveno = w32_getdrive(); + + if (driveno <= 0) driveno = w32_getlastdrive(); + if (driveno <= 0) driveno = w32_getsystemdrive(); + if (driveno > 0) { + npath[0] = driveno + ('A' - 1); + npath[1] = ':'; + npath[2] = PATH_SEP; + npath[3] = 0; + return w32_chdirW(npath); + } + } - if (serverlen > 0) { // UNC root path (//servername/) - free((void *)x_w32_vfscwd); - if (NULL != (x_w32_vfscwd = malloc(serverlen + 4))) { + errno = ENOTDIR; + return -1; +} + + +static int +set_vfs_directoryA(const char *path) +{ + free((void *)x_w32_vfscwd); + x_w32_vfscwd = NULL; + + if (path) { + int serverlen; + + if ((serverlen = w32_unc_validA(path)) > 0) { + + serverlen += 4; // delimiters + if (NULL != (x_w32_vfscwd = malloc(serverlen))) { char *cursor = (char *)x_w32_vfscwd; + int i; - path += 2; - *cursor++ = '/'; - *cursor++ = '/'; - while (serverlen-- > 0) { + path += 2; // "//" or "\\" + *cursor++ = '/'; *cursor++ = '/'; + for (i = serverlen - 4; i > 0; --i) { *cursor++ = toupper((unsigned char)*path++); } *cursor++ = '/'; *cursor = 0; + assert(cursor <= (x_w32_vfscwd + serverlen)); return 0; } } - return w32_errno_set(); } + return -1; +} + - free((void *)x_w32_vfscwd), x_w32_vfscwd = NULL; - - if (!(('/' == path[0] && '/' == path[1]) || // UNC paths - ('\\' == path[0] && '\\' == path[1]))) { - char t_cwd[1024] = {0}; - - if (w32_getcwd(t_cwd, sizeof(t_cwd))) { - if (isalpha((unsigned char)t_cwd[0]) && ':' == t_cwd[1]) { - const unsigned nDrive = toupper(t_cwd[0]) - 'A'; - char env_var[4] = { "=X:" }; - - /* - * Cache drive specific directory - */ - free((char *)x_w32_cwdd[nDrive]); - x_w32_cwdd[nDrive] = WIN32_STRDUP(t_cwd); - - /* - * Update the environment (=) - * This is required to support the MSVCRT runtime logic based on the current-directory-on-drive - * environment variables. Function like (fullpath, spawn, etc) *may* need them to be set. - * - * If associated with a 'drive', the current directory should have the form of the example below: - * - * C:\Program and Settings\users\ - * - * so that the environment variable should be of the form: - * - * =C:=C:\Program and Settings\users\ - */ - env_var[1] = toupper(t_cwd[0]); - w32_unix2dos(t_cwd); - (void) SetEnvironmentVariableA(env_var, t_cwd); +static int +set_vfs_directoryW(const wchar_t *path) +{ + free((void *)x_w32_vfscwd); + x_w32_vfscwd = NULL; + + if (path) { + int serverlen; + + if ((serverlen = w32_unc_validW(path)) > 0) { + + serverlen += 4; // delimiters + if (NULL != (x_w32_vfscwd = malloc(serverlen))) { + char *cursor = (char *)x_w32_vfscwd; + int i; + + path += 2; // "//" or "\\" + // Valid characters for hostnames are ASCII(7), letters from a to z, + // the digits from 0 to 9, and the hyphen (-). + *cursor++ = '/'; *cursor++ = '/'; + for (i = serverlen - 4; i > 0; --i) { + *cursor++ = toupper((unsigned char)*path++); + } + *cursor++ = '/'; + *cursor = 0; + assert(cursor <= (x_w32_vfscwd + serverlen)); + return 1; } } } - return 0; + return -1; +} + + +static void +cache_directory() +{ + char t_cwd[WIN32_PATH_MAX] = {0}; + + if (w32_getcwd(t_cwd, _countof(t_cwd))) { + if (isalpha((unsigned char)t_cwd[0]) && ':' == t_cwd[1]) { + const unsigned driveno = toupper(t_cwd[0]) - 'A'; + char env_var[4] = { "=X:" }; + + /* + * Cache drive specific directory + */ + free((char *)x_w32_cwdd[driveno]); + x_w32_cwdd[driveno] = WIN32_STRDUP(t_cwd); + x_w32_cwdn = driveno + 1; + + /* + * Update the environment (=) + * This is required to support the MSVCRT runtime logic based on the current-directory-on-drive + * environment variables. Function like (fullpath, spawn, etc) *may* need them to be set. + * + * If associated with a 'drive', the current directory should have the form of the example below: + * + * C:\Program and Settings\users\ + * + * so that the environment variable should be of the form: + * + * =C:=C:\Program and Settings\users\ + */ + env_var[1] = toupper(t_cwd[0]); + w32_unix2dos(t_cwd); + (void) SetEnvironmentVariableA(env_var, t_cwd); + } + } } @@ -380,6 +628,30 @@ w32_chdir(const char *path) */ LIBW32_API int w32_rmdir(const char *path) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return w32_rmdirW(wpath); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_rmdirA(path); +} + + +LIBW32_API int +w32_rmdirA(const char *path) { if (! RemoveDirectoryA(path)) { return w32_errno_set(); @@ -388,63 +660,94 @@ w32_rmdir(const char *path) } +LIBW32_API int +w32_rmdirW(const wchar_t *path) +{ + if (! RemoveDirectoryW(path)) { + return w32_errno_set(); + } + return 0; +} + + /* - * w32_root_unc --- - * determine if the specific path is a UNC root (i.e. //servername[/]) + * w32_lnkexpandA --- + * expand embedded shortcuts. */ -LIBW32_API int -w32_root_unc(const char *path) +LIBW32_API BOOL +w32_lnkexpandA(const char *name, char *buf, size_t buflen, unsigned flags) { - if (('/' == path[0] && '/' == path[1]) || // UNC prefix? - ('\\' == path[0] && '\\' == path[1])) { + const size_t length = strlen(name); + char *t_name; + BOOL ret = 0; - const char *slash = w32_strslash(path + 2); + if (length > 4 && NULL != (t_name = calloc(sizeof(char), length + 1 /*nul*/))) { + char *cursor, *end; + int dots = 0; - if (NULL == slash || 0 == slash[1]) { + memcpy(t_name, name, length + 1 /*nul*/); - const size_t serverlen = // servername length - (slash ? (slash - (path + 2)) : strlen(path + 2)); + for (cursor = t_name + length, end = cursor; --cursor >= t_name;) { + if ('.' == *cursor) { // extension + if (1 == ++dots) { // last/trailing + if (0 == w32_io_strnicmp(cursor, ".lnk", 4) && (cursor + 4) == end) { + // + // .lnk + // - attempt expansion, allowing one within any given path. + const size_t trailing = length - (end - t_name); + const char term = *end; + int t_ret; - if (serverlen > 0) { + assert((0 == trailing && 0 == term) || (trailing && ('/' == term || '\\' == term))); - char computerName[MAX_COMPUTERNAME_LENGTH + 1] = {0}; - DWORD computerSz = sizeof(computerName); + if (flags & (term ? SHORTCUT_COMPONENT : SHORTCUT_TRAILING)) { - // local server ? - if (GetComputerNameA(computerName, &computerSz)) { - if (serverlen == computerSz && - 0 == _strnicmp(path + 2, computerName, serverlen)) { - return (int)serverlen; + *end = 0; // remove trailing component. + if ((t_ret = w32_readlinkA(t_name, buf, buflen)) > 0) { + if (buflen > (t_ret + trailing)) { + if (trailing) { // appending trailing component(s). + *end = term, memcpy(buf + t_ret, end, trailing + 1 /*nul*/); + } + ret = 1; // success. + } + } + } + break; //done } } + + } else if ('/' == *cursor || '\\' == *cursor) { + end = cursor; // new component. + dots = 0; } } + free((void *)t_name); } - return 0; + return ret; } /* - * w32_shortcut_expand --- + * w32_lnkexpandW --- * expand embedded shortcuts. */ LIBW32_API BOOL -w32_shortcut_expand(const char *name, char *buf, size_t buflen, unsigned flags) +w32_lnkexpandW(const wchar_t *name, wchar_t *buf, size_t buflen, unsigned flags) { - const size_t length = strlen(name); - char *t_name; + const size_t length = wcslen(name); + wchar_t *t_name; BOOL ret = 0; - if (length > 4 && NULL != (t_name = malloc(length + 1 /*nul*/))) { - char *cursor, *end; + if (length > 4 && NULL != (t_name = calloc(sizeof(wchar_t), length + 1 /*nul*/))) { + wchar_t *cursor, *end; int dots = 0; - (void) memcpy(t_name, name, length + 1 /*nul*/); + wmemcpy(t_name, name, length + 1 /*nul*/); for (cursor = t_name + length, end = cursor; --cursor >= t_name;) { if ('.' == *cursor) { // extension if (1 == ++dots) { // last/trailing - if (0 == WIN32_STRNICMP(cursor, ".lnk", 4) && (cursor + 4) == end) { + if (0 == w32_io_wstrnicmp(cursor, ".lnk", 4) && (cursor + 4) == end) { // // .lnk // - attempt expansion, allowing one within any given path. @@ -457,10 +760,10 @@ w32_shortcut_expand(const char *name, char *buf, size_t buflen, unsigned flags) if (flags & (term ? SHORTCUT_COMPONENT : SHORTCUT_TRAILING)) { *end = 0; // remove trailing component. - if ((t_ret = w32_readlink(t_name, buf, buflen)) > 0) { + if ((t_ret = w32_readlinkW(t_name, buf, buflen)) > 0) { if (buflen > (t_ret + trailing)) { if (trailing) { // appending trailing component(s). - *end = term, memcpy(buf + t_ret, end, trailing + 1 /*nul*/); + *end = term, wmemcpy(buf + t_ret, end, trailing + 1 /*nul*/); } ret = 1; // success. } diff --git a/libw32/w32_dirent.c b/libw32/w32_dirent.c index 0eaf7d75..4cc0191b 100644 --- a/libw32/w32_dirent.c +++ b/libw32/w32_dirent.c @@ -1,11 +1,13 @@ #include -__CIDENT_RCSID(gr_w32_dirent_c,"$Id: w32_dirent.c,v 1.30 2020/06/18 13:22:51 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_dirent_c,"$Id: w32_dirent.c,v 1.32 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* - * win32 directory services + * win32 directory access services ... * - * Copyright (c) 1998 - 2019, Adam Young. + * opendir, closedir, readdir, seekdir, rewindir, telldir + * + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +23,10 @@ __CIDENT_RCSID(gr_w32_dirent_c,"$Id: w32_dirent.c,v 1.30 2020/06/18 13:22:51 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -42,11 +44,6 @@ __CIDENT_RCSID(gr_w32_dirent_c,"$Id: w32_dirent.c,v 1.30 2020/06/18 13:22:51 cvs #define _DIRENT_SOURCE #include "win32_internal.h" #include - -#pragma comment(lib, "Netapi32.lib") -#pragma comment(lib, "Advapi32.lib") -#include /* NetEnum... */ - #include #include #include @@ -56,19 +53,38 @@ __CIDENT_RCSID(gr_w32_dirent_c,"$Id: w32_dirent.c,v 1.30 2020/06/18 13:22:51 cvs #include #include -#define DIR_FISHPF 0x0001 -#define DIR_MAGIC 0x57333264 /* W32d */ +#include "win32_io.h" +#include "win32_direct.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#define SIZEOF_DIRENT (sizeof(struct dirent) - sizeof(((struct dirent *)0)->d_name)) typedef BOOL (WINAPI *Wow64DisableWow64FsRedirection_t)(PVOID *OldValue); typedef BOOL (WINAPI *Wow64RevertWow64FsRedirection_t)(PVOID OldValue); -static BOOL isshortcut(const char *path); -static DIR * unc_populate(const char *path); +static BOOL isshortcutA(const char *path); +static BOOL isshortcutW(const wchar_t *path); + +static DIR * unc_populateA(const char *servername); +static DIR * unc_populateW(const wchar_t *servername); + +static int dir_populateA(DIR *dp, const char *path); +static int dir_populateW(DIR *dp, const wchar_t *path); + +static struct _dirlist * dir_pushA(DIR *dp, const char *filename); +static struct _dirlist * dir_pushW(DIR *dp, const wchar_t *filename); +static void dir_read(DIR *dp, struct dirent *ent); + -static int dir_populate(DIR *dp, const char *path); -static struct _dirlist * dir_list_push(DIR *dp, const char *filename); static void dir_list_free(struct _dirlist *); -static int dir_ishpf(const char *directory); + +static int dir_ishpfA(const char *directory); +static int dir_ishpfW(const wchar_t *directory); + +static int dir_errno(DWORD rc); static BOOL d_Wow64DisableWow64FsRedirection(PVOID *OldValue); static BOOL d_Wow64RevertWow64FsRedirection(PVOID OldValue); @@ -76,8 +92,6 @@ static BOOL d_Wow64RevertWow64FsRedirection(PVOID OldValue); static Wow64DisableWow64FsRedirection_t x_Wow64DisableWow64FsRedirection; static Wow64RevertWow64FsRedirection_t x_Wow64RevertWow64FsRedirection; -static int x_dirid = 1; /* singleton */ - /* // NAME @@ -134,7 +148,31 @@ static int x_dirid = 1; /* singleton */ // Too many files are currently open in the system. */ LIBW32_API DIR * -opendir(const char *name) +opendir(const char *dirname) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wdirname[WIN32_PATH_MAX]; + + if (NULL == dirname) { + errno = EFAULT; + return (DIR *)NULL; + } + + if (w32_utf2wc(dirname, wdirname, _countof(wdirname)) > 0) { + return opendirW(wdirname); + } + + return NULL; + } +#endif //UTF8FILENAMES + + return opendirA(dirname); +} + + +LIBW32_API DIR * +opendirA(const char *dirname) { char fullpath[ MAX_PATH ], symlink[ MAX_PATH ], reparse[ MAX_PATH ], *path = fullpath; @@ -143,17 +181,23 @@ opendir(const char *name) int i, len; /* Copy to working buffer */ - if (0 == (len = strlen(name))) { + if (NULL == dirname) { + errno = EFAULT; + return (DIR *)NULL; + } else if (0 == (len = strlen(dirname))) { errno = ENOTDIR; return (DIR *)NULL; } + memset(symlink, 0, sizeof(symlink)); + memset(reparse, 0, sizeof(reparse)); + /* Convert path (note, UNC safe) */ - if (NULL == _fullpath(fullpath, name, sizeof(fullpath))) { + if (NULL == w32_realpathA(dirname, fullpath, _countof(fullpath))) { char *last; /* unknown, assume DOS */ - strncpy(fullpath, name, sizeof(fullpath)); - fullpath[sizeof(fullpath)-1] = 0; + strncpy(fullpath, dirname, _countof(fullpath)); + fullpath[_countof(fullpath)-1] = 0; for (i = 0; fullpath[i]; ++i) { if (fullpath[i] == '/') { fullpath[i] = '\\'; /* convert */ @@ -162,10 +206,8 @@ opendir(const char *name) last = &fullpath[len - 1]; /* - * DOS is very picky about its directory names; the following are valid. - * c:/ - * c:. - * c:name/name1 + * o/s can be very picky about its directory names; the following are valid. + * c:/ c:. c:name/name1 * * whereas the following are not valid * c:name/ @@ -184,7 +226,7 @@ opendir(const char *name) errormode = SetErrorMode(0); // disable hard errors if (INVALID_FILE_ATTRIBUTES == (attr = GetFileAttributesA(path))) { - switch(GetLastError()) { + switch (GetLastError()) { case ERROR_ACCESS_DENIED: case ERROR_SHARING_VIOLATION: rc = EACCES; break; @@ -199,8 +241,8 @@ opendir(const char *name) } else if (0 == (FILE_ATTRIBUTE_DIRECTORY & attr)) { rc = ENOTDIR; - if (isshortcut(path)) { // possible shortcut - if (w32_readlink(path, symlink, sizeof(symlink)) > 0) { + if (isshortcutA(path)) { // possible shortcut + if (w32_readlinkA(path, symlink, _countof(symlink)) > 0) { if ((attr = GetFileAttributesA(symlink)) != INVALID_FILE_ATTRIBUTES && (FILE_ATTRIBUTE_DIRECTORY & attr)) { path = symlink; // redirect @@ -212,15 +254,15 @@ opendir(const char *name) (void) SetErrorMode(errormode); // restore errors if (rc) { - if (w32_root_unc(path)) { - return unc_populate(path); /* //servername[/] */ + if (w32_unc_rootA(path, NULL)) { // "//servername[/]" + return unc_populateA(path); } errno = rc; return (DIR *)NULL; } if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { - if (-1 == w32_reparse_read(path, reparse, sizeof(reparse))) { + if (-1 == w32_reparse_readA(path, reparse, _countof(reparse))) { errno = EACCES; return (DIR *)NULL; } @@ -233,40 +275,173 @@ opendir(const char *name) while (len > 0) { --len; if (path[len] == '\\') { - path[len] = '\0'; /* remove slash */ + path[len] = '\0'; // remove slash } else { - ++len; /* end of path */ + ++len; // end of path break; } } - path[len++] = '\\'; /* insert pattern */ + path[len++] = '\\'; // insert pattern path[len++] = '*'; path[len++] = '.'; path[len++] = '*'; path[len++] = 0; - /* Create DIR structure */ - if (NULL == (dp = (DIR *)calloc(sizeof(DIR), 1)) || - NULL == (dp->dd_buf = (char *)calloc(sizeof(struct dirent), 1))) { - free(dp); + /* Open directory + * + * If you are writing a 32-bit application to list all the files in a directory and the + * application may be running on a 64-bit computer, you should call Wow64DisableWow64FsRedirection + * before calling FindFirstFileEx and call Wow64RevertWow64FsRedirection after the last call to FindNextFile. + * + * For more information, see File System Redirector. + */ + if (NULL == (dp = w32_dir_alloc())) { return (DIR *)NULL; } - dp->dd_magic = DIR_MAGIC; /* structure magic */ - dp->dd_id = ++x_dirid; /* generate unique directory identifier */ - dp->dd_fd = -1; /* file descriptor */ + if (d_Wow64DisableWow64FsRedirection(&OldValue)) { + const int ret = dir_populateA(dp, path); + + if (! d_Wow64RevertWow64FsRedirection(OldValue) || ret) { + closedir(dp); + errno = (ret ? ret : EIO); + dp = NULL; + } + } + return dp; +} + + +LIBW32_API DIR * +opendirW(const wchar_t *dirname) +{ + wchar_t fullpath[ MAX_PATH ], symlink[ MAX_PATH ], reparse[ MAX_PATH ], + *path = fullpath; + LPVOID OldValue = NULL; + DIR *dp; + int i, len; + + /* Copy to working buffer */ + if (NULL == dirname) { + errno = EFAULT; + return (DIR *)NULL; + } else if (0 == (len = wcslen(dirname))) { + errno = ENOTDIR; + return (DIR *)NULL; + } + + /* Convert path (note, UNC safe) */ + if (NULL == w32_realpathW(dirname, fullpath, _countof(fullpath))) { + wchar_t *last; /* unknown, assume DOS */ + + wcsncpy(fullpath, dirname, _countof(fullpath)); + fullpath[_countof(fullpath)-1] = 0; + for (i = 0; fullpath[i]; ++i) { + if (fullpath[i] == '/') { + fullpath[i] = '\\'; /* convert */ + } + } + last = &fullpath[len - 1]; + + /* + * o/s can be very picky about its directory names; the following are valid. + * c:/ c:. c:name/name1 + * + * whereas the following are not valid + * c:name/ + */ + if ((*last == '\\') && (len > 1) && (!((len == 3) && + (fullpath[1] == ':')))) { + *(last--) = 0; + } + } + + /* Is a directory ? */ + if (0 != wcscmp(path, L".")) { + UINT errormode; + DWORD attr; + int rc = 0; + + errormode = SetErrorMode(0); // disable hard errors + if (INVALID_FILE_ATTRIBUTES == (attr = GetFileAttributesW(path))) { + switch(GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + rc = EACCES; break; + case ERROR_FILE_NOT_FOUND: + rc = ENOENT; break; + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + rc = ENOTDIR; break; + default: + rc = EIO; + } + + } else if (0 == (FILE_ATTRIBUTE_DIRECTORY & attr)) { + rc = ENOTDIR; + if (isshortcutW(path)) { // possible shortcut + if (w32_readlinkW(path, symlink, _countof(symlink)) > 0) { + if ((attr = GetFileAttributesW(symlink)) != INVALID_FILE_ATTRIBUTES && + (FILE_ATTRIBUTE_DIRECTORY & attr)) { + path = symlink; // redirect + rc = 0; + } + } + } + } + (void) SetErrorMode(errormode); // restore errors + + if (rc) { + if (w32_unc_rootW(path, NULL)) { // "//servername[/]" + return unc_populateW(path); + } + errno = rc; + return (DIR *)NULL; + } + + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + if (-1 == w32_reparse_readW(path, reparse, _countof(reparse))) { + errno = EACCES; + return (DIR *)NULL; + } + path = reparse; + } + } + + /* Strip trailing slashes, so we can append "\*.*" */ + len = wcslen(path); + while (len > 0) { + --len; + if (path[len] == '\\') { + path[len] = '\0'; // remove slash + } else { + ++len; // end of path + break; + } + } + + path[len++] = '\\'; // insert pattern + path[len++] = '*'; + path[len++] = '.'; + path[len++] = '*'; + path[len++] = 0; /* Open directory * - * If you are writing a 32-bit application to list all the files in a directory and the + * If you are writing a 32-bit application to list all the files in a directory and the * application may be running on a 64-bit computer, you should call Wow64DisableWow64FsRedirection * before calling FindFirstFileEx and call Wow64RevertWow64FsRedirection after the last call to FindNextFile. * * For more information, see File System Redirector. */ + if (NULL == (dp = w32_dir_alloc())) { + return (DIR *)NULL; + } + dp->dd_flags |= DIR_FISUTF8; + if (d_Wow64DisableWow64FsRedirection(&OldValue)) { - const int ret = dir_populate(dp, path); + const int ret = dir_populateW(dp, path); if (! d_Wow64RevertWow64FsRedirection(OldValue) || ret) { closedir(dp); @@ -279,14 +454,14 @@ opendir(const char *name) static BOOL -isshortcut(const char *name) +isshortcutA(const char *name) { const size_t len = strlen(name); const char *cursor; for (cursor = name + len; --cursor >= name;) { if (*cursor == '.') { // extension - return (*++cursor && 0 == WIN32_STRICMP(cursor, "lnk")); + return (*++cursor && 0 == w32_io_stricmp(cursor, "lnk")); } if (*cursor == '/' || *cursor == '\\') { break; // delimiter @@ -296,175 +471,374 @@ isshortcut(const char *name) } -static DIR * -unc_populate(const char *path) +static BOOL +isshortcutW(const wchar_t *name) { - SHARE_INFO_502 *buffer = NULL; - NET_API_STATUS res = 0; - DIR *dp; - - (void)path; + const size_t len = wcslen(name); + const wchar_t *cursor; - if (NULL == (dp = (DIR *)calloc(sizeof(DIR), 1)) || - NULL == (dp->dd_buf = (char *)calloc(sizeof(struct dirent), 1))) { - free(dp); - return (DIR *)NULL; + for (cursor = name + len; --cursor >= name;) { + if (*cursor == '.') { // extension + return (*++cursor && 0 == w32_io_wstricmp(cursor, "lnk")); + } + if (*cursor == '/' || *cursor == '\\') { + break; // delimiter + } } + return FALSE; +} - do { - DWORD entries = (DWORD)-1, tr = 0, resume = 0; - res = NetShareEnum(NULL, 502, (LPBYTE *)&buffer, MAX_PREFERRED_LENGTH, &entries, &tr, &resume); +static int +unc_push(void *data, const wchar_t *filename) +{ + if (dir_pushW((DIR *)data, filename)) { + return 0; //success + } + return -1; //error +} - if (ERROR_SUCCESS == res || ERROR_MORE_DATA == res) { - const SHARE_INFO_502 *ent; - DWORD e; - for (e = 0, ent = buffer; e < entries; ++e, ++ent) { - if (STYPE_DISKTREE == ent->shi502_type) { - // - // build directory .. - // - char filename[MAX_PATH+1]; +static DIR * +unc_populateA(const char *servername) +{ + DIR *dp; - WideCharToMultiByte(CP_ACP, 0, - (void *)ent->shi502_netname, -1, filename, sizeof(filename)-1, NULL, NULL); - filename[sizeof(filename) - 1] = 0; + if (NULL == (dp = w32_dir_alloc()) || // alloc and populate + -1 == w32_unc_iterateA(servername, unc_push, dp)) { + w32_dir_free(dp); + return (DIR *)NULL; + } - if (0 == strcmp(filename, "prnproc$") || - 0 == strcmp(filename, "print$")) { - continue; - } + dp->dd_current = dp->dd_contents; // seed cursor + return dp; +} - if (NULL == dir_list_push(dp, filename)) { - break; - } - } - } - NetApiBufferFree(buffer); - } - } while (ERROR_MORE_DATA == res); - dp->dd_current = dp->dd_contents; /* seed cursor */ - dp->dd_magic = DIR_MAGIC; /* structure magic */ - dp->dd_id = ++x_dirid; /* generate unique directory identifier */ - dp->dd_fd = -1; /* file descriptor */ +static DIR * +unc_populateW(const wchar_t *servername) +{ + DIR *dp; + + if (NULL == (dp = w32_dir_alloc()) || // alloc and populate + -1 == w32_unc_iterateW(servername, unc_push, dp)) { + w32_dir_free(dp); + return (DIR *)NULL; + } + dp->dd_current = dp->dd_contents; // seed cursor return dp; } static int -dir_populate(DIR *dp, const char *path) +dir_populateA(DIR *dp, const char *path) { + WIN32_FIND_DATAA fd = {0}; + HANDLE hSearch = INVALID_HANDLE_VALUE; struct _dirlist *dplist; - WIN32_FIND_DATA finddata; - HANDLE hSearch; UINT errormode; BOOL isHPFS = FALSE; int rc, ret = 0; errormode = SetErrorMode(0); // disable hard errors - hSearch = FindFirstFileA(path, &finddata); + hSearch = FindFirstFileA(path, &fd); (void) SetErrorMode(errormode); // restore errors if (INVALID_HANDLE_VALUE == hSearch) { - switch (GetLastError()) { -#if defined(ERROR_EMPTY_DIR) - case ERROR_EMPTY_DIR: - return 0; + return dir_errno(GetLastError()); + } + + isHPFS = dir_ishpfA(path); // extended file system + if (isHPFS) dp->dd_flags = DIR_FISHPF; + + do { + +#if defined(FILE_ATTRIBUTE_VOLUME) // skip volume labels + // Not listed by Microsoft but it's there. + // Indicates a directory entry without corresponding file, used only to denote the name of a hard drive volume. + // Was used to 'hack' the long file name system of Windows 95. + if (fd.dwFileAttributes & FILE_ATTRIBUTE_VOLUME) { + continue; + } #endif - case ERROR_NO_MORE_FILES: - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - return ENOENT; - case ERROR_NOT_ENOUGH_MEMORY: + // skip '.' + if ('.' == fd.cFileName[0] && 0 == fd.cFileName[1]) { + continue; + } + + if (NULL == (dplist = dir_pushA(dp, fd.cFileName))) { + FindClose(hSearch); return ENOMEM; } - return EINVAL; + + dplist->dl_size2 = fd.nFileSizeHigh; + dplist->dl_size = fd.nFileSizeLow; + dplist->dl_attr = fd.dwFileAttributes; + + dplist->dl_type = DT_UNKNOWN; + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + dplist->dl_type = DT_DIR; + } else if ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (fd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) { + dplist->dl_type = DT_LNK; + } else { + dplist->dl_type = DT_REG; + } + + } while (FindNextFileA(hSearch, &fd)); + + if ((rc = GetLastError()) == ERROR_NO_MORE_FILES) { + dp->dd_current = dp->dd_contents; // seed cursor + dp->dd_flags |= DIR_FHAVESTATS; + } else { + ret = dir_errno(rc); } - isHPFS = dir_ishpf(path); /* extended file system */ - if (isHPFS) { - dp->dd_flags = DIR_FISHPF; + FindClose(hSearch); + return ret; +} + + +static int +dir_populateW(DIR *dp, const wchar_t *path) +{ + WIN32_FIND_DATAW fd = {0}; + struct _dirlist *dplist = NULL; + HANDLE hSearch = INVALID_HANDLE_VALUE; + UINT errormode; + BOOL isHPFS = FALSE; + int rc, ret = 0; + + errormode = SetErrorMode(0); // disable hard errors + hSearch = FindFirstFileW(path, &fd); + (void) SetErrorMode(errormode); // restore errors + + if (INVALID_HANDLE_VALUE == hSearch) { + return dir_errno(GetLastError()); } + isHPFS = dir_ishpfW(path); // extended file system + if (isHPFS) dp->dd_flags |= DIR_FISHPF; + dp->dd_flags |= DIR_FISUTF8; + do { -#if defined(FILE_ATTRIBUTE_VOLUME) /* skip volume labels */ + +#if defined(FILE_ATTRIBUTE_VOLUME) // skip volume labels // Not listed by Microsoft but it's there. // Indicates a directory entry without corresponding file, used only to denote the name of a hard drive volume. // Was used to 'hack' the long file name system of Windows 95. - if (finddata.dwFileAttributes & FILE_ATTRIBUTE_VOLUME) { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_VOLUME) { continue; } #endif - /* skip '.' */ - if (0 == strcmp(finddata.cFileName, ".")) { + // skip '.' + if ('.' == fd.cFileName[0] && 0 == fd.cFileName[1]) { continue; } - /* create new entry */ - if (NULL == (dplist = dir_list_push(dp, finddata.cFileName))) { + + if (NULL == (dplist = dir_pushW(dp, fd.cFileName))) { FindClose(hSearch); return ENOMEM; } - if (! isHPFS) { /* not HPFS, convert case */ -#if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) - _strlwr(dplist->dl_entry); -#else - strlwr(dplist->dl_entry); -#endif + dplist->dl_size2 = fd.nFileSizeHigh; + dplist->dl_size = fd.nFileSizeLow; + dplist->dl_attr = fd.dwFileAttributes; + + dplist->dl_type = DT_UNKNOWN; + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + dplist->dl_type = DT_DIR; + } else if ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (fd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) { + dplist->dl_type = DT_LNK; + } else { + dplist->dl_type = DT_REG; } - dplist->dl_size2 = finddata.nFileSizeHigh; - dplist->dl_size = finddata.nFileSizeLow; - dplist->dl_attr = finddata.dwFileAttributes; - } while (FindNextFileA(hSearch, &finddata)); + } while (FindNextFileW(hSearch, &fd)); if ((rc = GetLastError()) == ERROR_NO_MORE_FILES) { - dp->dd_current = dp->dd_contents; /* seed cursor */ + dp->dd_current = dp->dd_contents; // seed cursor + dp->dd_flags |= DIR_FHAVESTATS; } else { - switch (rc) { - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - ret = ENOENT; - break; - case ERROR_NOT_ENOUGH_MEMORY: - ret = ENOMEM; - break; - default: - break; - } - ret = EINVAL; + ret = dir_errno(rc); } + FindClose(hSearch); return ret; } +DIR * +w32_dir_alloc(void) +{ + const int dd_len = SIZEOF_DIRENT + (sizeof(char) * DIRBLKSIZ); /* working dirent storage */ + DIR *dp; + +#if defined(NAME_MAX) + assert(MAXNAMLEN >= NAME_MAX); /* POSIX requirement, verify */ +#endif + assert(DIRBLKSIZ > MAXNAMLEN); + + if (NULL == (dp = (DIR *)calloc(sizeof(DIR), 1)) || + NULL == (dp->dd_buf = (void *)calloc(dd_len, 1))) { + free(dp); + return (DIR *)NULL; + } + + dp->dd_magic = DIR_MAGIC; /* structure magic */ + dp->dd_len = dd_len; /* underlying dd_buf length, in bytes */ + dp->dd_id = w32_dir_identifier(); /* generate unique directory identifier */ + dp->dd_fd = -1; /* file descriptor */ + + return dp; +} + + +int +w32_dir_identifier(void) +{ + static int dir_identifer; + return ++dir_identifer; +} + + +void +w32_dir_free(DIR *dp) +{ + if (dp) { + assert(DIR_MAGIC == dp->dd_magic); + dir_list_free(dp->dd_contents); + free((void *)dp->dd_buf); /* working dirent storage */ + free((void *)dp); + } +} + + +static int +dir_errno(DWORD rc) +{ + switch (rc) { +#if defined(ERROR_EMPTY_DIR) + case ERROR_EMPTY_DIR: + return 0; +#endif + case ERROR_NO_MORE_FILES: + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return ENOENT; + case ERROR_NOT_ENOUGH_MEMORY: + return ENOMEM; + } + return EINVAL; +} + + +/* + * dir_pushA --- + * Create a directory list element. + */ static struct _dirlist * -dir_list_push(DIR *dp, const char *filename) +dir_pushA(DIR *dp, const char *filename) { - const size_t namelen = strlen(filename) + 1; + size_t nambytes, namlen = strlen(filename); struct _dirlist *dplist; - if (NULL == (dplist = (struct _dirlist *)calloc(1, sizeof(struct _dirlist))) || - NULL == (dplist->dl_entry = (char *)malloc(namelen))) { - free(dplist); + assert(namlen < DIRBLKSIZ); // d_name limit + if (namlen >= DIRBLKSIZ) namlen = DIRBLKSIZ-1; + + nambytes = sizeof(wchar_t) * (namlen + 1 /*nul*/); + if (NULL == (dplist = + (struct _dirlist *)malloc(sizeof(struct _dirlist) + nambytes))) { return NULL; } + + memset(dplist, 0, sizeof(*dplist)); if (dp->dd_contents) { - dp->dd_current = + dp->dd_current = dp->dd_current->dl_next = dplist; } else { dp->dd_contents = dp->dd_current = dplist; } - memcpy(dplist->dl_entry, filename, namelen); + + dplist->dl_namlen = (unsigned short)namlen; + memcpy(dplist->dl_name, filename, nambytes); dplist->dl_next = NULL; return dplist; } +/* + * dir_pushW --- + * Create a directory list element. + */ +struct _dirlist * +dir_pushW(DIR *dp, const wchar_t *filename) +{ + char t_filename[DIRBLKSIZ]; // d_name limit + + w32_wc2utf(filename, t_filename, _countof(t_filename)); + return dir_pushA(dp, t_filename); +} + + + +/* + * dir_read --- + * Read the next directory element. + */ +static void +dir_read(DIR *dp, struct dirent *ent) +{ + struct _dirlist *dplist = dp->dd_current; + size_t nambytes; + + assert(dplist); + + /* Standard fields */ + assert((dplist->dl_namlen + 1 /*nul*/) <= DIRBLKSIZ); + nambytes = sizeof(char) * (dplist->dl_namlen + 1 /*nul*/); + memcpy(ent->d_name, dplist->dl_name, nambytes); + ent->d_namlen = dplist->dl_namlen; + ent->d_reclen = (unsigned short)(SIZEOF_DIRENT + nambytes); + + if (0 == (dp->dd_flags & DIR_FISHPF)) { // not HPFS, convert case. +#if defined(_WIN32) && defined(_MSC_VER) + _strlwr(ent->d_name); +#else + strlwr(ent->d_name); +#endif + } + ent->d_fileno = 0; + + /* Extension fields */ + ent->d_ctime = dplist->dl_ctime; + ent->d_mtime = dplist->dl_mtime; + ent->d_size = dplist->dl_size; + ent->d_attr = dplist->dl_attr; + ent->d_type = dplist->dl_type; + + /* Update current location */ + dp->dd_current = dplist->dl_next; + ++dp->dd_loc; +} + + +/* + * dir_list_free --- + * Dispose of the directory list. + */ +static void +dir_list_free(struct _dirlist *dplist) +{ + struct _dirlist *odplist; + + while (dplist) { + dplist = (odplist = dplist)->dl_next; + free(odplist); + } +} + + /* // NAME // closedir - close a directory stream @@ -499,10 +873,7 @@ closedir(DIR *dp) errno = EBADF; return -1; } - assert(DIR_MAGIC == dp->dd_magic); - dir_list_free(dp->dd_contents); - free((char *)dp->dd_buf); - free((char *)dp); + w32_dir_free(dp); return 0; } @@ -516,7 +887,7 @@ closedir(DIR *dp) // // struct dirent *readdir(DIR *dirp); // int readdir_r(DIR *restrict dirp, struct dirent *restrict entry, -// struct dirent **restrict result); [Option End] +// struct dirent **restrict result); // // DESCRIPTION // The type DIR, which is defined in the header, represents a directory @@ -594,8 +965,7 @@ closedir(DIR *dp) // The readdir() function shall fail if: // // [EOVERFLOW] -// One of the values in the structure to be returned cannot be represented -// correctly. +// One of the values in the structure to be returned cannot be represented correctly. // // The readdir() function may fail if: // @@ -609,50 +979,65 @@ closedir(DIR *dp) // // [EBADF] // The dirp argument does not refer to an open directory stream. +// +// [ENAMETOOLONG] +// A directory entry whose name was too long to be read was encountered. +// */ LIBW32_API struct dirent * readdir(DIR *dp) { - struct _dirlist *pEntry; - struct dirent *dpent; + struct dirent *entry = (struct dirent *)dp->dd_buf; // working buffer. if (NULL == dp) { errno = EBADF; - return NULL; + return (struct dirent *)NULL; } assert(DIR_MAGIC == dp->dd_magic); + if (DIR_MAGIC != dp->dd_magic) { + errno = EBADF; + return (struct dirent *)NULL; + } - /* Retrieve associated fields */ - if (dp->dd_current == (struct _dirlist *)NULL) { + if ((struct _dirlist *)NULL == dp->dd_current) { + errno = ENOENT; return (struct dirent *)NULL; } - pEntry = dp->dd_current; - dpent = (struct dirent *)dp->dd_buf; - /* Standard fields */ - strcpy(dpent->d_name, pEntry->dl_entry); - dpent->d_namlen = (u_short) strlen(dpent->d_name); - dpent->d_reclen = sizeof(struct dirent); - if (0 == (dp->dd_flags & DIR_FISHPF)) { /* not HPFS, convert case */ -#if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) - _strlwr(dpent->d_name); -#else - strlwr(dpent->d_name); -#endif + dir_read(dp, entry); // retrieve next entry. + + return entry; +} + + +LIBW32_API int +readdir_r(DIR *dp, struct dirent *entry, struct dirent **result) +{ + if (NULL == dp) { + return EBADF; + } else if (NULL == entry || NULL == result) { + return EINVAL; + } + assert(DIR_MAGIC == dp->dd_magic); + if (DIR_MAGIC != dp->dd_magic) { + *result = NULL; + return EBADF; } - dpent->d_fileno = 0; - /* The following field are extensions */ - dpent->d_ctime = pEntry->dl_ctime; - dpent->d_mtime = pEntry->dl_mtime; - dpent->d_size = pEntry->dl_size; - dpent->d_attr = pEntry->dl_attr; + if ((struct _dirlist *)NULL == dp->dd_current) { + *result = NULL; + return ENOENT; + } - /* Update current location */ - dp->dd_current = pEntry->dl_next; - dp->dd_loc++; + if (dp->dd_current->dl_namlen > MAXNAMLEN) { + *result = NULL; + return ENAMETOOLONG; + } - return dpent; + dir_read(dp, entry); // retrieve next entry. + *result = entry; + + return 0; } @@ -663,7 +1048,7 @@ readdir(DIR *dp) // SYNOPSIS // #include // -// void seekdir(DIR *dirp, long loc); [Option End] +// void seekdir(DIR *dirp, long loc); // // DESCRIPTION // The seekdir() function shall set the position of the next readdir() operation on @@ -694,11 +1079,11 @@ seekdir(DIR *dp, long off) } assert(DIR_MAGIC == dp->dd_magic); - if (off > 0) { + if (off >= 0) { for (dplist = dp->dd_contents; --i >= 0 && dplist; dplist = dplist->dl_next) { - /*cont*/; + /*continue*/; } - dp->dd_loc = off - (i+1); + dp->dd_loc = off - (i + 1); dp->dd_current = dplist; } } @@ -778,24 +1163,6 @@ telldir(DIR *dp) } -/* - * dir_list_free --- - * Dispose of the directory list. - */ -static void -dir_list_free(struct _dirlist *dplist) -{ - struct _dirlist *odplist; - - while (dplist) { - free(dplist->dl_entry); - dplist = (odplist = dplist)->dl_next; - free(odplist); - } -} - - - /* * Wow64DisableWow64FsRedirection/Wow64RevertWow64FsRedirection -- * Disables file system redirection for the calling thread. File system @@ -883,28 +1250,119 @@ d_Wow64RevertWow64FsRedirection(PVOID OldValue) * Is High Performance File System. */ static int -dir_ishpf(const char *directory) +dir_ishpfA(const char *directory) { + int namelen; UINT errormode; - unsigned nDrive; - char szCurDir[MAX_PATH + 1]; - char bName[4] = "x:\\"; - DWORD flags, maxname; - BOOL rc; - - if (directory && - isalpha((unsigned char)directory[0]) && directory[1] == ':') { - nDrive = toupper(directory[0]) - 'A'; + DWORD flags = 0, maxname; + BOOL rc = 0; + + if ((namelen = w32_unc_validA(directory)) > 0) { + char rootdir[MAXHOSTNAMELEN + MAX_PATH], + *cursor = rootdir, *end = cursor + (_countof(rootdir) - 4); + int i; + + directory += 2; // "//" or "\\" + *cursor++ = '\\'; *cursor++ = '\\'; + for (i = namelen; i > 0; --i) { + *cursor++ = *directory++; + } + *cursor++ = '\\'; + if (*directory++) { // component + char ch; + while (cursor < end && (ch = *directory++) != 0) { + if (IS_PATH_SEP(ch)) break; + *cursor++ = ch; + } + *cursor++ = '\\'; + } + *cursor = 0; + + errormode = SetErrorMode(0); // disable hard errors + rc = GetVolumeInformationA(rootdir, (LPSTR)NULL, 0, + (LPDWORD)NULL, &maxname, &flags, (LPSTR)NULL, 0); + (void) SetErrorMode(errormode); // restore errors + } else { - GetCurrentDirectoryA(MAX_PATH, szCurDir); - nDrive = toupper(szCurDir[0]) - 'A'; + char rootdir[4] = "x:\\"; + int driveno; + + if (directory && + isalpha((unsigned char)directory[0]) && directory[1] == ':') { + driveno = toupper(directory[0]) - 'A'; + } else { + if (0 == (driveno = w32_getdrive())) { + return 0; + } + --driveno; + } + + rootdir[0] = (char)(driveno + 'A'); + errormode = SetErrorMode(0); // disable hard errors + rc = GetVolumeInformationA(rootdir, (LPSTR)NULL, 0, + (LPDWORD)NULL, &maxname, &flags, (LPSTR)NULL, 0); + (void) SetErrorMode(errormode); // restore errors } - bName[0] = (char)(nDrive + 'A'); - errormode = SetErrorMode(0); // disable hard errors - rc = GetVolumeInformationA(bName, (LPTSTR)NULL, 0, - (LPDWORD)NULL, &maxname, &flags, (LPTSTR)NULL, 0); - (void) SetErrorMode(errormode); // restore errors + return ((rc) && + (flags & (FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED))) ? TRUE : FALSE; +} + + +static int +dir_ishpfW(const wchar_t *directory) +{ + int namelen; + UINT errormode; + DWORD flags = 0, maxname; + BOOL rc = 0; + + if ((namelen = w32_unc_validW(directory)) > 0) { + wchar_t rootdir[MAXHOSTNAMELEN + MAX_PATH], + *cursor = rootdir, *end = cursor + (_countof(rootdir) - 4); + int i; + + directory += 2; // "//" or "\\" + *cursor++ = '\\'; *cursor++ = '\\'; + for (i = namelen; i > 0; --i) { + *cursor++ = *directory++; + } + *cursor++ = '\\'; + if (*directory++) { // component + wchar_t ch; + while (cursor < end && (ch = *directory++) != 0) { + if (IS_PATH_SEP(ch)) break; + *cursor++ = ch; + } + *cursor++ = '\\'; + } + *cursor = 0; + + errormode = SetErrorMode(0); // disable hard errors + rc = GetVolumeInformationW(rootdir, (LPWSTR)NULL, 0, + (LPDWORD)NULL, &maxname, &flags, (LPWSTR)NULL, 0); + (void) SetErrorMode(errormode); // restore errors + + } else { + wchar_t rootdir[4] = L"x:\\"; + int driveno; + + if (directory && + isalpha((unsigned char)directory[0]) && directory[1] == ':') { + driveno = toupper(directory[0]) - 'A'; + } else { + if (0 == (driveno = w32_getdrive())) { + return 0; + } + --driveno; + } + + rootdir[0] = (char)(driveno + 'A'); + errormode = SetErrorMode(0); // disable hard errors + rc = GetVolumeInformationW(rootdir, (LPWSTR)NULL, 0, + (LPDWORD)NULL, &maxname, &flags, (LPWSTR)NULL, 0); + (void) SetErrorMode(errormode); // restore errors + } return ((rc) && (flags & (FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED))) ? TRUE : FALSE; diff --git a/libw32/w32_direntunc.c b/libw32/w32_direntunc.c new file mode 100644 index 00000000..0fc7dabe --- /dev/null +++ b/libw32/w32_direntunc.c @@ -0,0 +1,429 @@ +#include +__CIDENT_RCSID(gr_w32_direntunc_c,"$Id: w32_direntunc.c,v 1.2 2022/03/21 14:29:40 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 unc directory access services ... + * + * Copyright (c) 2007, 2012 - 2022 Adam Young. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + */ + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 /* reparse */ +#endif + +#define _DIRENT_SOURCE +#include "win32_internal.h" +#include + +#pragma comment(lib, "Netapi32.lib") +#pragma comment(lib, "Advapi32.lib") +#pragma comment(lib, "Mpr.lib") + +#include /* NetEnum... */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "win32_direct.h" + +static void unc_errno(void); + + +///////////////////////////////////////////////////////////////////////////////////////// +// SMB shares +// +// Theses functions applies only to Server Message Block (SMB) shares. +// For other types of shares, such as Distributed File System (DFS) or WebDAV shares, +// use Windows Networking (WNet) functions, which support all types of shares. + +int +w32_unc_iterateA(const char *servername, unc_push_t push, void *data) +{ + wchar_t wservername[256], *param = NULL; + + if (servername && servername[0]) { + if (-1 == w32_utf2wc(servername, wservername, _countof(wservername))) { + wservername[0] = 0; + } + param = wservername; + } + + return w32_unc_iterateW(param, push, data); +} + + +int +w32_unc_iterateW(const wchar_t *servername, unc_push_t push, void *data) +{ + SHARE_INFO_502 *buffer = NULL; + NET_API_STATUS res = 0; + int ret = 0; + + assert(NULL != push); + assert(NULL != data); + do { + DWORD entries = (DWORD)-1, tr = 0, resume = 0; + + if (servername && !*servername) { // DNS or NetBIOS name + servername = NULL; // NULL == localserver + } + + res = NetShareEnum((wchar_t *)servername, 502, (LPBYTE *)&buffer, MAX_PREFERRED_LENGTH, &entries, &tr, &resume); + if (ERROR_SUCCESS == res || ERROR_MORE_DATA == res) { + const SHARE_INFO_502 *ent; + unsigned count = 0; + DWORD e; + + // build directory .. + for (e = 0, ent = buffer; e < entries; ++e, ++ent) { + if (STYPE_DISKTREE == ent->shi502_type) { + const WCHAR *filename = ent->shi502_netname; + + if ('p' == filename[0]) { // prnproc$ or print$ + if (0 == wcscmp(filename, L"prnproc$") || + 0 == wcscmp(filename, L"print$")) { + continue; + } + } + + if ((1 == ++count && // implied + -1 == (ret = push(data, L".."))) || + -1 == (ret = push(data, filename))) { + break; + } + } + } + NetApiBufferFree(buffer); + } + } while (ERROR_MORE_DATA == res); + + return ret; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// General UNC support + +DIR * +w32_unc_opendirA(const char *dirname) +{ + NETRESOURCEA nrw = {0}; + HANDLE handle = INVALID_HANDLE_VALUE; + DWORD result; + DIR *dp; + + nrw.dwScope = RESOURCE_GLOBALNET; + nrw.dwType = RESOURCETYPE_DISK; + nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; + nrw.dwUsage = RESOURCEUSAGE_CONTAINER; + nrw.lpRemoteName = (char *)dirname; + + result = WNetOpenEnumA(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, RESOURCEUSAGE_CONNECTABLE, &nrw, &handle); + if (NO_ERROR != result) { + errno = ENOTDIR; + return (DIR *)NULL; + } + + if (NULL == (dp = w32_dir_alloc())) { + WNetCloseEnum(handle); + return (DIR *)NULL; + } + + dp->dd_handle = handle; + dp->dd_magic = DIR_UMAGIC; + return dp; +} + + +DIR * +w32_unc_opendirW(const wchar_t *dirname) +{ + NETRESOURCEW nrw = {0}; + HANDLE handle = INVALID_HANDLE_VALUE; + DWORD result; + DIR *dp; + + nrw.dwScope = RESOURCE_GLOBALNET; + nrw.dwType = RESOURCETYPE_DISK; + nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; + nrw.dwUsage = RESOURCEUSAGE_CONTAINER; + nrw.lpRemoteName = (wchar_t *)dirname; + + result = WNetOpenEnumW(RESOURCE_GLOBALNET, RESOURCETYPE_DISK, RESOURCEUSAGE_CONNECTABLE, &nrw, &handle); + if (NO_ERROR != result) { + unc_errno(); + return (DIR *)NULL; + } + + if (NULL == (dp = w32_dir_alloc())) { + WNetCloseEnum(handle); + return (DIR *)NULL; + } + + dp->dd_handle = handle; + dp->dd_magic = DIR_UMAGIC; + return dp; +} + + +struct dirent * +w32_unc_readdirA(DIR *dp) +{ + DWORD bufsize = 4 * 1024; + DWORD result, count; + void *buffer; + char *cursor; + + if (NULL == dp || NULL == dp->dd_handle) { + errno = EBADF; + return NULL; + } + assert(DIR_UMAGIC == dp->dd_magic); + + if (NULL == (buffer = alloca(bufsize))) return NULL; + result = WNetEnumResourceA(dp->dd_handle, &count, buffer, &bufsize); + if (NO_ERROR != result) { + unc_errno(); + return NULL; + } + + cursor = ((LPNETRESOURCEA) buffer)->lpRemoteName; + if (cursor[0] && cursor[1]) { + + cursor += 2; // "//" + while (*cursor && !IS_PATH_SEP(*cursor)) { + ++cursor; + } + + if (IS_PATH_SEP(*cursor)) { // filename component + struct dirent *dpent = (struct dirent *)dp->dd_buf; + int namlen = strlen(cursor); + + if (namlen >= sizeof(dpent->d_name)) namlen = sizeof(dpent->d_name) - 1; + dpent->d_namlen = namlen; + memcpy(dpent->d_name, cursor, namlen + 1 /*nul*/); + dpent->d_reclen = sizeof(struct dirent); + return dpent; + } + } + return NULL; +} + + +struct dirent * +w32_unc_readdirW(DIR *dp) +{ + DWORD bufsize = 4 * 1024; + DWORD result, count; + void *buffer; + wchar_t *cursor; + + if (NULL == dp || NULL == dp->dd_handle) { + errno = EBADF; + return NULL; + } + assert(DIR_UMAGIC == dp->dd_magic); + + if (NULL == (buffer = alloca(bufsize))) return NULL; + result = WNetEnumResourceW(dp->dd_handle, &count, buffer, &bufsize); + if (NO_ERROR != result) { + unc_errno(); + return NULL; + } + + cursor = ((LPNETRESOURCEW) buffer)->lpRemoteName; + if (cursor[0] && cursor[1]) { + + cursor += 2; // "//" + while (*cursor && !IS_PATH_SEP(*cursor)) { + ++cursor; + } + + if (IS_PATH_SEP(*cursor)) { // filename component + struct dirent *dpent = (struct dirent *)dp->dd_buf; + char filename[sizeof(dpent->d_name)]; + int namlen; + + if ((namlen = w32_wc2utf(cursor, filename, _countof(filename))) < 0) { + namlen = 0; // shouldnt occur + } + dpent->d_namlen = namlen; + memcpy(dpent->d_name, filename, namlen + 1 /*nul*/); + dpent->d_reclen = sizeof(struct dirent); + return dpent; + } + } + return NULL; +} + + +int +w32_unc_closedir(DIR *dp) +{ + if (NULL == dp) { + errno = EBADF; + return -1; + } + if (dp->dd_handle && INVALID_HANDLE_VALUE != dp->dd_handle) { + WNetCloseEnum(dp->dd_handle); + dp->dd_handle = INVALID_HANDLE_VALUE; + } + w32_dir_free(dp); + return 0; +} + + + +/* + * Determine if the specific path is a UNC path (i.e. //servername[/[components]]) + */ + +int +w32_unc_validA(const char *path) +{ + if (IS_PATH_SEP(path[0]) && (path[0] == path[1])) { + const char *scan; // UNC prefix + + path += 2; // "//" or "\\" + if (NULL == (scan = strpbrk(path, "*?|<>\"\\/")) + || IS_PATH_SEP(scan[0])) { + const size_t namelen = // servername length + (scan ? (scan - path) : strlen(path)); + + if (namelen > 0) { + return namelen; + } + } + } + return 0; +} + + +int +w32_unc_validW(const wchar_t *path) +{ + if (IS_PATH_SEP(path[0]) && (path[0] == path[1])) { + const wchar_t *scan; // UNC prefix + + path += 2; // "//" or "\\" + if (NULL == (scan = wcspbrk(path, L"*?|<>\"\\/")) + || IS_PATH_SEP(scan[0])) { + const size_t namelen = // servername length + (scan ? (scan - path) : wcslen(path)); + + if (namelen > 0) { + return namelen; + } + } + } + return 0; +} + + +/* + * Determine if the specific path is a UNC root (i.e. //servername[/]) + */ + +int +w32_unc_rootA(const char *path, int *length) +{ + int namelen; + + if ((namelen = w32_unc_validA(path)) > 0) { + const char *end = path + 2 + namelen; + + if (0 == end[0] || // "//servername[/]" + (0 == end[1] && IS_PATH_SEP(end[0]))) { + + char computerName[MAX_COMPUTERNAME_LENGTH + 1] = {0}; + DWORD computerSz = _countof(computerName); + + if (length) *length = namelen; + if (GetComputerNameA(computerName, &computerSz)) { + if (namelen == computerSz && + 0 == _strnicmp(path + 2, computerName, namelen)) { + return 2; // local server + } + } + return 1; // remote + } + } + return 0; +} + + +int +w32_unc_rootW(const wchar_t *path, int *length) +{ + int namelen; + + if ((namelen = w32_unc_validW(path)) > 0) { + const wchar_t *end = path + 2 + namelen; + + if (0 == end[0] || // "//servername[/]" + (0 == end[1] && IS_PATH_SEP(end[0]))) { + + wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1] = {0}; + DWORD computerSz = _countof(computerName); + + if (length) *length = namelen; + if (GetComputerNameW(computerName, &computerSz)) { + if (namelen == computerSz && + 0 == _wcsnicmp(path + 2, computerName, namelen)) { + return 2; // local server + } + } + return 1; // remote + } + } + return 0; +} + + +static void +unc_errno(void) +{ + int ret = EINVAL; + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + ret = EACCES; break; + case ERROR_FILE_NOT_FOUND: + ret = ENOENT; break; + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + ret = ENOTDIR; break; + case ERROR_NOT_SUPPORTED: + ret = ENOTSUP; break; + default: break; + } + errno = ret; +} + +/*end*/ diff --git a/libw32/w32_dlfcn.c b/libw32/w32_dlfcn.c index 611976a4..6a534c37 100644 --- a/libw32/w32_dlfcn.c +++ b/libw32/w32_dlfcn.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_dlfcn_c,"$Id: w32_dlfcn.c,v 1.12 2019/03/15 23:12:10 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_dlfcn_c,"$Id: w32_dlfcn.c,v 1.14 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* @@ -7,7 +7,7 @@ __CIDENT_RCSID(gr_w32_dlfcn_c,"$Id: w32_dlfcn.c,v 1.12 2019/03/15 23:12:10 cvsus * * dlopen, dlsym, dlclose and dlerror * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -23,10 +23,10 @@ __CIDENT_RCSID(gr_w32_dlfcn_c,"$Id: w32_dlfcn.c,v 1.12 2019/03/15 23:12:10 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -37,12 +37,13 @@ __CIDENT_RCSID(gr_w32_dlfcn_c,"$Id: w32_dlfcn.c,v 1.12 2019/03/15 23:12:10 cvsus * ==extra== */ +#include "win32_internal.h" + #include -#include "win32_internal.h" #include -#define DLERROR_LEN 256 /* error buffer size */ +#define DLERROR_LEN 1024 /* error buffer size */ typedef TAILQ_HEAD(globallibs, globallib) globallibs_t; /* name global module list */ @@ -63,10 +64,13 @@ static int x_modules; static globallibs_t x_globals; static globallib_t * mod_find(HMODULE handle); -static globallib_t * mod_push(HMODULE handle, const char *file); +static globallib_t * mod_pushA(HMODULE handle, const char *file); +static globallib_t * mod_pushW(HMODULE handle, const wchar_t *file); -static void dlerror_set(const char *file, const char *msg); -static void dlerror_last(const char *file); +static void dlerror_setA(const char *file, const char *msg); +static void dlerror_lastA(const char *file); +static void dlerror_setW(const wchar_t *file, const char *msg); +static void dlerror_lastW(const wchar_t *file); #define HARD_ERRORS UINT __hardmode; #define HARD_ERRORS_DISABLE __hardmode = SetErrorMode (0); @@ -202,11 +206,37 @@ static void dlerror_last(const char *file); // ERRORS // No errors are defined. */ + LIBW32_API void * dlopen(const char *file, int mode) +{ +#if defined(UTF8FILENAMES) + if (file && w32_utf8filenames_state()) { + wchar_t *wfile = NULL; + void *ret = NULL; + + if (NULL != (wfile = w32_utf2wca(file, NULL))) { + ret = dlopenW(wfile, mode); + free((void *)wfile); + } + return ret; + } +#endif //UTF8FILENAMES + + return dlopenA(file, mode); +} + + +LIBW32_API void * +dlopenA(const char *file, int mode) { HMODULE hm = 0; + if (NULL == file || !*file) { + dlerror_lastA("missing file"); + return NULL; + } + if (0 == x_dlopen) { // runtime initialisation InitializeCriticalSection(&x_guard); TAILQ_INIT(&x_globals); @@ -215,7 +245,7 @@ dlopen(const char *file, int mode) if (NULL == file) { // global handle if (! (hm = GetModuleHandle(NULL))) { - dlerror_last("global handle"); + dlerror_lastA("global handle"); } } else { // module specific HARD_ERRORS @@ -240,8 +270,78 @@ dlopen(const char *file, int mode) t_file[i] = 0; HARD_ERRORS_DISABLE - if (! (hm = LoadLibrary(t_file))) { - dlerror_last(t_file); + if (0 == (hm = LoadLibraryA(t_file))) { + dlerror_lastA(t_file); + + } else if (RTLD_GLOBAL & mode) { // global + globallib_t *lib; + + EnterCriticalSection(&x_guard); + if (NULL != (lib = mod_find(hm))) { + ++lib->g_references; + } else { + lib = mod_pushA(hm, t_file); + } + LeaveCriticalSection(&x_guard); + if (! lib) { + dlerror_setA(t_file, "memory allocation error"); + (void) FreeLibrary(hm); + hm = 0; + } + } + HARD_ERRORS_ENABLE + } + return (void *)hm; +} + + +LIBW32_API void * +dlopenW(const wchar_t *file, int mode) +{ + HMODULE hm = 0; + + if (NULL == file || !*file) { + dlerror_lastA("missing file"); + return NULL; + } + + if (0 == x_dlopen) { // runtime initialisation + InitializeCriticalSection(&x_guard); + TAILQ_INIT(&x_globals); + ++x_dlopen; + } + + if (NULL == file) { // global handle + if (! (hm = GetModuleHandle(NULL))) { + dlerror_lastA("global handle"); + } + + } else { // module specific + HARD_ERRORS + const wchar_t *cursor; + wchar_t t_file[MAX_PATH*2]; + unsigned i; + // import and convert + for (cursor = file, i = 0; *cursor && i < _countof(t_file)-1; ++i, ++cursor) { + wchar_t c; + + if ('/' == (c = *cursor) || '\\' == c) { + if (i) { // compress + while (0 != (c = cursor[1]) && ('/' == c || '\\' == c)) { + ++cursor; + } + } + t_file[i] = '\\'; + } else { + t_file[i] = c; + } + } + t_file[i] = 0; + + HARD_ERRORS_DISABLE + if (0 == (hm = LoadLibraryW(t_file))) { + dlerror_lastW(t_file); + } else if (RTLD_GLOBAL & mode) { // global globallib_t *lib; @@ -249,11 +349,11 @@ dlopen(const char *file, int mode) if (NULL != (lib = mod_find(hm))) { ++lib->g_references; } else { - lib = mod_push(hm, t_file); + lib = mod_pushW(hm, t_file); } LeaveCriticalSection(&x_guard); if (! lib) { - dlerror_set(t_file, "memory allocation error"); + dlerror_setW(t_file, "memory allocation error"); (void) FreeLibrary(hm); hm = 0; } @@ -372,9 +472,9 @@ dlclose(void *handle) globallib_t *lib; if (NULL != (lib = mod_find(hm))) { - dlerror_last(lib->g_name); + dlerror_lastA(lib->g_name); } else { - dlerror_last(NULL); + dlerror_lastA(NULL); } return -1; @@ -446,7 +546,7 @@ mod_find(HMODULE handle) static globallib_t * -mod_push(HMODULE handle, const char *file) +mod_pushA(HMODULE handle, const char *file) { const size_t len = strlen(file); globallibs_t *libs = &x_globals; @@ -460,12 +560,26 @@ mod_push(HMODULE handle, const char *file) ++x_modules; return lib; } - return 0; + return NULL; +} + + +static globallib_t * +mod_pushW(HMODULE handle, const wchar_t *file) +{ + globallib_t *lib = NULL; + char *t_file = NULL; + + if (file && NULL != (t_file = w32_wc2utfa(file, NULL))) { + lib = mod_pushA(handle, t_file); + free(t_file); + } + return lib; } static void -dlerror_set(const char *file, const char *msg) +dlerror_setA(const char *file, const char *msg) { if (msg) { _snprintf(x_dlerror, sizeof(x_dlerror), "%s : %s", file, msg); @@ -477,13 +591,44 @@ dlerror_set(const char *file, const char *msg) static void -dlerror_last(const char *file) +dlerror_lastA(const char *file) { - int len; - len = _snprintf(x_dlerror, sizeof(x_dlerror), "%s : ", file); - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, - x_dlerror, sizeof(x_dlerror) - len, NULL); - x_dlerror[sizeof(x_dlerror)-1] = 0; + x_dlerror[0] = 0; + + if (file && *file) { + int len; + + len = _snprintf(x_dlerror, sizeof(x_dlerror), "%s : ", file); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, + x_dlerror, sizeof(x_dlerror) - len, NULL); + x_dlerror[sizeof(x_dlerror)-1] = 0; + } } -/*end*/ + +static void +dlerror_setW(const wchar_t *file, const char *msg) +{ + char *t_file = NULL; + + x_dlerror[0] = 0; + if ( NULL != (t_file = w32_wc2utfa(file, NULL))) { + dlerror_setA(t_file, msg); + free(t_file); + } +} + + +static void +dlerror_lastW(const wchar_t *file) +{ + char *t_file = NULL; + + x_dlerror[0] = 0; + if (NULL != (t_file = w32_wc2utfa(file, NULL))) { + dlerror_lastA(t_file); + free(t_file); + } +} + +/*end*/ diff --git a/libw32/w32_domainname.c b/libw32/w32_domainname.c index 5122f41b..994bcccc 100644 --- a/libw32/w32_domainname.c +++ b/libw32/w32_domainname.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_getdomainname_c,"$Id: w32_domainname.c,v 1.5 2019/03/15 23:12:15 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_getdomainname_c,"$Id: w32_domainname.c,v 1.7 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 getdomainname() * - * Copyright (c) 2017 - 2019, Adam Young. + * Copyright (c) 2017 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_getdomainname_c,"$Id: w32_domainname.c,v 1.5 2019/03/15 23 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -45,7 +45,6 @@ __CIDENT_RCSID(gr_w32_getdomainname_c,"$Id: w32_domainname.c,v 1.5 2019/03/15 23 #pragma comment(lib, "netapi32.lib") - /* // NAME // getdomainname, setdomainname - get/set domain name diff --git a/libw32/w32_err.c b/libw32/w32_err.c index dad8e7db..a91860d6 100644 --- a/libw32/w32_err.c +++ b/libw32/w32_err.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_err_c,"$Id: w32_err.c,v 1.3 2020/06/18 14:28:06 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_err_c,"$Id: w32_err.c,v 1.4 2022/03/21 14:29:40 cvsuser Exp $") /* * Copyright (c) 1993 @@ -61,7 +61,7 @@ vwarni(const char *fmt, va_list ap) vwarnxi(fmt, ap); if (fmt != NULL) fputs(": ", stderr); - fprintf(stderr, "%s\n", w32_strerror(sverrno)); + fprintf(stderr, "%s\n", w32_strerror(sverrno)); } diff --git a/libw32/w32_errno.c b/libw32/w32_errno.c index 7dcd06e3..7e4a21ed 100644 --- a/libw32/w32_errno.c +++ b/libw32/w32_errno.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_errno_c,"$Id: w32_errno.c,v 1.21 2020/04/21 21:16:55 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_errno_c,"$Id: w32_errno.c,v 1.22 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 errno mapping support * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_errno_c,"$Id: w32_errno.c,v 1.21 2020/04/21 21:16:55 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -365,7 +365,7 @@ static const int xlaterrno[] = { ENOSPC, /* 314 (0x13A) ERROR_DISK_RESOURCES_EXHAUSTED The physical resources of this disk have been exhausted. */ EINVAL, /* 315 (0x13B) ERROR_INVALID_TOKEN The token representing the data is invalid. */ ENOSYS, /* 316 (0x13C) ERROR_DEVICE_FEATURE_NOT_SUPPORTED The device does not support the command feature. */ - -1, /* 317 (0x13D) ERROR_MR_MID_NOT_FOUND The system cannot find message text for message number 0x % 1 in the message file for %2. */ + -1, /* 317 (0x13D) ERROR_MR_MID_NOT_FOUND The system cannot find message text for message number 0x%1 in the message file for %2. */ ENOENT, /* 318 (0x13E) ERROR_SCOPE_NOT_FOUND The scope specified was not found. */ -1, /* 319 (0x13F) ERROR_UNDEFINED_SCOPE The Central Access Policy specified is not defined on the target machine. */ EINVAL, /* 320 (0x140) ERROR_INVALID_CAP The Central Access Policy obtained from Active Directory is invalid. */ @@ -887,4 +887,3 @@ w32_strerror(int errnum) } /*end*/ - diff --git a/libw32/w32_fallocate.c b/libw32/w32_fallocate.c new file mode 100644 index 00000000..9e3a5c15 --- /dev/null +++ b/libw32/w32_fallocate.c @@ -0,0 +1,201 @@ +#include +__CIDENT_RCSID(gr_w32_fallocate_c, "$Id: w32_fallocate.c,v 1.1 2022/03/21 14:29:40 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 posix_fallocate() system calls + * + * Copyright (c) 2018 - 2022 Adam Young. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + */ + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 /* enable xp+ features */ +#endif + +#include "win32_internal.h" +#include + +static BOOL FileTell(HANDLE hFile, uint64_t *pos); +static BOOL FileSeek(HANDLE hFile, uint64_t pos); + + +/* +NAME + posix_fallocate - file space control (ADVANCED REALTIME) + +SYNOPSIS + #include + + int posix_fallocate(int fd, off_t offset, off_t len); + +DESCRIPTION + + The posix_fallocate() function shall ensure that any required storage for + regular file data starting at offset and continuing for len bytes is allocated + on the file system storage media. If posix_fallocate() returns successfully, + subsequent writes to the specified file data shall not fail due to the lack + of free space on the file system storage media. + + If the offset+ len is beyond the current file size, then posix_fallocate() + shall adjust the file size to offset+ len. Otherwise, the file size shall not + be changed. + + It is implementation-defined whether a previous posix_fadvise() call influences + allocation strategy. + + Space allocated via posix_fallocate() shall be freed by a successful call to + creat() or open() that truncates the size of the file. Space allocated via + posix_fallocate() may be freed by a successful call to ftruncate() that reduces + the file size to a size smaller than offset+ len. + +RETURN VALUE + + Upon successful completion, posix_fallocate() shall return zero; + otherwise, an error number shall be returned to indicate the error. + +ERRORS + + The posix_fallocate() function shall fail if: + + [EBADF] + The fd argument is not a valid file descriptor. + + [EBADF] + The fd argument references a file that was opened without write permission. + + [EFBIG] + The value of offset+ len is greater than the maximum file size. + + [EINTR] + A signal was caught during execution. + + [EINVAL] + The len argument was zero or the offset argument was less than zero. + + [EIO] + An I/O error occurred while reading from or writing to a file system. + + [ENODEV] + The fd argument does not refer to a regular file. + + [ENOSPC] + There is insufficient free space remaining on the file system storage media. + + [ESPIPE] + The fd argument is associated with a pipe or FIFO. + +*/ + +LIBW32_API int +posix_fallocate(int fd, off_t offset, off_t len) +{ + HANDLE handle; + int ret = -1; + + if (fd < 0) { + errno = EBADF; + } else if (fd >= WIN32_FILDES_MAX || + (handle = (HANDLE) _get_osfhandle(fd)) == INVALID_HANDLE_VALUE) { + errno = EBADF; + } else if (0 == (offset + len)) { + errno = EINVAL; + } else if ((offset + len) >= ((16LL * 1028 * 1024 * 1024) - (4 * 1024))) { + errno = EFBIG; // 16GB + } else { +#if (0) //TODO - additional testing + uint64_t newpos = offset + len, oldpos = 0; + DWORD err = 0; + char buf = 0; + + if (newpos <= oldpos) { + ret = 0; // success; no change + + } else if (! FileTell(handle, &oldpos)) { + err = GetLastError(); // access error etc + + // Seek and hen set the new physical file size for the specified file, extending the file. + } else if (! FileSeek(handle, newpos) || ! SetEndOfFile(handle)) { + err = GetLastError(); + (void) FileSeek(handle, oldpos); // attempt to restore position. + + // Sets the valid data length of the specified file: + // If SetFileValidData is used on a file, the potential performance gain is obtained by not filling the + // allocated clusters for the file with zeros. Therefore, reading from the file will return whatever + // the allocated clusters contain, potentially content from other users. + // + } else if (SetFileValidData(handle, newpos)) { + ret = 0; // success + + } else { // Alternative, mark file as sparse and zero-fill. + if (DeviceIoControl(handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &buf, NULL)) { + FILE_ZERO_DATA_INFORMATION zero = {0}; + + zero.FileOffset.QuadPart = oldpos; + zero.BeyondFinalZero.QuadPart = newpos; + if (DeviceIoControl(handle, FSCTL_SET_ZERO_DATA, &zero, sizeof(zero), NULL, 0, &buf, NULL)) { + ret = 0; // success + } + + } else { // Not-supported + (void) FileSeek(handle, oldpos); + errno = EOPNOTSUPP; + } + } + + if (ret && err) { + w32_errno_setas(err); + } + +#else //TODO - additional testing + errno = EOPNOTSUPP; +#endif + } + return ret; +} + + +static BOOL +FileTell(HANDLE hFile, uint64_t *pos) +{ + LARGE_INTEGER liDistanceToMove = {0}, liNewFilePointer = {0}; + + if (SetFilePointerEx(hFile, liDistanceToMove, &liNewFilePointer, FILE_CURRENT)) { + *pos = liNewFilePointer.QuadPart; + return TRUE; + } + return FALSE; +} + + +static BOOL +FileSeek(HANDLE hFile, uint64_t pos) +{ + LARGE_INTEGER liDistanceToMove = {0}, liNewFilePointer = {0}; + + liDistanceToMove.QuadPart = pos; + if (SetFilePointerEx(hFile, liDistanceToMove, &liNewFilePointer, FILE_BEGIN)) { + return TRUE; + } + return FALSE; +} + +/*end*/ diff --git a/libw32/w32_fcntl.c b/libw32/w32_fcntl.c index ae26ae82..35ad1296 100644 --- a/libw32/w32_fcntl.c +++ b/libw32/w32_fcntl.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_fcntl_c,"$Id: w32_fcntl.c,v 1.14 2019/03/15 23:12:16 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_fcntl_c,"$Id: w32_fcntl.c,v 1.15 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 fcntl() system calls * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_fcntl_c,"$Id: w32_fcntl.c,v 1.14 2019/03/15 23:12:16 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -321,4 +321,3 @@ w32_fcntl(int fd, int ctrl, int value) } /*end*/ - diff --git a/libw32/w32_flock.c b/libw32/w32_flock.c new file mode 100644 index 00000000..91a5e62e --- /dev/null +++ b/libw32/w32_flock.c @@ -0,0 +1,148 @@ +#include +__CIDENT_RCSID(gr_w32_flock_c,"$Id: w32_flock.c,v 1.2 2022/03/21 14:29:40 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 flockc() system calls + * + * Copyright (c) 2020, Adam Young. + * All rights reserved. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + * + * Notice: Portions of this text are reprinted and reproduced in electronic form. from + * IEEE Portable Operating System Interface (POSIX), for reference only. Copyright (C) + * 2001-2003 by the Institute of. Electrical and Electronics Engineers, Inc and The Open + * Group. Copyright remains with the authors and the original Standard can be obtained + * online at http://www.opengroup.org/unix/online.html. + * ==extra== + */ + + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 /* enable xp+ features */ +#endif + +#include "win32_internal.h" +#include +#include + +/* +// NAME +// flock -- apply or remove an advisory lock on an open file +// +// SYNOPSIS +// #include +// +// #define LOCK_SH 0x01 // shared file lock. +// #define LOCK_EX 0x02 // exclusive file lock. +// #define LOCK_NB 0x04 // do not block when locking. +// #define LOCK_UN 0x08 // unlock file. +// +// DESCRIPTION +// Apply or remove an advisory lock on the open file specified by fd. The argument operation is one of the following: +// +// LOCK_SH Place a shared lock. More than one process may hold a shared lock for a given file at a given time. +// LOCK_EX Place an exclusive lock. Only one process may hold an exclusive lock for a given file at a given time. +// LOCK_UN Remove an existing lock held by this process. +// +// A call to flock() may block if an incompatible lock is held by another process. To make a nonblocking request, +// include LOCK_NB (by ORing) with any of the above operations. +// +// A single file may not simultaneously have both shared and exclusive locks. +// +// Locks created by flock() are associated with an open file table entry. This means that duplicate file descriptors +// (created by, for example, fork(2) or dup(2)) refer to the same lock, and this lock may be modified or released using any of these descriptors. +// Furthermore, the lock is released either by an explicit LOCK_UN operation on any of these duplicate descriptors, or when all such descriptors have been closed. +// +// If a process uses open(2) (or similar) to obtain more than one descriptor for the same file, these descriptors are +// treated independently by flock(). An attempt to lock the file using one of these file descriptors may be denied by +// a lock that the calling process has already placed via another descriptor. +// +// A process may only hold one type of lock (shared or exclusive) on a file. Subsequent flock() calls on an already +// locked file will convert an existing lock to the new lock mode. +// +// Locks created by flock() are preserved across an execve(2). +// +// A shared or exclusive lock can be placed on a file regardless of the mode in which the file was opened. +// +// RETURN VALUE +// On success, zero is returned. On error, -1 is returned, and errno is set appropriately. +// +// EBADF fd is not an open file descriptor. +// EINTR While waiting to acquire a lock, the call was interrupted by delivery of a signal caught by a handler; see signal(7). +// EINVAL operation is invalid. +// ENOLCK The kernel ran out of memory for allocating lock records. +// EWOULDBLOCK The file is locked and the LOCK_NB flag was selected. +*/ + +LIBW32_API int +w32_flock(int fd, int operation) +{ + HANDLE handle = 0; + int ret = -1; + + if (fd < 0) { + errno = EBADF; + + } else if (fd >= WIN32_FILDES_MAX || + (handle = (HANDLE) _get_osfhandle(fd)) == INVALID_HANDLE_VALUE) { + errno = EBADF; + + } else { + DWORD szLower = 0, szUpper = 0; + OVERLAPPED ov = {0}; + + szLower = GetFileSize(handle, &szUpper); + if (LOCK_UN & operation) { // unlock + if (UnlockFileEx(handle, 0, szLower, szUpper, &ov)) { + ret = 0; + } else { + w32_errno_set(); + } + + } else { // lock + DWORD dwFlags = 0; + + if (0 == (LOCK_SH & operation)) // not-shared + dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; + + if (0 != (LOCK_NB & operation)) // non-blocking + dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; + + if (LockFileEx(handle, dwFlags, 0, szLower, szUpper, &ov)) { + ret = 0; + } else { + const DWORD err = GetLastError(); + switch (err) { + case ERROR_LOCK_VIOLATION: + errno = EWOULDBLOCK; + break; + default: + w32_errno_setas(err); + break; + } + } + } + } + return ret; +} + +/*end*/ diff --git a/libw32/w32_fsync.c b/libw32/w32_fsync.c index b9ba02d9..59b97cf1 100644 --- a/libw32/w32_fsync.c +++ b/libw32/w32_fsync.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_fsync_c,"$Id: w32_fsync.c,v 1.13 2020/03/28 00:22:45 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_fsync_c,"$Id: w32_fsync.c,v 1.15 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 fsync() system calls * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_fsync_c,"$Id: w32_fsync.c,v 1.13 2020/03/28 00:22:45 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -94,38 +94,39 @@ __CIDENT_RCSID(gr_w32_fsync_c,"$Id: w32_fsync.c,v 1.13 2020/03/28 00:22:45 cvsus LIBW32_API int w32_fsync(int fd) { - HANDLE handle; - int ret = 0; + HANDLE handle = 0; + int ret = -1; if (fd < 0) { errno = EBADF; - ret = -1; } else if (fd >= WIN32_FILDES_MAX || (handle = (HANDLE) _get_osfhandle(fd)) == INVALID_HANDLE_VALUE) { errno = EBADF; - ret = -1; - } else if (! FlushFileBuffers(handle)) { - const DWORD err = GetLastError(); - switch (err) { - case ERROR_ACCESS_DENIED: - /* For a read-only handle, fsync should succeed, - * even though we have no way to sync the access-time changes. - */ - return 0; - case ERROR_INVALID_HANDLE: - /* Most likely a non-supporting device, eg tty */ - errno = EINVAL; - break; - default: - w32_errno_setas(err); - break; + } else { + if (FlushFileBuffers(handle)) { + ret = 0; + + } else { + const DWORD err = GetLastError(); + switch (err) { + case ERROR_ACCESS_DENIED: + /* For a read-only handle, fsync should succeed, + * even though we have no way to sync the access-time changes. + */ + return 0; + case ERROR_INVALID_HANDLE: + /* Most likely a non-supporting device, eg tty */ + errno = EINVAL; + break; + default: + w32_errno_setas(err); + break; + } } - ret = -1; } return ret; } /*end*/ - diff --git a/libw32/w32_getcwd.c b/libw32/w32_getcwd.c index 0d9e878b..8f4bc4b0 100644 --- a/libw32/w32_getcwd.c +++ b/libw32/w32_getcwd.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_getcwd_c,"$Id: w32_getcwd.c,v 1.12 2020/04/20 23:03:59 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_getcwd_c,"$Id: w32_getcwd.c,v 1.14 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* - * win32 getcwd() system call + * win32 getcwd() implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_getcwd_c,"$Id: w32_getcwd.c,v 1.12 2020/04/20 23:03:59 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -86,11 +86,10 @@ __CIDENT_RCSID(gr_w32_getcwd_c,"$Id: w32_getcwd.c,v 1.12 2020/04/20 23:03:59 cvs // [ENOMEM] // Insufficient storage space is available. */ + LIBW32_API char * w32_getcwd(char *path, int size) { - char t_path[1024]; - if (NULL == path || size <= 0) { errno = EINVAL; @@ -98,8 +97,6 @@ w32_getcwd(char *path, int size) errno = ERANGE; } else { - DWORD ret; - if (x_w32_vfscwd) { /* vfs chdir() */ const char *in; char *out; @@ -115,18 +112,51 @@ w32_getcwd(char *path, int size) return path; } +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t *wpath; + + if (NULL != (wpath = alloca(sizeof(wchar_t) * (size + 1))) && + w32_getcwdW(wpath, size)) { + w32_wc2utf(wpath, path, size); + return path; + } + return NULL; + } +#endif //UTF8FILENAMES + } + + return w32_getcwdA(path, size); +} + + +LIBW32_API char * +w32_getcwdA(char *path, int size) +{ + char t_path[WIN32_PATH_MAX]; + + if (NULL == path || size <= 0) { + errno = EINVAL; + + } else if (size < 64) { + errno = ERANGE; + + } else { // If the function succeeds, the return value is the length, in characters, - // of the string copied to lpszLongPath, not including the terminating + // of the string copied to lpszLongPath, not including the terminating // null character. // - // If the lpBuffer buffer is too small to contain the path, the return value - // is the size, in characters, of the buffer that is required to hold + // If the lpBuffer buffer is too small to contain the path, the return value + // is the size, in characters, of the buffer that is required to hold // the path and the terminating null character. // - if ((ret = GetCurrentDirectoryA(sizeof(t_path), t_path)) == 0) { + DWORD ret; + + t_path[0] = 0; + if ((ret = GetCurrentDirectoryA(_countof(t_path), t_path)) == 0) { w32_errno_set(); - - } else if (ret >= (DWORD)size || ret >= sizeof(t_path)) { + + } else if (ret >= (DWORD)size || ret >= _countof(t_path)) { errno = ENOMEM; } else { /* standardise to the system seperator */ @@ -135,7 +165,7 @@ w32_getcwd(char *path, int size) for (in = t_path, out = path; *in; ++in) { if ('~' == *in) { /* shortname expand */ - (void) GetLongPathNameA(t_path, t_path, sizeof(t_path)); + (void) GetLongPathNameA(t_path, t_path, _countof(t_path)); for (in = t_path, out = path; *in; ++in) { *out++ = ('\\' == *in ? '/' : *in); } @@ -152,11 +182,10 @@ w32_getcwd(char *path, int size) } -LIBW32_API char * -w32_getcwdd(char drive, char *path, int size) +LIBW32_API wchar_t * +w32_getcwdW(wchar_t *path, int size) { - const unsigned nDrive = - (isalpha((unsigned char)drive) ? (toupper(drive) - 'A') : 0xff); + wchar_t t_path[WIN32_PATH_MAX]; if (NULL == path || size <= 0) { errno = EINVAL; @@ -164,52 +193,31 @@ w32_getcwdd(char drive, char *path, int size) } else if (size < 64) { errno = ERANGE; - } else if (nDrive >= 26) { - errno = EINVAL; - } else { - char t_path[1024]; - char pathrel[4] = {"X:."}, *file = NULL; - DWORD ret; - - if (x_w32_cwdd[nDrive]) { /* chdir() cache */ - const char *in; - char *out; - - for (in = x_w32_cwdd[nDrive], out = path; *in; ++in) { - if (--size <= 0) { - errno = ENOMEM; - break; - } - *out++ = *in; - } - *out = 0; - return path; - } - // If the function succeeds, the return value is the length, in characters, - // of the string copied to lpszLongPath, not including the terminating + // of the string copied to lpszLongPath, not including the terminating // null character. // - // If the lpBuffer buffer is too small to contain the path, the return value - // is the size, in characters, of the buffer that is required to hold + // If the lpBuffer buffer is too small to contain the path, the return value + // is the size, in characters, of the buffer that is required to hold // the path and the terminating null character. // - pathrel[0] = (char)('A' + nDrive); /* A ... Z */ + DWORD ret; - if ((ret = GetFullPathNameA(pathrel, sizeof(t_path), t_path, &file)) == 0) { + t_path[0] = 0; + if ((ret = GetCurrentDirectoryW(_countof(t_path), t_path)) == 0) { w32_errno_set(); - } else if (ret >= (DWORD)size || ret >= sizeof(t_path)) { + } else if (ret >= (DWORD)size || ret >= _countof(t_path)) { errno = ENOMEM; - - } else { - const char *in; - char *out; - + + } else { /* standardise to the system seperator */ + const wchar_t *in; + wchar_t *out; + for (in = t_path, out = path; *in; ++in) { if ('~' == *in) { /* shortname expand */ - (void) GetLongPathNameA(t_path, t_path, sizeof(t_path)); + (void) GetLongPathNameW(t_path, t_path, _countof(t_path)); for (in = t_path, out = path; *in; ++in) { *out++ = ('\\' == *in ? '/' : *in); } @@ -221,10 +229,63 @@ w32_getcwdd(char drive, char *path, int size) return path; } } - if (path && size > 0) path[0] = 0; return NULL; } -/*end*/ +LIBW32_API int +w32_getdrive(void) +{ + wchar_t t_path[WIN32_PATH_MAX]; + DWORD ret; + + t_path[0] = 0, t_path[1] = 0; + if ((ret = GetCurrentDirectoryW(_countof(t_path), t_path)) >= 2) { + if (t_path[1] == ':') { /* X: */ + const wchar_t ch = t_path[0]; + + if (ch >= L'A' && ch <= L'Z') { + return (ch - L'A') + 1; + } + + if (ch >= L'a' && ch <= L'z') { + return (ch - L'a') + 1; + } + } + } + return 0; // UNC +} + + +LIBW32_API int +w32_getsystemdrive(void) +{ + wchar_t t_path[WIN32_PATH_MAX]; + DWORD ret; + + t_path[0] = 0, t_path[1] = 0; + if ((ret = GetSystemDirectoryW(t_path, _countof(t_path))) >= 2) { + if (t_path[1] == ':') { /* X: */ + const wchar_t ch = t_path[0]; + + if (ch >= L'A' && ch <= L'Z') { + return (ch - L'A') + 1; + } + + if (ch >= L'a' && ch <= L'z') { + return (ch - L'a') + 1; + } + } + } + return 0; +} + + +LIBW32_API int +w32_getlastdrive(void) +{ + return x_w32_cwdn; +} + +/*end*/ diff --git a/libw32/w32_getcwdd.c b/libw32/w32_getcwdd.c new file mode 100644 index 00000000..f31cdb57 --- /dev/null +++ b/libw32/w32_getcwdd.c @@ -0,0 +1,240 @@ +#include +__CIDENT_RCSID(gr_w32_getcwdd_c,"$Id: w32_getcwdd.c,v 1.2 2022/03/21 14:29:40 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 getcwdd() implementation + * + * Copyright (c) 2007, 2012 - 2022 Adam Young. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + * + * Notice: Portions of this text are reprinted and reproduced in electronic form. from + * IEEE Portable Operating System Interface (POSIX), for reference only. Copyright (C) + * 2001-2003 by the Institute of. Electrical and Electronics Engineers, Inc and The Open + * Group. Copyright remains with the authors and the original Standard can be obtained + * online at http://www.opengroup.org/unix/online.html. + * ==extra== + */ + +#include "win32_internal.h" +#include +#include + +/* +// NAME +// +// getcwd, getcwdd - get the pathname of the current working directory +// +// SYNOPSIS +// +// #include +// +// char *getcwd(char *buf, size_t size); +// char *getcwdd(char drive, char *buf, size_t size); +// +// DESCRIPTION +// +// The getcwd() function shall place an absolute pathname of the current working +// directory in the array pointed to by buf, and return buf. The pathname copied to +// the array shall contain no components that are symbolic links. The size argument is +// the size in bytes of the character array pointed to by the buf argument. If buf is +// a null pointer, the behavior of getcwd() is unspecified. +// +// The getcwdd() function retrieves the absolute pathname of the current working for the +// specificed drive (A thru Z). +// +// RETURN VALUE +// +// Upon successful completion, getcwd() shall return the buf argument. Otherwise, +// getcwd() shall return a null pointer and set errno to indicate the error. The +// contents of the array pointed to by buf are then undefined. +// +// ERRORS +// +// The getcwd() function shall fail if: +// +// [EINVAL] +// The size argument is 0. +// +// [ERANGE] +// The size argument is greater than 0, but is smaller than the length of the pathname +1. +// +// The getcwd() function may fail if: +// +// [EACCES] +// Read or search permission was denied for a component of the pathname. +// +// [ENOMEM] +// Insufficient storage space is available. +*/ + +LIBW32_API char * +w32_getcwdd(char drive, char *path, int size) +{ + if (NULL == path || size <= 0) { + errno = EINVAL; + + } else if (size < 64) { + errno = ERANGE; + + } else { +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t *wpath; + + if (NULL != (wpath = alloca(sizeof(wchar_t) * (size + 1))) && + w32_getcwddW(drive, wpath, size)) { + w32_wc2utf(wpath, path, size); + return path; + } + return NULL; + } +#endif //UTF8FILENAMES + + return w32_getcwddA(drive, path, size); + } + return NULL; +} + + +LIBW32_API char * +w32_getcwddA(char drive, char *path, int size) +{ + const unsigned nDrive = + (isalpha((unsigned char)drive) ? (toupper(drive) - 'A') : 0xff); + + if (NULL == path || size <= 0) { + errno = EINVAL; + + } else if (size < 64) { + errno = ERANGE; + + } else if (nDrive >= 26) { + errno = EINVAL; + + } else { + // If the function succeeds, the return value is the length, in characters, + // of the string copied to lpszLongPath, not including the terminating + // null character. + // + // If the lpBuffer buffer is too small to contain the path, the return value + // is the size, in characters, of the buffer that is required to hold + // the path and the terminating null character. + // + char t_path[WIN32_PATH_MAX]; + char rel[4] = {"X:."}, *file = NULL; + DWORD ret; + + rel[0] = (char)('A' + nDrive); /* A ... Z */ + + t_path[0] = 0; + if ((ret = GetFullPathNameA(rel, _countof(t_path), t_path, &file)) == 0) { + w32_errno_set(); + + } else if (ret >= (DWORD)size || ret >= _countof(t_path)) { + errno = ENOMEM; + + } else { + const char *in; + char *out; + + for (in = t_path, out = path; *in; ++in) { + if ('~' == *in) { /* shortname expand */ + (void) GetLongPathNameA(t_path, t_path, _countof(t_path)); + for (in = t_path, out = path; *in; ++in) { + *out++ = ('\\' == *in ? '/' : *in); + } + break; + } + *out++ = ('\\' == *in ? '/' : *in); + } + *out = 0; + return path; + } + } + + if (path && size > 0) path[0] = 0; + return NULL; +} + + + +LIBW32_API wchar_t * +w32_getcwddW(char drive, wchar_t *path, int size) +{ + const unsigned nDrive = + (isalpha((unsigned char)drive) ? (toupper(drive) - 'A') : 0xff); + + if (NULL == path || size <= 0) { + errno = EINVAL; + + } else if (size < 64) { + errno = ERANGE; + + } else if (nDrive >= 26) { + errno = EINVAL; + + } else { + // If the function succeeds, the return value is the length, in characters, + // of the string copied to lpszLongPath, not including the terminating + // null character. + // + // If the lpBuffer buffer is too small to contain the path, the return value + // is the size, in characters, of the buffer that is required to hold + // the path and the terminating null character. + // + wchar_t t_path[WIN32_PATH_MAX]; + wchar_t rel[4] = {L"X:."}, *file = NULL; + DWORD ret; + + rel[0] = (wchar_t)('A' + nDrive); /* A ... Z */ + + t_path[0] = 0; + if ((ret = GetFullPathNameW(rel, _countof(t_path), t_path, &file)) == 0) { + w32_errno_set(); + + } else if (ret >= (DWORD)size || ret >= _countof(t_path)) { + errno = ENOMEM; + + } else { + const wchar_t *in; + wchar_t *out; + + for (in = t_path, out = path; *in; ++in) { + if ('~' == *in) { /* shortname expand */ + (void) GetLongPathNameW(t_path, t_path, _countof(t_path)); + for (in = t_path, out = path; *in; ++in) { + *out++ = ('\\' == *in ? '/' : *in); + } + break; + } + *out++ = ('\\' == *in ? '/' : *in); + } + *out = 0; + return path; + } + } + + if (path && size > 0) path[0] = 0; + return NULL; +} + +/*end*/ diff --git a/libw32/w32_gethostname.c b/libw32/w32_gethostname.c index 536114d7..33d7ec76 100644 --- a/libw32/w32_gethostname.c +++ b/libw32/w32_gethostname.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_gethostname_c,"$Id: w32_gethostname.c,v 1.14 2020/06/20 01:28:48 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_gethostname_c,"$Id: w32_gethostname.c,v 1.17 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 gethostname * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_gethostname_c,"$Id: w32_gethostname.c,v 1.14 2020/06/20 01 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -42,8 +42,6 @@ __CIDENT_RCSID(gr_w32_gethostname_c,"$Id: w32_gethostname.c,v 1.14 2020/06/20 01 #include -#include - #if !defined(WINDOWS_MEAN_AND_LEAN) #define WINDOWS_MEAN_AND_LEAN #endif diff --git a/libw32/w32_getlocale.c b/libw32/w32_getlocale.c index 8c15b90c..8d402e21 100644 --- a/libw32/w32_getlocale.c +++ b/libw32/w32_getlocale.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_getlocale_c,"$Id: w32_getlocale.c,v 1.13 2019/03/15 23:12:16 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_getlocale_c,"$Id: w32_getlocale.c,v 1.14 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 getlocale() system calls * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_getlocale_c,"$Id: w32_getlocale.c,v 1.13 2019/03/15 23:12: * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from diff --git a/libw32/w32_getopt.c b/libw32/w32_getopt.c index 33cbcaaf..90500ce5 100644 --- a/libw32/w32_getopt.c +++ b/libw32/w32_getopt.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_getopt_c,"$Id: w32_getopt.c,v 1.7 2020/06/18 14:32:39 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_getopt_c,"$Id: w32_getopt.c,v 1.9 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* @@ -38,17 +38,19 @@ __CIDENT_RCSID(gr_w32_getopt_c,"$Id: w32_getopt.c,v 1.7 2020/06/18 14:32:39 cvsu #include LIBW32_API int opterr = 1, /* if error message should be printed */ - optind = 1, /* index into parent argv vector */ - optopt = '?', /* character checked for validity */ - optreset = 0; /* reset getopt */ + optind = 1, /* index into parent argv vector */ + optopt = '?', /* character checked for validity */ + optreset = 0; /* reset getopt */ + LIBW32_API char * optarg = NULL; /* argument associated with option */ -static const char *__progname = ""; /* derived progname */ +static const char *__progname = ""; #define BADCH (int)'?' #define BADARG (int)':' #define EMSG "" + /* * getopt -- * Parse argc/argv argument vector. @@ -60,7 +62,7 @@ getopt(int nargc, char * const *nargv, const char *ostr) char *oli; /* option letter list index */ int ret; -#ifdef WIN32 +#if defined(_WIN32) || defined(WIN32) if (optind == 1 && (__progname == NULL || __progname[0] == '\0')) __progname = nargv[0]; /* MSVC special */ #endif diff --git a/libw32/w32_getopt_long.c b/libw32/w32_getopt_long.c new file mode 100644 index 00000000..02e2ab3b --- /dev/null +++ b/libw32/w32_getopt_long.c @@ -0,0 +1,495 @@ +#include +__CIDENT_RCSID(gr_w32_getopt_c,"$Id: w32_getopt_long.c,v 1.2 2022/03/21 14:29:40 cvsuser Exp $") + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $ + */ + +#include +#include +#include + +// #if defined(HAVE_GETOPT_H) && defined(HAVE_STRUCT_OPTION) +#include +// #endif + +#include +#include +#include + +//#define REPLACE_GETOPT + +#ifndef _DIAGASSERT +#define _DIAGASSERT assert +#endif + +#define IGNORE_FIRST (*options == '-' || *options == '+') +#define PRINT_ERROR ((opterr) && ((*options != ':') \ + || (IGNORE_FIRST && options[1] != ':'))) +#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) +#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) +/* XXX: GNU ignores PC if *options == '-' */ +#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((IGNORE_FIRST && options[1] == ':') \ + || (*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static int getopt_internal(int, char **, const char *, char *buf, int buflen); +static int gcd(int, int); +static void permute_args(int, int, int, char **); + +static const char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return b; +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, char **nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + _DIAGASSERT(nargv != NULL); + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + nargv[pos] = nargv[cstart]; + nargv[cstart] = swap; + } + } +} + +/* + * getopt_warn --- + * Generate a diagnostics message. + */ +static void +getopt_warn(char *buf, int buflen, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (buf && buflen) { /* stream to buffer */ + (void) _vsnprintf(buf, buflen, fmt, ap); + buf[buflen - 1] = 0; + } else { + vwarnx(fmt, ap); + } + va_end(ap); +} + + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + * + * Returns -2 if -- is found (can be long option or end of options marker). + */ +static int +getopt_internal(int nargc, char **nargv, const char *options, char *buf, int buflen) +{ + char *oli; /* option letter list index */ + int optchar; + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + + optarg = NULL; + + /* + * XXX Some programs (like rsyncd) expect to be able to + * XXX re-initialize optind to 0 and have getopt_long(3) + * XXX properly function again. Work around this braindamage. + */ + if (optind == 0) + optind = 1; + + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((*(place = nargv[optind]) != '-') + || (place[1] == '\0')) { /* found non-option */ + place = EMSG; + if (IN_ORDER) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return INORDER; + } + if (!PERMUTE) { + /* + * if no permutation wanted, stop parsing + * at first non-option + */ + return -1; + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + if (place[1] && *++place == '-') { /* found "--" */ + place++; + return -2; + } + } + if ((optchar = (int)*place++) == (int)':' || + (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { + /* option letter unknown or ':' */ + if (!*place) + ++optind; + if (PRINT_ERROR) + getopt_warn(buf, buflen, illoptchar, optchar); + optopt = optchar; + return BADCH; + } + if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ + /* XXX: what if no long options provided (called by getopt)? */ + if (*place) + return -2; + + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + getopt_warn(buf, buflen, recargchar, optchar); + optopt = optchar; + return BADARG; + } else /* white space */ + place = nargv[optind]; + /* + * Handle -W arg the same as --arg (which causes getopt to + * stop parsing). + */ + return -2; + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = (char *)place; + /* XXX: disable test for :: if PC? (GNU doesn't) */ + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + getopt_warn(buf, buflen, recargchar, optchar); + optopt = optchar; + return BADARG; + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return optchar; +} + + +#if defined(REPLACE_GETOPT) +// /* +// * getopt -- +// * Parse argc/argv argument vector. +// * +// * [eventually this will replace the real getopt] +// */ +// int +// getopt(nargc, nargv, options) +// int nargc; +// char * const *nargv; +// const char *options; +// { +// int retval; +// +// _DIAGASSERT(nargv != NULL); +// _DIAGASSERT(options != NULL); +// +// retval = getopt_internal(nargc, (char **)nargv, options); +// if (retval == -2) { +// ++optind; +// /* +// * We found an option (--), so if we skipped non-options, +// * we have to permute. +// */ +// if (nonopt_end != -1) { +// permute_args(nonopt_start, nonopt_end, optind, (char **)nargv); +// optind -= nonopt_end - nonopt_start; +// } +// nonopt_start = nonopt_end = -1; +// retval = -1; +// } +// return retval; +// } +#endif //REPLACE_GETOPT + + +int +__import_getopt(int nargc, char * const *nargv, const char *ostr) +{ + return getopt(nargc, nargv, ostr); +} + + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx) +{ + return getopt_long2(nargc, nargv, options, long_options, idx, NULL, 0); +} + + +int +getopt_long2(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx, char *buf, int buflen) +{ + int retval; + +#define IDENTICAL_INTERPRETATION(_x, _y) \ + (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ + long_options[(_x)].flag == long_options[(_y)].flag && \ + long_options[(_x)].val == long_options[(_y)].val) + + _DIAGASSERT(nargv != NULL); + _DIAGASSERT(options != NULL); + _DIAGASSERT(long_options != NULL); + /* idx may be NULL */ + + if (buf && buflen) opterr = 1; /* implied */ + + retval = getopt_internal(nargc, (char **)nargv, options, buf, buflen); + if (retval == -2) { + char *current_argv, *has_equal; + size_t current_argv_len; + int i, ambiguous, match; + + current_argv = (char *)place; + match = -1; + ambiguous = 0; + + optind++; + place = EMSG; + + if (*current_argv == '\0') { /* found "--" */ + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, optind, (char **)nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return -1; + } + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == + (unsigned)current_argv_len) { + /* exact match */ + match = i; + ambiguous = 0; + break; + } + if (match == -1) /* partial match */ + match = i; + else if (!IDENTICAL_INTERPRETATION(i, match)) + ambiguous = 1; + } + if (ambiguous) { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + getopt_warn(buf, buflen, ambig, (int)current_argv_len, current_argv); + optopt = 0; + return BADCH; + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + getopt_warn(buf, buflen, noarg, (int)current_argv_len, current_argv); + /* + * XXX: GNU sets optopt to val regardless of + * flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return BADARG; + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == required_argument) { + /* + * optional argument doesn't use + * next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' + * indicates no error should be generated + */ + if (PRINT_ERROR) + getopt_warn(buf, buflen, recargstring, current_argv); + /* + * XXX: GNU sets optopt to val regardless + * of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return BADARG; + } + } else { /* unknown option */ + if (PRINT_ERROR) + getopt_warn(buf, buflen, illoptstring, current_argv); + optopt = 0; + return BADCH; + } + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + retval = 0; + } else + retval = long_options[match].val; + if (idx) + *idx = match; + } + return retval; +#undef IDENTICAL_INTERPRETATION +} + +//end diff --git a/libw32/w32_getrusage.c b/libw32/w32_getrusage.c index d8e07f68..78a81f8e 100644 --- a/libw32/w32_getrusage.c +++ b/libw32/w32_getrusage.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_getrusage_c,"$Id: w32_getrusage.c,v 1.1 2020/05/03 21:34:19 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_getrusage_c,"$Id: w32_getrusage.c,v 1.2 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 getrusage() system calls * - * Copyright (c) 2020, Adam Young. + * Copyright (c) 2020 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_getrusage_c,"$Id: w32_getrusage.c,v 1.1 2020/05/03 21:34:1 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -51,20 +51,20 @@ __CIDENT_RCSID(gr_w32_getrusage_c,"$Id: w32_getrusage.c,v 1.1 2020/05/03 21:34:1 // [XSI] [Option Start] #include // // int getrusage(int who, struct rusage *r_usage); [Option End] -// +// // DESCRIPTION -// +// // The getrusage() function shall provide measures of the resources used by the current process or its terminated -// and waited-for child processes. If the value of the who argument is RUSAGE_SELF, information shall be returned -// about resources used by the current process. If the value of the who argument is RUSAGE_CHILDREN, information -// shall be returned about resources used by the terminated and waited-for children of the current process. -// -// If the child is never waited for (for example, if the parent has SA_NOCLDWAIT set or sets SIGCHLD to SIG_IGN), -// the resource information for the child process is discarded and not included in the resource information +// and waited-for child processes. If the value of the who argument is RUSAGE_SELF, information shall be returned +// about resources used by the current process. If the value of the who argument is RUSAGE_CHILDREN, information +// shall be returned about resources used by the terminated and waited-for children of the current process. +// +// If the child is never waited for (for example, if the parent has SA_NOCLDWAIT set or sets SIGCHLD to SIG_IGN), +// the resource information for the child process is discarded and not included in the resource information // provided by getrusage(). -// +// // The r_usage argument is a pointer to an object of type struct rusage in which the returned information is stored. -// +// // RETURN VALUE // // Upon successful completion, getrusage() shall return 0; otherwise, -1 shall be returned @@ -78,7 +78,7 @@ __CIDENT_RCSID(gr_w32_getrusage_c,"$Id: w32_getrusage.c,v 1.1 2020/05/03 21:34:1 // The value of the who argument is not valid. */ -static void +static void totimeval(const FILETIME *ft, struct timeval *tv) { ULARGE_INTEGER time; @@ -113,7 +113,7 @@ getrusage(int who, struct rusage *usage) ! GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) { w32_errno_set(); - } else { + } else { totimeval(&kerneltime, &usage->ru_stime); // system CPU time used totimeval(&usertime, &usage->ru_utime); // user CPU time used usage->ru_majflt = pmc.PageFaultCount; // page faults (hard page faults) diff --git a/libw32/w32_getsubopt.c b/libw32/w32_getsubopt.c index f7824075..938e1b33 100644 --- a/libw32/w32_getsubopt.c +++ b/libw32/w32_getsubopt.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_getsubopt_c,"$Id: w32_getsubopt.c,v 1.6 2018/10/16 15:09:54 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_getsubopt_c,"$Id: w32_getsubopt.c,v 1.8 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /*- @@ -45,7 +45,7 @@ __CIDENT_RCSID(gr_w32_getsubopt_c,"$Id: w32_getsubopt.c,v 1.6 2018/10/16 15:09:5 * tricky... The extern variable suboptarg is a pointer to the token * which didn't match. */ -char *suboptarg = NULL; +LIBW32_API char *suboptarg = NULL; LIBW32_API int getsubopt(char **optionp, char * const *tokens, char **valuep) @@ -98,4 +98,3 @@ getsubopt(char **optionp, char * const *tokens, char **valuep) } /*end*/ - diff --git a/libw32/w32_gistrerror.c b/libw32/w32_gistrerror.c index 4ceb768b..505016f1 100644 --- a/libw32/w32_gistrerror.c +++ b/libw32/w32_gistrerror.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_gistrerror_c,"$Id: w32_gistrerror.c,v 1.11 2019/03/15 23:12:16 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_gistrerror_c,"$Id: w32_gistrerror.c,v 1.12 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 gi_strerror() * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_gistrerror_c,"$Id: w32_gistrerror.c,v 1.11 2019/03/15 23:1 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -79,7 +79,7 @@ __CIDENT_RCSID(gr_w32_gistrerror_c,"$Id: w32_gistrerror.c,v 1.11 2019/03/15 23:1 #if (defined(_MSC_VER) && (_MSC_VER < 1400)) || \ defined(__WATCOMC__) -LIBW32_API const char * +LIBW32_API const char * gai_strerror(int ecode) { return w32_gai_strerror(ecode); @@ -120,4 +120,3 @@ w32_gai_strerror(int ecode) return "unknown error, gai_strerror"; } /*end*/ - diff --git a/libw32/w32_glob.c b/libw32/w32_glob.c index f73a4b2e..0582566b 100644 --- a/libw32/w32_glob.c +++ b/libw32/w32_glob.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_glob_c,"$Id: w32_glob.c,v 1.5 2020/06/18 14:32:39 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_glob_c,"$Id: w32_glob.c,v 1.6 2022/03/21 14:29:40 cvsuser Exp $") /* * win @@ -20,10 +20,10 @@ __CIDENT_RCSID(gr_w32_glob_c,"$Id: w32_glob.c,v 1.5 2020/06/18 14:32:39 cvsuser * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Copyright (c) 1989, 1993 @@ -243,7 +243,7 @@ glob(const char * /*__restrict*/ pattern, int flags, int (*errfunc)(const char * #endif if (flags & GLOB_NOESCAPE) { while (bufnext < bufend && (c = *patnext++) != EOS) - *bufnext++ = c; + *bufnext++ = (Char)c; } else { /* Protect the quoted characters. */ while (bufnext < bufend && (c = *patnext++) != EOS) @@ -261,10 +261,10 @@ glob(const char * /*__restrict*/ pattern, int flags, int (*errfunc)(const char * c = QUOTE; --patnext; } - *bufnext++ = c | M_PROTECT; + *bufnext++ = (Char)(c | M_PROTECT); } else - *bufnext++ = c; + *bufnext++ = (Char)c; } *bufnext = EOS; diff --git a/libw32/w32_grp.c b/libw32/w32_grp.c index 21c625af..a9fe3032 100644 --- a/libw32/w32_grp.c +++ b/libw32/w32_grp.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_grp_c,"$Id: w32_grp.c,v 1.11 2019/03/15 23:12:16 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_grp_c,"$Id: w32_grp.c,v 1.13 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 pwd() implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_grp_c,"$Id: w32_grp.c,v 1.11 2019/03/15 23:12:16 cvsuser E * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -35,198 +35,347 @@ __CIDENT_RCSID(gr_w32_grp_c,"$Id: w32_grp.c,v 1.11 2019/03/15 23:12:16 cvsuser E * ==extra== */ +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0500 +#endif + #include "win32_internal.h" #include #include #include +#include + +#include /* ConvertSidToStringSid */ +#include + +#pragma comment(lib, "Netapi32.lib") -static void fillin(void); +static void fill_groups(void); +static unsigned RID(PSID sid); +static void fill_group(void); +static int copy_group(const struct group *grp, struct group *dest, char *buffer, size_t bufsize); + +static unsigned x_groups_count; +static unsigned x_cursor; /* getgrent cursor */ +static struct group x_group; +static struct group *x_groups; +static char x_buffer[MAX_PATH * 2]; -static struct group grp; -static int counter; /* // NAME -// getgrgid - get group database entry for a group ID +// endgrent, getgrent, setgrent - group database entry functions // // SYNOPSIS // #include // -// struct group *getgrgid(gid_t gid); +// void endgrent(void); +// struct group *getgrent(void); +// void setgrent(void); // // DESCRIPTION -// The getgrgid() function shall search the group database for an entry with a -// matching gid. +// The getgrent() function shall return a pointer to a structure containing the +// broken-out fields of an entry in the group database. When first called, getgrent() +// shall return a pointer to a group structure containing the first entry in the group +// database. Thereafter, it shall return a pointer to a group structure containing the +// next group structure in the group database, so successive calls may be used to +// search the entire database. // -// The getgrgid() function need not be reentrant. A function that is not required to -// be reentrant is not required to be thread-safe. +// An implementation that provides extended security controls may impose further +// implementation-defined restrictions on accessing the group database. In particular, +// the system may deny the existence of some or all of the group database entries +// associated with groups other than those groups associated with the caller and may +// omit users other than the caller from the list of members of groups in database +// entries that are returned. // +// The setgrent() function shall rewind the group database to allow repeated searches. +// +// The endgrent() function may be called to close the group database when processing +// is complete. +// +// These functions need not be reentrant. A function that is not required to be +// reentrant is not required to be thread-safe. // // RETURN VALUE -// Upon successful completion, getgrgid() shall return a pointer to a struct group -// with the structure defined in with a matching entry if one is found. The -// getgrgid() function shall return a null pointer if either the requested entry was -// not found, or an error occurred. On error, errno shall be set to indicate the error. +// When first called, getgrent() shall return a pointer to the first group structure +// in the group database. Upon subsequent calls it shall return the next group +// structure in the group database. The getgrent() function shall return a null +// pointer on end-of-file or an error and errno may be set to indicate the error. // // The return value may point to a static area which is overwritten by a subsequent -// call to getgrent(), getgrgid(), or getgrnam(). +// call to getgrgid(), getgrnam(), or getgrent(). // // ERRORS -// The getgrgid() and getgrgid_r() functions may fail if: +// The getgrent() function may fail if: // +// [EINTR] +// A signal was caught during the operation. // [EIO] // An I/O error has occurred. -// [EINTR] -// A signal was caught during getgrgid(). // [EMFILE] // {OPEN_MAX} file descriptors are currently open in the calling process. // [ENFILE] // The maximum allowable number of files is currently open in the system. */ +LIBW32_API void +setgrent(void) +{ + x_cursor = 0; +} + + LIBW32_API struct group * -getgrgid(int gid) +getgrent(void) { - fillin(); - if (gid != grp.gr_gid) { - return NULL; + const unsigned cursor = x_cursor++; + + if (0 == cursor) { + fill_groups(); + return &x_group; + + } else if (cursor <= x_groups_count) { + return x_groups + (cursor - 1); } - return &grp; + return NULL; +} + + +LIBW32_API int +getgrent_r(struct group *grp, char *buffer, size_t bufsize, struct group **result) +{ + struct group *it = NULL; + unsigned cursor; + + if (NULL == grp || NULL == buffer || NULL == result) { + if (result) *result = NULL; + errno = EINVAL; + return EINVAL; // invalid arguments + } + + cursor = x_cursor++; + if (0 == cursor) { + fill_groups(); + it = &x_group; + } else if (cursor <= x_groups_count) { + it = x_groups + (cursor - 1); + } + + *result = NULL; + if (it) { + const int rc = copy_group(it, grp, buffer, bufsize); + if (0 == rc) *result = grp; // success + return rc; + } + + errno = EINVAL; + return ENOENT; // no-match +} + + +LIBW32_API void +endgrent(void) +{ + x_cursor = 1; } /* // NAME -// getgrnam - search group database for a name +// getgrgid - get group database entry for a group ID // // SYNOPSIS // #include -// struct group *getgrnam(const char *name); +// +// struct group *getgrgid(gid_t gid); // // DESCRIPTION -// The getgrnam() function shall search the group database for an entry with a -// matching name. +// The getgrgid() function shall search the group database for an entry with a +// matching gid. // -// The getgrnam() function need not be reentrant. A function that is not required to +// The getgrgid() function need not be reentrant. A function that is not required to // be reentrant is not required to be thread-safe. // +// // RETURN VALUE -// The getgrnam() function shall return a pointer to a struct group with the structure -// defined in with a matching entry if one is found. The getgrnam() function -// shall return a null pointer if either the requested entry was not found, or an -// error occurred. On error, errno shall be set to indicate the error. +// Upon successful completion, getgrgid() shall return a pointer to a struct group +// with the structure defined in with a matching entry if one is found. The +// getgrgid() function shall return a null pointer if either the requested entry was +// not found, or an error occurred. On error, errno shall be set to indicate the error. // // The return value may point to a static area which is overwritten by a subsequent // call to getgrent(), getgrgid(), or getgrnam(). // // ERRORS -// The getgrnam() and getgrnam_r() functions may fail if: +// The getgrgid() and getgrgid_r() functions may fail if: // // [EIO] // An I/O error has occurred. // [EINTR] -// A signal was caught during getgrnam(). +// A signal was caught during getgrgid(). // [EMFILE] // {OPEN_MAX} file descriptors are currently open in the calling process. // [ENFILE] // The maximum allowable number of files is currently open in the system. */ LIBW32_API struct group * -getgrnam(const char * n) +getgrgid(int gid) { - fillin(); - if (strcmp(n, grp.gr_name) != 0) { - return NULL; + const struct group *current = w32_group_user(); + + if (gid == current->gr_gid) { + fill_group(); + return &x_group; + + } else { + struct group *it, *end; + fill_groups(); + for (it = x_groups, end = it + x_groups_count; it != end; ++it) { + if (gid == it->gr_gid) { + return it; + } + } } - return &grp; + return NULL; +} + + +LIBW32_API int +getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result) +{ + const struct group *current = w32_group_user(); + + if (NULL == grp || NULL == buffer || NULL == result) { + if (result) *result = NULL; + errno = EINVAL; + return EINVAL; // invalid arguments + } + + *result = NULL; + if (gid == current->gr_gid) { + const int rc = copy_group(current, grp, buffer, bufsize); + if (0 == rc) *result = grp; // success + return rc; + + } else { + const struct group *it, *end; + fill_groups(); + for (it = x_groups, end = it + x_groups_count; it != end; ++it) { + if (gid == it->gr_gid) { + const int rc = copy_group(it, grp, buffer, bufsize); + if (0 == rc) *result = grp; // success + return rc; + } + } + } + return 0; // no-match } /* // NAME -// endgrent, getgrent, setgrent - group database entry functions +// getgrnam - search group database for a name // // SYNOPSIS // #include -// -// void endgrent(void); -// struct group *getgrent(void); -// void setgrent(void); [Option End] +// struct group *getgrnam(const char *name); +// int getgrnam_r(const char *name, struct group *grp, char *buffer, +// size_t bufsize, struct group **result); // // DESCRIPTION -// The getgrent() function shall return a pointer to a structure containing the -// broken-out fields of an entry in the group database. When first called, getgrent() -// shall return a pointer to a group structure containing the first entry in the group -// database. Thereafter, it shall return a pointer to a group structure containing the -// next group structure in the group database, so successive calls may be used to -// search the entire database. -// -// An implementation that provides extended security controls may impose further -// implementation-defined restrictions on accessing the group database. In particular, -// the system may deny the existence of some or all of the group database entries -// associated with groups other than those groups associated with the caller and may -// omit users other than the caller from the list of members of groups in database -// entries that are returned. -// -// The setgrent() function shall rewind the group database to allow repeated searches. +// The getgrnam() function shall search the group database for an entry with a +// matching name. // -// The endgrent() function may be called to close the group database when processing -// is complete. +// The getgrnam() function need not be reentrant. A function that is not required to +// be reentrant is not required to be thread-safe. // -// These functions need not be reentrant. A function that is not required to be -// reentrant is not required to be thread-safe. +// The getgrnam_r() function shall update the group structure pointed to by grp and store +// a pointer to that structure at the location pointed to by result. The structure shall +// contain an entry from the group database with a matching gid or name. Storage referenced +// by the group structure is allocated from the memory provided with the buffer parameter, +// which is bufsize bytes in size. The maximum size needed for this buffer can be determined +// with the {_SC_GETGR_R_SIZE_MAX} sysconf() parameter. A NULL pointer is returned at the +// location pointed to by result on error or if the requested entry is not found. // // RETURN VALUE -// When first called, getgrent() shall return a pointer to the first group structure -// in the group database. Upon subsequent calls it shall return the next group -// structure in the group database. The getgrent() function shall return a null -// pointer on end-of-file or an error and errno may be set to indicate the error. +// The getgrnam() function shall return a pointer to a struct group with the structure +// defined in with a matching entry if one is found. The getgrnam() function +// shall return a null pointer if either the requested entry was not found, or an +// error occurred. On error, errno shall be set to indicate the error. // // The return value may point to a static area which is overwritten by a subsequent -// call to getgrgid(), getgrnam(), or getgrent(). +// call to getgrent(), getgrgid(), or getgrnam(). // // ERRORS -// The getgrent() function may fail if: +// The getgrnam() and getgrnam_r() functions may fail if: // -// [EINTR] -// A signal was caught during the operation. // [EIO] // An I/O error has occurred. +// [EINTR] +// A signal was caught during getgrnam(). // [EMFILE] // {OPEN_MAX} file descriptors are currently open in the calling process. // [ENFILE] // The maximum allowable number of files is currently open in the system. +// +// The getgrnam_r() function may fail if: +// +// [ERANGE] +// Insufficient storage was supplied via buffer and bufsize to contain the data to +// be referenced by the resulting group structure. */ -LIBW32_API void -setgrent(void) +LIBW32_API struct group * +getgrnam(const char *name) { - counter = 0; -} + if (name) { + const struct group *current = w32_group_user(); + if (0 == _stricmp(name, current->gr_name)) { + fill_group(); + return &x_group; -LIBW32_API struct group * -getgrent(void) -{ - if (counter++ == 0) { - fillin(); - return &grp; + } else { + struct group *it, *end; + fill_groups(); + for (it = x_groups, end = it + x_groups_count; it != end; ++it) { + if (0 == _stricmp(name, it->gr_name)) { + return it; + } + } + } } return NULL; } -LIBW32_API void -endgrent(void) +LIBW32_API int +getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, struct group **result) { - counter = 1; -} + const struct group *current = w32_group_user(); + if (NULL == name || NULL == grp || NULL == buffer || NULL == result) { + if (result) *result = NULL; + errno = EINVAL; + return EINVAL; // invalid arguments + } -static void -fillin(void) -{ - grp.gr_name = "user"; - grp.gr_passwd = "*"; - grp.gr_gid = w32_getgid(); + *result = NULL; + if (0 == _stricmp(name, current->gr_name)) { + const int rc = copy_group(current, grp, buffer, bufsize); + if (0 == rc) *result = grp; // success + return rc; + + } else { + const struct group *it, *end; + fill_groups(); + for (it = x_groups, end = it + x_groups_count; it != end; ++it) { + if (0 == _stricmp(name, it->gr_name)) { + const int rc = copy_group(it, grp, buffer, bufsize); + if (0 == rc) *result = grp; // success + return rc; + } + } + } + return 0; // no-match } @@ -272,7 +421,7 @@ getgroups(int gidsetsize, gid_t grouplist[]) { if (gidsetsize >= 1) { if (grouplist) { - grouplist[0] = 42; + grouplist[0] = w32_getgid(); return 1; } } @@ -280,5 +429,264 @@ getgroups(int gidsetsize, gid_t grouplist[]) return -1; } -/*end*/ +/* +// NAME +// setgroups -- set group access list +// +// SYNOPSIS +// #include +// #include +// +// int setgroups(int ngroups, const gid_t *gidset); +// +// DESCRIPTION +// The setgroups() system call sets the group access list of the current user process according +// to the array gidset. The ngroups argument indicates the number of entries in the array and +// must be no more than {NGROUPS_MAX}+1. +// +// RETURN VALUES +// The setgroups() function returns the value 0 if successful; otherwise the value -1 is returned +// and the global variable errno is set to indicate the error. +// +// ERRORS +// The setgroups() system call will fail if: +// +// [EPERM] +// The caller is not the super-user. +// +// [EINVAL] +// The number specified in the ngroups argument is larger than the {NGROUPS_MAX}+1 limit. +// +// [EFAULT] +// The address specified for gidset is outside the process address space. +*/ +LIBW32_API int +setgroups(size_t size, const gid_t *gidset) +{ + (void) size; + (void) gidset; + errno = EINVAL; + return -1; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// group's database implementation + +static void +fill_groups(void) +{ + DWORD resume_handle = 0; + NET_API_STATUS nStatus; + unsigned cbufsz = 0; + char name[MAX_PATH]; + int nlen; + + fill_group(); + if (NULL != x_groups) + return; + + assert(0 == x_groups_count); + do { + DWORD i, dwEntriesRead = 0, dwTotalEntries = 0; + const unsigned ototal = x_groups_count; + unsigned bufsz = 0, count = 0; + PGROUP_INFO_2 groups = NULL; + + nStatus = NetGroupEnum(NULL, 2 /*GROUP_INFO_2*/, (LPBYTE*) &groups, + MAX_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, &resume_handle); + + switch (nStatus) { + case NERR_Success: + case ERROR_MORE_DATA: + break; + default: + return; + } + + // size storage + for (i = 0; i < dwEntriesRead; ++i) { + const PGROUP_INFO_2 group = groups + i; + if ((int)group->grpi2_group_id == x_group.gr_gid || + (nlen = w32_wc2utf(group->grpi2_name, name, sizeof(name))) <= 0) { + continue; + } + bufsz += (nlen + 1); + ++count; + } + +#if (TODO) + if (NERR_Success == nStatus) // last iteration. + for (i = 0; i < _countof(well_known_sids); ++i) { + const int nlen = fill_builtin(well_known_sids + i, NULL, NULL, 0); + if (nlen > 0) { + bufsz += (nlen + 1); + ++count; + } + } +#endif + + // new elements + if (count && bufsz) { + const unsigned ntotal = + ototal + count; // resulting total pwd's + + // allocate/expand + if (x_groups) { + struct group *t_groups = (struct group *)realloc(x_groups, + (sizeof(struct group) * ntotal) + cbufsz + bufsz); + const int addrdiff = ((char *)t_groups - (char *)x_groups) + + (sizeof(struct group) * count); + + if (NULL == t_groups) { // realloc failure + NetApiBufferFree(groups); + break; + } + + // reorg storage, insert 'count' pwd elements and adjust buffer addr's. + memmove(t_groups + ntotal, (const void *)(t_groups + ototal), cbufsz); + for (i = 0; i < ototal; ++i) { + t_groups[i].gr_name += addrdiff; + } + x_groups = t_groups; + + } else { + x_groups = (struct group *)malloc((sizeof(struct group) * count) + bufsz /*non-zero*/); + } + + // publish + if (NULL != x_groups) { + struct group *grp = x_groups + ototal; + char *cursor = ((char *)(x_groups + ntotal)) + cbufsz; +#if defined(_DEBUG) + wchar_t t_buffer[1024]; +#endif + + cbufsz += bufsz; // resulting name storage (inc nul) + + for (i = 0; i < dwEntriesRead; ++i) { + const PGROUP_INFO_2 group = groups + i; + + if ((int)group->grpi2_group_id == x_group.gr_gid || + (nlen = w32_wc2utf(group->grpi2_name, name, sizeof(name))) <= 0) { + continue; + } + +#if defined(_DEBUG) + swprintf_s(t_buffer, _countof(t_buffer), L"Group:%s,FullName:%s,RID:%u\n", + group->grpi2_name, group->grpi2_comment, (unsigned)group->grpi2_group_id); + OutputDebugStringW(t_buffer); +#endif + + memset(grp, 0, sizeof(*grp)); + grp->gr_name = cursor; + _strlwr(cursor); + grp->gr_gid = (short) group->grpi2_group_id; + cursor += (nlen + 1); + bufsz -= (nlen + 1); + ++x_groups_count; + --count; + ++grp; + } + +#if (TODO) + if (NERR_Success == nStatus) // last iteration. + for (i = 0; i < _countof(well_known_sids); ++i) { + const int nlen = fill_builtin(well_known_sids + i, pwd, cursor, bufsz); + if (nlen > 0) { + cursor += (nlen + 1); + bufsz -= (nlen + 1); + ++x_passwds_count; + --count; + ++pwd; + } + } +#endif + + assert(0 == count); + assert(0 == bufsz); + + } else { + nStatus = ERROR_NOT_ENOUGH_MEMORY; + } + } + + NetApiBufferFree(groups); + + } while (ERROR_MORE_DATA == nStatus); +} + + +static unsigned +RID(PSID sid) +{ + // Example: S-1-5-32-544 + // Returns the last component, 544. + const int subAuthorities = *GetSidSubAuthorityCount(sid); + if (subAuthorities >= 1) { // last sub-authority value. + return *GetSidSubAuthority(sid, subAuthorities - 1); + // Last component should be the user's relative identifier (RID). + // It uniquely defines this user account to SAM within the domain. + } + return 0; +} + + +static void +fill_group(void) +{ + const struct group *grp = w32_group_user(); + copy_group(grp, &x_group, x_buffer, sizeof(x_buffer)); +} + + +static int +gr_strlen(const char *s, size_t *total) +{ + if (s && *s) { + const int slen = strlen(s); + *total += (slen + 1); + return slen; + } + *total += 1; + return 0; +} + + +static char * +gr_strcpy(const char *s, size_t slen, char **cursor) +{ + char *dst = *cursor, *base = dst; + if (slen) { + memcpy(dst, s, slen), dst += slen; + } + *dst++ = 0; + *cursor = dst; + return base; +} + + +static int +copy_group(const struct group *grp, struct group *dst, char *buffer, size_t bufsize) +{ + size_t total = 0; + const size_t + namelen = gr_strlen(grp->gr_name, &total), + passwdlen = gr_strlen(grp->gr_passwd, &total); + + if (total > bufsize) { + return (errno = ERANGE); + } else if (NULL == dst) { + return (errno = EINVAL); + } + + dst->gr_name = gr_strcpy(grp->gr_name, namelen, &buffer); + dst->gr_passwd = gr_strcpy(grp->gr_passwd, passwdlen, &buffer); + dst->gr_gid = grp->gr_gid; + dst->gr_mem = NULL; + + return 0; //success +} + +/*end*/ diff --git a/libw32/w32_hunspell.c b/libw32/w32_hunspell.c index aceec08f..3262fb77 100644 --- a/libw32/w32_hunspell.c +++ b/libw32/w32_hunspell.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_hunspell_c,"$Id: w32_hunspell.c,v 1.18 2020/06/18 13:24:24 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_hunspell_c,"$Id: w32_hunspell.c,v 1.19 2022/03/21 14:29:40 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_hunspell_c,"$Id: w32_hunspell.c,v 1.18 2020/06/18 13:24:24 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from diff --git a/libw32/w32_iconv.c b/libw32/w32_iconv.c index 16afcd9d..3a2cac38 100644 --- a/libw32/w32_iconv.c +++ b/libw32/w32_iconv.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_iconv_c,"$Id: w32_iconv.c,v 1.17 2020/06/18 13:24:42 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_iconv_c,"$Id: w32_iconv.c,v 1.20 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 iconv dynamic loader. * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_iconv_c,"$Id: w32_iconv.c,v 1.17 2020/06/18 13:24:42 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -58,6 +58,13 @@ __CIDENT_RCSID(gr_w32_iconv_c,"$Id: w32_iconv.c,v 1.17 2020/06/18 13:24:42 cvsus typedef void * (DLLLINKAGE * iconvopenfn_t)(const char *to, const char *from); typedef void (DLLLINKAGE * iconvclosefn_t)(void *fd); typedef int (DLLLINKAGE * iconvfn_t)(void *fd, const char **from, size_t *fromlen, char **to, size_t *tolen); +typedef int (DLLLINKAGE * iconverrnofn_t)(void); + +#if defined(HAVE_LIBCITRUS) +typedef const char * (DLLLINKAGE * iconv_PATH_ESDB_t)(void); +typedef const char * (DLLLINKAGE * iconv_PATH_CSMAPPER_t)(void); +typedef const char * (DLLLINKAGE * iconv_PATH_ICONV_t)(void); +#endif static HINSTANCE x_iconvdll; static HINSTANCE x_msvcrtdll; @@ -65,28 +72,37 @@ static HINSTANCE x_msvcrtdll; static iconvopenfn_t x_iconv_open; static iconvclosefn_t x_iconv_close; static iconvfn_t x_iconv; -// static void * x_iconvctl; -// static void * x_iconv_errno; +// static void * x_iconvctl; +// static void * x_iconv_errno; -LIBW32_API int -w32_iconv_connect(int verbose) -{ -#ifndef MSVCRTDLL_NAME -#define MSVCRTDLL_NAME "msvcrt.dll" -#endif - static const char *iconvnames[] = { +static const char * x_iconvnames[] = { + NULL, // place-holder #if defined(ICONVDLL_NAME) - ICONVDLL_NAME, // configuration + ICONVDLL_NAME, // compile-time configuration #else -#define ICONVDLL_NAME "[lib]iconv[2].dll" +#define ICONVDLL_NAME "[lib]iconv[2].dll" // dynamic "libiconv2.dll", "libiconv.dll", "iconv2.dll", "iconv.dll", #endif - NULL }; + +LIBW32_API void +w32_iconv_dllname(const char *dllname) +{ + if (x_iconvnames[0]) free((void *)x_iconvnames[0]); + x_iconvnames[0] = (dllname && *dllname ? strdup(dllname) : NULL); +} + + +LIBW32_API int +w32_iconv_connect(int verbose) +{ +#ifndef MSVCRTDLL_NAME +#define MSVCRTDLL_NAME "msvcrt.dll" +#endif const char *name; char fullname[1024], *end; unsigned i; @@ -96,15 +112,21 @@ w32_iconv_connect(int verbose) } fullname[0] = 0; - GetModuleFileName(GetModuleHandle(NULL), fullname, sizeof(fullname)); + GetModuleFileNameA(GetModuleHandle(NULL), fullname, sizeof(fullname)); if (NULL != (end = (char *)strrchr(fullname, '\\'))) { *++end = 0; } - for (i = 0; NULL != (name = iconvnames[i]); ++i) { + for (i = 0; i < sizeof(x_iconvnames)/sizeof(x_iconvnames[0]); ++i) { + + if (NULL == (name = x_iconvnames[i])) { + continue; // empty slot + } + #if defined(DO_TRACE_LOG) trace_log("iconv_dll(%s)\n", name); #endif + if (end) { strncpy(end, name, sizeof(fullname) - (end - fullname)); fullname[sizeof(fullname)-1] = 0; @@ -147,10 +169,16 @@ w32_iconv_connect(int verbose) fullname[0] = 0; // resolve symbols, iconvctl() is optional GetModuleFileNameA(x_iconvdll, fullname, sizeof(fullname)); - x_iconv = (iconvfn_t)GetProcAddress(x_iconvdll, "libiconv"); - x_iconv_open = (iconvopenfn_t)GetProcAddress(x_iconvdll, "libiconv_open"); - x_iconv_close = (iconvclosefn_t)GetProcAddress(x_iconvdll, "libiconv_close"); -// x_iconvctl = (void *)GetProcAddress(x_iconvdll, "libiconvctl"); + if (NULL != (x_iconv = (iconvfn_t)GetProcAddress(x_iconvdll, "libiconv"))) { + x_iconv_open = (iconvopenfn_t)GetProcAddress(x_iconvdll, "libiconv_open"); + x_iconv_close = (iconvclosefn_t)GetProcAddress(x_iconvdll, "libiconv_close"); + + } else if (NULL != (x_iconv = (iconvfn_t)GetProcAddress(x_iconvdll, "iconv"))) { + x_iconv_open = (iconvopenfn_t)GetProcAddress(x_iconvdll, "iconv_open"); + x_iconv_close = (iconvclosefn_t)GetProcAddress(x_iconvdll, "iconv_close"); + } + +// x_iconvctl = (void *)GetProcAddress(x_iconvdll, "libiconvctl"); // x_iconv_errno = (void *)GetProcAddress(x_iconvdll, "libiconv_errno"); // if (NULL == x_iconv_errno) { // x_iconv_errno = (void *)GetProcAddress(x_msvcrtdll, "_errno"); @@ -234,4 +262,3 @@ w32_iconv(void * fd, const char **from, size_t *fromlen, char **to, size_t *tole #endif /*WIN32*/ /*end*/ - diff --git a/libw32/w32_ino.c b/libw32/w32_ino.c index 05d180db..7f8265af 100644 --- a/libw32/w32_ino.c +++ b/libw32/w32_ino.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_ino_c,"$Id: w32_ino.c,v 1.13 2020/04/20 23:18:24 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_ino_c,"$Id: w32_ino.c,v 1.15 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 ino implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_ino_c,"$Id: w32_ino.c,v 1.13 2020/04/20 23:18:24 cvsuser E * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -72,6 +72,34 @@ w32_ino_hash(const char *name) } +/* + * w32_ino_has --- + * Generate a file inode based on a simple hash of the specific file-name. + */ +LIBW32_API ino_t +w32_ino_whash(const wchar_t *name) +{ + const wchar_t *p = name; + short hash = 0; + wchar_t c; + + if (name[0] && name[1] == ':') { + p += 2; /* remove drive */ + } + + for (;*p; ++p) { + if (ISSLASH(*p)) { /* convert slashes */ + c = '/'; + } else { + c = *p; + if (c < 0x7f) c = (wchar_t)tolower((char)c); + } + hash = (hash << 7) + hash + (ino_t)c; + } + return hash + (ino_t)(p - name); +} + + /* * w32_ino_gen --- * Generate a file-name inode based on specific file index. @@ -192,5 +220,21 @@ w32_ino_file(const char *path) return 0; } -/*end*/ +LIBW32_API ino_t +w32_ino_wfile(const wchar_t *path) +{ + HANDLE handle; + + if (NULL != path && *path && + INVALID_HANDLE_VALUE != (handle = + CreateFileW(path, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, NULL))) { + const ino_t ino = w32_ino_handle(handle); + CloseHandle(handle); + return ino; + } + return 0; +} + +/*end*/ diff --git a/libw32/w32_io.c b/libw32/w32_io.c index cce46ef4..39f7fc3c 100644 --- a/libw32/w32_io.c +++ b/libw32/w32_io.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_io_c,"$Id: w32_io.c,v 1.37 2020/05/04 00:00:01 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_io_c,"$Id: w32_io.c,v 1.39 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* @@ -7,7 +7,7 @@ __CIDENT_RCSID(gr_w32_io_c,"$Id: w32_io.c,v 1.37 2020/05/04 00:00:01 cvsuser Exp * * stat, lstat, fstat, readlink, symlink, open * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -23,10 +23,10 @@ __CIDENT_RCSID(gr_w32_io_c,"$Id: w32_io.c,v 1.37 2020/05/04 00:00:01 cvsuser Exp * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -53,6 +53,10 @@ __CIDENT_RCSID(gr_w32_io_c,"$Id: w32_io.c,v 1.37 2020/05/04 00:00:01 cvsuser Exp #include /* SHSTDAPI */ #endif #include /* shell interface */ +#include /* wide-char support */ +#include +#include +#include #define PSAPI_VERSION 1 /* GetMappedFileName and psapi.dll */ #include @@ -72,6 +76,12 @@ __CIDENT_RCSID(gr_w32_io_c,"$Id: w32_io.c,v 1.37 2020/05/04 00:00:01 cvsuser Exp #ifdef HAVE_SYS_TIME_H #include #endif +#ifdef HAVE_WCHAR_H +#include +#endif +#if defined(_DEBUG) +#include +#endif #include #include #include @@ -86,41 +96,69 @@ __CIDENT_RCSID(gr_w32_io_c,"$Id: w32_io.c,v 1.37 2020/05/04 00:00:01 cvsuser Exp #pragma warning(disable : 4312) // type cast' : conversion from 'xxx' to 'xxx' of greater size #endif +typedef DWORD (WINAPI *GetFinalPathNameByHandleW_t)( + HANDLE hFile, LPWSTR lpszFilePath, DWORD length, DWORD dwFlags); + typedef DWORD (WINAPI *GetFinalPathNameByHandleA_t)( HANDLE hFile, LPSTR lpszFilePath, DWORD length, DWORD dwFlags); +typedef BOOL (WINAPI *CreateSymbolicLinkW_t)( + LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags); + typedef BOOL (WINAPI *CreateSymbolicLinkA_t)( - LPCSTR lpSymlinkFileName, LPCSTR lpTargetFileName, DWORD dwFlags); + LPCSTR lpSymlinkFileName, LPCSTR lpTargetFileName, DWORD dwFlags); typedef BOOL (WINAPI *GetVolumeInformationByHandleW_t)( HANDLE hFile, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize); -static DWORD my_GetFinalPathNameByHandle(HANDLE handle, char *name, int length); -static DWORD WINAPI my_GetFinalPathNameByHandleImp(HANDLE handle, LPSTR name, DWORD length, DWORD dwFlags); +static DWORD my_GetFinalPathNameByHandleW(HANDLE handle, LPWSTR name, int length); +static DWORD WINAPI my_GetFinalPathNameByHandleWImp(HANDLE handle, LPWSTR name, DWORD length, DWORD dwFlags); -static BOOL my_CreateSymbolicLink(const char *lpSymlinkFileName, const char *lpTargetFileName, DWORD dwFlags); -static BOOL WINAPI my_CreateSymbolicLinkImp(LPCSTR lpSymlinkFileName, LPCSTR lpTargetFileName, DWORD dwFlags); +static DWORD my_GetFinalPathNameByHandleA(HANDLE handle, LPSTR name, int length); +static DWORD WINAPI my_GetFinalPathNameByHandleAImp(HANDLE handle, LPSTR name, DWORD length, DWORD dwFlags); + +static DWORD my_GetFinalPathNameByHandleA(HANDLE handle, LPSTR name, int length); +static DWORD WINAPI my_GetFinalPathNameByHandleAImp(HANDLE handle, LPSTR name, DWORD length, DWORD dwFlags); + +static BOOL my_CreateSymbolicLinkW(LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags); +static BOOL WINAPI my_CreateSymbolicLinkWImp(LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags); + +static BOOL my_CreateSymbolicLinkA(const char *lpSymlinkFileName, const char *lpTargetFileName, DWORD dwFlags); +static BOOL WINAPI my_CreateSymbolicLinkAImp(const char *lpSymlinkFileName, const char *lpTargetFileName, DWORD dwFlags); static BOOL isshortcut(const char *name); -static void ApplyAttributes(struct stat *sb, const DWORD dwAttr, const char *name, const char *magic); +static void ApplyAttributesA(struct stat *sb, const DWORD dwAttr, const char *name, const char *magic); +static void ApplyAttributesW(struct stat *sb, const DWORD dwAttr, const wchar_t *name, const char *magic); +static void ApplyOwner(struct stat *sb, const DWORD dwAttributes, HANDLE handle); static void ApplyTimes(struct stat *sb, const FILETIME *ftCreationTime, - const FILETIME *ftLastAccessTime, const FILETIME *ftLastWriteTime); + const FILETIME *ftLastAccessTime, const FILETIME *ftLastWriteTime); static void ApplySize(struct stat *sb, const DWORD nFileSizeLow, const DWORD nFileSizeHigh); static time_t ConvertTime(const FILETIME *ft); -static BOOL IsExec(const char *name, const char *magic); -static const char * HasExtension(const char *name); -static BOOL IsExtension(const char *name, const char *ext); +static int IsScriptMagic(const char *magic); +static BOOL IsExecA(const char *name, const char *magic); +static BOOL IsExecW(const wchar_t *name, const char *magic); +static const char * HasExtensionA(const char *name); +static const wchar_t * HasExtensionW(const wchar_t *name); +static BOOL IsExtensionA(const char *name, const char *ext); +static BOOL IsExtensionW(const wchar_t *name, const char *ext); + +static int ReadlinkA(const char *path, const char **suffixes, char *buf, int maxlen); +static int ReadlinkW(const wchar_t *path, const char **suffixes, wchar_t *buf, int maxlen); +static int ReadShortcutA(const char *name, char *buf, int maxlen); +static int ReadShortcutW(const wchar_t *name, wchar_t *buf, int maxlen); -static int Readlink(const char *path, const char **suffixes, char *buf, int maxlen); -static int ReadShortcut(const char *name, char *buf, int maxlen); -static int CreateShortcut(const char *link, const char *name, const char *working, const char *desc); -static int Stat(const char *name, struct stat *sb); +static int CreateShortcutA(const char *link, const char *name, const char *working, const char *desc); + +static int StatA(const char *name, struct stat *sb); +static int StatW(const wchar_t *name, struct stat *sb); static BOOL my_GetVolumeInformationByHandle(HANDLE handle, DWORD *serialno, DWORD *flags); static BOOL WINAPI my_GetVolumeInformationByHandleImp(HANDLE, LPWSTR, DWORD, LPDWORD, LPDWORD, LPDWORD, LPWSTR, DWORD); +static int x_utf8filenames = 0; + static const char * suffixes_null[] = { "", NULL }; @@ -129,6 +167,36 @@ static const char * suffixes_default[] = { }; +/* +// NAME +// w32_utf8filenames_enable - enable UTF8 flenames +// +// SYNOPSIS +// #include +// +// int w32_utf8filenames_enable(void); +// int w32_utf8filenames_state(void); +// +// RETURN VALUE +// w32_utf8filenames_enable() returns the previous state, whereas w32_utf8filenames_state() +// returns the current UTF8 filename handling status. +*/ +LIBW32_API int +w32_utf8filenames_enable (void) +{ + const int previous = x_utf8filenames; + x_utf8filenames = 1; + return previous; +} + + +LIBW32_API int +w32_utf8filenames_state (void) +{ + return x_utf8filenames; +} + + /* // NAME // stat - get file status @@ -213,24 +281,78 @@ static const char * suffixes_default[] = { LIBW32_API int w32_stat(const char *path, struct stat *sb) { - char symbuf[WIN32_PATH_MAX]; +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path || NULL == sb) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return w32_statW(wpath, sb); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_statA(path, sb); +} + + +LIBW32_API int +w32_statA(const char *path, struct stat *sb) +{ + char symbuf[WIN32_PATH_MAX] = {0}; int ret = 0; if (NULL == path || NULL == sb) { ret = -EFAULT; + } else { + (void) memset(sb, 0, sizeof(struct stat)); + if ((ret = ReadlinkA(path, (void *)-1, symbuf, sizeof(symbuf))) > 0) { + path = symbuf; + } + } + + if (ret < 0 || (ret = StatA(path, sb)) < 0) { + if (-ENOTDIR == ret) { // component error. + if (path != symbuf && // expand embedded shortcut + w32_lnkexpandA(path, symbuf, _countof(symbuf), SHORTCUT_COMPONENT)) { + if ((ret = StatA(symbuf, sb)) >= 0) { + return ret; + } + } + } + errno = -ret; + return -1; + } + return 0; +} + + +LIBW32_API int +w32_statW(const wchar_t *path, struct stat *sb) +{ + wchar_t symbuf[WIN32_PATH_MAX] = {0}; + int ret = 0; + if (NULL == path || NULL == sb) { + ret = -EFAULT; } else { (void) memset(sb, 0, sizeof(struct stat)); - if ((ret = Readlink(path, (void *)-1, symbuf, sizeof(symbuf))) > 0) { + if ((ret = ReadlinkW(path, (void *)-1, symbuf, _countof(symbuf))) > 0) { path = symbuf; } } - if (ret < 0 || (ret = Stat(path, sb)) < 0) { - if (-ENOTDIR == ret) { // component error. + if (ret < 0 || (ret = StatW(path, sb)) < 0) { + if (-ENOTDIR == ret) { // component error. if (path != symbuf && // expand embedded shortcut - w32_shortcut_expand(path, symbuf, sizeof(symbuf), SHORTCUT_COMPONENT)) { - if ((ret = Stat(symbuf, sb)) >= 0) { + w32_lnkexpandW(path, symbuf, _countof(symbuf), SHORTCUT_COMPONENT)) { + if ((ret = StatW(symbuf, sb)) >= 0) { return ret; } } @@ -313,6 +435,30 @@ w32_stat(const char *path, struct stat *sb) */ LIBW32_API int w32_lstat(const char *path, struct stat *sb) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path || NULL == sb) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return w32_lstatW(wpath, sb); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_lstatA(path, sb); +} + + +LIBW32_API int +w32_lstatA(const char *path, struct stat *sb) { int ret = 0; @@ -322,12 +468,40 @@ w32_lstat(const char *path, struct stat *sb) (void) memset(sb, 0, sizeof(struct stat)); } - if (ret < 0 || (ret = Stat(path, sb)) < 0) { + if (ret < 0 || (ret = StatA(path, sb)) < 0) { if (-ENOTDIR == ret) { // component error. char lnkbuf[WIN32_PATH_MAX]; // expand embedded shortcut - if (w32_shortcut_expand(path, lnkbuf, sizeof(lnkbuf), SHORTCUT_COMPONENT)) { - if ((ret = Stat(lnkbuf, sb)) >= 0) { + if (w32_lnkexpandA(path, lnkbuf, _countof(lnkbuf), SHORTCUT_COMPONENT)) { + if ((ret = StatA(lnkbuf, sb)) >= 0) { + return ret; + } + } + } + errno = -ret; + return -1; + } + return 0; +} + + +LIBW32_API int +w32_lstatW(const wchar_t *path, struct stat *sb) +{ + int ret = 0; + + if (path == NULL || sb == NULL) { + ret = -EFAULT; + } else { + (void) memset(sb, 0, sizeof(struct stat)); + } + + if (ret < 0 || (ret = StatW(path, sb)) < 0) { + if (-ENOTDIR == ret) { // component error. + wchar_t lnkbuf[WIN32_PATH_MAX]; + // expand embedded shortcut + if (w32_lnkexpandW(path, lnkbuf, _countof(lnkbuf), SHORTCUT_COMPONENT)) { + if ((ret = StatW(lnkbuf, sb)) >= 0) { return ret; } } @@ -405,6 +579,21 @@ w32_lstat(const char *path, struct stat *sb) */ LIBW32_API int w32_fstat(int fd, struct stat *sb) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + return w32_fstatW(fd, sb); + } +#endif //UTF8FILENAMES + + return w32_fstatA(fd, sb); +} + + +/////////////////////////////////////////////////////////////////////////////// + +LIBW32_API int +w32_fstatW(int fd, struct stat *sb) { HANDLE handle; int ret = 0; @@ -437,12 +626,13 @@ w32_fstat(int fd, struct stat *sb) BY_HANDLE_FILE_INFORMATION fi = {0}; if (GetFileInformationByHandle(handle, &fi)) { - char t_name[MAX_PATH], *name = NULL; + wchar_t t_name[MAX_PATH], *name = NULL; - if (my_GetFinalPathNameByHandle(handle, t_name, sizeof(t_name))) { + if (my_GetFinalPathNameByHandleW(handle, t_name, _countof(t_name))) { name = t_name; // resolved filename. } - ApplyAttributes(sb, fi.dwFileAttributes, name, NULL); + ApplyAttributesW(sb, fi.dwFileAttributes, name, NULL); + ApplyOwner(sb, fi.dwFileAttributes, handle); ApplyTimes(sb, &fi.ftCreationTime, &fi.ftLastAccessTime, &fi.ftLastWriteTime); ApplySize(sb, fi.nFileSizeLow, fi.nFileSizeHigh); if (fi.nNumberOfLinks > 0) { @@ -481,18 +671,18 @@ w32_fstat(int fd, struct stat *sb) static DWORD -my_GetFinalPathNameByHandle(HANDLE handle, char *path, int length) +my_GetFinalPathNameByHandleW(HANDLE handle, LPWSTR path, int length) { - static GetFinalPathNameByHandleA_t x_GetFinalPathNameByHandleA = NULL; + static GetFinalPathNameByHandleW_t x_GetFinalPathNameByHandleW = NULL; - if (NULL == x_GetFinalPathNameByHandleA) { + if (NULL == x_GetFinalPathNameByHandleW) { HINSTANCE hinst; // Vista+ if (0 == (hinst = LoadLibraryA("Kernel32")) || - 0 == (x_GetFinalPathNameByHandleA = - (GetFinalPathNameByHandleA_t)GetProcAddress(hinst, "GetFinalPathNameByHandleA"))) { + 0 == (x_GetFinalPathNameByHandleW = + (GetFinalPathNameByHandleW_t)GetProcAddress(hinst, "GetFinalPathNameByHandleW"))) { // XP+ - x_GetFinalPathNameByHandleA = my_GetFinalPathNameByHandleImp; + x_GetFinalPathNameByHandleW = my_GetFinalPathNameByHandleWImp; (void)FreeLibrary(hinst); } } @@ -502,12 +692,12 @@ my_GetFinalPathNameByHandle(HANDLE handle, char *path, int length) #define VOLUME_NAME_DOS 0 #endif - return x_GetFinalPathNameByHandleA(handle, path, length, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + return x_GetFinalPathNameByHandleW(handle, path, length, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); } static DWORD WINAPI -my_GetFinalPathNameByHandleImp(HANDLE handle, LPSTR path, DWORD length, DWORD flags) +my_GetFinalPathNameByHandleWImp(HANDLE handle, LPWSTR path, DWORD length, DWORD flags) { // Determine underlying file-name, XP+ HANDLE map; DWORD ret; @@ -520,49 +710,42 @@ my_GetFinalPathNameByHandleImp(HANDLE handle, LPSTR path, DWORD length, DWORD fl ret = 0; - if (0 != (map = CreateFileMapping(handle, NULL, PAGE_READONLY, 0, 1, NULL))) { + if (0 != (map = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 1, NULL))) { LPVOID pmem = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 1); if (pmem) { // XP+ - if (GetMappedFileNameA(GetCurrentProcess(), pmem, path, length)) { + if (GetMappedFileNameW(GetCurrentProcess(), pmem, path, length)) { // // Translate path with device name to drive letters, for example: // // \Device\Volume4\ - // // => F:\ // - char t_drives[512] = {0}; // 27*4 ... + wchar_t t_drives[512] = {0}; // 27*4 ... - if (GetLogicalDriveStringsA(sizeof(t_drives) - 1, t_drives)) { + if (GetLogicalDriveStringsW(sizeof(t_drives) - 1, t_drives)) { BOOL found = FALSE; - const char *p = t_drives; - char t_name[MAX_PATH]; - char t_drive[3] = " :"; + const wchar_t *p = t_drives; + wchar_t t_name[MAX_PATH]; + wchar_t t_drive[3] = L" :"; do { // Look up each device name t_drive[0] = *p; - if (QueryDosDeviceA(t_drive, t_name, sizeof(t_name) - 1)) { - const size_t namelen = strlen(t_name); + if (QueryDosDeviceW(t_drive, t_name, _countof(t_name) - 1)) { + const size_t namelen = wcslen(t_name); if (namelen < MAX_PATH) { - found = (0 == _strnicmp(path, t_name, namelen) && - path[namelen] == '\\'); - - if (found) { - // - // Reconstruct path, replacing device path with DOS path - // - char t_path[MAX_PATH]; - size_t len; - - len = _snprintf(t_path, sizeof(t_path), "%s%s", t_drive, path + namelen); - t_path[sizeof(t_path) - 1] = 0; - memcpy(path, (const char *)t_path, (len < length ? len + 1 : length)); - path[length - 1] = 0; + found = (0 == _wcsnicmp(path, t_name, namelen) && path[namelen] == '\\'); + + if (found) { // Reconstruct path, replacing device with drive + wmemmove(path + 3, path + namelen, wcslen(path + namelen) + 1); + path[0] = *p; + path[1] = ':'; + path[2] = '\\'; ret = 1; + break; } } } @@ -571,7 +754,6 @@ my_GetFinalPathNameByHandleImp(HANDLE handle, LPSTR path, DWORD length, DWORD fl } while (!found && *p); // end of string } - ret = 1; } (void) UnmapViewOfFile(pmem); } @@ -581,134 +763,342 @@ my_GetFinalPathNameByHandleImp(HANDLE handle, LPSTR path, DWORD length, DWORD fl } +/////////////////////////////////////////////////////////////////////////////// -/* -// NAME -// readlink - read the contents of a symbolic link -// -// SYNOPSIS -// -// #include -// -// ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize); -// -// DESCRIPTION -// The readlink() function shall place the contents of the symbolic link referred to -// by path in the buffer buf which has size bufsize. If the number of bytes in the -// symbolic link is less than bufsize, the contents of the remainder of buf are -// unspecified. If the buf argument is not large enough to contain the link content, -// the first bufsize bytes shall be placed in buf. -// -// If the value of bufsize is greater than {SSIZE_MAX}, the result is -// implementation-defined. -// -// RETURN VALUE -// Upon successful completion, readlink() shall return the count of bytes placed in -// the buffer. Otherwise, it shall return a value of -1, leave the buffer unchanged, -// and set errno to indicate the error. -// -// ERRORS -// -// The readlink() function shall fail if: -// -// [EACCES] -// Search permission is denied for a component of the path prefix of path. -// -// [EINVAL] -// The path argument names a file that is not a symbolic link. -// -// [EIO] -// An I/O error occurred while reading from the file system. -// -// [ELOOP] -// A loop exists in symbolic links encountered during resolution of the path -// argument. -// -// [ENAMETOOLONG] -// The length of the path argument exceeds {PATH_MAX} or a pathname component is -// longer than {NAME_MAX}. -// -// [ENOENT] -// A component of path does not name an existing file or path is an empty string. -// -// [ENOTDIR] -// A component of the path prefix is not a directory. -// -// The readlink() function may fail if: -// -// [EACCES] -// Read permission is denied for the directory. -// -// [ELOOP] -// More than {SYMLOOP_MAX} symbolic links were encountered during resolution of -// the path argument. -// -// [ENAMETOOLONG] -// As a result of encountering a symbolic link in resolution of the path argument, -// the length of the substituted pathname string exceeded {PATH_MAX}. -// -// -// NOTES: -// Portable applications should not assume that the returned contents of -// the symblic link are null-terminated. -*/ LIBW32_API int -w32_readlink(const char *path, char *buf, int maxlen) +w32_fstatA(int fd, struct stat *sb) { + HANDLE handle; int ret = 0; - if (path == NULL || buf == NULL) { + if (NULL == sb) { ret = -EFAULT; - } else if (0 == (ret = Readlink(path, (void *)-1, buf, maxlen))) { - ret = -EINVAL; /* not a symlink */ - } + } else { + memset(sb, 0, sizeof(struct stat)); - if (ret < 0) { - errno = -ret; - return -1; - } - return ret; -} + if (fd < 0) { + ret = -EBADF; + } else if ((handle = ((HANDLE) _get_osfhandle(fd))) == INVALID_HANDLE_VALUE) { + // socket, a named pipe, or an anonymous pipe. + if (fd > WIN32_FILDES_MAX && FILE_TYPE_PIPE == GetFileType((HANDLE) fd)) { + sb->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; + sb->st_mode |= S_IFIFO; + sb->st_dev = sb->st_rdev = 1; -/* -// NAME -// symlink - make a symbolic link to a file -// -// SYNOPSIS -// -// #include -// -// int symlink(const char *path1, const char *path2); -// -// DESCRIPTION -// The symlink() function shall create a symbolic link called path2 that contains the -// string pointed to by path1 ( path2 is the name of the symbolic link created, path1 -// is the string contained in the symbolic link). -// -// The string pointed to by path1 shall be treated only as a character string and -// shall not be validated as a pathname. -// -// If the symlink() function fails for any reason other than [EIO], any file named by -// path2 shall be unaffected. -// -// RETURN VALUE -// Upon successful completion, symlink() shall return 0; otherwise, it shall return -1 -// and set errno to indicate the error. -// -// ERRORS -// The symlink() function shall fail if: -// -// [EACCES] -// Write permission is denied in the directory where the symbolic link is being -// created, or search permission is denied for a component of the path prefix of -// path2. -// -// [EEXIST] -// The path2 argument names an existing file or symbolic link. -// -// [EIO] + } else { + ret = -EBADF; + } + + } else { + const DWORD ftype = GetFileType(handle); + + switch (ftype) { + case FILE_TYPE_DISK: { // disk file. + BY_HANDLE_FILE_INFORMATION fi = {0}; + + if (GetFileInformationByHandle(handle, &fi)) { + char t_name[MAX_PATH], *name = NULL; + + if (my_GetFinalPathNameByHandleA(handle, t_name, sizeof(t_name))) { + name = t_name; // resolved filename. + } + ApplyAttributesA(sb, fi.dwFileAttributes, name, NULL); + ApplyOwner(sb, fi.dwFileAttributes, handle); + ApplyTimes(sb, &fi.ftCreationTime, &fi.ftLastAccessTime, &fi.ftLastWriteTime); + ApplySize(sb, fi.nFileSizeLow, fi.nFileSizeHigh); + if (fi.nNumberOfLinks > 0) { + sb->st_nlink = (int)fi.nNumberOfLinks; + } + } + } + break; + + case FILE_TYPE_CHAR: // character file, typically an LPT device or a console. + case FILE_TYPE_PIPE: // socket, a named pipe, or an anonymous pipe. + sb->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; + if (FILE_TYPE_PIPE == ftype) { + sb->st_mode |= S_IFIFO; + } else { + sb->st_mode |= S_IFCHR; + } + sb->st_dev = sb->st_rdev = 1; + break; + + case FILE_TYPE_REMOTE: + case FILE_TYPE_UNKNOWN: // others + default: + ret = -EBADF; + break; + } + } + } + + if (ret < 0) { + errno = -ret; + return -1; + } + return 0; +} + + +static DWORD +my_GetFinalPathNameByHandleA(HANDLE handle, char *path, int length) +{ + static GetFinalPathNameByHandleA_t x_GetFinalPathNameByHandleA = NULL; + + if (NULL == x_GetFinalPathNameByHandleA) { + HINSTANCE hinst; // Vista+ + + if (0 == (hinst = LoadLibraryA("Kernel32")) || + 0 == (x_GetFinalPathNameByHandleA = + (GetFinalPathNameByHandleA_t)GetProcAddress(hinst, "GetFinalPathNameByHandleA"))) { + // XP+ + x_GetFinalPathNameByHandleA = my_GetFinalPathNameByHandleAImp; + (void)FreeLibrary(hinst); + } + } + +#ifndef FILE_NAME_NORMALIZED +#define FILE_NAME_NORMALIZED 0 +#define VOLUME_NAME_DOS 0 +#endif + + return x_GetFinalPathNameByHandleA(handle, path, length, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); +} + + +static DWORD WINAPI +my_GetFinalPathNameByHandleAImp(HANDLE handle, LPSTR path, DWORD length, DWORD flags) +{ // Determine underlying file-name, XP+ + HANDLE map; + DWORD ret; + + __CUNUSED(flags) + + if (0 == GetFileSize(handle, &ret) && 0 == ret) { + return 0; // Cannot map a file with a length of zero + } + + ret = 0; + + if (0 != (map = CreateFileMappingA(handle, NULL, PAGE_READONLY, 0, 1, NULL))) { + LPVOID pmem = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 1); + + if (pmem) { // XP+ + if (GetMappedFileNameA(GetCurrentProcess(), pmem, path, length)) { + // + // Translate path with device name to drive letters, for example: + // + // \Device\Volume4\ + // => F:\ + // + char t_drives[512] = {0}; // 27*4 ... + + if (GetLogicalDriveStringsA(sizeof(t_drives) - 1, t_drives)) { + + BOOL found = FALSE; + const char *p = t_drives; + char t_name[MAX_PATH]; + char t_drive[3] = " :"; + + do { // Look up each device name + t_drive[0] = *p; + + if (QueryDosDeviceA(t_drive, t_name, sizeof(t_name) - 1)) { + const size_t namelen = strlen(t_name); + + if (namelen < MAX_PATH) { + found = (0 == _strnicmp(path, t_name, namelen) && path[namelen] == '\\'); + + if (found) { // Reconstruct path, replacing device with drive + memmove(path + 2, path + namelen, strlen(path + namelen) + 1); + path[0] = *p; + path[1] = ':'; + path[2] = '\\'; + ret = 1; + break; + } + } + } + + while (*p++); // Go to the next NULL character. + + } while (!found && *p); // end of string + } + } + (void) UnmapViewOfFile(pmem); + } + (void) CloseHandle(map); + } + return ret; +} + + +/* +// NAME +// readlink - read the contents of a symbolic link +// +// SYNOPSIS +// +// #include +// +// ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize); +// +// DESCRIPTION +// The readlink() function shall place the contents of the symbolic link referred to +// by path in the buffer buf which has size bufsize. If the number of bytes in the +// symbolic link is less than bufsize, the contents of the remainder of buf are +// unspecified. If the buf argument is not large enough to contain the link content, +// the first bufsize bytes shall be placed in buf. +// +// If the value of bufsize is greater than {SSIZE_MAX}, the result is +// implementation-defined. +// +// RETURN VALUE +// Upon successful completion, readlink() shall return the count of bytes placed in +// the buffer. Otherwise, it shall return a value of -1, leave the buffer unchanged, +// and set errno to indicate the error. +// +// ERRORS +// +// The readlink() function shall fail if: +// +// [EACCES] +// Search permission is denied for a component of the path prefix of path. +// +// [EINVAL] +// The path argument names a file that is not a symbolic link. +// +// [EIO] +// An I/O error occurred while reading from the file system. +// +// [ELOOP] +// A loop exists in symbolic links encountered during resolution of the path +// argument. +// +// [ENAMETOOLONG] +// The length of the path argument exceeds {PATH_MAX} or a pathname component is +// longer than {NAME_MAX}. +// +// [ENOENT] +// A component of path does not name an existing file or path is an empty string. +// +// [ENOTDIR] +// A component of the path prefix is not a directory. +// +// The readlink() function may fail if: +// +// [EACCES] +// Read permission is denied for the directory. +// +// [ELOOP] +// More than {SYMLOOP_MAX} symbolic links were encountered during resolution of +// the path argument. +// +// [ENAMETOOLONG] +// As a result of encountering a symbolic link in resolution of the path argument, +// the length of the substituted pathname string exceeded {PATH_MAX}. +// +// +// NOTES: +// Portable applications should not assume that the returned contents of +// the symblic link are null-terminated. +*/ +LIBW32_API int +w32_readlink(const char *path, char *buf, int maxlen) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + if (w32_readlinkW(wpath, wpath, _countof(wpath)) > 0) { + return w32_wc2utf(wpath, buf, maxlen); + } + } + return -1; + } +#endif //UTF8FILENAMES + + return w32_readlinkA(path, buf, maxlen); +} + + +LIBW32_API int +w32_readlinkW(const wchar_t *path, wchar_t *buf, int maxlen) +{ + int ret = 0; + + if (path == NULL || buf == NULL) { + ret = -EFAULT; + } else if (0 == (ret = ReadlinkW(path, (void *)-1, buf, maxlen))) { + ret = -EINVAL; /* not a symlink */ + } + if (ret < 0) { + errno = -ret; + return -1; + } + return ret; +} + + +LIBW32_API int +w32_readlinkA(const char *path, char *buf, int maxlen) +{ + int ret = 0; + + if (path == NULL || buf == NULL) { + ret = -EFAULT; + } else if (0 == (ret = ReadlinkA(path, (void *)-1, buf, maxlen))) { + ret = -EINVAL; /* not a symlink */ + } + if (ret < 0) { + errno = -ret; + return -1; + } + return ret; +} + + +/* +// NAME +// symlink - make a symbolic link to a file +// +// SYNOPSIS +// +// #include +// +// int symlink(const char *path1, const char *path2); +// +// DESCRIPTION +// The symlink() function shall create a symbolic link called path2 that contains the +// string pointed to by path1 ( path2 is the name of the symbolic link created, path1 +// is the string contained in the symbolic link). +// +// The string pointed to by path1 shall be treated only as a character string and +// shall not be validated as a pathname. +// +// If the symlink() function fails for any reason other than [EIO], any file named by +// path2 shall be unaffected. +// +// RETURN VALUE +// Upon successful completion, symlink() shall return 0; otherwise, it shall return -1 +// and set errno to indicate the error. +// +// ERRORS +// The symlink() function shall fail if: +// +// [EACCES] +// Write permission is denied in the directory where the symbolic link is being +// created, or search permission is denied for a component of the path prefix of +// path2. +// +// [EEXIST] +// The path2 argument names an existing file or symbolic link. +// +// [EIO] // An I/O error occurs while reading from or writing to the file system. // // [ELOOP] @@ -768,7 +1158,7 @@ w32_symlink(const char *name1, const char *name2) } else { ret = 0; if (isshortcut(name2)) { // possible shortcut (xxx.lnk) - if (! CreateShortcut(name2, name1, "", name1)) { + if (! CreateShortcutA(name2, name1, "", name1)) { errno = EIO; ret = -1; } @@ -785,7 +1175,7 @@ w32_symlink(const char *name1, const char *name2) DWORD attrs1, flag = // Note: Generally only available under an Admin account (((attrs1 = GetFileAttributesA(name1)) != INVALID_FILE_ATTRIBUTES && (attrs1 & FILE_ATTRIBUTE_DIRECTORY)) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0); - if (! my_CreateSymbolicLink(/*target-link*/name2, /*existing*/name1, flag)) { + if (! my_CreateSymbolicLinkA(/*target-link*/name2, /*existing*/name1, flag)) { switch (GetLastError()) { case ERROR_ACCESS_DENIED: case ERROR_SHARING_VIOLATION: @@ -812,7 +1202,39 @@ w32_symlink(const char *name1, const char *name2) static BOOL -my_CreateSymbolicLink(const char *lpSymlinkFileName, const char *lpTargetFileName, DWORD dwFlags) +my_CreateSymbolicLinkW(LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags) +{ + static CreateSymbolicLinkW_t x_CreateSymbolicLinkW = NULL; + + if (NULL == x_CreateSymbolicLinkW) { + HINSTANCE hinst; // Vista+ + + if (0 == (hinst = LoadLibraryA("Kernel32")) || + 0 == (x_CreateSymbolicLinkW = + (CreateSymbolicLinkW_t)GetProcAddress(hinst, "CreateSymbolicLinkW"))) { + // XP+ + x_CreateSymbolicLinkW = my_CreateSymbolicLinkWImp; + (void) FreeLibrary(hinst); + } + } + return x_CreateSymbolicLinkW(lpSymlinkFileName, lpTargetFileName, dwFlags); +} + + +static BOOL WINAPI +my_CreateSymbolicLinkWImp(LPCWSTR lpSymlinkFileName, LPCWSTR lpTargetFileName, DWORD dwFlags) +{ + __CUNUSED(lpSymlinkFileName) + __CUNUSED(lpTargetFileName) + __CUNUSED(dwFlags) + + SetLastError(ERROR_NOT_SUPPORTED); // not implemented + return FALSE; +} + + +static BOOL +my_CreateSymbolicLinkA(const char *lpSymlinkFileName, const char *lpTargetFileName, DWORD dwFlags) { static CreateSymbolicLinkA_t x_CreateSymbolicLinkA = NULL; @@ -823,7 +1245,7 @@ my_CreateSymbolicLink(const char *lpSymlinkFileName, const char *lpTargetFileNam 0 == (x_CreateSymbolicLinkA = (CreateSymbolicLinkA_t)GetProcAddress(hinst, "CreateSymbolicLinkA"))) { // XP+ - x_CreateSymbolicLinkA = my_CreateSymbolicLinkImp; + x_CreateSymbolicLinkA = my_CreateSymbolicLinkAImp; (void) FreeLibrary(hinst); } } @@ -832,7 +1254,7 @@ my_CreateSymbolicLink(const char *lpSymlinkFileName, const char *lpTargetFileNam static BOOL WINAPI -my_CreateSymbolicLinkImp(LPCSTR lpSymlinkFileName, LPCSTR lpTargetFileName, DWORD dwFlags) +my_CreateSymbolicLinkAImp(const char *lpSymlinkFileName, const char *lpTargetFileName, DWORD dwFlags) { __CUNUSED(lpSymlinkFileName) __CUNUSED(lpTargetFileName) @@ -851,7 +1273,7 @@ isshortcut(const char *name) for (cursor = name + len; --cursor >= name;) { if (*cursor == '.') { // extension - return (*++cursor && 0 == WIN32_STRICMP(cursor, "lnk")); + return (*++cursor && 0 == w32_io_stricmp(cursor, "lnk")); } if (*cursor == '/' || *cursor == '\\') { break; // delimiter @@ -1120,11 +1542,11 @@ isshortcut(const char *name) // oflag is O_WRONLY or O_RDWR. // */ + LIBW32_API int w32_open(const char *path, int oflag, ...) { - char symbuf[WIN32_PATH_MAX]; - int mode = 0, ret = 0; + int mode = 0; if (O_CREAT & oflag) { va_list ap; @@ -1133,13 +1555,103 @@ w32_open(const char *path, int oflag, ...) va_end(ap); } - if (0 == WIN32_STRICMP(path, "/dev/null")) { +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return w32_openW(wpath, oflag, mode); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_openA(path, oflag, mode); +} + + +LIBW32_API int +w32_openW(const wchar_t *path, int oflag, int mode) +{ + wchar_t symbuf[WIN32_PATH_MAX]; + int ret = 0; + + if (NULL == path) { + errno = EFAULT; + return -1; + } + + if (0 == w32_io_wstricmp(path, "/dev/null")) { + /* + * Redirect .. + */ + path = L"NUL"; + + } else if ((ret = ReadlinkW(path, (void *)-1, symbuf, _countof(symbuf))) < 0) { + /* + * If O_CREAT create the file if it does not exist, in which case the + * file is created with mode mode as described in chmod(2) and modified + * by the process' umask value (see umask(2)). + */ + if ((oflag & O_CREAT) && (ret == -ENOTDIR || ret == -ENOENT)) { + ret = 0; + } + + } else if (ret > 0) { + /* + * If O_NOFOLLOW and pathname is a symbolic link, then the open fails with ELOOP. + */ +#if defined(O_NOFOLLOW) && (O_NOFOLLOW) // extension + if (oflag & O_NOFOLLOW) { + ret = -ELOOP; + } +#endif + + /* + * If O_EXCL is set and the last component of the pathname is a symbolic link, + * open() will fail even if the symbolic link points to a non-existent name. + */ + if ((oflag & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) { + oflag &= ~(O_CREAT|O_EXCL); // link must exist ! + } + path = symbuf; + } + + if (ret < 0) { + errno = -ret; + return -1; + } + + // true open +#undef _wopen + return w32_sockfd_limit(_wopen(path, oflag, mode)); +} + + +LIBW32_API int +w32_openA(const char *path, int oflag, int mode) +{ + char symbuf[WIN32_PATH_MAX]; + int ret = 0; + + if (NULL == path) { + errno = EFAULT; + return -1; + } + + if (0 == w32_io_stricmp(path, "/dev/null")) { /* * Redirect .. */ path = "NUL"; - } else if ((ret = Readlink(path, (void *)-1, symbuf, sizeof(symbuf))) < 0) { + } else if ((ret = ReadlinkA(path, (void *)-1, symbuf, sizeof(symbuf))) < 0) { /* * If O_CREAT create the file if it does not exist, in which case the * file is created with mode mode as described in chmod(2) and modified @@ -1169,14 +1681,77 @@ w32_open(const char *path, int oflag, ...) path = symbuf; } - if (ret < 0) { - errno = -ret; - return -1; + if (ret < 0) { + errno = -ret; + return -1; + } + + // true open +#undef _open + return w32_sockfd_limit(_open(path, oflag, mode)); +} + + +/* + * Convert WIN attributes to thier Unix counterparts. + */ +static void +ApplyAttributesA(struct stat *sb, + const DWORD dwAttributes, const char *name, const char *magic) +{ + const char *p; + char symbuf[WIN32_PATH_MAX]; + mode_t mode = 0; + + /* + * mode + */ + + /* S_IFxxx */ + if (NULL != (p = name) && p[0] && p[1] == ':') { + p += 2; /* remove drive */ + } + + if (p && (!p[0] || (ISSLASH(p[0]) && !p[1]))) { + mode |= S_IFDIR|S_IEXEC; /* handle root directory explicity */ + + } else if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) { + mode |= S_IFDIR|S_IEXEC; /* directory */ + + } else if ((FILE_ATTRIBUTE_REPARSE_POINT & dwAttributes) || + (name && ReadlinkA(name, NULL, symbuf, sizeof(symbuf)) > 0)) { + mode |= S_IFLNK; /* link */ + + } else { + mode |= S_IFREG; /* normal file */ + } + + /* rw */ + mode |= (dwAttributes & FILE_ATTRIBUTE_READONLY) ? + S_IREAD : (S_IREAD|S_IWRITE); + + /* x */ + if (0 == (mode & S_IEXEC)) { + if (name && IsExecA(name, magic)) { + mode |= S_IEXEC; /* known exec type */ + } + } + + /* group/other */ + if (0 == (dwAttributes & FILE_ATTRIBUTE_SYSTEM)) { + mode |= (mode & 0700) >> 3; /* group */ + if (0 == (dwAttributes & FILE_ATTRIBUTE_HIDDEN)) { + mode |= (mode & 0700) >> 6; /* other */ + } + } + + /* + * apply + */ + sb->st_mode = mode; + if (sb->st_nlink <= 0) { /* assigned by caller? */ + sb->st_nlink = 1; } - - // true open -#undef _open - return w32_sockfd_limit(_open(path, oflag, mode)); } @@ -1184,11 +1759,11 @@ w32_open(const char *path, int oflag, ...) * Convert WIN attributes to thier Unix counterparts. */ static void -ApplyAttributes(struct stat *sb, - const DWORD dwAttributes, const char *name, const char *magic) +ApplyAttributesW(struct stat *sb, + const DWORD dwAttributes, const wchar_t *name, const char *magic) { - const char *p; - char symbuf[WIN32_PATH_MAX]; + const wchar_t *p; + wchar_t symbuf[WIN32_PATH_MAX]; mode_t mode = 0; /* @@ -1207,7 +1782,7 @@ ApplyAttributes(struct stat *sb, mode |= S_IFDIR|S_IEXEC; /* directory */ } else if ((FILE_ATTRIBUTE_REPARSE_POINT & dwAttributes) || - (name && Readlink(name, NULL, symbuf, sizeof(symbuf)) > 0)) { + (name && ReadlinkW(name, NULL, symbuf, _countof(symbuf)) > 0)) { mode |= S_IFLNK; /* link */ } else { @@ -1220,7 +1795,7 @@ ApplyAttributes(struct stat *sb, /* x */ if (0 == (mode & S_IEXEC)) { - if (name && IsExec(name, magic)) { + if (name && IsExecW(name, magic)) { mode |= S_IEXEC; /* known exec type */ } } @@ -1240,13 +1815,64 @@ ApplyAttributes(struct stat *sb, if (sb->st_nlink <= 0) { /* assigned by caller? */ sb->st_nlink = 1; } +} + + +static unsigned +RID(PSID sid) +{ + // Example: S-1-5-32-544 + // Returns the last component, 544. + const int subAuthorities = *GetSidSubAuthorityCount(sid); + if (subAuthorities >= 1) { // last sub-authority value. + return *GetSidSubAuthority(sid, subAuthorities - 1); + // Last component should be the user's relative identifier (RID). + // It uniquely defines this user account to SAM within the domain. + } + return 0; +} + - if (dwAttributes & FILE_ATTRIBUTE_SYSTEM) { - sb->st_uid = sb->st_gid = 0; /* root */ - } else { /* current user */ +static void +ApplyOwner(struct stat *sb, const DWORD dwAttributes, HANDLE handle) +{ + // Default uid/gid + if ((FILE_ATTRIBUTE_SYSTEM & dwAttributes) || 0 == handle) { + sb->st_uid = 0; // root/system + sb->st_gid = 0; + } else { // current user (default) sb->st_uid = w32_getuid(); sb->st_gid = w32_getgid(); } + + // Inquire + if (handle && INVALID_HANDLE_VALUE != handle) { + PSID owner = NULL, group = NULL; +#if defined(_DEBUG) && (0) + int uid = -1, gid = -1; +#endif + + if (GetSecurityInfo(handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, + &owner, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { + sb->st_uid = (short) RID(owner); + // Note: Unfortunately st_uid/st_gid are short's resulting in RID truncation. + + if (GetSecurityInfo(handle, SE_FILE_OBJECT, GROUP_SECURITY_INFORMATION, + NULL, &group, NULL, NULL, NULL) == ERROR_SUCCESS) { + sb->st_gid = (short) RID(group); +#if defined(_DEBUG) && (0) + if (sb->st_gid != sb->st_uid) { + char t_buffer[1024]; + struct group t_grp, *result = NULL; + getgrgid_r(sb->st_gid, &t_grp, t_buffer, _countof(t_buffer), &result); + assert(result); // verify returned group. + } +#endif //_DEBUG + } else { + sb->st_gid = sb->st_uid; + } + } + } } @@ -1309,7 +1935,6 @@ ConvertTime(const FILETIME *ft) } - static void ApplySize(struct stat *sb, const DWORD nFileSizeLow, const DWORD nFileSizeHigh) { @@ -1341,6 +1966,60 @@ ApplySize(struct stat *sb, const DWORD nFileSizeLow, const DWORD nFileSizeHigh) } +/* + * Well-known script magics' + */ + +static int +IsScriptMagic(const char *magic) +{ + int isscript = -1; + + if (magic[0] == '#' && magic[1] == '!' && magic[2]) { + /* + * #! [options]\n + */ + const char *exec = magic + 2; + int len = -1; + + while (*exec && ' ' == *exec) ++exec; + if (*exec == '/') { + if (0 == strncmp(exec, "/bin/sh", len = (sizeof("/bin/sh")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/ash", len = (sizeof("/bin/ash")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/csh", len = (sizeof("/bin/csh")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/ksh", len = (sizeof("/bin/ksh")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/zsh", len = (sizeof("/bin/zsh")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/bash", len = (sizeof("/bin/bash")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/dash", len = (sizeof("/bin/dash")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/fish", len = (sizeof("/bin/fish")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/tcsh", len = (sizeof("/bin/tcsh")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/sed", len = (sizeof("/bin/sed")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/bin/awk", len = (sizeof("/bin/awk")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/usr/bin/perl", len = (sizeof("/usr/bin/perl")-1))) + isscript = 1; + else if (0 == strncmp(exec, "/usr/bin/python", len = (sizeof("/usr/bin/python")-1))) + isscript = 1; + if (isscript && + exec[len] != ' ' && exec[len] != '\n' && exec[len] != '\r') { + isscript = 0; /* bad termination, ignore */ + } + } + } + return isscript; +} + + /* * Is the file an executFileType */ @@ -1368,132 +2047,295 @@ static const char * exec_exclude[] = { static int -IsExec(const char *name, const char *magic) +IsExecA(const char *name, const char *magic) { DWORD driveType; const char *dot; int idx = -1; - if ((dot = HasExtension(name)) != NULL) { /* check well-known extensions */ + if ((dot = HasExtensionA(name)) != NULL) { /* check well-known extensions */ for (idx = EXEC_ASSUME-1; idx >= 0; idx--) - if (WIN32_STRICMP(dot, exec_assume[idx]) == 0) { + if (w32_io_stricmp(dot, exec_assume[idx]) == 0) { return TRUE; } for (idx = EXEC_EXCLUDE-1; idx >= 0; idx--) - if (WIN32_STRICMP(dot, exec_exclude[idx]) == 0) { + if (w32_io_stricmp(dot, exec_exclude[idx]) == 0) { break; } - } + } - if (magic) { /* #! */ - if (magic[0] == '#' && magic[1] == '!' && magic[2]) { - /* - * #! [options]\n - */ - const char *exec = magic + 2; - int isscript = 0, len = -1; - - while (*exec && ' ' == *exec) ++exec; - if (*exec == '/') { - if (0 == strncmp(exec, "/bin/sh", len = (sizeof("/bin/sh")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/ash", len = (sizeof("/bin/ash")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/csh", len = (sizeof("/bin/csh")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/ksh", len = (sizeof("/bin/ksh")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/zsh", len = (sizeof("/bin/zsh")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/bash", len = (sizeof("/bin/bash")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/dash", len = (sizeof("/bin/dash")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/fish", len = (sizeof("/bin/fish")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/tcsh", len = (sizeof("/bin/tcsh")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/sed", len = (sizeof("/bin/sed")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/bin/awk", len = (sizeof("/bin/awk")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/usr/bin/perl", len = (sizeof("/usr/bin/perl")-1))) - isscript = 1; - else if (0 == strncmp(exec, "/usr/bin/python", len = (sizeof("/usr/bin/python")-1))) - isscript = 1; - if (isscript && - exec[len] != ' ' && exec[len] != '\n' && exec[len] != '\r') { - isscript = 0; /* bad termination, ignore */ - } - } - return isscript; - } + if (magic) { /* #! */ + int isscript; + if ((isscript = IsScriptMagic(magic)) >= 0) { + return isscript; } + } if (-1 == idx) { /* only local drives */ if ((driveType = GetDriveTypeA(name)) == DRIVE_FIXED) { DWORD binaryType = 0; - if (GetBinaryTypeA(name, &binaryType)) { - /* - switch(binaryType) { - case SCS_32BIT_BINARY: // 32-bit Windows-based application - case SCS_64BIT_BINARY: // 64-bit Windows-based application - case SCS_DOS_BINARY: // MS-DOS – based application - case SCS_OS216_BINARY: // 16-bit OS/2-based application - case SCS_PIF_BINARY: // PIF file that executes an MS-DOS based application - case SCS_POSIX_BINARY: // A POSIX based application - case SCS_WOW_BINARY: // A 16-bit Windows-based application - }*/ return TRUE; } } } - return FALSE; -} - - -static const char * -HasExtension(const char *name) -{ - const size_t len = strlen(name); - const char *cursor; - - for (cursor = name + len; --cursor >= name;) { - if (*cursor == '.') - return cursor; /* extension */ - if (*cursor == '/' || *cursor == '\\') - break; - } - return NULL; -} - - -static BOOL -IsExtension(const char *name, const char *ext) -{ - const char *dot; + return FALSE; +} + + +static int +IsExecW(const wchar_t *name, const char *magic) +{ + DWORD driveType; + const wchar_t *dot; + int idx = -1; + + if ((dot = HasExtensionW(name)) != NULL) { /* check well-known extensions */ + for (idx = EXEC_ASSUME-1; idx >= 0; idx--) + if (w32_io_wstricmp(dot, exec_assume[idx]) == 0) { + return TRUE; + } + + for (idx = EXEC_EXCLUDE-1; idx >= 0; idx--) + if (w32_io_wstricmp(dot, exec_exclude[idx]) == 0) { + break; + } + } + + if (magic) { /* #! */ + int isscript; + if ((isscript = IsScriptMagic(magic)) >= 0) { + return isscript; + } + } + + if (-1 == idx) { /* only local drives */ + if ((driveType = GetDriveTypeW(name)) == DRIVE_FIXED) { + DWORD binaryType = 0; + if (GetBinaryTypeW(name, &binaryType)) { + return TRUE; + } + } + } + return FALSE; +} + + +static const char * +HasExtensionA(const char *name) +{ + const size_t len = strlen(name); + const char *cursor; + + for (cursor = name + len; --cursor >= name;) { + if (*cursor == '.') + return cursor; /* extension */ + if (*cursor == '/' || *cursor == '\\') + break; + } + return NULL; +} + + +static const wchar_t * +HasExtensionW(const wchar_t *name) +{ + const size_t len = wcslen(name); + const wchar_t *cursor; + + for (cursor = name + len; --cursor >= name;) { + if (*cursor == '.') + return cursor; /* extension */ + if (*cursor == '/' || *cursor == '\\') + break; + } + return NULL; +} + + +static BOOL +IsExtensionA(const char *name, const char *ext) +{ + const char *dot; + + if (ext && (dot = HasExtensionA(name)) != NULL && + w32_io_stricmp(dot, ext) == 0) { + return TRUE; + } + return FALSE; +} + + +static BOOL +IsExtensionW(const wchar_t *name, const char *ext) +{ + const wchar_t *dot; + + if (ext && (dot = HasExtensionW(name)) != NULL && + w32_io_wstricmp(dot, ext) == 0) { + return TRUE; + } + return FALSE; +} + + +static int +ReadlinkA(const char *path, const char **suffixes, char *buf, int maxlen) +{ + DWORD attrs; + const char *suffix; + int length; + int ret = -ENOENT; + + (void) strncpy( buf, path, maxlen ); // prime working buffer + buf[ maxlen-1 ] = '\0'; + length = (int)strlen(buf); + + if (suffixes == (void *)NULL) { + suffixes = suffixes_null; + } else if (suffixes == (void *)-1) { + suffixes = suffixes_default; + } + + while ((suffix = *suffixes++) != NULL) { + /* Concat suffix */ + if (length + (int)strlen(suffix) >= maxlen) { + ret = -ENAMETOOLONG; + continue; + } + strcpy(buf + length, suffix); // concat suffix + + /* File attributes */ + if (0xffffffff == (attrs = GetFileAttributesA(buf))) { + DWORD rc; + + if ((rc = GetLastError()) == ERROR_ACCESS_DENIED || + rc == ERROR_SHARING_VIOLATION) { + ret = -EACCES; // true error ??? + } else if (rc == ERROR_PATH_NOT_FOUND) { + ret = -ENOTDIR; + } else if (rc == ERROR_FILE_NOT_FOUND) { + ret = -ENOENT; + } else { + ret = -EIO; + } + continue; // next suffix + } + + /* Parse attributes */ + if ((attrs & (FILE_ATTRIBUTE_DIRECTORY)) || +#ifdef FILE_ATTRIBUTE_COMPRESSED + (attrs & (FILE_ATTRIBUTE_COMPRESSED)) || +#endif +#ifdef FILE_ATTRIBUTE_DEVICE + (attrs & (FILE_ATTRIBUTE_DEVICE)) || +#endif +#ifdef FILE_ATTRIBUTE_ENCRYPTED + (attrs & (FILE_ATTRIBUTE_ENCRYPTED)) +#endif + ) { + ret = 0; // generally not a symlink + if ((attrs & FILE_ATTRIBUTE_DIRECTORY) && + (attrs & FILE_ATTRIBUTE_REPARSE_POINT)) { + // possible mount-point. + if (0 == w32_reparse_readA(path, buf, maxlen)) { + ret = (int)strlen(buf); + } + } + + /* readparse point - symlink/mount-point */ + } else if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) { + if ((ret = w32_reparse_readA(path, buf, maxlen)) >= 0) { + ret = (int)strlen(buf); + } else { + ret = -EIO; + } + + /* shortcut */ + } else if (attrs & FILE_ATTRIBUTE_OFFLINE) { + ret = -EACCES; // wont be able to access + +#define SHORTCUT_COOKIE "L\0\0\0" // shortcut magic + + // cygwin shortcut also syste/rdonly +#define CYGWIN_ATTRS FILE_ATTRIBUTE_SYSTEM +#define CYGWIN_COOKIE "!" // old style shortcut + + } else if (IsExtensionA(buf, ".lnk") || + (attrs & (FILE_ATTRIBUTE_HIDDEN|CYGWIN_ATTRS)) == CYGWIN_ATTRS) { + + SECURITY_ATTRIBUTES sa = {0}; + char cookie[sizeof(CYGWIN_COOKIE)-1]; + HANDLE fh; + DWORD got; + + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = FALSE; + + if ((fh = CreateFileA(buf, GENERIC_READ, FILE_SHARE_READ, + &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) { + + // read header + if (! ReadFile(fh, cookie, sizeof (cookie), &got, 0)) { + ret = -EIO; + + // win32 shortcut (will also read cygwin shortcuts) + } else if (got >= 4 && 0 == memcmp(cookie, SHORTCUT_COOKIE, 4)) { + if ((ret = ReadShortcutA(buf, buf, maxlen)) < 0) { + ret = -EIO; + } else { + ret = (int)strlen(buf); + } + + // cygwin symlink (old style) + } else if ((attrs & CYGWIN_ATTRS) && got == sizeof(cookie) && + 0 == memcmp(cookie, CYGWIN_COOKIE, sizeof(cookie))) { + + if (! ReadFile(fh, buf, maxlen, &got, 0)) { + ret = -EIO; + } else { + char *end; + + if ((end = (char *)memchr(buf, 0, got)) != NULL) { + ret = (int)(end - buf); // find the NUL terminator + } else { + ret = (int)got; + } + if (ret == 0) { + ret = -EIO; // hmmm .. empty link specification + } + } + } else { + ret = 0; // not a symlink + } + CloseHandle(fh); + } + } else { + ret = 0; // not a symlink + } + break; + } - if (ext && (dot = HasExtension(name)) != NULL && - WIN32_STRICMP(dot, ext) == 0) { - return TRUE; + if (ret > 0) { + w32_dos2unix(buf); } - return FALSE; + return ret; } static int -Readlink(const char *path, const char **suffixes, char *buf, int maxlen) +ReadlinkW(const wchar_t *path, const char **suffixes, wchar_t *buf, int maxlen) { DWORD attrs; const char *suffix; int length; int ret = -ENOENT; - (void) strncpy( buf, path, maxlen ); // prime working buffer + wcsncpy(buf, path, maxlen); // prime working buffer buf[ maxlen-1 ] = '\0'; - length = (int)strlen(buf); + length = (int)wcslen(buf); if (suffixes == (void *)NULL) { suffixes = suffixes_null; @@ -1507,10 +2349,17 @@ Readlink(const char *path, const char **suffixes, char *buf, int maxlen) ret = -ENAMETOOLONG; continue; } - strcpy(buf + length, suffix); // concat suffix + + { wchar_t *cursor; + for (cursor = buf + length;; ++cursor) { + if (0 == (*cursor = (wchar_t)*suffix++)) { + break; + } + } + } /* File attributes */ - if (0xffffffff == (attrs = GetFileAttributesA(buf))) { + if (0xffffffff == (attrs = GetFileAttributesW(buf))) { DWORD rc; if ((rc = GetLastError()) == ERROR_ACCESS_DENIED || @@ -1542,17 +2391,17 @@ Readlink(const char *path, const char **suffixes, char *buf, int maxlen) if ((attrs & FILE_ATTRIBUTE_DIRECTORY) && (attrs & FILE_ATTRIBUTE_REPARSE_POINT)) { // possible mount-point. - if (0 == w32_reparse_read(path, buf, maxlen)) { - ret = (int)strlen(buf); + if (0 == w32_reparse_readW(path, buf, maxlen)) { + ret = (int)wcslen(buf); } } /* readparse point - symlink/mount-point */ } else if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) { - if ((ret = w32_reparse_read(path, buf, maxlen)) < 0) { - ret = -EIO; + if ((ret = w32_reparse_readW(path, buf, maxlen)) >= 0) { + ret = (int)wcslen(buf); } else { - ret = (int)strlen(buf); + ret = -EIO; } /* shortcut */ @@ -1565,10 +2414,10 @@ Readlink(const char *path, const char **suffixes, char *buf, int maxlen) #define CYGWIN_ATTRS FILE_ATTRIBUTE_SYSTEM #define CYGWIN_COOKIE "!" // old style shortcut - } else if (IsExtension(buf, ".lnk") || + } else if (IsExtensionW(buf, ".lnk") || (attrs & (FILE_ATTRIBUTE_HIDDEN|CYGWIN_ATTRS)) == CYGWIN_ATTRS) { - SECURITY_ATTRIBUTES sa; + SECURITY_ATTRIBUTES sa = {0}; char cookie[sizeof(CYGWIN_COOKIE)-1]; HANDLE fh; DWORD got; @@ -1577,7 +2426,7 @@ Readlink(const char *path, const char **suffixes, char *buf, int maxlen) sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = FALSE; - if ((fh = CreateFileA(buf, GENERIC_READ, FILE_SHARE_READ, + if ((fh = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE) { // read header @@ -1586,10 +2435,10 @@ Readlink(const char *path, const char **suffixes, char *buf, int maxlen) // win32 shortcut (will also read cygwin shortcuts) } else if (got >= 4 && 0 == memcmp(cookie, SHORTCUT_COOKIE, 4)) { - if ((ret = ReadShortcut (buf, buf, maxlen)) < 0) { + if ((ret = ReadShortcutW(buf, buf, maxlen)) < 0) { ret = -EIO; } else { - ret = (int)strlen(buf); + ret = (int)wcslen(buf); } // cygwin symlink (old style) @@ -1599,12 +2448,12 @@ Readlink(const char *path, const char **suffixes, char *buf, int maxlen) if (! ReadFile(fh, buf, maxlen, &got, 0)) { ret = -EIO; } else { - char *end; + wchar_t *end; - if ((end = (char *)memchr(buf, 0, got)) != NULL) { + if ((end = (wchar_t *)wmemchr(buf, 0, got)) != NULL) { ret = (int)(end - buf); // find the NUL terminator } else { - ret = (int)got; + ret = (int)(got / sizeof(wchar_t)); } if (ret == 0) { ret = -EIO; // hmmm .. empty link specification @@ -1622,7 +2471,7 @@ Readlink(const char *path, const char **suffixes, char *buf, int maxlen) } if (ret > 0) { - w32_dos2unix(buf); + w32_dos2unixW(buf); } return ret; } @@ -1663,7 +2512,58 @@ static const IID x_IID_IPersistFile = * Resolve(), GetWorkingDirectory(), and so on. */ static int -ReadShortcut(const char *name, char *buf, int maxlen) +ReadShortcutA(const char *name, char *buf, int maxlen) +{ + HRESULT hres = FALSE; + WIN32_FIND_DATA wfd; + IShellLink *pShLink; + + (void) CoInitialize(NULL); + + hres = CoCreateInstance(&x_CLSID_ShellLink, NULL, + CLSCTX_INPROC_SERVER, &x_IID_IShellLink, (LPVOID *)&pShLink); + + if (name != buf) buf[0] = 0; + if (SUCCEEDED(hres)) { + IPersistFile *ppf; + + hres = pShLink->lpVtbl->QueryInterface(pShLink, &x_IID_IPersistFile, (LPVOID *)&ppf); + if (SUCCEEDED(hres)) { + wchar_t wname[WIN32_PATH_MAX]; + + w32_utf2wc(name, wname, _countof(wname)); + hres = ppf->lpVtbl->Load(ppf, wname, STGM_READ); + if (SUCCEEDED(hres)) { + /* + - if (SUCCEEDED(hres)) { + - hres = pShLink->lpVtbl->Resolve( + - pShLink, 0, SLR_NOUPDATE | SLR_ANY_MATCH | SLR_NO_UI); + - } + */ + hres = pShLink->lpVtbl->GetPath(pShLink, buf, maxlen, &wfd, 0); + if (!SUCCEEDED(hres) || 0 == buf[0]) { + /* + * A document shortcut may only have a description ... + * Also CYGWIN generates this style of link. + */ + hres = pShLink->lpVtbl->GetDescription(pShLink, buf, maxlen); + if (SUCCEEDED(hres) && 0 == buf[0]) { + hres = -1; + } + } + ppf->lpVtbl->Release(ppf); + } + } + pShLink->lpVtbl->Release(pShLink); + } + CoUninitialize(); + + return (SUCCEEDED(hres) ? 0 : -1); +} + + +static int +ReadShortcutW(const wchar_t *name, wchar_t *buf, int maxlen) { HRESULT hres = FALSE; WIN32_FIND_DATA wfd; @@ -1671,95 +2571,368 @@ ReadShortcut(const char *name, char *buf, int maxlen) (void) CoInitialize(NULL); - hres = CoCreateInstance(&x_CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER, &x_IID_IShellLink, (LPVOID *)&pShLink); + hres = CoCreateInstance(&x_CLSID_ShellLink, NULL, + CLSCTX_INPROC_SERVER, &x_IID_IShellLink, (LPVOID *)&pShLink); + + if (name != buf) buf[0] = 0; + if (SUCCEEDED(hres)) { + IPersistFile *ppf; + + hres = pShLink->lpVtbl->QueryInterface(pShLink, &x_IID_IPersistFile, (LPVOID *)&ppf); + if (SUCCEEDED(hres)) { + hres = ppf->lpVtbl->Load(ppf, name, STGM_READ); + if (SUCCEEDED(hres)) { + char t_buf[WIN32_PATH_MAX]; + + t_buf[0] = 0; + hres = pShLink->lpVtbl->GetPath(pShLink, t_buf, sizeof(t_buf), &wfd, 0); + if (!SUCCEEDED(hres) || 0 == t_buf[0]) { + /* + * A document shortcut may only have a description ... + * Also CYGWIN generates this style of link. + */ + hres = pShLink->lpVtbl->GetDescription(pShLink, t_buf, sizeof(t_buf)); + if (SUCCEEDED(hres) && 0 == t_buf[0]) { + hres = -1; + } + } + + if (SUCCEEDED(hres) && t_buf[0]) { + w32_utf2wc(t_buf, buf, maxlen); + } + + ppf->lpVtbl->Release(ppf); + } + } + pShLink->lpVtbl->Release(pShLink); + } + CoUninitialize(); + + return (SUCCEEDED(hres) ? 0 : -1); +} + + +static int +CreateShortcutA(const char *link, const char *name, const char *working, const char *desc) +{ + IShellLink *pShLink; + HRESULT hres; + + (void) CoInitialize(NULL); + + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(&x_CLSID_ShellLink, NULL, + CLSCTX_INPROC_SERVER, &x_IID_IShellLink, (PVOID *) &pShLink); + + if (SUCCEEDED(hres)) { + IPersistFile* ppf; + + // Set the path to the shortcut target and add the + // description. + // if (flags & MAXIMIZED) + // pShLink->lpVtbl->SetShowCmd(pShLink, SW_SHOW); + if (name) + pShLink->lpVtbl->SetPath(pShLink, (LPCSTR) name); + if (working) + pShLink->lpVtbl->SetWorkingDirectory(pShLink, (LPCSTR) working); + if (desc) + pShLink->lpVtbl->SetDescription(pShLink, (LPCSTR) desc); + // if (icon) + // pShLink->lpVtbl->SetIconLocation(pShLink, (LPCSTR) icon); + + // Query IShellLink for the IPersistFile interface for saving the + // shortcut in persistent storage. + hres = pShLink->lpVtbl->QueryInterface(pShLink, &x_IID_IPersistFile, (PVOID *) &ppf); + + if (SUCCEEDED(hres)) { + wchar_t wlink[ MAX_PATH ]; + + // Ensure that the string is ANSI. + w32_utf2wc(link, wlink, _countof(wlink)); + + // Save the link by calling IPersistFile::Save. + hres = ppf->lpVtbl->Save(ppf, wlink, TRUE); + ppf->lpVtbl->Release(ppf); + } + + pShLink->lpVtbl->Release(pShLink); + } + + CoUninitialize(); + + return (SUCCEEDED(hres) ? TRUE : FALSE); +} + + +/* + * Stat() system call + */ +static int +StatA(const char *name, struct stat *sb) +{ + char fullname[WIN32_PATH_MAX] = {0}, *pfname = NULL; + int flength, ret = -1; + BOOL domagic = 0; + + if (name == NULL || sb == NULL) { + ret = -EFAULT; /* basic checks */ + + } else if (name[0] == '\0' || + (name[1] == ':' && name[2] == '\0')) { + ret = -ENOENT; /* missing directory ??? */ + + } else if (strchr(name, '?') || strchr(name, '*')) { + ret = -ENOENT; /* wildcards -- break FindFirstFile() */ + + } else if (0 == (flength = GetFullPathNameA(name, sizeof(fullname), fullname, &pfname))) { + ret = -ENOENT; /* parse error */ + + } else if (flength >= (int)sizeof(fullname)) { + ret = -ENAMETOOLONG; /* buffer overflow */ + + } else { + HANDLE h = INVALID_HANDLE_VALUE; + WIN32_FIND_DATAA fb = {0}; + DWORD dwRootAttributes = 0; + int drive = 0; + + /* + * determine the drive .. used as st_dev + */ + if (! ISSLASH(fullname[0])) { /* A=1 .. */ + drive = toupper(fullname[0]) - 'A' + 1; + } + + /* + * retrieve the file details + */ + memset(sb, 0, sizeof(struct stat)); + + if ((h = FindFirstFileA(fullname, &fb)) == INVALID_HANDLE_VALUE) { + + if (((fullname[0] && fullname[1] == ':' && + ISSLASH(fullname[2]) && fullname[3] == '\0')) && + GetDriveTypeA(fullname) > 1) { + /* "x:\" */ + /* + * root directories + */ + dwRootAttributes = FILE_ATTRIBUTE_DIRECTORY; + ret = 0; + + } else if (ISSLASH(fullname[0]) && ISSLASH(fullname[1])) { + /* + * root UNC (//servername/xxx) + */ + const char *slash = w32_strslash(fullname + 2); + const char *nextslash = w32_strslash(slash ? slash + 1 : NULL); + + ret = -ENOENT; + if (NULL != slash && + (NULL == nextslash || 0 == nextslash[1])) { + dwRootAttributes = FILE_ATTRIBUTE_DIRECTORY; + ret = 0; + } + + } else { + /* + * Determine cause + */ + DWORD rc = GetLastError(), attrs; + + if (0xffffffff == (attrs = GetFileAttributesA(fullname))) { + // Decode error. + if ((rc = GetLastError()) == ERROR_ACCESS_DENIED || + rc == ERROR_SHARING_VIOLATION) { + ret = -EACCES; + } else if (rc == ERROR_PATH_NOT_FOUND) { + ret = -ENOTDIR; + } else if (rc == ERROR_FILE_NOT_FOUND) { + ret = -ENOENT; + } else { + ret = -EIO; + } + + } else if (rc == ERROR_ACCESS_DENIED) { + // Junction encountered (e.g C:/Users/Default User --> Default), + // FindFirstFile() behaviour is by design to stop applications recursively accessing symlinks. + fb.dwFileAttributes = attrs; + ret = 0; + + } else { + // Other conditions. + ret = -EIO; + } + } + + } else { + (void) FindClose(h); /* release find session */ + ret = 0; + } - if (SUCCEEDED(hres)) { - WORD wsz[ MAX_PATH ]; - IPersistFile *ppf; + /* + * assign results + */ +#if defined(DO_FILEMAGIC) /* verify file magic */ + domagic = (HasExtension(fullname) == NULL); +#endif - hres = pShLink->lpVtbl->QueryInterface(pShLink, &x_IID_IPersistFile, (LPVOID *)&ppf); - if (SUCCEEDED(hres)) { - MultiByteToWideChar(CP_ACP, 0, name, -1, wsz, _countof(wsz)); + while (0 == ret) { + char magic[1024] = {0}; + BOOL dirsymlink = FALSE; + DWORD count = 0; + HANDLE handle; - hres = ppf->lpVtbl->Load(ppf, wsz, STGM_READ); - if (SUCCEEDED(hres)) { -/* if (SUCCEEDED(hres)) { - * hres = pShLink->lpVtbl->Resolve( - * pShLink, 0, SLR_NOUPDATE | SLR_ANY_MATCH | SLR_NO_UI); - * } - */ + if (INVALID_HANDLE_VALUE != (handle = + CreateFileA(fullname, (domagic ? GENERIC_READ : 0), 0, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, NULL))) { + // + // file information + // FILE_FLAG_BACKUP_SEMANTICS permit directories to be open'ed + BY_HANDLE_FILE_INFORMATION fi = {0}; - hres = pShLink->lpVtbl->GetPath(pShLink, buf, maxlen, &wfd, 0); - if (!SUCCEEDED(hres) || buf[0] == '\0') { - /* - * A document shortcut may only have a description ... - * Also CYGWIN generates this style of link. - */ - hres = pShLink->lpVtbl->GetDescription(pShLink, buf, maxlen); - if (buf[0] == '\0') - hres = !S_OK; + if (GetFileInformationByHandle(handle, &fi)) { + if (fi.nNumberOfLinks > 0) { +#if defined(_MSC_VER) /* XXX/NOTE */ + sb->st_nlink = (short)fi.nNumberOfLinks; +#else + sb->st_nlink = fi.nNumberOfLinks; +#endif + } + fb.nFileSizeHigh = fi.nFileSizeHigh; + fb.nFileSizeLow = fi.nFileSizeLow; + fb.ftCreationTime = fi.ftCreationTime; + fb.ftLastAccessTime = fi.ftLastAccessTime; + fb.ftLastWriteTime = fi.ftLastWriteTime; + sb->st_ino = w32_ino_gen(fi.nFileIndexLow, fi.nFileIndexHigh); + //Note: Generate an inode from nFileIndexHigh and nFileIndexLow, yet warning + // The identifier that is stored in the nFileIndexHigh and nFileIndexLow members is called the file ID. + // Support for file IDs is file system - specific.File IDs are not guaranteed to be unique over time, + // because file systems are free to reuse them.In some cases, the file ID for a file can change over time. } - ppf->lpVtbl->Release(ppf); - } - } - pShLink->lpVtbl->Release(pShLink); - } - CoUninitialize(); + // + // directory symlinks + // see: https://docs.microsoft.com/en-us/windows/desktop/FileIO/reparse-point-tags + if ((fb.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + (fb.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + /* retrieve reparse details */ + if (IO_REPARSE_TAG_SYMLINK == fb.dwReserved0) { + dirsymlink = TRUE; - return (SUCCEEDED(hres) ? 0 : -1); -} + } else if (IO_REPARSE_TAG_MOUNT_POINT == fb.dwReserved0 || 0 == fb.dwReserved0) { + BYTE reparseBuffer[MAX_REPARSE_SIZE]; + /* XXX: warning: owc crash if = {0} under full optimisation */ + PREPARSE_DATA_BUFFER rdb = (PREPARSE_DATA_BUFFER)reparseBuffer; + DWORD returnedLength = 0; + memset(reparseBuffer, 0, sizeof(MAX_REPARSE_SIZE)); -static int -CreateShortcut(const char *link, const char *name, const char *working, const char *desc) -{ - IShellLink *pShLink; - HRESULT hres; + if (DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, + NULL, 0, rdb, sizeof(reparseBuffer), &returnedLength, NULL)) { + if (IsReparseTagMicrosoft(rdb->ReparseTag)) { + switch (rdb->ReparseTag) { + case IO_REPARSE_TAG_SYMLINK: + dirsymlink = TRUE; + /*XXX: unexpected */ + break; + case IO_REPARSE_TAG_MOUNT_POINT: + if (rdb->MountPointReparseBuffer.SubstituteNameLength > 0) { + const size_t offset = rdb->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + const wchar_t* mount = rdb->MountPointReparseBuffer.PathBuffer + offset; - (void) CoInitialize(NULL); + if (0 == memcmp(mount, L"\\??\\", 4 * sizeof(wchar_t)) && + 0 != memcmp(mount, L"\\??\\Volume{", 11 * sizeof(wchar_t))) { + dirsymlink = TRUE; + /* not a volume mount point -- hard-link */ + } + } + break; + } + } + } + } + } - // Get a pointer to the IShellLink interface. - hres = CoCreateInstance(&x_CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER, &x_IID_IShellLink, (PVOID *) &pShLink); + // + // extended file-type +#if defined(DO_FILEMAGIC) + if (domagic) { /* read file magic; regular files only */ + /* performed on files without an extension to determine whether an exec script */ + if (0 == (fb.dwFileAttributes & + (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_TEMPORARY | + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_ENCRYPTED))) { + (void) ReadFile(handle, magic, sizeof(magic)-1, &count, NULL); + } + } +#endif //DO_MAGIC + magic[count] = 0; /* null terminate magic buffer */ - if (SUCCEEDED(hres)) { - IPersistFile* ppf; - WORD wsz[ MAX_PATH ]; + // + // dev emulation + { DWORD serialno = 0, flags = 0; + if (my_GetVolumeInformationByHandle(handle, &serialno, &flags)) { + sb->st_dev = serialno; + } + } - // Set the path to the shortcut target and add the - // description. - // if (flags & MAXIMIZED) - // pShLink->lpVtbl->SetShowCmd(pShLink, SW_SHOW); - if (name) - pShLink->lpVtbl->SetPath(pShLink, (LPCSTR) name); - if (working) - pShLink->lpVtbl->SetWorkingDirectory(pShLink, (LPCSTR) working); - if (desc) - pShLink->lpVtbl->SetDescription(pShLink, (LPCSTR) desc); - // if (icon) - // pShLink->lpVtbl->SetIconLocation(pShLink, (LPCSTR) icon); + // + // inode emulation + if (0 == sb->st_ino) { + sb->st_ino = w32_ino_hash(fullname); + } + ApplyOwner(sb, fb.dwFileAttributes, handle); - // Query IShellLink for the IPersistFile interface for saving the - // shortcut in persistent storage. - hres = pShLink->lpVtbl->QueryInterface(pShLink, &x_IID_IPersistFile, (PVOID *) &ppf); + CloseHandle(handle); - if (SUCCEEDED(hres)) { - // Ensure that the string is ANSI. - MultiByteToWideChar(CP_ACP, 0, (LPCSTR) link, -1, wsz, MAX_PATH); + } else { +#if defined(DO_FILEMAGIC) + if (domagic) { + domagic = 0; + continue; /* retry without read; eg directories */ + } +#endif //DO_MAGIC - // Save the link by calling IPersistFile::Save. - hres = ppf->lpVtbl->Save(ppf, wsz, TRUE); - ppf->lpVtbl->Release(ppf); - } + if (dwRootAttributes) { + ret = -ENOENT; + } else if (0 == (sb->st_ino = w32_ino_file(fullname))) { + sb->st_ino = w32_ino_hash(fullname); + ApplyOwner(sb, fb.dwFileAttributes, NULL); + } + } - pShLink->lpVtbl->Release(pShLink); - } + ApplyAttributesA(sb, fb.dwFileAttributes|dwRootAttributes, fullname, magic); + if (dirsymlink) { + // NOTE: Directory reparse-points are hidden, as these are closer to hard-links + // other link types are reclassed as symlinks. + sb->st_mode &= ~S_IFDIR; /* can only be one type */ + sb->st_mode |= S_IFLNK; + } - CoUninitialize(); + ApplyTimes(sb, &fb.ftCreationTime, &fb.ftLastAccessTime, &fb.ftLastWriteTime); + ApplySize(sb, fb.nFileSizeLow, fb.nFileSizeHigh); - return (SUCCEEDED(hres) ? TRUE : FALSE); + // st_dev + // This field describes the device on which this file resides. + // + // st_rdev + // This field describes the device that this file (inode) represents. + // + // st_ino + // This field contains the file's inode number. + // + sb->st_rdev = (dev_t)(drive - 1); /* A=0 ... */ + + if (0 == sb->st_dev) { + sb->st_dev = sb->st_rdev; + //XXX: This wont work for reparse-points, hence it is not possible to test in call cases + // as to whether a parent/child directory represent a mount-point or are cross-device. + } + + break; // done + } + } + return ret; } @@ -1767,9 +2940,9 @@ CreateShortcut(const char *link, const char *name, const char *working, const ch * Stat() system call */ static int -Stat(const char *name, struct stat *sb) +StatW(const wchar_t *name, struct stat *sb) { - char fullname[WIN32_PATH_MAX] = {0}, *pfname = NULL; + wchar_t fullname[WIN32_PATH_MAX] = {0}, *pfname = NULL; int flength, ret = -1; BOOL domagic = 0; @@ -1780,19 +2953,20 @@ Stat(const char *name, struct stat *sb) (name[1] == ':' && name[2] == '\0')) { ret = -ENOENT; /* missing directory ??? */ - } else if (strchr(name, '?') || strchr(name, '*')) { + } else if (StrChrW(name, '?') || StrChrW(name, '*')) { ret = -ENOENT; /* wildcards -- break FindFirstFile() */ - } else if (0 == (flength = GetFullPathNameA(name, sizeof(fullname), fullname, &pfname))) { + } else if (0 == (flength = GetFullPathNameW(name, _countof(fullname), fullname, &pfname))) { ret = -ENOENT; /* parse error */ - } else if (flength >= (int)sizeof(fullname)) { + } else if (flength >= (int)_countof(fullname)) { ret = -ENAMETOOLONG; /* buffer overflow */ } else { HANDLE h = INVALID_HANDLE_VALUE; - WIN32_FIND_DATAA fb = {0}; - int root = FALSE, drive = 0; + WIN32_FIND_DATAW fb = {0}; + DWORD dwRootAttributes = 0; + int drive = 0; /* * determine the drive .. used as st_dev @@ -1806,29 +2980,29 @@ Stat(const char *name, struct stat *sb) */ memset(sb, 0, sizeof(struct stat)); - if ((h = FindFirstFileA(fullname, &fb)) == INVALID_HANDLE_VALUE) { + if ((h = FindFirstFileW(fullname, &fb)) == INVALID_HANDLE_VALUE) { if (((fullname[0] && fullname[1] == ':' && ISSLASH(fullname[2]) && fullname[3] == '\0')) && - GetDriveTypeA(fullname) > 1) { + GetDriveTypeW(fullname) > 1) { /* "x:\" */ /* * root directories */ - root = 1; + dwRootAttributes = FILE_ATTRIBUTE_DIRECTORY; ret = 0; } else if (ISSLASH(fullname[0]) && ISSLASH(fullname[1])) { /* * root UNC (//servername/xxx) */ - const char *slash = w32_strslash(fullname + 2); - const char *nextslash = w32_strslash(slash ? slash+1 : NULL); + const wchar_t *slash = w32_wcsslash(fullname + 2); + const wchar_t *nextslash = w32_wcsslash(slash ? slash+1 : NULL); ret = -ENOENT; if (NULL != slash && (NULL == nextslash || 0 == nextslash[1])) { - root = 2; + dwRootAttributes = FILE_ATTRIBUTE_DIRECTORY; ret = 0; } @@ -1838,7 +3012,7 @@ Stat(const char *name, struct stat *sb) */ DWORD rc = GetLastError(), attrs; - if (0xffffffff == (attrs = GetFileAttributesA(fullname))) { + if (0xffffffff == (attrs = GetFileAttributesW(fullname))) { // Decode error. if ((rc = GetLastError()) == ERROR_ACCESS_DENIED || rc == ERROR_SHARING_VIOLATION) { @@ -1850,11 +3024,13 @@ Stat(const char *name, struct stat *sb) } else { ret = -EIO; } + } else if (rc == ERROR_ACCESS_DENIED) { - // Junction enountered (e.g C:/Users/Default User --> Default), - // FindFirstFileA() behaviour is by design to stop applications recursively accessing symlinks. + // Junction encountered (e.g C:/Users/Default User --> Default), + // FindFirstFile() behaviour is by design to stop applications recursively accessing symlinks. fb.dwFileAttributes = attrs; ret = 0; + } else { // Other conditions. ret = -EIO; @@ -1879,9 +3055,14 @@ Stat(const char *name, struct stat *sb) DWORD count = 0; HANDLE handle; - if (INVALID_HANDLE_VALUE != (handle = - CreateFileA(fullname, (domagic ? GENERIC_READ : 0), 0, NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, NULL))) { + handle = CreateFileW(fullname, READ_CONTROL, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, NULL); + if (INVALID_HANDLE_VALUE == handle) { + handle = CreateFileW(fullname, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, NULL); + } + + if (INVALID_HANDLE_VALUE != handle) { // // file information // FILE_FLAG_BACKUP_SEMANTICS permit directories to be open'ed @@ -1937,8 +3118,8 @@ Stat(const char *name, struct stat *sb) const size_t offset = rdb->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); const wchar_t* mount = rdb->MountPointReparseBuffer.PathBuffer + offset; - if (0 == memcmp(mount, L"\\??\\", 4 * sizeof(wchar_t)) && - 0 != memcmp(mount, L"\\??\\Volume{", 11 * sizeof(wchar_t))) { + if (0 == wmemcmp(mount, L"\\??\\", 4) && + 0 != wmemcmp(mount, L"\\??\\Volume{", 11)) { dirsymlink = TRUE; /* not a volume mount point -- hard-link */ } @@ -1969,15 +3150,18 @@ Stat(const char *name, struct stat *sb) { DWORD serialno = 0, flags = 0; if (my_GetVolumeInformationByHandle(handle, &serialno, &flags)) { sb->st_dev = serialno; + // volume serial number that the operating system assigns + // when a hard disk is formatted. } } // // inode emulation if (0 == sb->st_ino) { - sb->st_ino = w32_ino_hash(fullname); + sb->st_ino = w32_ino_whash(fullname); } + ApplyOwner(sb, fb.dwFileAttributes, handle); CloseHandle(handle); } else { @@ -1988,17 +3172,15 @@ Stat(const char *name, struct stat *sb) } #endif //DO_MAGIC - if (root) { + if (dwRootAttributes) { ret = -ENOENT; - } else if (0 == (sb->st_ino = w32_ino_file(fullname))) { - sb->st_ino = w32_ino_hash(fullname); + } else if (0 == (sb->st_ino = w32_ino_wfile(fullname))) { + sb->st_ino = w32_ino_whash(fullname); + ApplyOwner(sb, fb.dwFileAttributes, NULL); } } - if (root) { - fb.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; - } - ApplyAttributes(sb, fb.dwFileAttributes, fullname, magic); + ApplyAttributesW(sb, fb.dwFileAttributes|dwRootAttributes, fullname, magic); if (dirsymlink) { // NOTE: Directory reparse-points are hidden, as these are closer to hard-links // other link types are reclassed as symlinks. @@ -2067,7 +3249,6 @@ my_GetVolumeInformationByHandle(HANDLE handle, DWORD *serialno, DWORD *flags) } - static BOOL WINAPI my_GetVolumeInformationByHandleImp(HANDLE hFile, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, @@ -2086,4 +3267,78 @@ my_GetVolumeInformationByHandleImp(HANDLE hFile, return FALSE; } + +int +w32_io_stricmp(const char *s1, const char *s2) +{ + char a = 0, b = 0; + + do { + a = *s1++; if (a < 0x7f) a = tolower(a); + b = *s2++; if (b < 0x7f) b = tolower(b); + if (a != b) { + return a - b; + } + } while (a); + return 0; +} + + +int +w32_io_strnicmp(const char *s1, const char *s2, int slen) +{ + char a = 0, b = 0; + + if (slen > 0) { + do { + a = *s1++; if (a < 0x7f) a = tolower(a); + b = *s2++; if (b < 0x7f) b = tolower(b); + if (a != b) { + return a - b; + } + if (0 == --slen) { + break; + } + } while (a); + } + return 0; +} + + +int +w32_io_wstricmp(const wchar_t *s1, const char *s2) +{ + wchar_t a = 0, b = 0; + + do { + a = *s1++; if (a < 0x7f) a = tolower((char)a); + b = *s2++; if (b < 0x7f) b = tolower((char)b); + if (a != b) { + return a - b; + } + } while (a); + return 0; +} + + +int +w32_io_wstrnicmp(const wchar_t *s1, const char *s2, int slen) +{ + wchar_t a = 0, b = 0; + + if (slen > 0) { + do { + a = *s1++; if (a < 0x7f) a = tolower((char)a); + b = *s2++; if (b < 0x7f) b = tolower((char)b); + if (a != b) { + return a - b; + } + if (0 == --slen) { + break; + } + } while (a); + } + return 0; +} + /*end*/ diff --git a/libw32/w32_itimer.c b/libw32/w32_itimer.c index 5fcba40c..905c61f3 100644 --- a/libw32/w32_itimer.c +++ b/libw32/w32_itimer.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_itimer_c,"$Id: w32_itimer.c,v 1.2 2020/06/18 14:32:39 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_itimer_c,"$Id: w32_itimer.c,v 1.4 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 itimer system calls -- INCOMPLETE, signal interface required. * - * Copyright (c) 2018 - 2019, Adam Young. + * Copyright (c) 2018 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_itimer_c,"$Id: w32_itimer.c,v 1.2 2020/06/18 14:32:39 cvsu * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -160,7 +160,9 @@ timer_thread(LPVOID param) LeaveCriticalSection(&itimer.lock); } else if (WAIT_TIMEOUT == rc) { /* trigger */ - w32_raise(SIGALRM); //HOW??? +#if defined(SIGALRM) + w32_raise(SIGALRM); +#endif waitms = INFINITE; } else { @@ -250,7 +252,3 @@ setitimer(int which, const struct itimerval *value, struct itimerval *ovalue) } /*end*/ - - - - diff --git a/libw32/w32_langinfo.c b/libw32/w32_langinfo.c index be080427..ded4d658 100644 --- a/libw32/w32_langinfo.c +++ b/libw32/w32_langinfo.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_langinfo_c,"$Id: w32_langinfo.c,v 1.10 2019/03/15 23:12:17 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_langinfo_c,"$Id: w32_langinfo.c,v 1.12 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 langinfo() implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_langinfo_c,"$Id: w32_langinfo.c,v 1.10 2019/03/15 23:12:17 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -80,11 +80,10 @@ LIBW32_API const char * nl_langinfo(nl_item item) { switch (item) { - case CODESET: /* assume terminal is UTF-8 */ - return "UTF-8"; + case CODESET: /* assume terminal is UTF-8 */ + return "UTF-8"; /* TODO: Hook vio driver*/ } return "n/a"; } /*end*/ - diff --git a/libw32/w32_link.c b/libw32/w32_link.c index 5cdece87..06643f13 100644 --- a/libw32/w32_link.c +++ b/libw32/w32_link.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_link_c,"$Id: w32_link.c,v 1.14 2020/04/20 23:18:24 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_link_c,"$Id: w32_link.c,v 1.17 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win2 link system calls. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_link_c,"$Id: w32_link.c,v 1.14 2020/04/20 23:18:24 cvsuser * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -36,13 +36,20 @@ __CIDENT_RCSID(gr_w32_link_c,"$Id: w32_link.c,v 1.14 2020/04/20 23:18:24 cvsuser */ #include "win32_internal.h" +#include "win32_io.h" #include +typedef BOOL(WINAPI *CreateHardLinkW_t)( + LPCWSTR lpFileName, LPCWSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); + typedef BOOL(WINAPI *CreateHardLinkA_t)( LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); -static BOOL my_CreateHardLink(const char *lpLinkFileName, const char *lpTargetFileName); -static BOOL WINAPI my_CreateHardLinkImp(LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); +static BOOL my_CreateHardLinkW(const wchar_t *lpLinkFileName, const wchar_t *lpTargetFileName); +static BOOL WINAPI my_CreateHardLinkImpW(LPCWSTR lpFileName, LPCWSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); + +static BOOL my_CreateHardLinkA(const char *lpLinkFileName, const char *lpTargetFileName); +static BOOL WINAPI my_CreateHardLinkImpA(LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); int __w32_link_backup = FALSE; @@ -127,8 +134,77 @@ int __w32_link_backup = FALSE; // As a result of encountering a symbolic link in resolution of the path1 or path2 // argument, the length of the substituted pathname string exceeded { PATH_MAX}. */ + LIBW32_API int w32_link(const char *path1, const char *path2) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath1[WIN32_PATH_MAX], wpath2[WIN32_PATH_MAX]; + + if (NULL == path1 || NULL == path2) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path1, wpath1, _countof(wpath1)) > 0 && + w32_utf2wc(path2, wpath2, _countof(wpath2)) > 0) { + return w32_linkW(wpath1, wpath2); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_linkA(path1, path2); +} + + +LIBW32_API int +w32_linkW(const wchar_t *path1, const wchar_t *path2) +{ + int ret = -1; + + if (!path1 || !path2) { + errno = EFAULT; + + } else if (!*path1 || !*path2) { + errno = ENOENT; + + } else if (wcslen(path1) > MAX_PATH || wcslen(path2) > MAX_PATH) { + errno = ENAMETOOLONG; + + } else if (GetFileAttributesW(path2) != INVALID_FILE_ATTRIBUTES /*0xffffffff*/) { + errno = EEXIST; + + } else { // Note: Generally only available under an Admin account + ret = 0; + if (! my_CreateHardLinkW(/*target-link*/ path2, /*existing*/ path1)) { + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_PRIVILEGE_NOT_HELD: + errno = EACCES; break; + case ERROR_FILE_NOT_FOUND: + errno = ENOENT; break; + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + errno = ENOTDIR; break; + case ERROR_WRITE_PROTECT: + errno = EROFS; break; + default: + w32_errno_set(); + break; + } + ret = -1; + } + } + return ret; +} + + +LIBW32_API int +w32_linkA(const char *path1, const char *path2) { int ret = -1; @@ -146,7 +222,7 @@ w32_link(const char *path1, const char *path2) } else { // Note: Generally only available under an Admin account ret = 0; - if (! my_CreateHardLink(/*target-link*/ path2, /*existing*/ path1)) { + if (! my_CreateHardLinkA(/*target-link*/ path2, /*existing*/ path1)) { switch (GetLastError()) { case ERROR_ACCESS_DENIED: case ERROR_SHARING_VIOLATION: @@ -171,7 +247,73 @@ w32_link(const char *path1, const char *path2) static BOOL -my_CreateHardLink(LPCSTR lpFileName, LPCSTR lpExistingFileName) +my_CreateHardLinkW(LPCWSTR lpFileName, LPCWSTR lpExistingFileName) +{ + static CreateHardLinkW_t x_CreateHardLinkW = NULL; + + if (NULL == x_CreateHardLinkW) { + HINSTANCE hinst; // Vista+ + + if (0 == (hinst = LoadLibraryA("Kernel32")) || + 0 == (x_CreateHardLinkW = + (CreateHardLinkW_t)GetProcAddress(hinst, "CreateHardLinkW"))) { + // XP+ + x_CreateHardLinkW = my_CreateHardLinkImpW; + (void)FreeLibrary(hinst); + } + } + return x_CreateHardLinkW(lpFileName, lpExistingFileName, NULL); +} + + +static BOOL WINAPI +my_CreateHardLinkImpW(LPCWSTR lpFileName, LPCWSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) +{ + __PUNUSED(lpSecurityAttributes) + + if (!__w32_link_backup) { /* backup fallback option */ + SetLastError(ERROR_NOT_SUPPORTED); // not implemented + return FALSE; + + } else { + WIN32_STREAM_ID wsi = { 0 }; + void *ctx = NULL; + HANDLE handle; + int wlen; + DWORD cnt; + + if (INVALID_HANDLE_VALUE == /* source image */ + (handle = CreateFileW(lpExistingFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL))) { + w32_errno_set(); + CloseHandle(handle); + return FALSE; + } + + wlen = wcslen(lpFileName); + wsi.dwStreamId = BACKUP_LINK; + wsi.dwStreamAttributes = 0; + wsi.dwStreamNameSize = 0; + wsi.Size.QuadPart = wlen; + + if (!BackupWrite(handle, (LPBYTE)&wsi, offsetof(WIN32_STREAM_ID, cStreamName), &cnt, FALSE, FALSE, &ctx) || + offsetof(WIN32_STREAM_ID, cStreamName) != cnt || + !BackupWrite(handle, (LPBYTE)lpFileName, wlen, &cnt, FALSE, FALSE, &ctx)) { + w32_errno_set(); + CloseHandle(handle); + return FALSE; + } + + BackupWrite(handle, NULL, 0, &cnt, TRUE, FALSE, &ctx); + CloseHandle(handle); + + return TRUE; + } +} + + +static BOOL +my_CreateHardLinkA(LPCSTR lpFileName, LPCSTR lpExistingFileName) { static CreateHardLinkA_t x_CreateHardLinkA = NULL; @@ -182,7 +324,7 @@ my_CreateHardLink(LPCSTR lpFileName, LPCSTR lpExistingFileName) 0 == (x_CreateHardLinkA = (CreateHardLinkA_t)GetProcAddress(hinst, "CreateHardLinkA"))) { // XP+ - x_CreateHardLinkA = my_CreateHardLinkImp; + x_CreateHardLinkA = my_CreateHardLinkImpA; (void)FreeLibrary(hinst); } } @@ -191,7 +333,7 @@ my_CreateHardLink(LPCSTR lpFileName, LPCSTR lpExistingFileName) static BOOL WINAPI -my_CreateHardLinkImp(LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) +my_CreateHardLinkImpA(LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) { __PUNUSED(lpSecurityAttributes) @@ -208,7 +350,7 @@ my_CreateHardLinkImp(LPCSTR lpFileName, LPCSTR lpExistingFileName, LPSECURITY_AT DWORD cnt; if (INVALID_HANDLE_VALUE == /* source image */ - (handle = CreateFile(lpExistingFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + (handle = CreateFileA(lpExistingFileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL))) { w32_errno_set(); CloseHandle(handle); diff --git a/libw32/w32_mknod.c b/libw32/w32_mknod.c index d3cfdc1f..212b3b2a 100644 --- a/libw32/w32_mknod.c +++ b/libw32/w32_mknod.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_mknod_c,"$Id: w32_mknod.c,v 1.13 2019/03/15 23:12:18 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_mknod_c,"$Id: w32_mknod.c,v 1.15 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 mknod() system calls. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_mknod_c,"$Id: w32_mknod.c,v 1.13 2019/03/15 23:12:18 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -198,5 +198,26 @@ mknod(const char *path, int mode, int dev) return -1; } -/*end*/ +LIBW32_API int +mknodA(const char *path, int mode, int dev) +{ + __CUNUSED(path) + __CUNUSED(mode) + __CUNUSED(dev) + errno = EIO; + return -1; +} + + +LIBW32_API int +mknodW(const wchar_t *path, int mode, int dev) +{ + __CUNUSED(path) + __CUNUSED(mode) + __CUNUSED(dev) + errno = EIO; + return -1; +} + +/*end*/ diff --git a/libw32/w32_mkstemp.c b/libw32/w32_mkstemp.c index be60a0b5..1b65379d 100644 --- a/libw32/w32_mkstemp.c +++ b/libw32/w32_mkstemp.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_mkstemp_c,"$Id: w32_mkstemp.c,v 1.15 2019/03/15 23:12:18 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_mkstemp_c,"$Id: w32_mkstemp.c,v 1.17 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 mkstemp implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_mkstemp_c,"$Id: w32_mkstemp.c,v 1.15 2019/03/15 23:12:18 c * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -36,92 +36,421 @@ __CIDENT_RCSID(gr_w32_mkstemp_c,"$Id: w32_mkstemp.c,v 1.15 2019/03/15 23:12:18 c */ #include "win32_internal.h" +#include "win32_io.h" #include #include #include #include #include +#ifdef HAVE_WCHAR_H +#include +#endif #include #define DISABLE_HARD_ERRORS (void)SetErrorMode (0); #define ENABLE_HARD_ERRORS (void)SetErrorMode (SEM_FAILCRITICALERRORS | \ SEM_NOOPENFILEERRORBOX); + + /* + // NAME + // mkstemp - make a unique filename + // + // SYNOPSIS + // #include + // + // int mkstemp(char *template); + // int mkstemps(char *template, int suffixlen); + // + // DESCRIPTION + // + // The mkstemp() function shall replace the contents of the string pointed to by + // template by a unique filename, and return a file descriptor for the file open for + // reading and writing. The function thus prevents any possible race condition between + // testing whether the file exists and opening it for use. + // + // The string in template should look like a filename with six trailing 'X' s; + // mkstemp() replaces each 'X' with a character from the portable filename character + // set. The characters are chosen such that the resulting name does not duplicate the + // name of an existing file at the time of a call to mkstemp(). + // + // Each successful call to mkstemp modifies template. In each subsequent call from the same + // process or thread with the same template argument, mkstemp checks for filenames that + // match names returned by mkstemp in previous calls. If no file exists for a given name, + // mkstemp returns that name. If files exist for all previously returned names, mkstemp + // creates a new name by replacing the alphabetic character it used in the previously + // returned name with the next available lowercase letter, in order, from 'a' through 'z'. + // + // RETURN VALUE + // + // Upon successful completion, mkstemp() shall return an open file descriptor. + // Otherwise, -1 shall be returned if no suitable file could be created. + // + // ERRORS + // No errors are defined. + */ + +#define GETTEMP_SUCCESS 1 +#define GETTEMP_ERROR 0 + +#define DO_DEFAULT 0 +#define DO_TEMPORARY 1 +#define DO_MKDIR 2 + +static int gettempA_tmp(char *result, const char *path, int suffixlen, int *fildes, unsigned flags); +static int gettempA(char *path, int suffixlen, int *fildes, unsigned flags, char *save); +static int gettempW_tmp(wchar_t *result, const wchar_t *path, int suffixlen, int *fildes, unsigned flags); +static int gettempW(wchar_t *path, int suffixlen, int *fildes, unsigned flags, wchar_t *save); + + +LIBW32_API int +w32_mkstemp(char *path) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[MAX_PATH]; + int fildes; + + w32_utf2wc(path, wpath, _countof(wpath)); + if ((fildes = w32_mkstempW(wpath)) >= 0) { + w32_wc2utf(wpath, path, strlen(path) + 1); + return fildes; + } + return -1; + } +#endif //UTF8FILENAMES + + return w32_mkstempA(path); +} + + +LIBW32_API int +w32_mkstempA(char *path) +{ + char t_path[MAX_PATH]; + int fildes = -1; + if (GETTEMP_SUCCESS == gettempA(path, 0, &fildes, DO_DEFAULT, t_path) || + GETTEMP_SUCCESS == gettempA_tmp(path, t_path, 0, &fildes, DO_DEFAULT)) { + return fildes; + } + return -1; +} + + +LIBW32_API int +w32_mkstempW(wchar_t *path) +{ + wchar_t t_path[MAX_PATH]; + int fildes = -1; + if (GETTEMP_SUCCESS == gettempW(path, 0, &fildes, DO_DEFAULT, t_path) || + GETTEMP_SUCCESS == gettempW_tmp(path, t_path, 0, &fildes, DO_DEFAULT)) { + return fildes; + } + return -1; +} + + +///////////////////////////////////////////////////////////////////////////////////////// + +LIBW32_API int +w32_mkstemps(char *path, int suffixlen) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[MAX_PATH]; + int fildes; + + w32_utf2wc(path, wpath, _countof(wpath)); + if ((fildes = w32_mkstempsW(wpath, suffixlen)) >= 0) { + w32_wc2utf(wpath, path, strlen(path) + 1); + return fildes; + } + return -1; + } +#endif //UTF8FILENAMES + + return w32_mkstempsA(path, suffixlen); +} + + +LIBW32_API int +w32_mkstempsA(char *path, int suffixlen) +{ + char t_path[MAX_PATH]; + int fildes = -1; + if (GETTEMP_SUCCESS == gettempA(path, suffixlen, &fildes, DO_DEFAULT, t_path) || + GETTEMP_SUCCESS == gettempA_tmp(path, t_path, suffixlen, &fildes, DO_DEFAULT)) { + return fildes; + } + return -1; +} + + +LIBW32_API int +w32_mkstempsW(wchar_t *path, int suffixlen) +{ + wchar_t t_path[MAX_PATH]; + int fildes = -1; + if (GETTEMP_SUCCESS == gettempW(path, suffixlen, &fildes, DO_DEFAULT, t_path) || + GETTEMP_SUCCESS == gettempW_tmp(path, t_path, suffixlen, &fildes, DO_DEFAULT)) { + return fildes; + } + return -1; +} + + +///////////////////////////////////////////////////////////////////////////////////////// + +LIBW32_API int +w32_mkstempx(char *path) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[MAX_PATH]; + int fildes; + + w32_utf2wc(path, wpath, _countof(wpath)); + if ((fildes = w32_mkstempxW(wpath)) >= 0) { + w32_wc2utf(wpath, path, strlen(path) + 1); + return fildes; + } + return -1; + } +#endif //UTF8FILENAMES + + return w32_mkstempxA(path); +} + + +LIBW32_API int +w32_mkstempxA(char *path) +{ + char t_path[MAX_PATH]; + int fildes = -1; + if (GETTEMP_SUCCESS == gettempA(path, 0, &fildes, DO_TEMPORARY, t_path) || + GETTEMP_SUCCESS == gettempA_tmp(path, t_path, 0, &fildes, DO_TEMPORARY)) { + return fildes; + } + return -1; +} + + +LIBW32_API int +w32_mkstempxW(wchar_t *path) +{ + wchar_t t_path[MAX_PATH]; + int fildes = -1; + if (GETTEMP_SUCCESS == gettempW(path, 0, &fildes, DO_TEMPORARY, t_path) || + GETTEMP_SUCCESS == gettempW_tmp(path, t_path, 0, &fildes, DO_TEMPORARY)) { + return fildes; + } + return -1; +} + + /* // NAME -// mkstemp - make a unique filename +// mkdtemp - create a unique temporary directory. // // SYNOPSIS // #include // -// int mkstemp(char *template); +// char *mkdtemp(char *template); // // DESCRIPTION +// The mkdtemp() function shall create a directory with a unique name derived from +// template. The application shall ensure that the string provided in template is a +// pathname ending with at least six trailing 'X' characters. The mkdtemp() function +// shall modify the contents of template by replacing six or more 'X' characters at +// the end of the pathname with the same number of characters from the portable +// filename character set. The characters shall be chosen such that the resulting +// pathname does not duplicate the name of an existing file at the time of the call +// to mkdtemp(). The mkdtemp() function shall use the resulting pathname to create +// the new directory as if by a call to: // -// The mkstemp() function shall replace the contents of the string pointed to by -// template by a unique filename, and return a file descriptor for the file open for -// reading and writing. The function thus prevents any possible race condition between -// testing whether the file exists and opening it for use. +// mkdir(pathname, S_IRWXU) // -// The string in template should look like a filename with six trailing 'X' s; -// mkstemp() replaces each 'X' with a character from the portable filename character -// set. The characters are chosen such that the resulting name does not duplicate the -// name of an existing file at the time of a call to mkstemp(). +// The mkstemp() function shall create a regular file with a unique name derived from +// template and return a file descriptor for the file open for reading and writing. +// The application shall ensure that the string provided in template is a pathname +// ending with at least six trailing 'X' characters. The mkstemp() function shall +// modify the contents of template by replacing six or more 'X' characters at the +// end of the pathname with the same number of characters from the portable filename +// character set. The characters shall be chosen such that the resulting pathname +// does not duplicate the name of an existing file at the time of the call to mkstemp(). +// The mkstemp() function shall use the resulting pathname to create the file, and +// obtain a file descriptor for it, as if by a call to: // -// Each successful call to mkstemp modifies template. In each subsequent call from the same -// process or thread with the same template argument, mkstemp checks for filenames that -// match names returned by mkstemp in previous calls. If no file exists for a given name, -// mkstemp returns that name. If files exist for all previously returned names, mkstemp -// creates a new name by replacing the alphabetic character it used in the previously -// returned name with the next available lowercase letter, in order, from 'a' through 'z'. -// -// RETURN VALUE +// open(pathname, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR) // -// Upon successful completion, mkstemp() shall return an open file descriptor. -// Otherwise, -1 shall be returned if no suitable file could be created. +// By behaving as if the O_EXCL flag for open() is set, the function prevents any possible +// race condition between testing whether the file exists and opening it for use. // -// ERRORS -// No errors are defined. +// RETURN VALUE +// Upon successful completion, the mkdtemp() function shall return the value of template. +// Otherwise, it shall return a null pointer and shall set errno to indicate the error. */ -#define GETTEMP_SUCCESS 1 -#define GETTEMP_ERROR 0 -static int gettemp(char *path, register int *fd, int temporary); +LIBW32_API char * +w32_mkdtemp(char *path) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[MAX_PATH]; + w32_utf2wc(path, wpath, _countof(wpath)); + if (w32_mkdtempW(wpath)) { + w32_wc2utf(wpath, path, strlen(path) + 1); + return path; + } + return NULL; + } +#endif //UTF8FILENAMES -LIBW32_API int -w32_mkstemp(char *path) + return w32_mkdtempA(path); +} + + +LIBW32_API char * +w32_mkdtempA(char *path) { - int fildes = -1; - return (GETTEMP_SUCCESS == gettemp(path, &fildes, FALSE) ? fildes : -1); + return (GETTEMP_SUCCESS == gettempA(path, 0, NULL, DO_MKDIR, NULL) ? path : NULL); } -LIBW32_API int -w32_mkstempx(char *path) +LIBW32_API wchar_t * +w32_mkdtempW(wchar_t *path) { - int fildes = -1; - return (GETTEMP_SUCCESS == gettemp(path, &fildes, TRUE) ? fildes : -1); + return (GETTEMP_SUCCESS == gettempW(path, 0, NULL, DO_MKDIR, NULL) ? path : NULL); +} + + +LIBW32_API char * +w32_mkdtemps(char *path, int suffixlen) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[MAX_PATH]; + + w32_utf2wc(path, wpath, _countof(wpath)); + if (w32_mkdtempsW(wpath, suffixlen)) { + w32_wc2utf(wpath, path, strlen(path) + 1); + return path; + } + return NULL; + } +#endif //UTF8FILENAMES + + return w32_mkdtempsA(path, suffixlen); +} + + +LIBW32_API char * +w32_mkdtempsA(char *path, int suffixlen) +{ + return (GETTEMP_SUCCESS == gettempA(path, suffixlen, NULL, DO_MKDIR, NULL) ? path : NULL); +} + + +LIBW32_API wchar_t * +w32_mkdtempsW(wchar_t *path, int suffixlen) +{ + return (GETTEMP_SUCCESS == gettempW(path, suffixlen, NULL, DO_MKDIR, NULL) ? path : NULL); +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// Implementation + +static unsigned +generate_seed(void) +{ + static unsigned seed; + if (0 == seed) seed = (WIN32_GETPID() * GetTickCount()); + seed = (1103515245 * seed + 12345); + return seed; } static int -gettemp(char *path, register int *fildes, int temporary) +gettempA_tmp(char *result, const char *path, int suffixlen, int *fildes, unsigned flags) { - register char *start, *trv; + /* + * "/tmp/", reference system temporary path + */ + if (path && 0 == memcmp(path, "/tmp/", 5)) { + char t_path[MAX_PATH], *p; + int pathlen = strlen(path + 5), + tmplen = (int)GetTempPathA(_countof(t_path), t_path); + // TMP, TEMP, USERPROFILE environment variables, default windows directory. + + if (pathlen && tmplen) { + if ((pathlen + tmplen) >= _countof(t_path)) { + errno = ENAMETOOLONG; + + } else { + if (t_path[tmplen-1] != '\\') { + t_path[tmplen-1] = '\\', ++tmplen; + } + memcpy(t_path + tmplen, path + 5, pathlen + 1 /*nul*/); + for (p = t_path; NULL != (p = strchr(p, '/'));) { + *p++ = '\\'; /* convert */ + } + + if (GETTEMP_SUCCESS == gettempA(t_path, suffixlen, fildes, flags, NULL)) { + strcpy(result, "/tmp/"); + strcpy(result + 5, t_path + tmplen); + return GETTEMP_SUCCESS; + } + } + } + } + return GETTEMP_ERROR; +} + + +static int +gettempA(char *path, int suffixlen, int *fildes, unsigned flags, char *save) +{ + register char *start, *trv, *end, c; struct stat sbuf; - unsigned pid; + unsigned seed; int rc; - char c; - pid = (unsigned) WIN32_GETPID(); - for (trv = path; *trv; ++trv) /* extra X's get set to 0's */ - /*continue*/; - while (*--trv == 'X' && trv >= path) { - *trv = (char)((pid % 10) + '0'); - pid /= 10; + if (save) { + for (trv = path; (*save = *trv) != 0; ++save) { + if ((++trv - path) >= MAX_PATH) { + errno = ENAMETOOLONG; + return GETTEMP_ERROR; + } + } + } else { + for (trv = path; *trv; ++trv); + if ((trv - path) >= MAX_PATH) { + errno = ENAMETOOLONG; + return GETTEMP_ERROR; + } + } + + trv -= suffixlen; + end = trv; + if (suffixlen < 0 || trv <= path || /* out-of-bounds? */ + NULL != strchr(end, '/') || NULL != strchr(end, '\\')) { + errno = EINVAL; + return GETTEMP_ERROR; + } + + seed = generate_seed(); + while (--trv >= path && *trv == 'X') { + *trv = (char)((seed % 10) + '0'); + seed /= 10; /* extra X's get set to 0's */ + } + + if ((trv + 1) == end) { /* missing template? */ + errno = EINVAL; + return GETTEMP_ERROR; } /* @@ -134,14 +463,14 @@ gettemp(char *path, register int *fildes, int temporary) } if ((c = *trv) == '/' || c == '\\') { - *trv = '\0'; if (trv[-1] == ':') { - *trv = c; break; } + *trv = '\0'; DISABLE_HARD_ERRORS - rc = stat(path, &sbuf); + rc = w32_statA(path, &sbuf); ENABLE_HARD_ERRORS + *trv = c; if (rc) { return GETTEMP_ERROR; } @@ -149,7 +478,6 @@ gettemp(char *path, register int *fildes, int temporary) errno = ENOTDIR; return GETTEMP_ERROR; } - *trv = c; break; } } @@ -170,33 +498,216 @@ gettemp(char *path, register int *fildes, int temporary) for (;;) { errno = 0; - if (fildes) { - if ((*fildes = WIN32_OPEN(path, (temporary ? O_MODEX : O_MODE), 0600)) >= 0) { - return GETTEMP_SUCCESS; + if (DO_MKDIR & flags) { + if (0 == w32_mkdirA(path, 0700)) { + return GETTEMP_SUCCESS; + } + if (EEXIST != errno) { + return GETTEMP_ERROR; + } + + } else if (fildes) { + if ((*fildes = WIN32_OPEN(path, ((DO_TEMPORARY & flags) ? O_MODEX : O_MODE), 0600)) >= 0) { + return GETTEMP_SUCCESS; + } + if (EEXIST != errno) { + return GETTEMP_ERROR; + } + + } else { + DISABLE_HARD_ERRORS + rc = w32_statA(path, &sbuf); + ENABLE_HARD_ERRORS + if (rc) { +#ifndef ENMFILE + return (((ENOENT == errno)) ? GETTEMP_SUCCESS : GETTEMP_ERROR); +#else + return (((ENOENT == errno) || (ENMFILE == errno)) ? GETTEMP_ERROR); +#endif + } + } + + /* next is sequence */ + for (trv = start;;) { + if (trv == end) { + return GETTEMP_ERROR; /* EOS */ + } + + if ('z' == *trv) { /* 0..9a..z */ + *trv++ = 'a'; + } else { + if (isdigit(*trv)) { + *trv = 'a'; + } else { + ++*trv; } - if (EEXIST != errno) { - return GETTEMP_ERROR; + break; + } + } + } + /*NOTREACHED*/ +} + + +static int +gettempW_tmp(wchar_t *result, const wchar_t *path, int suffixlen, int *fildes, unsigned flags) +{ + /* + * "/tmp/", reference system temporary path + */ + if (path && 0 == wmemcmp(path, L"/tmp/", 5)) { + wchar_t t_path[MAX_PATH], *p; + int pathlen = wcslen(path + 5), + tmplen = (int)GetTempPathW(_countof(t_path), t_path); + // TMP, TEMP, USERPROFILE environment variables, default windows directory. + + if (pathlen && tmplen) { + if ((pathlen + tmplen) >= (_countof(t_path) + 1)) { + errno = ENAMETOOLONG; + + } else { + if (t_path[tmplen-1] != '\\') { + t_path[tmplen-1] = '\\', ++tmplen; + } + wmemcpy(t_path + tmplen, path + 5, pathlen + 1 /*nul*/); + for (p = t_path; NULL != (p = wcschr(p, '/'));) { + *p++ = '\\'; /* convert */ } + + if (GETTEMP_SUCCESS == gettempW(t_path, suffixlen, fildes, flags, NULL)) { + wcscpy(result, L"/tmp/"); + wcscpy(result + 5, t_path + tmplen); + return GETTEMP_SUCCESS; + } + } + } + } + return GETTEMP_ERROR; +} + + +static int +gettempW(wchar_t *path, int suffixlen, int *fildes, unsigned flags, wchar_t *save) +{ + register wchar_t *start, *trv, *end, c; + struct stat sbuf; + unsigned seed; + int rc; + + if (save) { + for (trv = path; (*save = *trv) != 0; ++save) { + if ((++trv - path) >= MAX_PATH) { + errno = ENAMETOOLONG; + return GETTEMP_ERROR; + } + } + } else { + for (trv = path; *trv; ++trv); + if ((trv - path) >= MAX_PATH) { + errno = ENAMETOOLONG; + return GETTEMP_ERROR; + } + } + + trv -= suffixlen; + end = trv; + if (suffixlen < 0 || trv <= path || /* out-of-bounds? */ + NULL != wcschr(end, '/') || NULL != wcschr(end, '\\')) { + errno = EINVAL; + return GETTEMP_ERROR; + } + + seed = generate_seed(); + while (--trv >= path && *trv == 'X') { + *trv = (char)((seed % 10) + '0'); + seed /= 10; /* extra X's get set to 0's */ + } + + if ((trv + 1) == end) { /* missing template? */ + errno = EINVAL; + return GETTEMP_ERROR; + } + + /* + * check the target directory; if you have six X's and it + * doesn't exist this runs for a *very* long time. + */ + for (start = trv + 1;; --trv) { + if (trv <= path) { + break; + } + + if ((c = *trv) == '/' || c == '\\') { + if (trv[-1] == ':') { + break; + } + *trv = '\0'; + DISABLE_HARD_ERRORS + rc = w32_statW(path, &sbuf); + ENABLE_HARD_ERRORS + *trv = c; + if (rc) { + return GETTEMP_ERROR; + } + if (!(sbuf.st_mode & S_IFDIR)) { + errno = ENOTDIR; + return GETTEMP_ERROR; + } + break; + } + } + + /* + * Create file as temporary; file is deleted when last file descriptor is closed. + */ +#if defined(_O_TEMPORARY) +#define O_MODEX (O_CREAT|O_EXCL|O_RDWR|O_BINARY|_O_TEMPORARY) +#elif defined(O_TEMPORARY) +#define O_MODEX (O_CREAT|O_EXCL|O_RDWR|O_BINARY|O_TEMPORARY) +#else +#define O_MODEX (O_CREAT|O_EXCL|O_RDWR|O_BINARY) +#endif + +#define O_MODE (O_CREAT|O_EXCL|O_RDWR|O_BINARY) + + for (;;) { + errno = 0; + if (DO_MKDIR & flags) { + if (0 == w32_mkdirW(path, 0700)) { + return GETTEMP_SUCCESS; + } + if (EEXIST != errno) { + return GETTEMP_ERROR; + } + + } else if (fildes) { + if ((*fildes = WIN32_WOPEN(path, ((DO_TEMPORARY & flags) ? O_MODEX : O_MODE), 0600)) >= 0) { + return GETTEMP_SUCCESS; + } + if (EEXIST != errno) { + return GETTEMP_ERROR; + } + } else { - DISABLE_HARD_ERRORS - rc = stat(path, &sbuf); - ENABLE_HARD_ERRORS - if (rc) { + DISABLE_HARD_ERRORS + rc = w32_statW(path, &sbuf); + ENABLE_HARD_ERRORS + if (rc) { #ifndef ENMFILE - return (((ENOENT == errno)) ? GETTEMP_SUCCESS : GETTEMP_ERROR); + return (((ENOENT == errno)) ? GETTEMP_SUCCESS : GETTEMP_ERROR); #else - return (((ENOENT == errno) || (ENMFILE == errno)) ? GETTEMP_ERROR); + return (((ENOENT == errno) || (ENMFILE == errno)) ? GETTEMP_ERROR); #endif - } + } } /* next is sequence */ for (trv = start;;) { - if (*trv == '\0') { /* EOS */ - return GETTEMP_ERROR; + if (trv == end) { + return GETTEMP_ERROR; /* EOS */ } - if ('z' == *trv) { + if ('z' == *trv) { /* 0..9a..z */ *trv++ = 'a'; } else { if (isdigit(*trv)) { @@ -212,4 +723,3 @@ gettemp(char *path, register int *fildes, int temporary) } /*end*/ - diff --git a/libw32/w32_mmap.c b/libw32/w32_mmap.c index ed7ad58f..b28b0e78 100644 --- a/libw32/w32_mmap.c +++ b/libw32/w32_mmap.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_mmap_c,"$Id: w32_mmap.c,v 1.11 2020/03/28 00:24:23 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_mmap_c,"$Id: w32_mmap.c,v 1.12 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win2 mmap() system calls * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_mmap_c,"$Id: w32_mmap.c,v 1.11 2020/03/28 00:24:23 cvsuser * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -47,76 +47,76 @@ __CIDENT_RCSID(gr_w32_mmap_c,"$Id: w32_mmap.c,v 1.11 2020/03/28 00:24:23 cvsuser /* // NAME -// -// mmap - map pages of memory -// +// +// mmap - map pages of memory +// // SYNOPSIS -// +// // #include -// +// // void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off); -// +// // DESCRIPTION -// +// // The mmap() function establishes a mapping between a process' address space and a // file or shared memory object. The format of the call is as follows: -// +// // pa=mmap(addr, len, prot, flags, fildes, off); -// +// // The mmap() function establishes a mapping between the address space of the process // at an address pa for len bytes to the memory object represented by the file // descriptor fildes at offset off for len bytes. The value of pa is an -// implementation-dependent function of the parameter addr and the values of flags, +// implementation-dependent function of the parameter addr and the values of flags, // further described below. A successful mmap() call returns pa as its result. The // address range starting at pa and continuing for len bytes will be legitimate for // the possible (not necessarily current) address space of the process. The range of // bytes starting at off and continuing for len bytes will be legitimate for the // possible (not necessarily current) offsets in the file or shared memory object // represented by fildes. -// +// // The mapping established by mmap() replaces any previous mappings for those whole // pages containing any part of the address space of the process starting at pa and // continuing for len bytes. -// +// // If the size of the mapped file changes after the call to mmap() as a result of some // other operation on the mapped file, the effect of references to portions of the // mapped region that correspond to added or removed portions of the file is // unspecified. -// +// // The mmap() function is supported for regular files and shared memory objects. // Support for any other type of file is unspecified. -// +// // The parameter prot determines whether read, write, execute, or some combination of // accesses are permitted to the data being mapped. The prot should be either // PROT_NONE or the bitwise inclusive OR of one or more of the other flags in the // following table, defined in the header . -// +// // Symbolic Constant Description // PROT_READ Data can be read. // PROT_WRITE Data can be written. // PROT_EXEC Data can be executed. // PROT_NONE Data cannot be accessed. -// +// // If an implementation cannot support the combination of access types specified by // prot, the call to mmap() fails. An implementation may permit accesses other than // those specified by prot; however, the implementation will not permit a write to // succeed where PROT_WRITE has not been set or permit any access where PROT_NONE // alone has been set. The implementation will support at least the following values // of prot: PROT_NONE, PROT_READ, PROT_WRITE, and the inclusive OR of PROT_READ and -// PROT_WRITE. The file descriptor fildes will have been opened with read permission, +// PROT_WRITE. The file descriptor fildes will have been opened with read permission, // regardless of the protection options specified. If PROT_WRITE is specified, the // application must have opened the file descriptor fildes with write permission // unless MAP_PRIVATE is specified in the flags parameter as described below. -// +// // The parameter flags provides other information about the handling of the mapped // data. The value of flags is the bitwise inclusive OR of these options, defined in // : -// +// // Symbolic Constant Description // MAP_SHARED Changes are shared. // MAP_PRIVATE Changes are private. // MAP_FIXED Interpret addr exactly. -// +// // MAP_SHARED and MAP_PRIVATE describe the disposition of write references to the // memory object. If MAP_SHARED is specified, write references change the underlying // object. If MAP_PRIVATE is specified, modifications to the mapped data by the @@ -125,13 +125,13 @@ __CIDENT_RCSID(gr_w32_mmap_c,"$Id: w32_mmap.c,v 1.11 2020/03/28 00:24:23 cvsuser // done after the MAP_PRIVATE mapping is established are visible through the // MAP_PRIVATE mapping. Either MAP_SHARED or MAP_PRIVATE can be specified, but not // both. The mapping type is retained across fork(). -// +// // When MAP_FIXED is set in the flags argument, the implementation is informed that // the value of pa must be addr, exactly. If MAP_FIXED is set, mmap() may return // MAP_FAILED and set errno to [EINVAL]. If a MAP_FIXED request is successful, the // mapping established by mmap() replaces any previous mappings for the process' pages // in the range [pa, pa + len). -// +// // When MAP_FIXED is not set, the implementation uses addr in an unspecified manner to // arrive at pa. The pa so chosen will be an area of the address space that the // implementation deems suitable for a mapping of len bytes to the file. All @@ -140,111 +140,111 @@ __CIDENT_RCSID(gr_w32_mmap_c,"$Id: w32_mmap.c,v 1.11 2020/03/28 00:24:23 cvsuser // non-zero value of addr is taken to be a suggestion of a process address near which // the mapping should be placed. When the implementation selects a value for pa, it // never places a mapping at address 0, nor does it replace any extant mapping. -// +// // The off argument is constrained to be aligned and sized according to the value // returned by sysconf() when passed _SC_PAGESIZE or _SC_PAGE_SIZE. When MAP_FIXED is // specified, the argument addr must also meet these constraints. The implementation // performs mapping operations over whole pages. Thus, while the argument len need not // meet a size or alignment constraint, the implementation will include, in any // mapping operation, any partial page specified by the range [pa, pa + len). -// +// // The system always zero-fills any partial page at the end of an object. Further, the // system never writes out any modified portions of the last page of an object that // are beyond its end. References within the address range starting at pa and // continuing for len bytes to whole pages following the end of an object result in // delivery of a SIGBUS signal. -// +// // An implementation may deliver SIGBUS signals when a reference would cause an error // in the mapped object, such as out-of-space condition. -// +// // The mmap() function adds an extra reference to the file associated with the file // descriptor fildes which is not removed by a subsequent close() on that file // descriptor. This reference is removed when there are no more mappings to the file. -// +// // The st_atime field of the mapped file may be marked for update at any time between // the mmap() call and the corresponding munmap() call. The initial read or write // reference to a mapped region will cause the file's st_atime field to be marked for // update if it has not already been marked for update. -// +// // The st_ctime and st_mtime fields of a file that is mapped with MAP_SHARED and // PROT_WRITE, will be marked for update at some point in the interval between a write // reference to the mapped region and the next call to msync() with MS_ASYNC or -// MS_SYNC for that portion of the file by any process. If there is no such call, +// MS_SYNC for that portion of the file by any process. If there is no such call, // these fields may be marked for update at any time after a write reference if the // underlying file is modified as a result. -// +// // There may be implementation-dependent limits on the number of memory regions that // can be mapped (per process or per system). If such a limit is imposed, whether the // number of memory regions that can be mapped by a process is decreased by the use of // shmat() is implementation-dependent. -// +// // RETURN VALUE -// +// // Upon successful completion, the mmap() function returns the address at which the // mapping was placed (pa); otherwise, it returns a value of MAP_FAILED and sets errno // to indicate the error. The symbol MAP_FAILED is defined in the header . // No successful return from mmap() will return the value MAP_FAILED. -// +// // If mmap() fails for reasons other than [EBADF], [EINVAL] or [ENOTSUP], some of the // mappings in the address range starting at addr and continuing for len bytes may // have been unmapped. -// +// // ERRORS -// +// // The mmap() function will fail if: -// +// // [EACCES] // The fildes argument is not open for read, regardless of the protection // specified, or fildes is not open for write and PROT_WRITE was specified for a // MAP_SHARED type mapping. -// +// // [EAGAIN] // The mapping could not be locked in memory, if required by mlockall(), due to a // lack of resources. -// +// // [EBADF] // The fildes argument is not a valid open file descriptor. -// +// // [EINVAL] // The addr argument (if MAP_FIXED was specified) or off is not a multiple of the // page size as returned by sysconf(), or are considered invalid by the // implementation. -// +// // [EINVAL] // The value of flags is invalid (neither MAP_PRIVATE nor MAP_SHARED is set). -// +// // [EMFILE] // The number of mapped regions would exceed an implementation-dependent limit // (per process or per system). -// +// // [ENODEV] // The fildes argument refers to a file whose type is not supported by mmap(). -// +// // [ENOMEM] // MAP_FIXED was specified, and the range [addr, addr + len) exceeds that allowed // for the address space of a process; or if MAP_FIXED was not specified and there // is insufficient room in the address space to effect the mapping. -// +// // [ENOMEM] // The mapping could not be locked in memory, if required by mlockall(), because // it would require more space than the system is able to supply. -// +// // [ENOTSUP] -// The implementation does not support the combination of accesses requested in the prot argument. -// +// The implementation does not support the combination of accesses requested in the prot argument. +// // [ENXIO] -// Addresses in the range [off, off + len) are invalid for the object specified by fildes. -// +// Addresses in the range [off, off + len) are invalid for the object specified by fildes. +// // [ENXIO] // MAP_FIXED was specified in flags and the combination of addr, len and off is // invalid for the object specified by fildes. -// +// // [EOVERFLOW] // The file is a regular file and the value of off plus len exceeds the offset // maximum established in the open file description associated with fildes. -// +// // EXAMPLES -// None. +// None. */ LIBW32_API void * mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) @@ -255,8 +255,8 @@ mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) int ntflags; DWORD ntprot; - /* - * Map prot and flags, to system flags + /* + * Map prot and flags, to system flags */ if ((flags & MAP_PRIVATE) && (flags & MAP_SHARED) == 0) { if ((prot & PROT_ALL) == 0) { /* NONE */ @@ -318,8 +318,8 @@ mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) errno = EINVAL; } - /* - * Map the region + /* + * Map the region */ } else { #if defined(_WINCE) @@ -337,7 +337,7 @@ mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) errno = EINVAL; (void) UnmapViewOfFile( region ); region = MAP_FAILED; - + } else if ((flags & PROT_ALL) == 0) { (void) mprotect(addr, len, PROT_NONE); } @@ -351,13 +351,13 @@ mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) /* // NAME -// mprotect - set protection of memory mapping -// +// mprotect - set protection of memory mapping +// // SYNOPSIS // #include -// +// // int mprotect(void *addr, size_t len, int prot); -// +// // DESCRIPTION // The function mprotect() changes the access protections to be that specified by prot // for those whole pages containing any part of the address space of the process @@ -365,63 +365,63 @@ mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) // determines whether read, write, execute, or some combination of accesses are // permitted to the data being mapped. The prot argument should be either PROT_NONE or // the bitwise inclusive OR of one or more of PROT_READ, PROT_WRITE and PROT_EXEC. -// +// // If an implementation cannot support the combination of access types specified by // prot, the call to mprotect() fails. -// -// An implementation may permit accesses other than those specified by prot; however, +// +// An implementation may permit accesses other than those specified by prot; however, // no implementation permits a write to succeed where PROT_WRITE has not been set or // permits any access where PROT_NONE alone has been set. Implementations will support // at least the following values of prot: PROT_NONE, PROT_READ, PROT_WRITE, and the // inclusive OR of PROT_READ and PROT_WRITE. If PROT_WRITE is specified, the // application must have opened the mapped objects in the specified address range with -// write permission, unless MAP_PRIVATE was specified in the original mapping, +// write permission, unless MAP_PRIVATE was specified in the original mapping, // regardless of whether the file descriptors used to map the objects have since been // closed. -// +// // The implementation will require that addr be a multiple of the page size as // returned by sysconf(). -// +// // The behaviour of this function is unspecified if the mapping was not established by // a call to mmap(). -// +// // When mprotect() fails for reasons other than [EINVAL], the protections on some of // the pages in the range [addr, addr + len) may have been changed. -// +// // RETURN VALUE // Upon successful completion, mprotect() returns 0. Otherwise, it returns -1 and sets // errno to indicate the error. -// +// // ERRORS -// +// // The mprotect() function will fail if: -// +// // [EACCES] // The prot argument specifies a protection that violates the access permission // the process has to the underlying memory object. -// +// // [EAGAIN] // The prot argument specifies PROT_WRITE over a MAP_PRIVATE mapping and there are // insufficient memory resources to reserve for locking the private page. -// +// // [EINVAL] // The addr argument is not a multiple of the page size as returned by sysconf(). -// +// // [ENOMEM] // Addresses in the range [addr, addr + len) are invalid for the address space of // a process, or specify one or more pages which are not mapped. -// +// // [ENOMEM] // The prot argument specifies PROT_WRITE on a MAP_PRIVATE mapping, and it would // require more space than the system is able to supply for locking the private // pages, if required. -// +// // [ENOTSUP] // The implementation does not support the combination of accesses requested in // the prot argument. -// +// // EXAMPLES -// None. +// None. */ LIBW32_API int mprotect(void *addr, size_t len, int prot) @@ -454,12 +454,12 @@ mprotect(void *addr, size_t len, int prot) /* // NAME // msync - synchronize memory with physical storage -// +// // SYNOPSIS // #include -// +// // int msync(void *addr, size_t len, int flags); -// +// // DESCRIPTION // The msync() function shall write all modified data to permanent storage locations, // if any, in those whole pages containing any part of the address space of the @@ -480,49 +480,49 @@ mprotect(void *addr, size_t len, int prot) // on a shared memory object or a typed memory object is unspecified. [Option End] The // behavior of this function is unspecified if the mapping was not established by a // call to mmap(). -// +// // The flags argument is constructed from the bitwise-inclusive OR of one or more of // the following flags defined in the header: -// +// // Symbolic Constant Description // MS_ASYNC Perform asynchronous writes. // MS_SYNC Perform synchronous writes. // MS_INVALIDATE Invalidate cached data. -// +// // When MS_ASYNC is specified, msync() shall return immediately once all the write -// operations are initiated or queued for servicing; when MS_SYNC is specified, +// operations are initiated or queued for servicing; when MS_SYNC is specified, // msync() shall not return until all write operations are completed as defined for -// synchronized I/O data integrity completion. Either MS_ASYNC or MS_SYNC is specified, +// synchronized I/O data integrity completion. Either MS_ASYNC or MS_SYNC is specified, // but not both. -// +// // When MS_INVALIDATE is specified, msync() shall invalidate all cached copies of // mapped data that are inconsistent with the permanent storage locations such that // subsequent references shall obtain data that was consistent with the permanent // storage locations sometime between the call to msync() and the first subsequent // memory reference to the data. -// +// // If msync() causes any write to a file, the file's st_ctime and st_mtime fields // shall be marked for update. -// -// +// +// // RETURN VALUE // Upon successful completion, msync() shall return 0; otherwise, it shall return -1 // and set errno to indicate the error. -// +// // ERRORS -// +// // The msync() function shall fail if: -// +// // [EBUSY] // Some or all of the addresses in the range starting at addr and continuing for // len bytes are locked, and MS_INVALIDATE is specified. -// +// // [EINVAL] // The value of flags is invalid. -// +// // [EINVAL] // The value of addr is not a multiple of the page size {PAGESIZE}. -// +// // [ENOMEM] // The addresses in the range starting at addr and continuing for len bytes are // outside the range allowed for the address space of a process or specify one or @@ -547,59 +547,59 @@ msync(void *addr, size_t len, int flags) /* // NAME // munmap - unmap pages of memory -// +// // SYNOPSIS // #include -// +// // int munmap(void *addr, size_t len); -// +// // DESCRIPTION // The munmap() function shall remove any mappings for those entire pages containing // any part of the address space of the process starting at addr and continuing for // len bytes. Further references to these pages shall result in the generation of a // SIGSEGV signal to the process. If there are no mappings in the specified address // range, then munmap() has no effect. -// +// // The implementation shall require that addr be a multiple of the page size { // PAGESIZE}. -// +// // If a mapping to be removed was private, any modifications made in this address // range shall be discarded. -// +// // [ML|MLR] [Option Start] Any memory locks (see mlock() and mlockall() ) associated // with this address range shall be removed, as if by an appropriate call to // munlock(). [Option End] -// +// // [TYM] [Option Start] If a mapping removed from a typed memory object causes the // corresponding address range of the memory pool to be inaccessible by any process in // the system except through allocatable mappings (that is, mappings of typed memory // objects opened with the POSIX_TYPED_MEM_MAP_ALLOCATABLE flag), then that range of // the memory pool shall become deallocated and may become available to satisfy future // typed memory allocation requests. -// +// // A mapping removed from a typed memory object opened with the // POSIX_TYPED_MEM_MAP_ALLOCATABLE flag shall not affect in any way the availability // of that typed memory for allocation. [Option End] -// +// // The behavior of this function is unspecified if the mapping was not established by // a call to mmap(). -// +// // RETURN VALUE -// +// // Upon successful completion, munmap() shall return 0; otherwise, it shall return -1 // and set errno to indicate the error. -// +// // ERRORS -// +// // The munmap() function shall fail if: -// +// // [EINVAL] // Addresses in the range [addr, addr+len) are outside the valid range for the // address space of a process. -// +// // [EINVAL] // The len argument is 0. -// +// // [EINVAL] // The addr argument is not a multiple of the page size as returned by sysconf(). */ @@ -645,4 +645,3 @@ munlock(const void *addr, size_t len) //int munlockall(void); /*end*/ - diff --git a/libw32/w32_neterr.c b/libw32/w32_neterr.c index e9bbfbf1..7d108866 100644 --- a/libw32/w32_neterr.c +++ b/libw32/w32_neterr.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_neterr_c,"$Id: w32_neterr.c,v 1.11 2019/03/15 23:12:18 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_neterr_c,"$Id: w32_neterr.c,v 1.12 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 network errno mapping support * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_neterr_c,"$Id: w32_neterr.c,v 1.11 2019/03/15 23:12:18 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -151,4 +151,3 @@ w32_sockerrno_map(int nerrno) return nerrno; } #endif //DEFUNCT - diff --git a/libw32/w32_poll.c b/libw32/w32_poll.c index d63ddabc..915e7642 100644 --- a/libw32/w32_poll.c +++ b/libw32/w32_poll.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_poll_c,"$Id: w32_poll.c,v 1.6 2019/03/15 23:12:18 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_poll_c,"$Id: w32_poll.c,v 1.8 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 poll system calls * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_poll_c,"$Id: w32_poll.c,v 1.6 2019/03/15 23:12:18 cvsuser * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -209,7 +209,7 @@ w32_poll(int native, struct pollfd *fds, int cnt, int timeout) // WINSOCK_API_LINKAGE int WSAAPI WSAPoll(LPWSAPOLLFD, ULONG, INT); // ==> source: ws2_32.lib // - struct timeval tmval; + struct timeval tmval = {0}; struct fd_set rfds; struct fd_set wfds; struct fd_set efds; @@ -328,7 +328,7 @@ w32_poll(int native, struct pollfd *fds, int cnt, int timeout) - OOB data is available for reading (only if SO_OOBINLINE is disabled). */ BOOL state; - u_long val; + u_long val = 0; int len; for (i = 0; i < cnt; ++i) { @@ -371,4 +371,3 @@ w32_poll(int native, struct pollfd *fds, int cnt, int timeout) } /*end*/ - diff --git a/libw32/w32_popen.c b/libw32/w32_popen.c index aefde24f..fb28d7e1 100644 --- a/libw32/w32_popen.c +++ b/libw32/w32_popen.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_popen_c,"$Id: w32_popen.c,v 1.13 2020/04/20 23:05:42 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_popen_c,"$Id: w32_popen.c,v 1.14 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 popen implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_popen_c,"$Id: w32_popen.c,v 1.13 2020/04/20 23:05:42 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -37,6 +37,7 @@ __CIDENT_RCSID(gr_w32_popen_c,"$Id: w32_popen.c,v 1.13 2020/04/20 23:05:42 cvsus #include "win32_internal.h" #include "win32_child.h" +#include "win32_misc.h" /*#define USE_NATIVE_POPEN*/ /* test only */ @@ -59,10 +60,15 @@ struct pipe { struct pipe * next; }; +static FILE * PipeA(const char *cmd, const char *mode); +static FILE * PipeW(const wchar_t *cmd, const char *mode); + static int Dup(HANDLE old, HANDLE *dup, BOOL inherit); static int Pipe2(HANDLE *read, HANDLE *write, int inherit); static void Close(HANDLE handle); static void Close2(HANDLE handle, const char *desc); + +static void DisplayErrorA(HANDLE hOutput, const char *pszAPI, const char *args); static void InternalError(const char *pszAPI); static CRITICAL_SECTION pipe_guard; @@ -142,6 +148,45 @@ static struct pipe * pipe_queue = (void *)-1; */ LIBW32_API FILE * w32_popen(const char *cmd, const char *mode) +{ + if (NULL == cmd) { + errno = EFAULT; + return NULL; + } + +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t *wcmd = NULL; + FILE *ret = NULL; + + if (NULL != (wcmd = w32_utf2wca(cmd, NULL))) { + ret = PipeW(wcmd, mode); + free((void *)wcmd); + } + return ret; + } +#endif //UTF8FILENAMES + + return PipeA(cmd, mode); +} + + +LIBW32_API FILE * +w32_popenA(const char *cmd, const char *mode) +{ + return PipeA(cmd, mode); +} + + +LIBW32_API FILE * +w32_popenW(const wchar_t *cmd, const char *mode) +{ + return PipeW(cmd, mode); +} + + +static FILE * +PipeA(const char *cmd, const char *mode) { #if (defined(_MSVC_VER) || defined(__WATCOMC__)) && \ defined(USE_NATIVE_POPEN) @@ -151,7 +196,7 @@ w32_popen(const char *cmd, const char *mode) int redirect_error = FALSE; const char *shell = w32_getshell(); win32_spawn_t args = {0}; - char readOrWrite, textOrBinary; + char readOrWrite = 0, textOrBinary = 0; HANDLE in_read = INVALID_HANDLE_VALUE, in_write = INVALID_HANDLE_VALUE, out_read = INVALID_HANDLE_VALUE, out_write = INVALID_HANDLE_VALUE, err_read = INVALID_HANDLE_VALUE, err_write = INVALID_HANDLE_VALUE; @@ -159,9 +204,8 @@ w32_popen(const char *cmd, const char *mode) struct pipe *p = NULL; char *cmd2 = NULL; - if (NULL == cmd || NULL == mode ) { - errno = EINVAL; - return NULL; + if (NULL == cmd || NULL == mode) { + goto einvalid; } // new pipe node @@ -169,17 +213,26 @@ w32_popen(const char *cmd, const char *mode) case 'r': readOrWrite = 'r'; break; case 'w': readOrWrite = 'w'; break; default: - return NULL; // either r or w + goto einvalid; // either r or w } - switch (mode[1]) { - case 't': textOrBinary = 't'; break; - case 'b': textOrBinary = 'b'; break; - case 0: - textOrBinary = 'b'; // optional - break; - default: - return NULL; + + for (++mode; *mode; ++mode) { + switch (*mode) { + case 't': //text mode. + if (textOrBinary) goto einvalid; + textOrBinary = 't'; + break; + case 'b': //binary mode. + if (textOrBinary) goto einvalid; + textOrBinary = 'b'; + break; + case 'e': //ignore, close on exec (linux) + break; + default: + return NULL; + } } + if (!textOrBinary) textOrBinary = 'b'; // optional, binary default. if (NULL == (p = calloc(1, sizeof(*p)))) { return NULL; @@ -221,6 +274,9 @@ w32_popen(const char *cmd, const char *mode) } } + assert('t' == p->textOrBinary || 'b' == p->textOrBinary); + assert('r' == p->readOrWrite || 'w' == p->readOrWrite); + if ('r' == p->readOrWrite) { if (NULL == (p->file = _fdopen( // readable end of the pipe _open_osfhandle((long)out_read, @@ -241,9 +297,7 @@ w32_popen(const char *cmd, const char *mode) } setvbuf(p->file, NULL, _IONBF, 0); // non-buffered - // create the child process, - // on success return pipe - // + // create the child process, on success return pipe args.argv = argv; // argument vector args._dwFlags = // creation flags CREATE_DEFAULT_ERROR_MODE|CREATE_NO_WINDOW; @@ -254,7 +308,7 @@ w32_popen(const char *cmd, const char *mode) } if (0 != (p->handle = - w32_child_exec(&args, in_read, out_write, err_write))) { + w32_child_execA(&args, in_read, out_write, err_write))) { Close(in_read); Close(out_write); Close(err_write); free(cmd2); @@ -278,10 +332,167 @@ w32_popen(const char *cmd, const char *mode) free(cmd2); free(p); return NULL; + +einvalid: + errno = EINVAL; + return NULL; + #endif /*USE_NATIVE_POPEN*/ } +static FILE * +PipeW(const wchar_t *cmd, const char *mode) +{ +#if (defined(_MSVC_VER) || defined(__WATCOMC__)) && \ + defined(USE_NATIVE_POPEN) + return _wpopen(cmd, mode); + +#else + int redirect_error = FALSE; + const wchar_t *shell = w32_getshellW(); + win32_spawnw_t args = {0}; + char readOrWrite = 0, textOrBinary = 0; + HANDLE in_read = INVALID_HANDLE_VALUE, in_write = INVALID_HANDLE_VALUE, + out_read = INVALID_HANDLE_VALUE, out_write = INVALID_HANDLE_VALUE, + err_read = INVALID_HANDLE_VALUE, err_write = INVALID_HANDLE_VALUE; + const wchar_t *argv[4] = {0}; + struct pipe *p = NULL; + wchar_t *cmd2 = NULL; + + if (NULL == cmd || NULL == mode) { + goto einvalid; + } + + // new pipe node + switch (mode[0]) { + case 'r': readOrWrite = 'r'; break; + case 'w': readOrWrite = 'w'; break; + default: + goto einvalid; // either r or w + } + + for (++mode; *mode; ++mode) { + switch (*mode) { + case 't': //text mode. + if (textOrBinary) goto einvalid; + textOrBinary = 't'; + break; + case 'b': //binary mode. + if (textOrBinary) goto einvalid; + textOrBinary = 'b'; + break; + case 'e': //ignore, close on exec (linux) + break; + default: + return NULL; + } + } + if (!textOrBinary) textOrBinary = 'b'; // optional, binary default. + + if (NULL == (p = calloc(1, sizeof(*p)))) { + return NULL; + } + p->magic = PIPE_MAGIC; + p->readOrWrite = readOrWrite; + p->textOrBinary = textOrBinary; + + // detect the type of shell + argv[0] = shell; + if (w32_iscommandW(shell)) { + argv[1] = L"/C"; + if (NULL == wcsstr(L"2>&1", cmd)) { // redirect stderr to stdout ? */ + argv[2] = cmd; + } else { + argv[2] = cmd2 = WIN32_STRDUPW(cmd); + wcsncpy(wcsstr(L"2>&1", cmd2), L" ", 4); + redirect_error = TRUE; + } + argv[3] = NULL; + } else { + argv[1] = L"-i"; + argv[2] = cmd; + argv[3] = NULL; + } + + // create the Pipes... + if (! Pipe2(&in_read, &in_write, 1) || ! Pipe2(&out_read, &out_write, 2)) { + goto pipe_error; + } + + if (redirect_error) { // 2>&1 + if (! Dup(out_write, &err_write, TRUE)) { + goto pipe_error; + } + } else { // .. otherwise seperate pipe + if (! Pipe2(&err_read, &err_write, 2)) { + goto pipe_error; + } + } + + if ('r' == p->readOrWrite) { + if (NULL == (p->file = _fdopen( // readable end of the pipe + _open_osfhandle((long)out_read, + _O_NOINHERIT | ('b' == textOrBinary ? _O_BINARY : _O_TEXT)), + 'b' == textOrBinary ? "rb" : "rt"))) { + goto pipe_error; + } + out_read = INVALID_HANDLE_VALUE; + + } else { + if (NULL == (p->file = _fdopen( // writeable end of the pipe + _open_osfhandle((long)in_write, + _O_NOINHERIT | ('b' == textOrBinary ? _O_BINARY : _O_TEXT)), + 'b' == textOrBinary ? "wb" : "wt"))) { + goto pipe_error; + } + in_write = INVALID_HANDLE_VALUE; + } + setvbuf(p->file, NULL, _IONBF, 0); // non-buffered + + // create the child process, on success return pipe + args.argv = argv; // argument vector + args._dwFlags = // creation flags + CREATE_DEFAULT_ERROR_MODE|CREATE_NO_WINDOW; + + if ((void *)-1 == pipe_queue) { + InitializeCriticalSection(&pipe_guard); + pipe_queue = NULL; + } + + if (0 != (p->handle = + w32_child_execW(&args, in_read, out_write, err_write))) { + + Close(in_read); Close(out_write); Close(err_write); + free(cmd2); + + p->hIn = in_write; + p->hOut = out_read; + p->hErr = err_read; + p->pid = args._dwProcessId; // process identifier + + EnterCriticalSection(&pipe_guard); + p->next = pipe_queue; + pipe_queue = p; + LeaveCriticalSection(&pipe_guard); + return p->file; + } + + // on error, release pipe resources. +pipe_error: + Close(in_read); Close(out_write); Close(err_write); + Close(in_write); Close(out_read); Close(err_read); + free(cmd2); + free(p); + return NULL; + +einvalid: + errno = EINVAL; + return NULL; + +#endif /*USE_NATIVE_POPEN*/ +} + /* * w32_pread_err --- @@ -298,11 +509,11 @@ w32_pread_err(FILE *file, char *buf, int length) if ((void *)-1 != pipe_queue) { struct pipe **p2; // list pointers - + EnterCriticalSection(&pipe_guard); for (p2 = &pipe_queue; *p2; p2 = &(*p2)->next) { struct pipe *p = *p2; - + assert(p->magic == PIPE_MAGIC); if (p->file == file) { handle = p->hErr; @@ -316,7 +527,7 @@ w32_pread_err(FILE *file, char *buf, int length) DWORD result; if (ReadFile(handle, buf, length, &result, NULL)) { return (int)result; - } + } } } return -1; // done @@ -389,16 +600,16 @@ w32_pclose(FILE *file) struct pipe *pipe = NULL; if ((void *)-1 != pipe_queue) { - struct pipe **p2; // list pointers - + struct pipe **p2; // list pointers + EnterCriticalSection(&pipe_guard); for (p2 = &pipe_queue; *p2; p2 = &(*p2)->next) { - struct pipe *t_p = *p2; + struct pipe *p = *p2; - assert(t_p->magic == PIPE_MAGIC); - if (t_p->file == file) { - *p2 = t_p->next; // remove from chain - pipe = t_p; + assert(p->magic == PIPE_MAGIC); + if (p->file == file) { + *p2 = p->next; // remove from chain + pipe = p; break; } } @@ -411,13 +622,19 @@ w32_pclose(FILE *file) if ('w' == pipe->readOrWrite) fclose(file); Close2(pipe->hIn, "pclose/stdin"); if ('r' == pipe->readOrWrite) fclose(file); Close2(pipe->hOut, "pclose/stdout"); Close2(pipe->hErr, "pclose/stderr"); - if (! w32_child_wait(pipe->handle, &status, FALSE)) { + if (! w32_child_wait(pipe->handle, &status, FALSE /*block*/)) { ret = -1; } free(pipe); - return (0 == ret ? status : -1); + if (0 == ret) { + errno = 0; + return status; + } + return -1; } } + + errno = EINVAL; return -1; #endif /*USE_NATIVE_POPEN*/ } @@ -488,7 +705,7 @@ Pipe2(HANDLE *read, HANDLE *write, int inherit) static void Close(HANDLE handle) { - if (handle != INVALID_HANDLE_VALUE) { + if (handle && handle != INVALID_HANDLE_VALUE) { if (! CloseHandle(handle)) { InternalError("CloseHandle(popen)"); } @@ -503,7 +720,7 @@ Close(HANDLE handle) static void Close2(HANDLE handle, const char *desc) { - if (handle != INVALID_HANDLE_VALUE) { + if (handle && handle != INVALID_HANDLE_VALUE) { if (! CloseHandle(handle)) { InternalError(desc); } @@ -515,36 +732,26 @@ Close2(HANDLE handle, const char *desc) * InternalError --- * Displays the error number and corresponding message. */ + static void -DisplayError( - HANDLE hOutput, const char *pszAPI, const char *args) +DisplayErrorA( + HANDLE hOutput, const char *msg, const char *cmd) { - DWORD rc = GetLastError(); - LPVOID lpvMessageBuffer; - char szPrintBuffer[512]; - DWORD nCharsWritten; - - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpvMessageBuffer, 0, NULL); - - (void) _snprintf(szPrintBuffer, sizeof(szPrintBuffer), - "Internal Error: %s = %d (%s).\n%s%s", pszAPI, rc, (char *)lpvMessageBuffer, - args ? args : "", args ? "\n" : "" ); - szPrintBuffer[sizeof(szPrintBuffer) - 1] = 0; - - if (hOutput == INVALID_HANDLE_VALUE) { - hOutput = GetStdHandle(STD_OUTPUT_HANDLE); - } - - WriteConsoleA(hOutput, szPrintBuffer, lstrlenA(szPrintBuffer), &nCharsWritten, NULL); - LocalFree(lpvMessageBuffer); + const DWORD rc = GetLastError(); + char t_rcbuffer[512], buffer[512]; + const char *rcmsg = w32_vsyserrorA(rc, t_rcbuffer, sizeof(t_rcbuffer), cmd, NULL); + int len; + + len = _snprintf(buffer, sizeof(buffer), + "Internal Error: %s = %d (%s).\n", msg, rc, rcmsg); + WriteConsoleA(hOutput, buffer, len, NULL, NULL); } static void InternalError(const char *pszAPI) { - DisplayError(INVALID_HANDLE_VALUE, pszAPI, NULL); + DisplayErrorA(GetStdHandle(STD_OUTPUT_HANDLE), pszAPI, NULL); ExitProcess(GetLastError()); } diff --git a/libw32/w32_progname.c b/libw32/w32_progname.c index 089ea7e9..2d73ffce 100644 --- a/libw32/w32_progname.c +++ b/libw32/w32_progname.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_progname_c,"$Id: w32_progname.c,v 1.7 2020/06/18 14:30:48 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_progname_c,"$Id: w32_progname.c,v 1.9 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 set/getprogname * - * Copyright (c) 2016 - 2020, Adam Young. + * Copyright (c) 2016 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_progname_c,"$Id: w32_progname.c,v 1.7 2020/06/18 14:30:48 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -40,6 +40,8 @@ __CIDENT_RCSID(gr_w32_progname_c,"$Id: w32_progname.c,v 1.7 2020/06/18 14:30:48 #include static const char *progname = NULL; +static const wchar_t *wprogname = NULL; + LIBW32_API void setprogname(const char *name) @@ -52,8 +54,8 @@ setprogname(const char *name) name = (p1 > p2 ? p1 : p2) + 1; //consume leading path. } - free((char *)progname); - progname = _strdup(name); //clone buffer. + free((void *)progname); + progname = WIN32_STRDUP(name); //clone buffer. if (NULL != (p = strrchr(progname, '.')) && (0 == stricmp(p, ".exe") || 0 == stricmp(p, ".com"))) { @@ -65,8 +67,55 @@ setprogname(const char *name) } } + +LIBW32_API void +setprognameW(const wchar_t *name) +{ + const wchar_t *p1 = wcsrchr(name, '\\'), + *p2 = wcsrchr(name, '/'); + wchar_t *p; + + if (p1 || p2) { //last component. + name = (p1 > p2 ? p1 : p2) + 1; //consume leading path. + } + + free((void *)wprogname); + wprogname = WIN32_STRDUPW(name); //clone buffer. + + if (NULL != (p = wcsrchr(wprogname, '.')) && + (0 == _wcsicmp(p, L".exe") || 0 == _wcsicmp(p, L".com"))) { + *p = 0; //consume trailing exe/com extension. + } + + for (p = (wchar_t *)wprogname; *p; ++p) { //hide case issues. + if (*p < 0x7f) *p = tolower((char)*p); + } +} + + LIBW32_API const char * getprogname(void) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + if (NULL == progname) { + char path[1024]; + const wchar_t *wpath; + if (NULL != (wpath = getprognameW())) { + w32_wc2utf(wpath, path, sizeof(path)); + setprogname(path); + } + } + return (progname ? progname : "program"); + } +#endif //UTF8FILENAMES + + return getprognameA(); +} + + +LIBW32_API const char * +getprognameA(void) { if (NULL == progname) { char t_buffer[1024]; @@ -79,5 +128,19 @@ getprogname(void) return (progname ? progname : "program"); } -/*end*/ +LIBW32_API const wchar_t * +getprognameW(void) +{ + if (NULL == wprogname) { + wchar_t t_buffer[1024]; + DWORD buflen; + if ((buflen = GetModuleFileNameW(NULL, t_buffer, _countof(t_buffer)-1)) > 0) { + t_buffer[buflen] = 0; + setprognameW(t_buffer); + } + } + return (wprogname ? wprogname : L"program"); +} + +/*end*/ diff --git a/libw32/w32_pwd.c b/libw32/w32_pwd.c index 30a050de..988abdf1 100644 --- a/libw32/w32_pwd.c +++ b/libw32/w32_pwd.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_pwd_c,"$Id: w32_pwd.c,v 1.13 2020/06/18 14:32:39 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_pwd_c,"$Id: w32_pwd.c,v 1.15 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 pwd(2) implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_pwd_c,"$Id: w32_pwd.c,v 1.13 2020/06/18 14:32:39 cvsuser E * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -35,15 +35,32 @@ __CIDENT_RCSID(gr_w32_pwd_c,"$Id: w32_pwd.c,v 1.13 2020/06/18 14:32:39 cvsuser E * ==extra== */ +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0500 +#endif + #include "win32_internal.h" -#include /* gethome */ +#include /* gethome */ #include #include +#include + +#include /* ConvertSidToStringSid */ +#include -static void fillin(void); +#pragma comment(lib, "Netapi32.lib") -static struct passwd pw; -static int counter; +static void fill_passwds(void); +static int fill_builtin(const struct WellKnownSID *wksid, struct passwd *pwd, char *name, size_t namlen); +static unsigned RID(PSID sid); +static void fill_passwd(void); +static int copy_passwd(const struct passwd *passwd, struct passwd *dest, char *buffer, size_t bufsize); + +static unsigned x_passwds_count; +static int x_cursor; /* getpwent cursor */ +static struct passwd *x_passwds; +static struct passwd x_passwd; +static char x_buffer[MAX_PATH * 5]; /* @@ -56,7 +73,7 @@ static int counter; // // void endpwent(void); // struct passwd *getpwent(void); -// void setpwent(void); [Option End] +// void setpwent(void); // // DESCRIPTION // @@ -69,6 +86,18 @@ static int counter; // it shall return a pointer to a passwd structure containing the next entry in the // user database. Successive calls can be used to search the entire user database. // +// The passwd structure is defined in as follows: +// +// struct passwd { +// char *pw_name; // username +// char *pw_passwd; // user password +// uid_t pw_uid; // user ID +// gid_t pw_gid; // group ID +// char *pw_gecos; // user information +// char *pw_dir; // home directory +// char *pw_shell; // shell program +// }; +// // If an end-of-file or an error is encountered on reading, getpwent() shall return a // null pointer. // @@ -111,15 +140,66 @@ static int counter; LIBW32_API struct passwd * getpwent(void) { - if (counter == 0) { - counter++; - fillin(); - return &pw; + const unsigned cursor = x_cursor++; + + if (0 == cursor) { + fill_passwds(); + return &x_passwd; + + } else if (cursor <= x_passwds_count) { + return x_passwds + (cursor - 1); } return NULL; } +LIBW32_API int +getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) +{ + struct passwd *it = NULL; + unsigned cursor; + + if (NULL == pwd || NULL == buffer || NULL == result) { + if (result) *result = NULL; + errno = EINVAL; + return EINVAL; // invalid arguments + } + + cursor = x_cursor++; + if (0 == cursor) { + fill_passwds(); + it = &x_passwd; + + } else if (cursor <= x_passwds_count) { + it = x_passwds + (cursor - 1); + } + + *result = NULL; + if (it) { + const int rc = copy_passwd(it, pwd, buffer, bufsize); + if (0 == rc) *result = pwd; // success + return rc; + } + + errno = EINVAL; + return ENOENT; // no-match +} + + +LIBW32_API void +setpwent(void) +{ + x_cursor = 0; +} + + +LIBW32_API void +endpwent(void) +{ + x_cursor = 0xffff; +} + + /* // NAME // getpwuid, getpwuid_r - search user database for a user ID @@ -130,7 +210,7 @@ getpwent(void) // // struct passwd *getpwuid(uid_t uid); // int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, -// size_t bufsize, struct passwd **result); [Option End] +// size_t bufsize, struct passwd **result); // // DESCRIPTION // The getpwuid() function shall search the user database for an entry with a matching @@ -150,7 +230,7 @@ getpwent(void) // buffer parameter, which is bufsize bytes in size. The maximum size needed for this // buffer can be determined with the {_SC_GETPW_R_SIZE_MAX} sysconf() parameter. A // NULL pointer shall be returned at the location pointed to by result on error or if -// the requested entry is not found. [Option End] +// the requested entry is not found. // // RETURN VALUE // @@ -163,7 +243,7 @@ getpwent(void) // call to getpwent(), getpwnam(), or getpwuid(). // // If successful, the getpwuid_r() function shall return zero; otherwise, an error -// number shall be returned to indicate the error. [Option End] +// number shall be returned to indicate the error. // // ERRORS // @@ -185,17 +265,62 @@ getpwent(void) // // [ERANGE] // Insufficient storage was supplied via buffer and bufsize to contain the data to -// be referenced by the resulting passwd structure. [Option End] +// be referenced by the resulting passwd structure. */ LIBW32_API struct passwd * getpwuid(int uid) { - fillin(); - if (pw.pw_uid == uid) return &pw; + const struct passwd *current = w32_passwd_user(); + + if (uid == current->pw_uid) { + fill_passwd(); + return &x_passwd; + + } else { + struct passwd *it, *end; + fill_passwds(); + for (it = x_passwds, end = it + x_passwds_count; it != end; ++it) { + if (uid == it->pw_uid) { + return it; + } + } + } return NULL; } +LIBW32_API int +getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) +{ + const struct passwd *current = w32_passwd_user(); + + if (NULL == pwd || NULL == buffer || NULL == result) { + if (result) *result = NULL; + errno = EINVAL; + return EINVAL; // invalid arguments + } + + *result = NULL; + if (uid == current->pw_uid) { + const int rc = copy_passwd(current, pwd, buffer, bufsize); + if (0 == rc) *result = pwd; // success + return rc; + + } else { + const struct passwd *it, *end; + fill_passwds(); + for (it = x_passwds, end = it + x_passwds_count; it != end; ++it) { + if (uid == it->pw_uid) { + const int rc = copy_passwd(it, pwd, buffer, bufsize); + if (0 == rc) *result = pwd; // success + return rc; + } + } + } + return 0; // no-match +} + + /* // NAME // @@ -207,7 +332,7 @@ getpwuid(int uid) // // struct passwd *getpwnam(const char *name); // int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, -// size_t bufsize, struct passwd **result); [Option End] +// size_t bufsize, struct passwd **result); // // DESCRIPTION // @@ -228,7 +353,7 @@ getpwuid(int uid) // buffer parameter, which is bufsize bytes in size. The maximum size needed for this // buffer can be determined with the {_SC_GETPW_R_SIZE_MAX} sysconf() parameter. A // NULL pointer shall be returned at the location pointed to by result on error or if -// the requested entry is not found. [Option End] +// the requested entry is not found. // // RETURN VALUE // @@ -241,7 +366,7 @@ getpwuid(int uid) // call to getpwent(), getpwnam(), or getpwuid(). // // If successful, the getpwnam_r() function shall return zero; otherwise, an error -// number shall be returned to indicate the error. [Option End] +// number shall be returned to indicate the error. // // ERRORS // @@ -263,48 +388,387 @@ getpwuid(int uid) // // [ERANGE] // Insufficient storage was supplied via buffer and bufsize to contain the data to -// be referenced by the resulting passwd structure. [Option End] +// be referenced by the resulting passwd structure. */ LIBW32_API struct passwd * getpwnam(const char *name) { - fillin(); - if (0 == strcmp(pw.pw_name, name)) { - return &pw; + if (name) { + const struct passwd *current = w32_passwd_user(); + + if (0 == _stricmp(name, current->pw_name)) { + fill_passwd(); + return &x_passwd; + + } else { + struct passwd *it, *end; + fill_passwds(); + for (it = x_passwds, end = it + x_passwds_count; it != end; ++it) { + if (0 == _stricmp(name, it->pw_name)) { + return it; + } + } + } } return NULL; } -LIBW32_API void -setpwent(void) +LIBW32_API int +getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) { - counter = 0; + const struct passwd *current = w32_passwd_user(); + + if (NULL == name || NULL == pwd || NULL == buffer || NULL == result) { + if (result) *result = NULL; + errno = EINVAL; + return EINVAL; // invalid arguments + } + + *result = NULL; + if (0 == _stricmp(name, current->pw_name)) { + const int rc = copy_passwd(current, pwd, buffer, bufsize); + if (0 == rc) *result = pwd; // success + return rc; + + } else { + const struct passwd *it, *end; + fill_passwds(); + for (it = x_passwds, end = it + x_passwds_count; it != end; ++it) { + if (0 == _stricmp(name, it->pw_name)) { + const int rc = copy_passwd(it, pwd, buffer, bufsize); + if (0 == rc) *result = pwd; // success + return rc; + } + } + } + return 0; // no-match } -LIBW32_API void -endpwent(void) +///////////////////////////////////////////////////////////////////////////////////////// +// passwd's database implementation + +static struct WellKnownSID { + const char *name; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + BYTE SubAuthCount; + DWORD SubAuth[2]; + +} well_known_sids[] = { + // See: "wmic sysaccount get name,sid" + {"S-1-5-1", SECURITY_NT_AUTHORITY, 1, {SECURITY_DIALUP_RID}}, + {"S-1 5-2", SECURITY_NT_AUTHORITY, 1, {SECURITY_NETWORK_RID}}, + {"S-1-5-3", SECURITY_NT_AUTHORITY, 1, {SECURITY_BATCH_RID}}, + {"S-1-5-4", SECURITY_NT_AUTHORITY, 1, {SECURITY_INTERACTIVE_RID}}, + {"S-1-5-6", SECURITY_NT_AUTHORITY, 1, {SECURITY_SERVICE_RID}}, + {"S-1-5-11", SECURITY_NT_AUTHORITY, 1, {SECURITY_AUTHENTICATED_USER_RID}}, + {"S-1-5-15", SECURITY_NT_AUTHORITY, 1, {SECURITY_THIS_ORGANIZATION_RID}}, + {"S-1-5-18", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SYSTEM_RID}}, + {"S-1-5-19", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_SERVICE_RID}}, + {"S-1-5-20", SECURITY_NT_AUTHORITY, 1, {SECURITY_NETWORK_SERVICE_RID}}, + {"S-1-5-32", SECURITY_NT_AUTHORITY, 1, {SECURITY_BUILTIN_DOMAIN_RID}}, + {"S-1-5-32-544", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS}}, + {"S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"} + // TrustedInstaller, RID:704 (short) + + // groups! +// {"S-1-5-113", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_ACCOUNT_RID}}, +// {"S-1-5-114", SECURITY_NT_AUTHORITY, 1, {SECURITY_LOCAL_ACCOUNT_AND_ADMIN_RID}}, +// {"S-1-5-32-545", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS}}, +// {"S-1-5-32-546", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS}}, +// {"S-1-5-32-547", SECURITY_NT_AUTHORITY, 2, {SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS}}, +// {"S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464"} + // TrustedInstaller, RID:704 (short) +}; + + +static void +fill_passwds(void) { - counter = 0; + DWORD resume_handle = 0; + NET_API_STATUS nStatus; + unsigned cbufsz = 0; + char name[MAX_PATH]; + int nlen; + + fill_passwd(); + if (NULL != x_passwds) + return; + + assert(0 == x_passwds_count); + do { + DWORD i, dwEntriesRead = 0, dwTotalEntries = 0; + const unsigned ototal = x_passwds_count; + unsigned bufsz = 0, count = 0; + PUSER_INFO_20 users = NULL; + + // see: wmic useraccount get name,sid + nStatus = NetUserEnum(NULL, 20 /*USER_INFO_20*/, 0, (LPBYTE *) &users, + MAX_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, &resume_handle); + + switch (nStatus) { + case NERR_Success: + case ERROR_MORE_DATA: + break; + default: + return; + } + + // size storage + for (i = 0; i < dwEntriesRead; ++i) { + const PUSER_INFO_20 user = users + i; + if ((int)user->usri20_user_id == x_passwd.pw_uid || + (nlen = w32_wc2utf(user->usri20_name, name, sizeof(name))) <= 0) { + continue; + } + bufsz += (nlen + 1); + ++count; + } + + if (NERR_Success == nStatus) // last iteration. + for (i = 0; i < _countof(well_known_sids); ++i) { + const int xlen = fill_builtin(well_known_sids + i, NULL, NULL, 0); + if (xlen > 0) { + bufsz += (xlen + 1); + ++count; + } + } + + // new elements + if (count && bufsz) { + const unsigned ntotal = + ototal + count; // resulting total pwd's + + // allocate/expand + if (x_passwds) { + struct passwd *t_passwds = (struct passwd *)realloc(x_passwds, + (sizeof(struct passwd) * ntotal) + cbufsz + bufsz); + const int addrdiff = ((char *)t_passwds - (char *)x_passwds) + + (sizeof(struct passwd) * count); + + if (NULL == t_passwds) { // realloc failure + NetApiBufferFree(users); + break; + } + + // reorg storage, insert 'count' pwd elements and adjust buffer addr's. + memmove(t_passwds + ntotal, (const void *)(t_passwds + ototal), cbufsz); + for (i = 0; i < ototal; ++i) { + t_passwds[i].pw_name += addrdiff; + } + x_passwds = t_passwds; + + } else { + x_passwds = (struct passwd *)malloc((sizeof(struct passwd) * count) + bufsz /*non-zero*/); + } + + // publish + if (NULL != x_passwds) { + struct passwd *pwd = x_passwds + ototal; + char *cursor = ((char *)(x_passwds + ntotal)) + cbufsz; +#if defined(_DEBUG) + wchar_t t_buffer[1024]; +#endif + + cbufsz += bufsz; // resulting name storage (inc nul) + + for (i = 0; i < dwEntriesRead; ++i) { + const PUSER_INFO_20 user = users + i; + +#if defined(_DEBUG) + swprintf_s(t_buffer, _countof(t_buffer), L"User:%s,FullName:%s,Comment:%s,RID:%u\n", + user->usri20_name, user->usri20_full_name, user->usri20_comment, (unsigned)user->usri20_user_id); + OutputDebugStringW(t_buffer); +#endif + + if ((int)user->usri20_user_id == x_passwd.pw_uid || + (nlen = w32_wc2utf(user->usri20_name, cursor, bufsz)) <= 0) { + continue; + } + + memset(pwd, 0, sizeof(*pwd)); + pwd->pw_name = cursor; + _strlwr(cursor); + pwd->pw_uid = (short) user->usri20_user_id; + pwd->pw_gid = pwd->pw_uid; + cursor += (nlen + 1); + bufsz -= (nlen + 1); + ++x_passwds_count; + --count; + ++pwd; + } + + if (NERR_Success == nStatus) // last iteration. + for (i = 0; i < _countof(well_known_sids); ++i) { + const int xlen = fill_builtin(well_known_sids + i, pwd, cursor, bufsz); + if (xlen > 0) { + cursor += (xlen + 1); + bufsz -= (xlen + 1); + ++x_passwds_count; + --count; + ++pwd; + } + } + + assert(0 == count); + assert(0 == bufsz); + + } else { + nStatus = ERROR_NOT_ENOUGH_MEMORY; + } + } + + NetApiBufferFree(users); + + } while (ERROR_MORE_DATA == nStatus); +} + + +static int +fill_builtin(const struct WellKnownSID *wksid, + struct passwd *pwd, char *name, size_t namelen) +{ + PSID pSID = NULL; + int ret = 0; + + if (wksid->SubAuthCount) { + if (! AllocateAndInitializeSid((PSID_IDENTIFIER_AUTHORITY) &wksid->IdentifierAuthority, + wksid->SubAuthCount, wksid->SubAuth[0], wksid->SubAuth[1], 0, 0, 0, 0, 0, 0, &pSID)) { + pSID = NULL; + } + } else { + if (! ConvertStringSidToSidA(wksid->name, &pSID)) { + pSID = NULL; + } + } + + if (pSID) { + char t_name[WIN32_LOGIN_LEN], t_domain[1024]; + DWORD nlen = sizeof(t_name), dlen = sizeof(t_domain); + SID_NAME_USE user_type = {0}; +#if defined(_DEBUG) + char t_buffer[1024]; +#endif + + if (LookupAccountSidA(NULL, pSID, t_name, &nlen, t_domain, &dlen, &user_type)) { + + if (name) { // "[domain\\]name" + if (SidTypeDomain == user_type && strcmp(t_name, t_domain)) { + sprintf_s(name, namelen, "%s\\%s", t_name, t_domain); + } else { + strcpy_s(name, namelen, t_name); + } + } + + if (pwd) { + memset(pwd, 0, sizeof(*pwd)); + pwd->pw_name = name; + _strlwr(name); + pwd->pw_uid = (short) RID(pSID); + pwd->pw_gid = pwd->pw_uid; // TODO + +#if defined(_DEBUG) + sprintf_s(t_buffer, _countof(t_buffer), "User:%s,uid:%u\n", + pwd->pw_name, (unsigned)pwd->pw_uid); + OutputDebugStringA(t_buffer); +#endif + } + + ret = (SidTypeDomain == user_type ? nlen + 1 + dlen : nlen); + + } else { + if (name) name[0] = 0; + } + + assert(SidTypeWellKnownGroup == user_type || SidTypeAlias == user_type || SidTypeDomain == user_type); + FreeSid(pSID); + } + return ret; +} + + +static unsigned +RID(PSID sid) +{ + // Example: S-1-5-32-544 + // Returns the last component, 544. + const int subAuthorities = *GetSidSubAuthorityCount(sid); + if (subAuthorities >= 1) { // last sub-authority value. + return *GetSidSubAuthority(sid, subAuthorities - 1); + // Last component should be the user's relative identifier (RID). + // It uniquely defines this user account to SAM within the domain. + } + return 0; } static void -fillin(void) +fill_passwd(void) { - pw.pw_name = getlogin(); - pw.pw_passwd = "*"; - pw.pw_uid = w32_getuid(); - pw.pw_gid = w32_getgid(); - pw.pw_age = ""; - pw.pw_comment = ""; - pw.pw_gecos = "pc User"; - pw.pw_dir = w32_gethome(FALSE); - pw.pw_shell = w32_getshell(); - pw.pw_audid = -1; - pw.pw_audflg = -1; + const struct passwd *current = w32_passwd_user(); + copy_passwd(current, &x_passwd, x_buffer, sizeof(x_buffer)); } -/*end*/ +static int +pw_strlen(const char *s, size_t *total) +{ + if (s && *s) { + const int slen = strlen(s); + *total += (slen + 1); + return slen; + } + *total += 1; + return 0; +} + + +static char * +pw_strcpy(const char *s, size_t slen, char **cursor) +{ + char *dst = *cursor, *base = dst; + if (slen) { + memcpy(dst, s, slen), dst += slen; + } + *dst++ = 0; + *cursor = dst; + return base; +} + + +static int +copy_passwd(const struct passwd *pwd, struct passwd *dst, char *buffer, size_t bufsize) +{ + size_t total = 0; + const size_t + namelen = pw_strlen(pwd->pw_name, &total), + passwdlen = pw_strlen(pwd->pw_passwd, &total), + agelen = pw_strlen(pwd->pw_age, &total), + commentlen = pw_strlen(pwd->pw_comment, &total), + gecoslen = pw_strlen(pwd->pw_gecos, &total), + dirlen = pw_strlen(pwd->pw_dir, &total), + shelllen = pw_strlen(pwd->pw_shell, &total); + + if (total > bufsize) { + return (errno = ERANGE); + } else if (NULL == dst) { + return (errno = EINVAL); + } + + dst->pw_name = pw_strcpy(pwd->pw_name, namelen, &buffer); + dst->pw_passwd = pw_strcpy(pwd->pw_passwd, passwdlen, &buffer); + dst->pw_uid = pwd->pw_uid; + dst->pw_gid = pwd->pw_gid; + dst->pw_age = pw_strcpy(pwd->pw_age, agelen, &buffer); + dst->pw_comment = pw_strcpy(pwd->pw_comment, commentlen, &buffer); + dst->pw_gecos = pw_strcpy(pwd->pw_gecos, gecoslen, &buffer); + dst->pw_dir = pw_strcpy(pwd->pw_dir, dirlen, &buffer); + dst->pw_shell = pw_strcpy(pwd->pw_shell, shelllen, &buffer); + dst->pw_audid = pwd->pw_audid; + dst->pw_audflg = pwd->pw_audflg; + + return 0; //success +} + +/*end*/ diff --git a/libw32/w32_read.c b/libw32/w32_read.c index a44ac35b..b558ff7f 100644 --- a/libw32/w32_read.c +++ b/libw32/w32_read.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_read_c,"$Id: w32_read.c,v 1.15 2020/04/20 23:18:24 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_read_c,"$Id: w32_read.c,v 1.16 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 read() implementation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_read_c,"$Id: w32_read.c,v 1.15 2020/04/20 23:18:24 cvsuser * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -354,4 +354,3 @@ pread(int fildes, void *buf, size_t nbyte, off_t offset) } /*end*/ - diff --git a/libw32/w32_readv.c b/libw32/w32_readv.c new file mode 100644 index 00000000..957c256d --- /dev/null +++ b/libw32/w32_readv.c @@ -0,0 +1,99 @@ +#include +__CIDENT_RCSID(gr_w32_readv_c,"$Id: w32_readv.c,v 1.3 2022/03/21 14:29:41 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 readv() implementation + * + * Copyright (c) 2018 - 2022, Adam Young. + * All rights reserved. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + * + * Notice: Portions of this text are reprinted and reproduced in electronic form. from + * IEEE Portable Operating System Interface (POSIX), for reference only. Copyright (C) + * 2001-2003 by the Institute of. Electrical and Electronics Engineers, Inc and The Open + * Group. Copyright remains with the authors and the original Standard can be obtained + * online at http://www.opengroup.org/unix/online.html. + * ==extra== + */ + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 /* enable xp+ features */ +#endif + +#include "win32_internal.h" +#include "win32_misc.h" + +#include +#include + +#pragma comment(lib, "Ws2_32.lib") + +LIBW32_API int /*ssize_t*/ +readv(int fildes, const struct iovec *iov, int iovcnt) +{ + SOCKET s = (SOCKET)-1; + int i, ret = -1; + + if (fildes < 0) { + errno = EBADF; + + } else if (NULL == iov || iovcnt <= 0){ + errno = EINVAL; + + } else if (w32_issockfd(fildes, &s)) { + ret = 0; + for (i = 0; i < iovcnt; ++i) { +#undef recvfrom + const int cnt = recvfrom(s, iov[i].iov_base, iov[i].iov_len, 0, NULL, 0); + if (cnt > 0) { + ret += cnt; + } else if (0 == cnt) { + break; + } else { + if (0 == ret) { + w32_neterrno_set(); + ret = -1; + } + break; + } + } + + } else { + ret = 0; + for (i = 0; i < iovcnt; ++i) { + const int cnt = _read(fildes, iov[i].iov_base, iov[i].iov_len); + if (cnt > 0) { + ret += cnt; + } else if (0 == cnt) { + break; + } else if (errno == EINTR) { + continue; + } else { + if (ret == 0) ret = -1; + break; + } + } + } + return ret; +} + +/*end*/ diff --git a/libw32/w32_realpath.c b/libw32/w32_realpath.c index f035a2ae..b3243811 100644 --- a/libw32/w32_realpath.c +++ b/libw32/w32_realpath.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_realpath_c,"$Id: w32_realpath.c,v 1.4 2018/10/11 01:49:01 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_realpath_c,"$Id: w32_realpath.c,v 1.6 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* @@ -7,6 +7,25 @@ __CIDENT_RCSID(gr_w32_realpath_c,"$Id: w32_realpath.c,v 1.4 2018/10/11 01:49:01 * * realpath * + * Copyright (c) 2018 - 2022 Adam Young. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. * ==end== */ @@ -16,6 +35,7 @@ __CIDENT_RCSID(gr_w32_realpath_c,"$Id: w32_realpath.c,v 1.4 2018/10/11 01:49:01 #define _DIRENT_SOURCE #include "win32_internal.h" + #include #include @@ -28,12 +48,14 @@ __CIDENT_RCSID(gr_w32_realpath_c,"$Id: w32_realpath.c,v 1.4 2018/10/11 01:49:01 #include #include +#include "win32_io.h" + // NAME // realpath - resolve a pathname // // SYNOPSIS -// #include [optional] +// #include // char *realpath(const char *restrict file_name, char *restrict resolved_name); // // DESCRIPTION @@ -61,7 +83,7 @@ __CIDENT_RCSID(gr_w32_realpath_c,"$Id: w32_realpath.c,v 1.4 2018/10/11 01:49:01 // [ELOOP] // A loop exists in symbolic links encountered during resolution of the file_name argument. // [ENAMETOOLONG] -// The length of the file_name argument exceeds { PATH_MAX} or a pathname component is longer +// The length of the file_name argument exceeds { PATH_MAX} or a pathname component is longer // than {NAME_MAX}. // [ENOENT] // A component of file_name does not name an existing file or file_name points to an empty string. @@ -83,10 +105,43 @@ w32_realpath(const char *path, char *resolved_path /*[PATH_MAX]*/) return w32_realpath2(path, resolved_path, PATH_MAX); } + LIBW32_API char * w32_realpath2(const char *path, char *resolved_path, int maxlen) { - char *result = NULL; +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t *wresolved_path, wpath[WIN32_PATH_MAX]; + + w32_utf2wc(path, wpath, _countof(wpath)); + + if (NULL != (wresolved_path = alloca(sizeof(wchar_t *) * WIN32_PATH_MAX))) { + if (w32_realpathW(wpath, wresolved_path, WIN32_PATH_MAX)) { + if (NULL == resolved_path) { // dynamic; implementation specific. + maxlen = WIN32_PATH_MAX; + if (NULL == (resolved_path = (char *)malloc(sizeof(char) * maxlen))) { + return NULL; + } + } + + if (resolved_path) { + w32_wc2utf(wresolved_path, resolved_path, maxlen); + return resolved_path; + } + } + } + return NULL; + } +#endif //UTF8FILENAMES + + return w32_realpathA(path, resolved_path, maxlen); +} + + +LIBW32_API char * +w32_realpathA(const char *path, char *resolved_path, int maxlen) +{ + char *result = NULL, symlink[WIN32_PATH_MAX]; if (path && *path) { if (NULL != (result = resolved_path)) { // user buffer. @@ -95,10 +150,36 @@ w32_realpath2(const char *path, char *resolved_path, int maxlen) result = NULL; } } else { // glibc style extension. - result = (char *)malloc(maxlen = 1024 /*PATH_MAX*/); + maxlen = WIN32_PATH_MAX; + result = (char *)malloc(sizeof(char) * maxlen); // malloc() shall set errno on error. } + if (result) { // root + /* + * Generic chdir("/") behaviour is context specific, meaning goto root of current drive, + * mount point or current UNC. Normalisze this behaviour to root of current/last drive. + */ + if (('/' == path[0] || '\\' == path[0]) && 0 == path[1]) { + int driveno = w32_getdrive(); // also see chdir() + if (driveno <= 0) driveno = w32_getlastdrive(); + if (driveno <= 0) driveno = w32_getsystemdrive(); + if (driveno > 0) { + result[0] = (char)(driveno + ('A' - 1)); + result[1] = ':'; + result[2] = '/'; + result[3] = 0; + return result; + } + } + } + + if (result) { // resolve symlink component + if (w32_lnkexpandA(path, symlink, _countof(symlink), SHORTCUT_COMPONENT)) { + path = symlink; + } + } + if (result) { const size_t size = // resolve, including .. and . components GetFullPathNameA(path, maxlen, result, 0); @@ -108,7 +189,9 @@ w32_realpath2(const char *path, char *resolved_path, int maxlen) if (size >= (size_t)maxlen) { if (result != resolved_path) { free((void *)result); - result = (char *)malloc(maxlen = (size + 1 /*plus null*/)); + + maxlen = size + 1 /*plus null*/; + result = (char *)malloc(sizeof(char) * maxlen); // malloc() shall set errno on error. if (result) { @@ -155,7 +238,7 @@ w32_realpath2(const char *path, char *resolved_path, int maxlen) // Success, verify the result. if (result) { struct stat sb = { 0 }; - if (w32_stat(result, &sb)) { + if (w32_statA(result, &sb)) { if (result != resolved_path) { free(result); } @@ -179,4 +262,129 @@ w32_realpath2(const char *path, char *resolved_path, int maxlen) return result; } + +LIBW32_API wchar_t * +w32_realpathW(const wchar_t *path, wchar_t *resolved_path, int maxlen) +{ + wchar_t *result = NULL, symlink[WIN32_PATH_MAX]; + + if (path && *path) { + if (NULL != (result = resolved_path)) { // user buffer. + if (maxlen < 4) { // "X:/\0" + errno = EINVAL; // invalid length. + result = NULL; + } + } else { // glibc style extension. + maxlen = WIN32_PATH_MAX; + result = (wchar_t *)malloc(sizeof(wchar_t) * maxlen); + // malloc() shall set errno on error. + } + + if (result) { // root + /* + * Generic chdir("/") behaviour is context specific, meaning goto root of current drive, + * mount point or current UNC. Normalisze this behaviour to root of current/last drive. + */ + if (('/' == path[0] || '\\' == path[0]) && 0 == path[1]) { + int driveno = w32_getdrive(); + if (driveno <= 0) driveno = w32_getlastdrive(); + if (driveno <= 0) driveno = w32_getsystemdrive(); + if (driveno > 0) { + result[0] = (wchar_t)(driveno + ('A' - 1)); + result[1] = ':'; + result[2] = '/'; + result[3] = 0; + return result; + } + } + } + + if (result) { // resolve symlink component + if (w32_lnkexpandW(path, symlink, _countof(symlink), SHORTCUT_COMPONENT)) { + path = symlink; + } + } + + if (result) { + const size_t size = // resolve, including .. and . components + GetFullPathNameW(path, maxlen, result, 0); + + // + // GetFullPathNameA() returns a size larger than buffer if buffer is too small + if (size >= (size_t)maxlen) { + if (result != resolved_path) { + free((void *)result); + + maxlen = size + 1 /*plus null*/; + result = (wchar_t *)malloc(sizeof(wchar_t) * maxlen); + // malloc() shall set errno on error. + + if (result) { + const size_t new_size = + GetFullPathNameW(path, maxlen, result, 0); + if (new_size >= (size_t)maxlen) { + free((void *)result); + errno = ENAMETOOLONG; + result = NULL; + return NULL; + } + } + } else { // resolved_path buffer isn't big enough + errno = ENAMETOOLONG; + result = NULL; + } + } + + // + // GetFullPathNameA() returns 0 if some path resolve problem occured + if (0 == size) { + switch (GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_PRIVILEGE_NOT_HELD: + errno = EACCES; break; + case ERROR_FILE_NOT_FOUND: + errno = ENOENT; break; + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + errno = ENOTDIR; break; + default: + errno = EIO; + break; + } + + if (result != resolved_path) { + free((void *)result); + } + result = NULL; + } + + // + // Success, verify the result. + if (result) { + struct stat sb = { 0 }; + if (w32_statW(result, &sb)) { + if (result != resolved_path) { + free(result); + } + result = NULL; + // stat() shall set errno on error. + } + } + } + } else { + errno = EINVAL; // invalid source. + } + + if (result) { + if (result[0] && result[1] == ':') { // normalize directory slashes. + wchar_t *cursor; + for (cursor = result; *cursor; ++cursor) { + if ('\\' == *cursor) *cursor = '/'; + } + } + } + return result; +} + /*end*/ diff --git a/libw32/w32_rename.c b/libw32/w32_rename.c new file mode 100644 index 00000000..f2c46409 --- /dev/null +++ b/libw32/w32_rename.c @@ -0,0 +1,151 @@ +#include +__CIDENT_RCSID(gr_w32_rename_c,"$Id: w32_rename.c,v 1.2 2022/03/21 14:29:41 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 rename() system calls. + * + * Copyright (c) 2020 - 2022 Adam Young. + * All rights reserved. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + * + * Notice: Portions of this text are reprinted and reproduced in electronic form. from + * IEEE Portable Operating System Interface (POSIX), for reference only. Copyright (C) + * 2001-2003 by the Institute of. Electrical and Electronics Engineers, Inc and The Open + * Group. Copyright remains with the authors and the original Standard can be obtained + * online at http://www.opengroup.org/unix/online.html. + * ==extra== + */ + +#include "win32_internal.h" +#include "win32_misc.h" + +#include +#ifdef HAVE_WCHAR_H +#include +#endif +#include + + +/* +// NAME +// +// rename - rename a file +// +// SYNOPSIS +// +// #include +// +// int rename(const char *old, const char *new); +// +// DESCRIPTION +// +// The rename() function shall change the name of a file. The old argument points to +// the pathname of the file to be renamed. The new argument points to the new pathname +// of the file. +// +// If either the old or new argument names a symbolic link, rename() shall operate on +// the symbolic link itself, and shall not resolve the last component of the argument. +// If the old argument and the new argument resolve to the same existing file, +// rename() shall return successfully and perform no other action. +// +// If the old argument points to the pathname of a file that is not a directory, the +// new argument shall not point to the pathname of a directory. If the link named by +// the new argument exists, it shall be removed and old renamed to new. In this case, +// a link named new shall remain visible to other processes throughout the renaming +// operation and refer either to the file referred to by new or old before the +// operation began. Write access permission is required for both the directory +// containing old and the directory containing new. +// +// If the old argument points to the pathname of a directory, the new argument shall +// not point to the pathname of a file that is not a directory. If the directory named +// by the new argument exists, it shall be removed and old renamed to new. In this +// case, a link named new shall exist throughout the renaming operation and shall +// refer either to the directory referred to by new or old before the operation began. +// If new names an existing directory, it shall be required to be an empty directory. +// +// If the old argument points to a pathname of a symbolic link, the symbolic link +// shall be renamed. If the new argument points to a pathname of a symbolic link, the +// symbolic link shall be removed. +// +// The new pathname shall not contain a path prefix that names old. Write access +// permission is required for the directory containing old and the directory +// containing new. If the old argument points to the pathname of a directory, write +// access permission may be required for the directory named by old, and, if it exists, +// the directory named by new. +// +// If the link named by the new argument exists and the file's link count becomes 0 +// when it is removed and no process has the file open, the space occupied by the file +// shall be freed and the file shall no longer be accessible. If one or more processes +// have the file open when the last link is removed, the link shall be removed before +// rename() returns, but the removal of the file contents shall be postponed until all +// references to the file are closed. +// +// Upon successful completion, rename() shall mark for update the st_ctime and +// st_mtime fields of the parent directory of each file. +// +// RETURN VALUE +// +// Upon successful completion, rename() shall return 0; otherwise, -1 shall be returned, +// +*/ + +LIBW32_API int +w32_rename(const char *ofile, const char *nfile) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wofile[WIN32_PATH_MAX], wnfile[WIN32_PATH_MAX]; + + if (NULL == ofile || NULL == nfile) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(ofile, wofile, _countof(wofile)) > 0) { + if (w32_utf2wc(nfile, wnfile, _countof(wnfile)) > 0) { + return w32_renameW(wofile, wnfile); + } + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_renameA(ofile, nfile); +} + + +LIBW32_API int +w32_renameA(const char *ofile, const char *nfile) +{ +#undef rename + return rename(ofile, nfile); +} + + +LIBW32_API int +w32_renameW(const wchar_t *ofile, const wchar_t *nfile) +{ + return _wrename(ofile, nfile); +} + +/*end*/ diff --git a/libw32/w32_reparse.c b/libw32/w32_reparse.c index 72308eb9..8abfe60b 100644 --- a/libw32/w32_reparse.c +++ b/libw32/w32_reparse.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_reparse_c,"$Id: w32_reparse.c,v 1.6 2020/04/20 23:17:16 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_reparse_c,"$Id: w32_reparse.c,v 1.8 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 reparse support * - * Copyright (c) 2007, 2012 - 2019 Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -20,10 +20,10 @@ __CIDENT_RCSID(gr_w32_reparse_c,"$Id: w32_reparse.c,v 1.6 2020/04/20 23:17:16 cv * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Sourced originally from a public domain implementation and highly. @@ -36,13 +36,19 @@ __CIDENT_RCSID(gr_w32_reparse_c,"$Id: w32_reparse.c,v 1.6 2020/04/20 23:17:16 cv #include "win32_internal.h" #include "win32_ioctl.h" -#include - #include #include #include #include +#ifdef HAVE_WCHAR_H +#include +#endif #include +#include + +#if !defined(SYMLINK_FLAG_RELATIVE) +#define SYMLINK_FLAG_RELATIVE 1 +#endif static void @@ -65,7 +71,32 @@ replace_dir(char *buf, int maxlen, const char *original, const char *replacement } else { strncpy(buf, replacement, maxlen); } - buf[maxlen] = 0; /* nul terminate */ + buf[maxlen-1] = 0; /* nul terminate */ + } +} + + +static void +replace_wdir(wchar_t *buf, int maxlen, const wchar_t *original, const wchar_t *replacement) +{ + assert(buf && maxlen > 0); + + if (maxlen-- > 0) { /* reserve nul */ + const wchar_t *d1 = wcsrchr(original, '/'), *d2 = wcsrchr(original, '\\'), + *d = (d1 > d2 ? d1 : d2); /* last delimitor; if any */ + + /* note: wont deal with parent directory references */ + if (d++) { /* include delimitor within result */ + const int dirlen = + ((d - original) < maxlen ? (d - original) : maxlen); + + wmemcpy(buf, original, dirlen); + wcsncpy(buf + dirlen, replacement, maxlen - dirlen); + + } else { + wcsncpy(buf, replacement, maxlen); + } + buf[maxlen-1] = 0; /* nul terminate */ } } @@ -80,7 +111,7 @@ memxcpy(char *dst, const char *src, int len, int maxlen) LIBW32_API int -w32_reparse_read(const char *name, char *buf, int maxlen) +w32_reparse_readA(const char *name, char *buf, int maxlen) { BYTE reparseBuffer[MAX_REPARSE_SIZE]; /* XXX: warning: owc crash if = {0} under full optimisation */ PREPARSE_DATA_BUFFER rdb = (PREPARSE_DATA_BUFFER)reparseBuffer; @@ -91,7 +122,7 @@ w32_reparse_read(const char *name, char *buf, int maxlen) assert(24 == sizeof(REPARSE_DATA_BUFFER)); memset(reparseBuffer, 0, sizeof(reparseBuffer)); - if ((fileHandle = CreateFile(name, 0, /* open the file image */ + if ((fileHandle = CreateFileA(name, 0, /* open the file image */ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL)) == INVALID_HANDLE_VALUE) { return -1; @@ -113,25 +144,19 @@ w32_reparse_read(const char *name, char *buf, int maxlen) // if ((length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength) >= 4) { const size_t offset = rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); - const wchar_t* symlink = rdb->SymbolicLinkReparseBuffer.PathBuffer + offset; + const wchar_t* symlink = rdb->SymbolicLinkReparseBuffer.PathBuffer + offset; size_t len = wcstombs(resolved, symlink, sizeof(resolved) - 1); if (len != (size_t)-1) { assert(len < sizeof(resolved)); resolved[len] = 0; - // - // XXX: rdb->SymbolicLinkReparseBuffer.Flags & 1) - // SYMLINK_FLAG_RELATIVE - // if (len >= 2 && /* eg: "C://link" */ ':' == resolved[1] && isalpha(resolved[0])) { memxcpy(buf, resolved, len, maxlen); - } else if (0 == strncmp(resolved, "\\??\\", 4)) { /* eg: "C:/Users/All Users" */ memxcpy(buf, resolved + 4, len - 4, maxlen); - } else { /* relative */ replace_dir(buf, maxlen, name, resolved); } @@ -169,7 +194,7 @@ w32_reparse_read(const char *name, char *buf, int maxlen) ret = 0; } } - } else { /* junction, remove trailing \??\ */ + } else { /* junction, remove leading "\??\" */ memxcpy(buf, resolved + 4, len - 4, maxlen); ret = 0; } @@ -188,4 +213,96 @@ w32_reparse_read(const char *name, char *buf, int maxlen) return ret; } + +LIBW32_API int +w32_reparse_readW(const wchar_t *name, wchar_t *buf, int maxlen) +{ + BYTE reparseBuffer[MAX_REPARSE_SIZE]; /* XXX: warning: owc crash if = {0} under full optimisation */ + PREPARSE_DATA_BUFFER rdb = (PREPARSE_DATA_BUFFER)reparseBuffer; + HANDLE fileHandle = INVALID_HANDLE_VALUE; + DWORD returnedLength = 0; + int ret = -1; + + assert(24 == sizeof(REPARSE_DATA_BUFFER)); + memset(reparseBuffer, 0, sizeof(reparseBuffer)); + + if ((fileHandle = CreateFileW(name, 0, /* open the file image */ + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL)) == INVALID_HANDLE_VALUE) { + return -1; + } + + /* + * retrieve reparse details + */ + if (DeviceIoControl(fileHandle, FSCTL_GET_REPARSE_POINT, + NULL, 0, rdb, sizeof(reparseBuffer), &returnedLength, NULL)) { + if (IsReparseTagMicrosoft(rdb->ReparseTag)) { + int length; + + switch (rdb->ReparseTag) { + case IO_REPARSE_TAG_SYMLINK: + // + // Symbolic links. + // + if ((length = rdb->SymbolicLinkReparseBuffer.SubstituteNameLength) >= 4) { + const size_t offset = rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + const wchar_t* symlink = rdb->SymbolicLinkReparseBuffer.PathBuffer + offset; + + if (SYMLINK_FLAG_RELATIVE & rdb->SymbolicLinkReparseBuffer.Flags) { + replace_wdir(buf, maxlen, name, symlink); + + } else if (0 == wcsncmp(symlink, L"\\??\\", 4)) { + /* junction, remove leading "\??\", eg: "C:/Users/All Users" */ + wcsncpy_s(buf, maxlen, symlink + 4, maxlen); + + } else { + wcsncpy_s(buf, maxlen, symlink, maxlen); + } + ret = 0; + } + break; + + case IO_REPARSE_TAG_MOUNT_POINT: + // + // Mount points and junctions. + // + if ((length = rdb->MountPointReparseBuffer.SubstituteNameLength) > 0) { + const size_t offset = rdb->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t); + const wchar_t* mount = rdb->MountPointReparseBuffer.PathBuffer + offset; + + ret = 0; + if (SYMLINK_FLAG_RELATIVE & rdb->SymbolicLinkReparseBuffer.Flags) { + replace_wdir(buf, maxlen, name, mount); + + } else if (0 == wcsncmp(mount, L"\\??\\", 4)) { + if (0 == wcsncmp(mount, L"\\??\\Volume{", 11)) { + /* mount, resolve volume. */ + wchar_t volume[1024], pathNames[1024 * 4]; + DWORD pathLen = 0; + + ret = -1; + wcscpy(volume, L"\\\\?\\"); + wcscpy(volume + 4, mount + 4); + if (GetVolumePathNamesForVolumeNameW(volume, pathNames, _countof(pathNames), &pathLen) && pathLen > 0) { + wcsncpy_s(buf, maxlen, pathNames, maxlen); + ret = 0; + } + } else { /* junction, remove leading "\??\" */ + wcsncpy_s(buf, maxlen, mount + 4, maxlen); + } + + } else { + wcsncpy_s(buf, maxlen, mount, maxlen); + } + } + break; + } + } + } + + CloseHandle(fileHandle); + return ret; +} + /*end*/ diff --git a/libw32/w32_rwlock.c b/libw32/w32_rwlock.c index 5f3b8eb6..48fadbb1 100644 --- a/libw32/w32_rwlock.c +++ b/libw32/w32_rwlock.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_rwlock_c,"$Id: w32_rwlock.c,v 1.11 2019/03/15 23:12:19 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_rwlock_c,"$Id: w32_rwlock.c,v 1.12 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 rwlock functionality/emulation * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_rwlock_c,"$Id: w32_rwlock.c,v 1.11 2019/03/15 23:12:19 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -97,7 +97,7 @@ initialisation(void) acquire_srw_lock_exclusive = (AcquireSRWLockExclusive_t) GetProcAddress(library, "AcquireSRWLockExclusive"); release_srw_lock_exclusive = (ReleaseSRWLockExclusive_t) GetProcAddress(library, "ReleaseSRWLockExclusive"); - if (initialize_srw_lock && + if (initialize_srw_lock && acquire_srw_lock_shared && release_srw_lock_shared && acquire_srw_lock_exclusive && release_srw_lock_exclusive) { return; // success @@ -208,7 +208,7 @@ static void WINAPI my_ReleaseSRWLockShared(PSRWLOCK srw) { xpsrwlock_t *rw = (xpsrwlock_t *)srw; - + EnterCriticalSection(&rw->reader_lock); assert(rw->readers > 0); if (rw->readers > 0) { @@ -247,4 +247,3 @@ my_ReleaseSRWLockExclusive(PSRWLOCK srw) } /*end*/ - diff --git a/libw32/w32_select.c b/libw32/w32_select.c index fe0dc045..e6df35be 100644 --- a/libw32/w32_select.c +++ b/libw32/w32_select.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_select_c,"$Id: w32_select.c,v 1.12 2020/04/20 23:18:24 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_select_c,"$Id: w32_select.c,v 1.14 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * Windows 'select' compat interface * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_select_c,"$Id: w32_select.c,v 1.12 2020/04/20 23:18:24 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -280,14 +280,23 @@ sel_console(Select_t *selfd) selfd->s_avail |= T_WRITE; if (selfd->s_wanted & T_READ) - while (PeekConsoleInput(h, &k, 1, &count) && count) { +#if defined(USE_UNICODE) + while (PeekConsoleInputW(h, &k, 1, &count) && count) { +#else + while (PeekConsoleInputA(h, &k, 1, &count) && count) { +#endif if (k.EventType == KEY_EVENT) { if (k.Event.KeyEvent.bKeyDown) { selfd->s_avail |= T_READ; break; } } - (void) ReadConsoleInput (h, &k, 1, &count); + +#if defined(USE_UNICODE) + (void) ReadConsoleInputW(h, &k, 1, &count); +#else + (void) ReadConsoleInputA(h, &k, 1, &count); +#endif } } @@ -341,4 +350,3 @@ sel_unknown(Select_t *selfd) } /*end*/ - diff --git a/libw32/w32_shell.c b/libw32/w32_shell.c index b19e761d..1218a1eb 100644 --- a/libw32/w32_shell.c +++ b/libw32/w32_shell.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_shell_c,"$Id: w32_shell.c,v 1.13 2020/04/20 23:16:39 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_shell_c,"$Id: w32_shell.c,v 1.14 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 shell and sub-process support * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_shell_c,"$Id: w32_shell.c,v 1.13 2020/04/20 23:16:39 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -37,6 +37,7 @@ __CIDENT_RCSID(gr_w32_shell_c,"$Id: w32_shell.c,v 1.13 2020/04/20 23:16:39 cvsus #include "win32_internal.h" #include "win32_child.h" +#include "win32_misc.h" #include #include @@ -64,9 +65,15 @@ typedef struct { int fd; } Redirect_t; -static const char * OutDirect(const char *path, int *append); +static int ShellA(const char *shell, const char *cmd, const char *fstdin, const char *fstdout, const char *fstderr); +static int ShellW(const wchar_t *shell, const wchar_t *cmd, const wchar_t *fstdin, const wchar_t *fstdout, const wchar_t *fstderr); +static const char * OutDirectA(const char *path, int *append); +static const wchar_t * OutDirectW(const wchar_t *path, int *append); static void ShellCleanup(void *p); +static const wchar_t * ImportArgv(const char **argv); +static const wchar_t ** ImportEnvv(const char **envv); + static int Dup(HANDLE old, HANDLE *dup, BOOL inherit); static int Pipe(HANDLE *read, HANDLE *write); static void Close(HANDLE handle); @@ -75,7 +82,8 @@ static void Close2(HANDLE handle, const char *desc); static int StartRedirectThread(const char *what, HANDLE hPipe, int fd, HANDLE hDupPipe); static DWORD WINAPI RedirectThread(LPVOID p); -static void DisplayError(HANDLE hOutput, const char *pszAPI, const char *args); +static void DisplayErrorA(HANDLE hOutput, const char *pszAPI, const char *args); +static void DisplayErrorW(HANDLE hOutput, const wchar_t *pszAPI, const wchar_t *args); static void InternalError(const char *pszAPI); @@ -86,12 +94,63 @@ static void InternalError(const char *pszAPI); int w32_shell(const char *shell, const char *cmd, const char *fstdin, const char *fstdout, const char *fstderr) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t *wshell = NULL, *wcmd = NULL, + *wfstdin = NULL, *wfstdout = NULL, *wfstderr = NULL; + int ret = -1; + + if (NULL == shell || NULL != (wshell = w32_utf2wca(shell, NULL))) { + if (NULL == cmd || NULL != (wcmd = w32_utf2wca(cmd, NULL))) { + if (NULL == fstdin || NULL != (wfstdin = w32_utf2wca(fstdin, NULL))) { + if (NULL == fstdout || NULL != (wfstdout = w32_utf2wca(fstdout, NULL))) { + if (NULL == fstderr || NULL != (wfstderr = w32_utf2wca(fstderr, NULL))) { + ret = ShellW(wshell, wcmd, wfstdin, wfstdout, wfstderr); + free((void *)wfstderr); + } + free((void *)wfstdout); + } + free((void *)wfstdin); + } + free((void *)wcmd); + } + free((void *)wshell); + } + return ret; + } +#endif //UTF8FILENAMES + + return ShellA(shell, cmd, fstdin, fstdout, fstderr); +} + + +int +w32_shellA(const char *shell, const char *cmd, + const char *fstdin, const char *fstdout, const char *fstderr) +{ + return ShellA(shell, cmd, fstdin, fstdout, fstderr); +} + + +int +w32_shellW(const wchar_t *shell, const wchar_t *cmd, + const wchar_t *fstdin, const wchar_t *fstdout, const wchar_t *fstderr) +{ + return ShellW(shell, cmd, fstdin, fstdout, fstderr); +} + + +static int +ShellA(const char *shell, const char *cmd, + const char *fstdin, const char *fstdout, const char *fstderr) { static const char * sharg[] = { // shell arguments "/C", // command "/k" // interactive }; - char *slash, *shname = WIN32_STRDUP(shell ? shell : w32_getshell()); + const int interactive = ((NULL == cmd || !*cmd) ? 1 : 0); + char *slash, *shname = WIN32_STRDUP(shell && *shell ? shell : w32_getshell()); int xstdout = FALSE, xstderr = FALSE; // mode (TRUE == append) SECURITY_ATTRIBUTES sa; HANDLE hInFile, hOutFile, hErrFile; @@ -99,7 +158,6 @@ w32_shell(const char *shell, const char *cmd, win32_spawn_t args = {0}; const char *argv[4] = {0}; HANDLE hProc = 0; - int interactive = 0; int status = 0; // sync or async @@ -107,8 +165,8 @@ w32_shell(const char *shell, const char *cmd, sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; // inherited - fstdout = OutDirect(fstdout, &xstdout); - fstderr = OutDirect(fstderr, &xstderr); + fstdout = OutDirectA(fstdout, &xstdout); + fstderr = OutDirectA(fstderr, &xstderr); // redirection hInFile = hOutFile = hErrFile = INVALID_HANDLE_VALUE; @@ -171,9 +229,8 @@ w32_shell(const char *shell, const char *cmd, } } else { - // Create a duplicate of the output (file) handle for the - // std error write handle. This is necessary in case the - // child application closes one of its std output handles. + // Create a duplicate of the output (file) handle for thestd error write handle. + // This is necessary in case the child application closes one of its std output handles. // if (! Dup(hOutFile, &pd.hError, TRUE)) { InternalError("shell: dup (fileout)"); @@ -181,27 +238,180 @@ w32_shell(const char *shell, const char *cmd, } // command or interactive - if (w32_iscommand(shname)) { + (void)memset(&args, 0, sizeof(args)); + + if (w32_iscommandA(shname)) { slash = shname - 1; while ((slash = strchr(slash + 1, XSLASHCHAR)) != NULL) { *slash = SLASHCHAR; // convert slashes } - } - if (NULL == cmd || !*cmd) { - ++interactive; // interactive if no cmd + if (!interactive && // /C embedded + cmd[0] == sharg[0][0] && cmd[1] == sharg[0][1]) { + argv[0] = shname; + argv[1] = cmd; + argv[2] = NULL; + + } else { + argv[0] = shname; + argv[1] = sharg[ interactive ]; // /C or /K + argv[2] = cmd; + argv[3] = NULL; + } + + } else { + argv[0] = shname; + argv[1] = cmd; + argv[2] = NULL; } // create child process + args.argv = argv; + args._dwFlags = 0; + + if (0 == (hProc = w32_child_execA(&args, pd.hInput, pd.hOutput, pd.hError))) { + ShellCleanup((void *)&pd); + status = -1; + + } else { + ShellCleanup((void *)&pd); + (void) w32_waitpid((int) hProc, &status, 0); + } + + free(shname); + return status; +} + + +static int +ShellW(const wchar_t *shell, const wchar_t *cmd, + const wchar_t *fstdin, const wchar_t *fstdout, const wchar_t *fstderr) +{ + static const wchar_t *sharg[] = { // shell arguments + L"/C", // command + L"/k" // interactive + }; + const int interactive = ((NULL == cmd || !*cmd) ? 1 : 0); + wchar_t *slash, *shname = WIN32_STRDUPW(shell && *shell ? shell : w32_getshellW()); + int xstdout = FALSE, xstderr = FALSE; // mode (TRUE == append) + SECURITY_ATTRIBUTES sa; + HANDLE hInFile, hOutFile, hErrFile; + struct procdata pd = {0}; + win32_spawnw_t args = {0}; + const wchar_t *argv[4] = {0}; + HANDLE hProc = 0; + int status = 0; + + // sync or async + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; // inherited + + fstdout = OutDirectW(fstdout, &xstdout); + fstderr = OutDirectW(fstderr, &xstderr); + + // redirection + hInFile = hOutFile = hErrFile = INVALID_HANDLE_VALUE; + + if (fstdin) { // O_RDONLY + hInFile = CreateFileW(fstdin, GENERIC_READ, + 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } + + if (fstdout) { + if (! xstdout) { // O_RDWR|O_CREAT|O_TRUNC + hOutFile = CreateFileW(fstdout, GENERIC_READ | GENERIC_WRITE, + 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + } else { // O_RDWR|O_CREAT|O_APPEND + hOutFile = CreateFileW(fstdout, GENERIC_READ | GENERIC_WRITE | FILE_APPEND_DATA, + 0, &sa, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + } + + if (fstderr) { + if (! xstderr) { // O_RDWR|O_CREAT|O_TRUNC + hErrFile = CreateFileW(fstderr, GENERIC_READ | GENERIC_WRITE, + 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + } else { // O_RDWR|O_CREAT|O_APPEND + hErrFile = CreateFileW(fstderr, GENERIC_READ | GENERIC_WRITE | FILE_APPEND_DATA, + 0, &sa, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + + } else if (fstdout) { + if (! xstdout) { // O_RDWR|O_CREAT|O_TRUNC + hErrFile = CreateFileW(fstdout, GENERIC_READ | GENERIC_WRITE, + 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + } else { // O_RDWR|O_CREAT|O_APPEND + hErrFile = CreateFileW(fstdout, GENERIC_READ | GENERIC_WRITE | FILE_APPEND_DATA, + 0, &sa, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + } + + // stdin + if ((pd.hInput = hInFile) == INVALID_HANDLE_VALUE) { + if (! Dup(GetStdHandle(STD_INPUT_HANDLE), &pd.hInput, TRUE)) { + InternalError("shell: dup (stdin)"); + } + } + + // stdout + if ((pd.hOutput = hOutFile) == INVALID_HANDLE_VALUE) { + if (! Dup(GetStdHandle(STD_OUTPUT_HANDLE), &pd.hOutput, TRUE)) { + InternalError("shell: dup (stdout)"); + } + } + + // stderr + if ((pd.hError = hErrFile) == INVALID_HANDLE_VALUE) { + if (! Dup(GetStdHandle(STD_ERROR_HANDLE), &pd.hError, TRUE)) { + InternalError("shell: dup (stderr)"); + } + + } else { + // Create a duplicate of the output (file) handle for thestd error write handle. + // This is necessary in case the child application closes one of its std output handles. + // + if (! Dup(hOutFile, &pd.hError, TRUE)) { + InternalError("shell: dup (fileout)"); + } + } + + // command or interactive (void)memset(&args, 0, sizeof(args)); - argv[0] = shname; - argv[1] = sharg[ interactive ]; - argv[2] = cmd; - argv[3] = NULL; + + if (w32_iscommandW(shname)) { + slash = shname - 1; + while ((slash = wcschr(slash + 1, XSLASHCHAR)) != NULL) { + *slash = SLASHCHAR; // convert slashes + } + + if (!interactive && // /C embedded + cmd[0] == sharg[0][0] && cmd[1] == sharg[0][1]) { + argv[0] = shname; + argv[1] = cmd; + argv[2] = NULL; + + } else { + argv[0] = shname; + argv[1] = sharg[ interactive ]; // /C or /K + argv[2] = cmd; + argv[3] = NULL; + } + + } else { + argv[0] = shname; + argv[1] = cmd; + argv[2] = NULL; + } + + // create child process args.argv = argv; args._dwFlags = 0; - if (0 == (hProc = w32_child_exec(&args, pd.hInput, pd.hOutput, pd.hError))) { + if (0 == (hProc = w32_child_execW(&args, pd.hInput, pd.hOutput, pd.hError))) { ShellCleanup((void *)&pd); status = -1; @@ -216,7 +426,24 @@ w32_shell(const char *shell, const char *cmd, static const char * -OutDirect(const char *path, int *append) +OutDirectA(const char *path, int *append) +{ + *append = FALSE; + if (path) { + if ('>' == *path) { // ">name" + ++path; + if ('>' == *path) { // ">>name" + *append = TRUE; + ++path; + } + } + } + return path; +} + + +static const wchar_t * +OutDirectW(const wchar_t *path, int *append) { *append = FALSE; if (path) { @@ -256,7 +483,8 @@ ShellCleanup(void *p) * Non-zero on success, otherwise 0 on error. */ int -w32_spawn(win32_spawn_t *args, int Stdout, int Stderr, int *Stdin) +w32_spawnA( + win32_spawn_t *args, int Stdout, int Stderr, int *Stdin) { assert(Stdout >= 0); // non-optional assert(Stderr >= -1); // optional @@ -268,7 +496,25 @@ w32_spawn(win32_spawn_t *args, int Stdout, int Stderr, int *Stdin) *Stdin = -1; // file descriptors - return w32_spawn2(args, Stdin, &Stdout, (Stderr >= 0 ? &Stderr : NULL)); + return w32_spawnA2(args, Stdin, &Stdout, (Stderr >= 0 ? &Stderr : NULL)); +} + + +int +w32_spawnW( + win32_spawnw_t *args, int Stdout, int Stderr, int *Stdin) +{ + assert(Stdout >= 0); // non-optional + assert(Stderr >= -1); // optional + assert(Stdin); // output, non-optional + + if (Stdout < 0 || Stderr < -1 || NULL == Stdin) { + return 0; + } + + *Stdin = -1; // file descriptors + + return w32_spawnW2(args, Stdin, &Stdout, (Stderr >= 0 ? &Stderr : NULL)); } @@ -285,7 +531,140 @@ w32_spawn(win32_spawn_t *args, int Stdout, int Stderr, int *Stdin) * Non-zero process handle on success, otherwise 0 on error. */ int -w32_spawn2(win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr) +w32_spawnA2( + win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr) +{ + int in = -1, out = -1, err = -1; + HANDLE hInputWriteTmp = 0, hInputRead = 0, hInputWrite = 0, + hErrorReadTmp = 0, hErrorRead = 0, hErrorWrite = 0, + hOutputReadTmp = 0, hOutputRead = 0, hOutputWrite = 0; + HANDLE hProc = 0; + + if (NULL == Stdin || NULL == Stdout) { // must be supplied + return 0; + } + + // Create the child input pipe. + // + if (! Pipe(&hInputRead, &hInputWriteTmp)) { + InternalError("pipe (stdin)"); + } + + // Create the child output pipe. + // + if (! Pipe(&hOutputReadTmp, &hOutputWrite)) { + InternalError("spawn: pipe (stdout)"); + } + + // Create the child error pipe. + // + // Either, + // Create a duplicate of the output write handle for the + // std error write handle. This is necessary in case the + // child application closes one of its std output handles. + // or + // Create stderr pipe, if stderr redirection is required. + // + if (! Stderr) { // no 'stderr' redirection + if (! Dup(hOutputWrite, &hErrorWrite, TRUE)) { + InternalError("spawn: dup (stdout)"); + } + } else { // stderr redirection + if (! Pipe(&hErrorReadTmp, &hErrorWrite)) { + InternalError("spawn: pipe (stderr)"); + } + } + + // Create new output read handle and the input write handles. Set + // the Properties to FALSE. Otherwise, the child inherits the + // properties and, as a result, non-closeable handles to the pipes + // are created. + // + if (! Dup(hInputWriteTmp, &hInputWrite, FALSE)) InternalError("spawn: dup (stdin)"); + if (! Dup(hOutputReadTmp, &hOutputRead, FALSE)) InternalError("spawn: dup (stdout)"); + if (Stderr) { + if (! Dup(hErrorReadTmp, &hErrorRead, FALSE)) { + InternalError("spawn: dup (stderr)"); + } + } else { + hErrorRead = 0; + } + + // Close inheritable copies of the handles you do + // not want to be inherited. + // + Close2(hOutputReadTmp, "spawn (stdput1)"); + Close2(hInputWriteTmp, "spawn (stdin1)"); + if (Stderr) { + Close2(hErrorReadTmp, "spawn (stderr1)"); + } + + // Open LIBC compatible handles (if required) and launch child process + // + if ((*Stdin >= 0 || + (in = _open_osfhandle((long)hInputWrite, _O_NOINHERIT)) >= 0) && + (*Stdout >= 0 || + (out = _open_osfhandle((long)hOutputRead, _O_NOINHERIT)) >= 0) && + (Stderr == NULL || *Stderr >= 0 || + (err = _open_osfhandle((long)hErrorRead, _O_NOINHERIT)) >= 0)) { + hProc = w32_child_execA(args, hInputRead, hOutputWrite, hErrorWrite); + } + + // Close pipe handles (do not continue to modify the parent). + // You need to make sure that no handles to the write end of the + // output pipe are maintained in this process or else the pipe will + // not close when the child process exits and the ReadFile will hang. + // + Close(hInputRead); Close(hOutputWrite); Close(hErrorWrite); + + // Launch the thread(s) that gets the input and sends it to the child. + // + // Theses are only required if the caller supplied the out/err fds. + // + if (hProc) { + if (*Stdin >= 0) { + assert(in == -1); + } else { + assert(in >= 0); + *Stdin = in; + } + + if (*Stdout >= 0) { + assert(out == -1); + StartRedirectThread("stdout", hOutputRead, *Stdout, + (Stderr ? INVALID_HANDLE_VALUE : hErrorRead) ); + } else { + assert(out >= 0); + *Stdout = out; + } + + if (Stderr) { + if (*Stderr >= 0) { + assert(err == -1); + StartRedirectThread("stderr", + hErrorRead, *Stderr, INVALID_HANDLE_VALUE); + } else { + assert(err >= 0); + *Stderr = err; + } + } else { + assert(err == -1); + } + + } else { + Close(hInputWrite); + Close(hOutputRead); + if (Stderr) { + Close(hErrorRead); + } + } + return (int)(hProc); +} + + +int +w32_spawnW2( + win32_spawnw_t *args, int *Stdin, int *Stdout, int *Stderr) { int in = -1, out = -1, err = -1; HANDLE hInputWriteTmp = 0, hInputRead = 0, hInputWrite = 0, @@ -294,6 +673,7 @@ w32_spawn2(win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr) HANDLE hProc = 0; if (NULL == Stdin || NULL == Stdout) { // must be supplied + errno = EINVAL; return 0; } @@ -301,12 +681,16 @@ w32_spawn2(win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr) // if (! Pipe(&hInputRead, &hInputWriteTmp)) { InternalError("pipe (stdin)"); + errno = EINVAL; + return 0; } // Create the child output pipe. // - if (! Pipe(&hOutputReadTmp, &hOutputWrite )) { + if (! Pipe(&hOutputReadTmp, &hOutputWrite)) { InternalError("spawn: pipe (stdout)"); + errno = EINVAL; + return 0; } // Create the child error pipe. @@ -321,10 +705,14 @@ w32_spawn2(win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr) if (! Stderr) { // no 'stderr' redirection if (! Dup(hOutputWrite, &hErrorWrite, TRUE)) { InternalError("spawn: dup (stdout)"); + errno = EINVAL; + return 0; } } else { // stderr redirection if (! Pipe(&hErrorReadTmp, &hErrorWrite)) { InternalError("spawn: pipe (stderr)"); + errno = EINVAL; + return 0; } } @@ -338,6 +726,8 @@ w32_spawn2(win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr) if (Stderr) { if (! Dup(hErrorReadTmp, &hErrorRead, FALSE)) { InternalError("spawn: dup (stderr)"); + errno = EINVAL; + return 0; } } else { hErrorRead = 0; @@ -360,7 +750,7 @@ w32_spawn2(win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr) (out = _open_osfhandle((long)hOutputRead, _O_NOINHERIT)) >= 0) && (Stderr == NULL || *Stderr >= 0 || (err = _open_osfhandle((long)hErrorRead, _O_NOINHERIT)) >= 0)) { - hProc = w32_child_exec(args, hInputRead, hOutputWrite, hErrorWrite); + hProc = w32_child_execW(args, hInputRead, hOutputWrite, hErrorWrite); } // Close pipe handles (do not continue to modify the parent). @@ -424,52 +814,318 @@ w32_spawn2(win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr) * Returns: * Non-zero on success, otherwise 0 on error. */ + int w32_exec(win32_exec_t *args) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + if (args->spawn.cmd || args->spawn.argv) { + win32_execw_t wargs = { 0 }; + const wchar_t *wcmd = NULL; + int ret = 0; + + if ((args->spawn.cmd && + NULL != (wcmd = w32_utf2wca(args->spawn.cmd, NULL))) || + (args->spawn.argv && + NULL != (wcmd = ImportArgv(args->spawn.argv)))) { + + wargs.spawn.cmd = wcmd; + wargs.spawn.envv = (args->spawn.envv ? ImportEnvv(args->spawn.envv) : NULL); + wargs.spawn.dir = (args->spawn.dir ? w32_utf2wca(args->spawn.dir, NULL) : NULL); + wargs.spawn.flags = args->spawn.flags; + + ret = w32_execW(&wargs); + + free((void *)wargs.spawn.dir); + free((void *)wargs.spawn.envv); + free((void *)wcmd); + } + + args->hError = wargs.hError; + args->hInput = wargs.hInput; + args->hOutput = wargs.hOutput; + args->hProc = wargs.hProc; + return ret; + } + } +#endif //UTF8FILENAMES + + return w32_execA(args); +} + + +static const wchar_t * +ImportArgv(const char **argv) +{ + const char * const *vp; + size_t bytes; + char *buffer; + int cnt, len; + + /* + * Allocate space for environment strings, count the number of bytes + * in the environment strings including nulls between strings + */ + if (NULL == argv) { + return NULL; + } + + for (vp = argv, cnt = 0, len = 2 /*quotes*/ + 2 /*delim*/; *vp; ++vp) { + const char *arg = *vp; + if (*arg) { // non-empty. + const int wlen = w32_utf2wcl(arg); + if (wlen < 0) { + return NULL; // conversion error. + } + len += wlen; // inc's nul + ++cnt; + } + } + + bytes = len * sizeof(wchar_t); + if (NULL == (buffer = (char *)calloc(bytes, 1))) { + return NULL; + } + + /* + * Build the command line by concatenating the argument strings + * with spaces between, and two null bytes at the end. + */ + { wchar_t *cursor = (wchar_t *)(buffer), + *end = (wchar_t *)(buffer + bytes); + int argc, wlen; + + vp = argv; + for (argc = 0; *vp; ++argc) { + const char *arg = *vp++; + int quote = FALSE; + + if (*arg) { // non-empty. + if (0 == argc && *arg != '"' && strchr(arg, ' ')) { + quote = TRUE; // quote, contains space. + } + + if (quote) *cursor++ = '"'; + if ((wlen = w32_utf2wc(arg, cursor, end - cursor)) <= 0) { + free((void *)buffer); + assert(FALSE); + return NULL; + } + if (0 == argc) { + while (*cursor) { // convert slashs within arg0. + if ('/' == *cursor) *cursor = '\\'; + ++cursor; + } + } else { + cursor += wlen - 1 /*nul*/; + } + if (quote) *cursor++ = '"'; + + *cursor++ = ' '; // space delimiter. + } + } + + assert(cnt == argc); + assert(cursor <= end); + cursor[-1] = '\0'; // remove extra delimiter. + *cursor = '\0'; // terminator. + } + + return (wchar_t *) buffer; // result. +} + + +static const wchar_t ** +ImportEnvv(const char **envv) +{ + const char * const *vp; + const wchar_t **ret; + size_t bytes; + char *buffer; + int cnt, len; + + /* + * Allocate space for environment strings, count the number of bytes + * in the environment strings including nulls between strings + */ + if (NULL == envv) { + return NULL; + } + + for (vp = envv, cnt = 0, len = 0; *vp; ++vp) { + const char *arg = *vp; + if (*arg) { // non-empty. + const int wlen = w32_utf2wcl(arg); + if (wlen < 0) { + return NULL; // conversion error. + } + len += wlen; // inc's nul + ++cnt; + } + } + + bytes = ((cnt + 1) * sizeof(wchar_t *)) + (len * sizeof(wchar_t)); + if (NULL == (buffer = (char *)calloc(bytes, 1))) { + return NULL; + } + + /* + * Build the environment vector by importing the env collection. + */ + ret = (const wchar_t **)buffer; + + { wchar_t *cursor = (wchar_t *)(buffer + ((cnt + 1) * sizeof(void *))), + *end = (wchar_t *)(buffer + bytes); + int envc, wlen; + + vp = envv; + assert((void *)(&ret[cnt+1]) == (void *)cursor); + for (envc = 0; *vp; ++vp) { + const char *arg = *vp; + if (*arg) { // non-empty. + if ((wlen = w32_utf2wc(arg, cursor, end - cursor)) <= 0) { + free((void *)buffer); + assert(FALSE); + return NULL; + } + ret[envc++] = cursor; + cursor += wlen; + } + } + + assert(cnt == envc); + assert(cursor == end); + ret[envc] = NULL; + } + + return ret; // result. +} + + +/* + * Exec -- exec a child process, returning native win32 handles. + * + * Parameters: + * args - [in/out] Spawn arguments. + * + * Returns: + * Non-zero on success, otherwise 0 on error. + */ + +int +w32_execA(win32_exec_t *args) { HANDLE hInputWriteTmp = 0, hInputRead = 0, hInputWrite = 0, hErrorReadTmp = 0, hErrorRead = 0, hErrorWrite = 0, hOutputReadTmp = 0, hOutputRead = 0, hOutputWrite = 0; - // Create the child input/out/err pipe. - // + // Non-optional arguments. + if (NULL == args || + (NULL == args->spawn.cmd && NULL == args->spawn.argv)) { + errno = EINVAL; + return -1; + } + + // Create the child input/out/err pipes. if (! Pipe(&hInputRead, &hInputWriteTmp) || ! Pipe(&hOutputReadTmp, &hOutputWrite) || ! Pipe(&hErrorReadTmp, &hErrorWrite)) { InternalError("exec: pipe"); + goto einval; } - // Create new output read handle and the input write handles, set as non - // inheritable. Otherwise, the child inherits the properties and, as a result, - // non-closeable handles to the pipes are created. - // + // Create new output read handle and the input write handles, set as non inheritable. + // Otherwise, the child inherits the properties and, as a result, non-closeable handles to the pipes are created. if (! Dup(hInputWriteTmp, &hInputWrite, FALSE) || ! Dup(hOutputReadTmp, &hOutputRead, FALSE) || ! Dup(hErrorReadTmp, &hErrorRead, FALSE)) { InternalError("exec: dup"); + goto einval; } Close(hOutputReadTmp); Close(hInputWriteTmp); Close(hErrorReadTmp); - // Execute child. - // - args->hProc = - w32_child_exec(&args->spawn, hInputRead, hOutputWrite, hErrorWrite); + // Execute child. + args->hProc = w32_child_execA(&args->spawn, hInputRead, hOutputWrite, hErrorWrite); - // Close pipe handles. - // + // Close pipe handles. Close(hInputRead); Close(hOutputWrite); Close(hErrorWrite); - // Completion. - // + // Completion. + if (0 == args->hProc) { + Close(hInputWrite); Close(hOutputRead); Close(hErrorRead); + return 0; + } + + args->hInput = hInputWrite; + args->hOutput = hOutputRead; + args->hError = hErrorRead; + return (int)args->hProc; + +einval:; + Close(hOutputReadTmp); Close(hInputWriteTmp); Close(hErrorReadTmp); + Close(hInputRead); Close(hOutputWrite); Close(hErrorWrite); + Close(hInputWrite); Close(hOutputRead); Close(hErrorRead); + errno = EINVAL; + return -1; +} + + +int +w32_execW(win32_execw_t *args) +{ + HANDLE hInputWriteTmp = 0, hInputRead = 0, hInputWrite = 0, + hErrorReadTmp = 0, hErrorRead = 0, hErrorWrite = 0, + hOutputReadTmp = 0, hOutputRead = 0, hOutputWrite = 0; + + // Non-optional arguments. + if (NULL == args || + (NULL == args->spawn.cmd && NULL == args->spawn.argv)) { + errno = EINVAL; + return -1; + } + + // Create the child input/out/err pipes. + if (! Pipe(&hInputRead, &hInputWriteTmp) || + ! Pipe(&hOutputReadTmp, &hOutputWrite) || + ! Pipe(&hErrorReadTmp, &hErrorWrite)) { + InternalError("exec: pipe"); + goto einval; + } + + // Create new output read handle and the input write handles, set as non inheritable. + // Otherwise, the child inherits the properties and, as a result, non-closeable handles to the pipes are created. + if (! Dup(hInputWriteTmp, &hInputWrite, FALSE) || + ! Dup(hOutputReadTmp, &hOutputRead, FALSE) || + ! Dup(hErrorReadTmp, &hErrorRead, FALSE)) { + InternalError("exec: dup"); + goto einval; + } + Close(hOutputReadTmp); Close(hInputWriteTmp); Close(hErrorReadTmp); + + // Execute child. + args->hProc = w32_child_execW(&args->spawn, hInputRead, hOutputWrite, hErrorWrite); + + // Close pipe handles. + Close(hInputRead); Close(hOutputWrite); Close(hErrorWrite); + + // Completion. if (0 == args->hProc) { Close(hInputWrite); Close(hOutputRead); Close(hErrorRead); return 0; } - args->hInput = hInputWrite; + args->hInput = hInputWrite; args->hOutput = hOutputRead; - args->hError = hErrorRead; - return 1; + args->hError = hErrorRead; + return (int)args->hProc; + +einval:; + Close(hOutputReadTmp); Close(hInputWriteTmp); Close(hErrorReadTmp); + Close(hInputRead); Close(hOutputWrite); Close(hErrorWrite); + Close(hInputWrite); Close(hOutputRead); Close(hErrorRead); + errno = EINVAL; + return -1; } @@ -485,9 +1141,9 @@ Dup(HANDLE old, HANDLE *dup, BOOL inherit) if (dup == NULL || old == INVALID_HANDLE_VALUE || !DuplicateHandle(self, old, self, dup, 0, inherit, DUPLICATE_SAME_ACCESS)) { *dup = INVALID_HANDLE_VALUE; - return (FALSE); + return FALSE; } - return (TRUE); + return TRUE; } @@ -518,7 +1174,7 @@ Pipe(HANDLE *read, HANDLE *write) static void Close(HANDLE handle) { - if (handle != INVALID_HANDLE_VALUE) { + if (handle && handle != INVALID_HANDLE_VALUE) { if (! CloseHandle(handle)) { InternalError("closehandle()"); } @@ -533,7 +1189,7 @@ Close(HANDLE handle) static void Close2(HANDLE handle, const char *desc) { - if (handle != INVALID_HANDLE_VALUE) { + if (handle && handle != INVALID_HANDLE_VALUE) { if (! CloseHandle(handle)) { char buffer[512]; _snprintf(buffer, sizeof(buffer), "closehandle(%s)", desc); @@ -556,7 +1212,7 @@ StartRedirectThread( DWORD tid; Redirect_t *p; - if ((p = malloc(sizeof(*p))) == NULL) { + if (NULL == (p = malloc(sizeof(*p)))) { InternalError("malloc"); } p->what = what; @@ -588,7 +1244,6 @@ RedirectThread(LPVOID p) } InternalError("ReadFile"); // .. something bad } - // redirect write loop if (_write(fd, buffer, cnt) != (int)cnt) { break; @@ -611,36 +1266,40 @@ RedirectThread(LPVOID p) * Displays the error number and corresponding message. */ static void -DisplayError( - HANDLE hOutput, const char *pszAPI, const char *args ) +DisplayErrorA( + HANDLE hOutput, const char *msg, const char *cmd) { - DWORD rc = GetLastError(); - LPVOID lpvMessageBuffer; - char szPrintBuffer[512]; - DWORD nCharsWritten; - - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpvMessageBuffer, 0, NULL); - - (void) _snprintf(szPrintBuffer, sizeof(szPrintBuffer), - "Internal Error: %s = %d (%s).\n%s%s", pszAPI, rc, (char *)lpvMessageBuffer, - args ? args : "", args ? "\n" : ""); - szPrintBuffer[sizeof(szPrintBuffer) - 1] = 0; + const DWORD rc = GetLastError(); + char t_rcbuffer[512], buffer[512]; + const char *rcmsg = w32_vsyserrorA(rc, t_rcbuffer, sizeof(t_rcbuffer), cmd, NULL); + int len; + + len = _snprintf(buffer, sizeof(buffer), + "Internal Error: %s = %d (%s).\n", msg, rc, rcmsg); + WriteConsoleA(hOutput, buffer, len, NULL, NULL); +} - WriteConsoleA(hOutput, szPrintBuffer, - lstrlenA(szPrintBuffer), &nCharsWritten, NULL); - LocalFree(lpvMessageBuffer); +static void +DisplayErrorW( + HANDLE hOutput, const wchar_t *msg, const wchar_t *cmd) +{ + const DWORD rc = GetLastError(); + wchar_t t_rcbuffer[512], buffer[512]; + const wchar_t *rcmsg = w32_vsyserrorW(rc, t_rcbuffer, _countof(t_rcbuffer), cmd, NULL); + int len; + + len = _snwprintf(buffer, _countof(buffer), + L"Internal Error: %s = %d (%s).\n", msg, rc, rcmsg); + WriteConsoleW(hOutput, buffer, len, NULL, NULL); } static void -InternalError( - const char *pszAPI) +InternalError(const char *pszAPI) { - DisplayError(GetStdHandle(STD_OUTPUT_HANDLE), pszAPI, NULL); + DisplayErrorA(GetStdHandle(STD_OUTPUT_HANDLE), pszAPI, NULL); ExitProcess(GetLastError()); } /*end*/ - diff --git a/libw32/w32_signal.c b/libw32/w32_signal.c index 16b042ae..a90b36e0 100644 --- a/libw32/w32_signal.c +++ b/libw32/w32_signal.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_signal_c,"$Id: w32_signal.c,v 1.14 2020/05/03 21:34:19 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_signal_c,"$Id: w32_signal.c,v 1.15 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 signal support * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_signal_c,"$Id: w32_signal.c,v 1.14 2020/05/03 21:34:19 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -43,18 +43,18 @@ __CIDENT_RCSID(gr_w32_signal_c,"$Id: w32_signal.c,v 1.14 2020/05/03 21:34:19 cvs /* // NAME // sigemptyset - initialize and empty a signal set -// +// // SYNOPSIS // #include -// +// // int sigemptyset(sigset_t *set); [Option End] -// +// // DESCRIPTION // The sigemptyset() function initializes the signal set pointed to by set, such that all signals defined in POSIX.1-2017 are excluded. -// +// // RETURN VALUE // Upon successful completion, sigemptyset() shall return 0; otherwise, it shall return -1 and set errno to indicate the error. -// +// // ERRORS // No errors are defined. // diff --git a/libw32/w32_sockbase.c b/libw32/w32_sockbase.c index 89b3b150..12a567c7 100644 --- a/libw32/w32_sockbase.c +++ b/libw32/w32_sockbase.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_sockbase_c,"$Id: w32_sockbase.c,v 1.6 2020/06/18 14:32:39 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_sockbase_c,"$Id: w32_sockbase.c,v 1.7 2022/03/21 14:29:41 cvsuser Exp $") /* * win32 socket () system calls * Base functionality. * - * Copyright (c) 2007, 2012 - 2019 Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -20,10 +20,10 @@ __CIDENT_RCSID(gr_w32_sockbase_c,"$Id: w32_sockbase.c,v 1.6 2020/06/18 14:32:39 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -204,4 +204,3 @@ w32_sockerror(void) } /*end*/ - diff --git a/libw32/w32_socket.c b/libw32/w32_socket.c index b92b40a4..26fca78d 100644 --- a/libw32/w32_socket.c +++ b/libw32/w32_socket.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_socket_c,"$Id: w32_socket.c,v 1.17 2020/06/06 00:37:02 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_socket_c,"$Id: w32_socket.c,v 1.19 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 socket () system calls * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_socket_c,"$Id: w32_socket.c,v 1.17 2020/06/06 00:37:02 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -363,6 +363,27 @@ w32_recvfrom_fd(int fd, char *buf, int len, int flags, } +/* + * socksetblockingmode() + */ +LIBW32_API int +w32_sockblockingmode_fd(int fd, int enabled) +{ + SOCKET osf; + int ret; + + if ((osf = w32_sockhandle(fd)) == (SOCKET)INVALID_SOCKET) { + ret = -1; + } else { + u_long mode = (long)enabled; + if ((ret = ioctlsocket(osf, FIONBIO, &mode)) == -1 /*SOCKET_ERROR*/) { + w32_sockerror(); + } + } + return ret; +} + + /* * sockwrite() system call; aka write() for sockets. */ @@ -417,8 +438,11 @@ w32_sockclose_fd(int fd) #undef closesocket if ((osf = w32_sockhandle(fd)) == (SOCKET)INVALID_SOCKET) { ret = -1; - } else if ((ret = closesocket(osf)) == -1 /*SOCKET_ERROR*/) { - w32_sockerror(); + } else { + w32_sockfd_close(fd, osf); + if ((ret = closesocket(osf)) == -1 /*SOCKET_ERROR*/) { + w32_sockerror(); + } } return ret; } @@ -457,4 +481,3 @@ w32_sockhandle(int fd) } /*end*/ - diff --git a/libw32/w32_socket2.c b/libw32/w32_socket2.c index 0f9e5767..166b4a20 100644 --- a/libw32/w32_socket2.c +++ b/libw32/w32_socket2.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_socket2_c,"$Id: w32_socket2.c,v 1.7 2020/06/18 14:32:40 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_socket2_c,"$Id: w32_socket2.c,v 1.9 2022/03/21 14:29:41 cvsuser Exp $") /* * win32 socket () system calls * Light weight replacement functions, which maintain the global errno. * - * Copyright (c) 2007, 2012 - 2019 Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -20,11 +20,11 @@ __CIDENT_RCSID(gr_w32_socket2_c,"$Id: w32_socket2.c,v 1.7 2020/06/18 14:32:40 cv * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. - * ==extra== + * license for more details. + * ==end== */ #ifndef _WIN32_WINNT @@ -37,6 +37,7 @@ __CIDENT_RCSID(gr_w32_socket2_c,"$Id: w32_socket2.c,v 1.7 2020/06/18 14:32:40 cv #include #include #include +#include #include #include @@ -44,8 +45,13 @@ __CIDENT_RCSID(gr_w32_socket2_c,"$Id: w32_socket2.c,v 1.7 2020/06/18 14:32:40 cv #include #include #include +#include #include +#if defined(__WATCOMC__) +#pragma disable_message(124) /* Comparison result always 0 */ +#endif + /* * determine whether a valid socket file descriptor. @@ -223,7 +229,7 @@ w32_accept_native(int fd, struct sockaddr *addr, int *addrlen) * getpeername() system call */ LIBW32_API int -w32_getpeername_native(int fd, struct sockaddr *name, int *namelen) +w32_getpeername_native(int fd, struct sockaddr *name, socklen_t *namelen) { SOCKET osf; int ret; @@ -242,7 +248,7 @@ w32_getpeername_native(int fd, struct sockaddr *name, int *namelen) * getsockname() system call. */ LIBW32_API int -w32_getsockname_native(int fd, struct sockaddr *name, int *namelen) +w32_getsockname_native(int fd, struct sockaddr *name, socklen_t *namelen) { SOCKET osf; int ret; @@ -320,6 +326,58 @@ w32_sendto_native(int fd, const void *buf, size_t len, int flags, } +/* + * sendmsg() system call + */ +LIBW32_API int +w32_sendmsg_native(int fd, const struct msghdr *message, int flags) +{ + SOCKET osf; + int ret = -1; + + if (NULL == message || NULL == message->msg_iov || + message->msg_iovlen < 0 || message->msg_iovlen > IOV_MAX) { + errno = EINVAL; /* invalid argument */ + + } else if (0 == message->msg_iovlen) { + ret = 0; /* nothing to send */ + + } else if ((osf = nativehandle(fd)) != (SOCKET)INVALID_SOCKET) { +#if defined(_MSC_VER) || defined(__WATCOMC__) + WSABUF *wsabufs = _alloca(sizeof(WSABUF) * message->msg_iovlen); +#else + WSABUF *wsabufs = alloca(sizeof(WSABUF) * message->msg_iovlen); +#endif + const struct iovec *iov = message->msg_iov; + unsigned i, cnt; + + for (i = 0, cnt = 0; i < message->msg_iovlen; ++i, ++iov) { + if (iov->iov_len) { + wsabufs[cnt].len = iov->iov_len; + wsabufs[cnt].buf = iov->iov_base; + ++cnt; + } + } + + // The WSASend function is used to write outgoing data from one or more buffers on a connection-oriented socket specified by s. + // It can also be used, however, on connectionless sockets that have a stipulated default peer address established + // through the connect or WSAConnect function. + // + ret = 0; + if (cnt) { + DWORD num_bytes_sent = 0; + const int srv = WSASend(osf, wsabufs, cnt, &num_bytes_sent, flags, NULL, NULL); + if (0 == srv) { + return (int) num_bytes_sent; + } + w32_sockerror(); + ret = -1; + } + } + return ret; +} + + /* * recv() system call */ @@ -359,6 +417,28 @@ w32_recvfrom_native(int fd, char *buf, int len, int flags, } + +/* + * sockblockingmode + */ +LIBW32_API int +w32_sockblockingmode_native(int fd, int enabled) +{ + SOCKET osf; + int ret; + + if ((osf = nativehandle(fd)) == (SOCKET)INVALID_SOCKET) { + ret = -1; + } else { + u_long mode = (long)enabled; + if ((ret = ioctlsocket(osf, FIONBIO, &mode)) == -1 /*SOCKET_ERROR*/) { + w32_sockerror(); + } + } + return ret; +} + + /* * sockwrite() system call; aka write() for sockets. */ @@ -431,11 +511,10 @@ w32_shutdown_native(int fd, int how) #undef shutdown if ((osf = nativehandle(fd)) == (SOCKET)INVALID_SOCKET) { ret = -1; - } else if ((ret = shutdown((SOCKET)osf, how)) == -1 /*SOCKET_ERROR*/) { + } else if ((ret = shutdown((SOCKET)osf, how)) == -1) { w32_sockerror(); } return ret; } /*end*/ - diff --git a/libw32/w32_sockfd.c b/libw32/w32_sockfd.c index 1bb6d817..b329ace8 100644 --- a/libw32/w32_sockfd.c +++ b/libw32/w32_sockfd.c @@ -1,10 +1,10 @@ #include -__CIDENT_RCSID(gr_w32_sockfd_c,"$Id: w32_sockfd.c,v 1.5 2019/03/15 23:12:20 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_sockfd_c,"$Id: w32_sockfd.c,v 1.7 2022/03/21 14:29:41 cvsuser Exp $") /* * win32 socket file-descriptor support * - * Copyright (c) 2007, 2012 - 2019 Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -19,11 +19,11 @@ __CIDENT_RCSID(gr_w32_sockfd_c,"$Id: w32_sockfd.c,v 1.5 2019/03/15 23:12:20 cvsu * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. - * ==extra== + * license for more details. + * ==end== */ #ifndef _WIN32_WINNT @@ -158,6 +158,13 @@ w32_sockfd_close(int fd, SOCKET s) // return 0; // } +static int +IsSocket(HANDLE h) +{ + return (GetFileType(h) == FILE_TYPE_PIPE && + 0 == GetNamedPipeInfo(h, NULL, NULL, NULL, NULL)); +} + LIBW32_API int w32_issockfd(int fd, SOCKET *s) { @@ -175,18 +182,23 @@ w32_issockfd(int fd, SOCKET *s) } else if (fd >= x_fdinit || /* local socket mapping */ (t_s = x_fdsockets[fd]) == INVALID_SOCKET) { + /* - * MSVC 2015+ no longer suitable without fdlimit; asserts when out-of-range + * MSVC 2015+ no longer suitable; asserts when out-of-range. + * Unfortunately socket handles can be small numeric values yet so are file descriptors. */ - if (fd >= x_fdlimit || + if (fd >= 0x80 && 0 == (fd & 0x3) && IsSocket((HANDLE)fd)) { + t_s = (SOCKET)fd; + + } else if (fd >= x_fdlimit || _get_osfhandle(fd) == (SOCKET)INVALID_HANDLE_VALUE) { t_s = (SOCKET)fd; /* invalid assume socket; otherwise file */ } } } + if (s) *s = t_s; return (t_s != INVALID_SOCKET); } /*end*/ - diff --git a/libw32/w32_sockpair.c b/libw32/w32_sockpair.c index ae688f3e..cecb0eb7 100644 --- a/libw32/w32_sockpair.c +++ b/libw32/w32_sockpair.c @@ -1,10 +1,10 @@ #include -__CIDENT_RCSID(gr_w32_sockpair_c,"$Id: w32_sockpair.c,v 1.6 2020/04/20 23:18:24 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_sockpair_c,"$Id: w32_sockpair.c,v 1.9 2022/03/21 14:29:41 cvsuser Exp $") /* * win32 socket file-descriptor support * - * Copyright (c) 2007, 2012 - 2019 Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -19,11 +19,11 @@ __CIDENT_RCSID(gr_w32_sockpair_c,"$Id: w32_sockpair.c,v 1.6 2020/04/20 23:18:24 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. - * ==notice== + * license for more details. + * ==end== */ #ifndef _WIN32_WINNT @@ -164,23 +164,25 @@ w32_socketpair_fd(int af, int type, int proto, int sock[2]) int ret; if (0 == (ret = w32_socketpair_native(af, type, proto, sock))) { - int s1, s2; + int s0 = -1, s1 = -1; + + if (sock[0] < WIN32_FILDES_MAX || + (s0 = _open_osfhandle((long)sock[0], 0)) == -1 || + sock[1] < WIN32_FILDES_MAX || + (s1 = _open_osfhandle((long)sock[1], 0)) == -1) { - if ((s1 = (int)sock[0]) < WIN32_FILDES_MAX && - (s2 = _open_osfhandle((long)sock[0], 0)) == -1 || - (s2 = (int)sock[1]) < WIN32_FILDES_MAX && - (s2 = _open_osfhandle((long)sock[1], 0)) == -1) { closesocket((SOCKET)sock[1]); - closesocket((SOCKET)sock[0]); + if (s0 >= 0) _close(s0); + else closesocket((SOCKET)sock[0]); errno = EMFILE; ret = -1; } else { - w32_sockfd_open(s1, sock[0]); /* associate file-descriptor */ - sock[0] = s1; + w32_sockfd_open(s0, sock[0]); /* associate file-descriptor */ + sock[0] = s0; - w32_sockfd_open(s2, sock[1]); /* associate file-descriptor */ - sock[1] = s2; + w32_sockfd_open(s0, sock[1]); /* associate file-descriptor */ + sock[1] = s1; } } return ret; @@ -200,12 +202,13 @@ w32_socketpair_native(int af, int type, int proto, int sock[2]) int addr2_len = sizeof (addr2); int nerr; + sock[0] = INVALID_SOCKET; sock[1] = INVALID_SOCKET; - sock[2] = INVALID_SOCKET; - assert(af == AF_INET && type == SOCK_STREAM && (proto == IPPROTO_IP || proto == IPPROTO_TCP)); + assert(af == AF_INET && type == SOCK_STREAM && (0 == proto || IPPROTO_IP == proto || IPPROTO_TCP == proto)); #undef socket + if (0 == proto) proto = IPPROTO_IP; if ((listen_sock = socket(af, type, proto)) == INVALID_SOCKET) goto error; @@ -274,4 +277,3 @@ w32_socketpair_native(int af, int type, int proto, int sock[2]) } /*end*/ - diff --git a/libw32/w32_statfs.c b/libw32/w32_statfs.c index ad8feeec..7d9d2f1b 100644 --- a/libw32/w32_statfs.c +++ b/libw32/w32_statfs.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_statfs_c,"$Id: w32_statfs.c,v 1.16 2020/04/20 23:16:18 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_statfs_c,"$Id: w32_statfs.c,v 1.19 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* - * win32 statfs()/statvfs() system calls. + * win32 statfs()/statvfs() and getmntinfo() system calls. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_statfs_c,"$Id: w32_statfs.c,v 1.16 2020/04/20 23:16:18 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -53,14 +53,15 @@ __CIDENT_RCSID(gr_w32_statfs_c,"$Id: w32_statfs.c,v 1.16 2020/04/20 23:16:18 cvs // #include // // int fstatvfs(int fildes, struct statvfs *buf); -// int statvfs(const char *restrict path, struct statvfs *restrict buf); [Option End] +// int statvfs(const char *restrict path, struct statvfs *restrict buf); // // DESCRIPTION // The fstatvfs() function shall obtain information about the file system containing the file referenced by fildes. // // The statvfs() function shall obtain information about the file system containing the file named by path. // -// For both functions, the buf argument is a pointer to a statvfs structure that shall be filled.Read, write, or execute permission of the named file is not required. +// For both functions, the buf argument is a pointer to a statvfs structure that shall be filled. +// Read, write, or execute permission of the named file is not required. // // The following flags can be returned in the f_flag member : // @@ -97,13 +98,42 @@ __CIDENT_RCSID(gr_w32_statfs_c,"$Id: w32_statfs.c,v 1.16 2020/04/20 23:16:18 cvs // [ENAMETOOLONG] Pathname resolution of a symbolic link produced an intermediate result whose length exceeds{ PATH_MAX }. */ int -statfs(const char *path, struct statfs *sb) +statfs(const char *path, struct statfs *buf) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path || NULL == buf) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return statfsW(wpath, buf); + } + + return -1; + } +#endif //UTF8FILENAMES + + return statfsA(path, buf); +} + + +int +statfsA(const char *path, struct statfs *sb) { char volName[MNAMELEN], fsName[MFSNAMELEN]; DWORD SectorsPerCluster, BytesPerSector, FreeClusters, Clusters; DWORD MaximumComponentLength, FileSystemFlags; int mnamelen; + if (NULL == path || NULL == sb) { + errno = EFAULT; + return -1; + } + (void) memset(sb, 0, sizeof(*sb)); sb->f_bsize = 1024; /* block size */ @@ -153,10 +183,10 @@ statfs(const char *path, struct statfs *sb) } sb->f_type = MOUNT_PC; - strncpy(sb->f_fstypename, "unknown", MFSNAMELEN); + strncat(sb->f_fstypename, "unknown", MFSNAMELEN); if (GetVolumeInformationA(path, volName, MNAMELEN, /* VolumeName and size */ - NULL, &MaximumComponentLength, &FileSystemFlags, fsName, MFSNAMELEN)) /* filesystem type */ + NULL, &MaximumComponentLength, &FileSystemFlags, fsName, MNAMELEN)) /* filesystem type */ { /* FileSystem type/NTFS, FAT etc */ if (fsName[0]) { strncpy(sb->f_fstypename, fsName, MFSNAMELEN); @@ -166,6 +196,81 @@ statfs(const char *path, struct statfs *sb) } +int +statfsW(const wchar_t *path, struct statfs *sb) +{ + wchar_t volName[MNAMELEN], fsName[MFSNAMELEN]; + DWORD SectorsPerCluster, BytesPerSector, FreeClusters, Clusters; + DWORD MaximumComponentLength, FileSystemFlags; + int mnamelen; + + if (NULL == path || NULL == sb) { + errno = EFAULT; + return -1; + } + + (void) memset(sb, 0, sizeof(*sb)); + + sb->f_bsize = 1024; /* block size */ + + if (GetDiskFreeSpaceW(path, &SectorsPerCluster, &BytesPerSector, &FreeClusters, &Clusters)) { + /* KBytes available */ + sb->f_bavail = (unsigned int) + (((__int64)SectorsPerCluster * BytesPerSector * FreeClusters) / 1024); + + /* KBytes total */ + sb->f_blocks = (unsigned int) + (((__int64)SectorsPerCluster * BytesPerSector * Clusters) / 1024); + + /* inodes */ + sb->f_ffree = FreeClusters/10; + sb->f_files = Clusters/10; + } + + w32_wc2utf(path, sb->f_mntonname, sizeof(sb->f_mntonname)); + w32_dos2unix(sb->f_mntonname); + if ((mnamelen = strlen(sb->f_mntonname)) > 3) { + if (sb->f_mntonname[mnamelen - 1] == '/') { + sb->f_mntonname[mnamelen - 1] = 0; + //remove trailing delimiter on mount-points. + } + } + + switch (GetDriveTypeW(path)) { /* device */ + case DRIVE_REMOVABLE: + strncpy(sb->f_mntfromname, "Removable", MNAMELEN); + break; + case DRIVE_FIXED: + strncpy(sb->f_mntfromname, "Hard Disk", MNAMELEN); + break; + case DRIVE_REMOTE: + strncpy(sb->f_mntfromname, "Networked", MNAMELEN); + break; + case DRIVE_CDROM: + strncpy(sb->f_mntfromname, "CD-ROM", MNAMELEN); + break; + case DRIVE_RAMDISK: + strncpy(sb->f_mntfromname, "RAM disk", MNAMELEN); + break; + default: + strncpy(sb->f_mntfromname, "Unknown", MNAMELEN); + break; + } + + sb->f_type = MOUNT_PC; + strncat(sb->f_fstypename, "unknown", MFSNAMELEN); + if (GetVolumeInformationW(path, + volName, MNAMELEN, /* VolumeName and size */ + NULL, &MaximumComponentLength, &FileSystemFlags, fsName, MNAMELEN)) /* filesystem type */ + { /* FileSystem type/NTFS, FAT etc */ + if (fsName[0]) { + w32_wc2utf(fsName, sb->f_fstypename, sizeof(sb->f_fstypename)); + } + } + return 0; +} + + int statvfs(const char *path, struct statvfs *vfs) { @@ -225,8 +330,8 @@ statvfs(const char *path, struct statvfs *vfs) // // The memory allocated by getmntinfo() cannot be free'd by the application. */ -static struct statfs *enum_volumes(struct statfs *result, long resultsize, int *mnts); +static struct statfs *enum_volumes(struct statfs *result, long resultsize, int *mnts); int getfsstat(struct statfs *buf, long bufsize, int mode) @@ -253,7 +358,6 @@ getmntinfo(struct statfs **psb, int flags) static struct statfs *x_getmntinfo = NULL; // global instance struct statfs *sb; char szDrivesAvail[32*4], *p; -// int numVolumes[32] = {0}; int cnt; if (! psb) { // invalid @@ -320,7 +424,6 @@ enum_volumes(struct statfs *result, long resultsize, int *mnts) struct statfs *sb = result; WCHAR volume[1024] = {0}; - char path[1024]; HANDLE handle; BOOL ret; @@ -350,28 +453,27 @@ enum_volumes(struct statfs *result, long resultsize, int *mnts) PWCHAR cursor, end; for (cursor = names, end = cursor + count; cursor < end && *cursor; ++cursor) { const unsigned len = wcslen(cursor); - size_t cnt = wcstombs(path, cursor, sizeof(path) - 1); - if (cnt && cnt < sizeof(path)) { - if (sbcnt >= sballoc) { - struct statfs *t_sb = - (NULL == result ? realloc(sb, (sballoc += 32) * sizeof(*sb)) : NULL); - if (NULL == t_sb) { - sballoc = -1; - break; // nomem/overflow. - } - sb = t_sb; + if (sbcnt >= sballoc) { + struct statfs *t_sb = + (NULL == result ? realloc(sb, (sballoc += 32) * sizeof(*sb)) : NULL); + if (NULL == t_sb) { + sballoc = -1; + break; // nomem/overflow. } + sb = t_sb; + } - if (0 == statfs(path, sb + sbcnt)) { - ++sbcnt; - } + if (0 == statfsW(cursor, sb + sbcnt)) { + ++sbcnt; } + cursor += len; } free((void *)names); } - if (-1 == sballoc) break; // allocation error. + if (-1 == sballoc) // allocation error. + break; } // diff --git a/libw32/w32_strftime.c b/libw32/w32_strftime.c index 6eb37dfa..eba7ab62 100644 --- a/libw32/w32_strftime.c +++ b/libw32/w32_strftime.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_strftime_c,"$Id: w32_strftime.c,v 1.12 2019/03/15 23:12:20 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_strftime_c,"$Id: w32_strftime.c,v 1.13 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* @@ -20,10 +20,18 @@ __CIDENT_RCSID(gr_w32_strftime_c,"$Id: w32_strftime.c,v 1.12 2019/03/15 23:12:20 * The GRIEF Editor is free software: you can redistribute it * and/or modify it under the terms of the GRIEF Editor License. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -521,4 +529,3 @@ _add (const char *str) } /*end*/ - diff --git a/libw32/w32_string.c b/libw32/w32_string.c index 78ff60bf..218ab555 100644 --- a/libw32/w32_string.c +++ b/libw32/w32_string.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_string_c,"$Id: w32_string.c,v 1.13 2019/03/15 23:12:21 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_string_c,"$Id: w32_string.c,v 1.14 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 string functions. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_string_c,"$Id: w32_string.c,v 1.13 2019/03/15 23:12:21 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -78,4 +78,3 @@ strnlen(const char *s, size_t maxlen) #endif /*end*/ - diff --git a/libw32/w32_strlcat.c b/libw32/w32_strlcat.c index 4673b156..9c85a5f4 100644 --- a/libw32/w32_strlcat.c +++ b/libw32/w32_strlcat.c @@ -1,9 +1,9 @@ #include -__CIDENT_RCSID(gr_w32_strlcat_c,"$Id: w32_strlcat.c,v 1.13 2019/03/15 23:12:21 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_strlcat_c,"$Id: w32_strlcat.c,v 1.14 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -19,10 +19,10 @@ __CIDENT_RCSID(gr_w32_strlcat_c,"$Id: w32_strlcat.c,v 1.13 2019/03/15 23:12:21 c * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -202,4 +202,3 @@ __stdlibrary_has_strlcat(void) #endif /*_MSC_VER*/ /*end*/ - diff --git a/libw32/w32_strlcpy.c b/libw32/w32_strlcpy.c index 294f3b41..17f33f3a 100644 --- a/libw32/w32_strlcpy.c +++ b/libw32/w32_strlcpy.c @@ -1,9 +1,9 @@ #include -__CIDENT_RCSID(gr_w32_strlcpy_c,"$Id: w32_strlcpy.c,v 1.13 2019/03/15 23:12:21 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_strlcpy_c,"$Id: w32_strlcpy.c,v 1.14 2022/03/21 14:29:41 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -19,10 +19,10 @@ __CIDENT_RCSID(gr_w32_strlcpy_c,"$Id: w32_strlcpy.c,v 1.13 2019/03/15 23:12:21 c * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -197,4 +197,3 @@ __stdlibrary_has_strlcpy(void) #endif /*end*/ - diff --git a/libw32/w32_strtoll.c b/libw32/w32_strtoll.c index fb26986c..33b16567 100644 --- a/libw32/w32_strtoll.c +++ b/libw32/w32_strtoll.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_strtoll_c,"$Id: w32_strtoll.c,v 1.8 2018/10/11 01:49:38 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_strtoll_c,"$Id: w32_strtoll.c,v 1.9 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /*- @@ -154,4 +154,3 @@ __stdlibrary_has_strtoll(void) #endif /*end*/ - diff --git a/libw32/w32_strtoull.c b/libw32/w32_strtoull.c index 38c5430a..33c63d32 100644 --- a/libw32/w32_strtoull.c +++ b/libw32/w32_strtoull.c @@ -1,5 +1,5 @@ #include -__CIDENT_RCSID(gr_w32_strtoull_c,"$Id: w32_strtoull.c,v 1.8 2018/10/11 01:49:38 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_strtoull_c,"$Id: w32_strtoull.c,v 1.9 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /*- @@ -132,4 +132,3 @@ __stdlibrary_has_strtoull(void) #endif /*end*/ - diff --git a/libw32/w32_sysdir.c b/libw32/w32_sysdir.c index 6d88f311..c27730a3 100644 --- a/libw32/w32_sysdir.c +++ b/libw32/w32_sysdir.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_sysdir_c,"$Id: w32_sysdir.c,v 1.12 2019/03/15 23:12:21 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_sysdir_c,"$Id: w32_sysdir.c,v 1.14 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 interface support * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_sysdir_c,"$Id: w32_sysdir.c,v 1.12 2019/03/15 23:12:21 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -32,6 +32,7 @@ __CIDENT_RCSID(gr_w32_sysdir_c,"$Id: w32_sysdir.c,v 1.12 2019/03/15 23:12:21 cvs * 2001-2003 by the Institute of. Electrical and Electronics Engineers, Inc and The Open * Group. Copyright remains with the authors and the original Standard can be obtained * online at http://www.opengroup.org/unix/online.html. + * ==extra== */ #include "win32_internal.h" @@ -43,55 +44,179 @@ __CIDENT_RCSID(gr_w32_sysdir_c,"$Id: w32_sysdir.c,v 1.12 2019/03/15 23:12:21 cvs LIBW32_API int -w32_getsysdir( - int id, char *buf, int maxlen) +w32_getsysdir(int id, char *buf, int maxlen) { - char szPath[ MAX_PATH ]; - HRESULT hres; - int len; +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (w32_getsysdirW(id, wpath, _countof(wpath)) > 0) { + return w32_wc2utf(wpath, buf, maxlen); + } + return -1; + } +#endif + + return w32_getsysdirA(id, buf, maxlen); +} + +static int +map_csidl(int id) +{ + // https://docs.microsoft.com/en-us/windows/win32/shell/csidl switch (id) { case SYSDIR_TEMP: - id = CSIDL_INTERNET_CACHE; - break; - default: + return CSIDL_INTERNET_CACHE; + case SYSDIR_WINDOWS: + return CSIDL_WINDOWS; + case SYSDIR_SYSTEM: + return CSIDL_SYSTEM; + case SYSDIR_PROGRAM_FILES: + return CSIDL_PROGRAM_FILES; + } + return -1; +} + + +LIBW32_API int +w32_getsysdirA(int id, char *buf, int maxlen) +{ + char t_path[ MAX_PATH ], *path = buf; + HRESULT hres; + int len; + + if (NULL == buf || maxlen < 4 || + -1 == (id = map_csidl(id))) { + return -1; + } + + if (maxlen < MAX_PATH) path = t_path; + hres = SHGetSpecialFolderPathA(NULL, path, id, FALSE); + if (SUCCEEDED(hres)) { + len = (int)strlen(path); + if (path == buf) { // direct + return len; + } else if (len < maxlen) { // indirect + (void) strcpy(buf, (const char *)t_path); + return len; + } + } + return -1; +} + + +LIBW32_API int +w32_getsysdirW(int id, wchar_t *buf, int maxlen) +{ + wchar_t t_path[ MAX_PATH ], *path = buf; + HRESULT hres; + int len; + + if (NULL == buf || maxlen < 4 || + -1 == (id = map_csidl(id))) { return -1; } - hres = SHGetSpecialFolderPath(NULL, szPath, id, FALSE); - if (SUCCEEDED(hres) && - (len = (int)strlen(szPath)) <= maxlen) { - (void) strcpy(buf, (const char *)szPath); - return len; + if (maxlen < MAX_PATH) path = t_path; + hres = SHGetSpecialFolderPathW(NULL, path, id, FALSE); + if (SUCCEEDED(hres)) { + len = (int)wcslen(path); + if (path == buf) { // direct + return len; + } else if (len < maxlen) { // indirect + (void) wcscpy(buf, (const wchar_t *)t_path); + return len; + } + } + return -1; +} + + +LIBW32_API const char * +w32_selectfolder(const char *message, char *buffer, int buflen) +{ + if (NULL == message || NULL == buffer || buflen < MAX_PATH) { + return NULL; + } + +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[MAX_PATH + 1], *wmessage; + const wchar_t *wresult; + char *result = NULL; + + if (NULL != (wmessage = w32_utf2wca(message, NULL))) { + if (NULL != (wresult = w32_selectfolderW(wmessage, wpath, _countof(wpath)))) { + if (w32_wc2utf(wresult, buffer, buflen) > 0) { + result = buffer; + } + } + free(wmessage); + } + return result; } - return (-1); +#endif + + return w32_selectfolderA(message, buffer, buflen); } LIBW32_API const char * -w32_selectfolder( - const char *strMessage, char *szBuffer) +w32_selectfolderA(const char *message, char *buffer, int buflen) { - char const * Result = NULL; - BROWSEINFO BrowseInfo; - LPITEMIDLIST pList; + const char *result = NULL; + BROWSEINFOA bi; + LPITEMIDLIST pl; + + if (NULL == message || NULL == buffer || buflen < MAX_PATH) { + return NULL; + } /* Throw display dialog */ - memset(&BrowseInfo, 0, sizeof(BrowseInfo)); - BrowseInfo.hwndOwner = NULL; /* XXX */ - BrowseInfo.pszDisplayName = szBuffer; - BrowseInfo.lpszTitle = strMessage; - BrowseInfo.ulFlags = BIF_RETURNONLYFSDIRS; - pList = SHBrowseForFolder(&BrowseInfo); + memset(&bi, 0, sizeof(bi)); + bi.hwndOwner = NULL; + bi.pszDisplayName = buffer; + bi.lpszTitle = message; + bi.ulFlags = BIF_RETURNONLYFSDIRS; + pl = SHBrowseForFolderA(&bi); /* Convert from MIDLISt to real string path */ - if (pList != NULL) { - SHGetPathFromIDList(pList, szBuffer); - CoTaskMemFree(pList); - Result = szBuffer; + if (pl != NULL) { + SHGetPathFromIDListA(pl, buffer); + CoTaskMemFree(pl); + result = buffer; } - return (Result); + return result; } -/*end*/ +LIBW32_API const wchar_t * +w32_selectfolderW(const wchar_t *message, wchar_t *buffer, int buflen) +{ + const wchar_t *result = NULL; + BROWSEINFOW bi; + LPITEMIDLIST pl; + + if (NULL == message || NULL == buffer || buflen < MAX_PATH) { + return NULL; + } + + /* Throw display dialog */ + memset(&bi, 0, sizeof(bi)); + bi.hwndOwner = NULL; + bi.pszDisplayName = buffer; + bi.lpszTitle = message; + bi.ulFlags = BIF_RETURNONLYFSDIRS; + pl = SHBrowseForFolderW(&bi); + + /* Convert from MIDLISt to real string path */ + if (pl != NULL) { + SHGetPathFromIDListW(pl, buffer); + CoTaskMemFree(pl); + result = buffer; + } + return result; +} + +/*end*/ diff --git a/libw32/w32_time.c b/libw32/w32_time.c index c9ee11f2..d404ef71 100644 --- a/libw32/w32_time.c +++ b/libw32/w32_time.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_time_c,"$Id: w32_time.c,v 1.18 2019/03/15 23:12:21 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_time_c,"$Id: w32_time.c,v 1.20 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 time system calls * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_time_c,"$Id: w32_time.c,v 1.18 2019/03/15 23:12:21 cvsuser * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -36,17 +36,26 @@ __CIDENT_RCSID(gr_w32_time_c,"$Id: w32_time.c,v 1.18 2019/03/15 23:12:21 cvsuser */ #include + #include "win32_internal.h" #include + +#include + #if defined(HAVE_SYS_UTIME_H) ||\ - defined(__MINGW32__) + defined(__MINGW32__) #include #endif #if defined(HAVE_SYS_TIME_H) #include #endif + +#if defined(_MSC_VER) || defined(__WATCOMC__) +#include +#endif #include #include +#include /* @@ -145,18 +154,49 @@ w32_sleep (unsigned int secs) // No errors are defined. // */ -int + +LIBW32_API int w32_gettimeofday( struct timeval *tv, /*struct timezone*/ void *tz) { __CUNUSED(tz) if (tv) { - //FIXME - tv->tv_usec = GetTickCount() * 1000; - tv->tv_sec = (long)time(NULL); +#if defined(_MSC_VER) || defined(__WATCOMC__) + struct _timeb lt; + + _ftime(<); + tv->tv_sec = (long)(lt.time + lt.timezone); + tv->tv_usec = lt.millitm * 1000; + assert(4 == sizeof(tv->tv_sec)); + +#elif defined(__MINGW32__) +#undef gettimeofday + return gettimeofday(tv, tz) + +#else //DEFAULT + FILETIME ft; + long long hnsec; + + (void) GetSystemTimeAsFileTime(&ft); + hnsec = filetime_to_hnsec(&ft); + tv->tv_sec = hnsec / 10000000; + tv->tv_usec = (hnsec % 10000000) / 10; +#endif + return 0; } - return 0; + errno = EINVAL; + return -1; +} + + +#if !defined(__MINGW32__) +LIBW32_API int +gettimeofday( + struct timeval *tv, struct timezone *tz) +{ + return w32_gettimeofday(tv, tz); } +#endif /* @@ -250,9 +290,33 @@ w32_gettimeofday( // pathname string exceeded {PATH_MAX}. // */ -int +LIBW32_API int w32_utime(const char *path, const struct utimbuf *times) { +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path || NULL == times) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return w32_utimeW(wpath, times); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_utimeA(path, times); +} + + +LIBW32_API int +w32_utimeA(const char *path, const struct utimbuf *times) +{ #if defined(__MINGW32__) #undef utime return utime(path, (struct utimbuf *)times); @@ -261,5 +325,16 @@ w32_utime(const char *path, const struct utimbuf *times) #endif } -/*end*/ +LIBW32_API int +w32_utimeW(const wchar_t *path, const struct utimbuf *times) +{ +#if defined(__MINGW32__) +#undef utime + return wutime(path, (struct utimbuf *)times); +#else + return _wutime(path, (struct _utimbuf *)times); +#endif +} + +/*end*/ diff --git a/libw32/w32_truncate.c b/libw32/w32_truncate.c index 7e7398a1..ebb9824e 100644 --- a/libw32/w32_truncate.c +++ b/libw32/w32_truncate.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_truncate_c,"$Id: w32_truncate.c,v 1.11 2020/03/28 00:25:03 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_truncate_c,"$Id: w32_truncate.c,v 1.13 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 ftruncate()/truncate() system calls. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_truncate_c,"$Id: w32_truncate.c,v 1.11 2020/03/28 00:25:03 * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -36,6 +36,11 @@ __CIDENT_RCSID(gr_w32_truncate_c,"$Id: w32_truncate.c,v 1.11 2020/03/28 00:25:03 */ #include "win32_internal.h" + +#include +#ifdef HAVE_WCHAR_H +#include +#endif #include /* @@ -164,8 +169,6 @@ ftruncate(int fildes, off_t length) return -1; } -// _chsize(fildes, length); - if (0xFFFFFFFF == SetFilePointer (handle, 0, NULL, FILE_CURRENT) || 0xFFFFFFFF == SetFilePointer (handle, length, NULL, FILE_BEGIN) || !SetEndOfFile (handle)) { @@ -187,6 +190,62 @@ ftruncate(int fildes, off_t length) int truncate(const char *path, off_t length) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return truncateW(wpath, length); + } + + return -1; + } +#endif //UTF8FILENAMES + + return truncateA(path, length); +} + + +int +truncateA(const char *path, off_t length) +{ + HANDLE handle; + + if (length < 0) { + errno = EINVAL; + return -1; + + } else if (NULL == path || 0 == *path) { + errno = EINVAL; + return -1; + } + + if (INVALID_HANDLE_VALUE == (handle = + CreateFileA(path, GENERIC_WRITE, 0, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) || + + 0xFFFFFFFF == SetFilePointer (handle, 0, NULL, FILE_CURRENT) || + 0xFFFFFFFF == SetFilePointer (handle, length, NULL, FILE_BEGIN) || + !SetEndOfFile (handle)) { + w32_errno_set(); + if (INVALID_HANDLE_VALUE != handle) { + CloseHandle(handle); + } + return -1; + } + CloseHandle(handle); + return 0; +} + + +int +truncateW(const wchar_t *path, off_t length) { HANDLE handle; @@ -200,7 +259,7 @@ truncate(const char *path, off_t length) } if (INVALID_HANDLE_VALUE == (handle = - CreateFile(path, GENERIC_WRITE, 0, + CreateFileW(path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) || 0xFFFFFFFF == SetFilePointer (handle, 0, NULL, FILE_CURRENT) || @@ -225,4 +284,3 @@ truncate(const char *path, off_t length) // } /*end*/ - diff --git a/libw32/w32_uname.c b/libw32/w32_uname.c index fe0909c1..55d33a12 100644 --- a/libw32/w32_uname.c +++ b/libw32/w32_uname.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_uname_c,"$Id: w32_uname.c,v 1.15 2020/05/03 21:34:19 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_uname_c,"$Id: w32_uname.c,v 1.17 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 uname() system calls * - * Copyright (c) 1998 - 2020, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_uname_c,"$Id: w32_uname.c,v 1.15 2020/05/03 21:34:19 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -442,4 +442,3 @@ uname(struct utsname *u) } /*end*/ - diff --git a/libw32/w32_unlink.c b/libw32/w32_unlink.c index a72fb963..62905bea 100644 --- a/libw32/w32_unlink.c +++ b/libw32/w32_unlink.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_unlink_c,"$Id: w32_unlink.c,v 1.11 2019/03/15 23:12:21 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_unlink_c,"$Id: w32_unlink.c,v 1.13 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win2 unlink() system calls * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_unlink_c,"$Id: w32_unlink.c,v 1.11 2019/03/15 23:12:21 cvs * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -131,6 +131,30 @@ __CIDENT_RCSID(gr_w32_unlink_c,"$Id: w32_unlink.c,v 1.11 2019/03/15 23:12:21 cvs */ int w32_unlink(const char *path) +{ +#if defined(UTF8FILENAMES) + if (w32_utf8filenames_state()) { + wchar_t wpath[WIN32_PATH_MAX]; + + if (NULL == path) { + errno = EFAULT; + return -1; + } + + if (w32_utf2wc(path, wpath, _countof(wpath)) > 0) { + return w32_unlinkW(wpath); + } + + return -1; + } +#endif //UTF8FILENAMES + + return w32_unlinkA(path); +} + + +int +w32_unlinkA(const char *path) { int ret = -1; // success=0, otherwise=-1 @@ -193,4 +217,69 @@ w32_unlink(const char *path) return ret; } + +int +w32_unlinkW(const wchar_t *path) +{ + int ret = -1; // success=0, otherwise=-1 + + if (!path) { + errno = EFAULT; + + } else if (!*path) { + errno = ENOENT; + + } else { + DWORD attrs, rc = 0; // completion code + +#ifndef ERROR_DIRECTORY_NOT_SUPPORTED +#define ERROR_DIRECTORY_NOT_SUPPORTED 336L // An operation is not supported on a directory. +#endif + + if (INVALID_FILE_ATTRIBUTES /*0xffffffff*/ + == (attrs = GetFileAttributesW(path)) ) { + rc = GetLastError(); + } else { + if (FILE_ATTRIBUTE_DIRECTORY & attrs) { + if (FILE_ATTRIBUTE_REPARSE_POINT & attrs) { + if (! RemoveDirectoryW(path)) { + rc = GetLastError(); + } + } else { + rc = ERROR_DIRECTORY_NOT_SUPPORTED; + } + } else { + if (! DeleteFileW(path) && + ERROR_ACCESS_DENIED == (rc = GetLastError())) { + (void) WIN32_WCHMOD(path, S_IWRITE); + rc = (DeleteFileW(path) ? 0 : GetLastError()); + } + } + } + + if (0 == rc) { + ret = 0; // success + } else { + switch (rc) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + case ERROR_PRIVILEGE_NOT_HELD: + errno = EACCES; break; + case ERROR_FILE_NOT_FOUND: + errno = ENOENT; break; + case ERROR_PATH_NOT_FOUND: + errno = ENOTDIR; break; + case ERROR_DIRECTORY_NOT_SUPPORTED: + errno = EISDIR; break; + case ERROR_NOT_ENOUGH_MEMORY: + errno = ENOMEM; break; + default: + errno = w32_errno_cnv(rc); + break; + } + } + } + return ret; +} + /*end*/ diff --git a/libw32/w32_user.c b/libw32/w32_user.c index 2e1f0b7d..e98c9871 100644 --- a/libw32/w32_user.c +++ b/libw32/w32_user.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_user_c,"$Id: w32_user.c,v 1.16 2019/03/15 23:12:22 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_user_c,"$Id: w32_user.c,v 1.18 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 user identification functionality * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_user_c,"$Id: w32_user.c,v 1.16 2019/03/15 23:12:22 cvsuser * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -40,9 +40,49 @@ __CIDENT_RCSID(gr_w32_user_c,"$Id: w32_user.c,v 1.16 2019/03/15 23:12:22 cvsuser #endif #include "win32_internal.h" +#include "win32_child.h" +#include +#include #include +#include /* ConvertSidToStringSid */ +#include + #pragma comment(lib, "Advapi32.lib") +#pragma comment(lib, "Netapi32.lib") + +static char x_passwd_name[WIN32_LOGIN_LEN]; +static char x_passwd_passwd[32]; +static char x_passwd_gecos[32]; +static char x_passwd_dir[MAX_PATH]; +static char x_passwd_shell[MAX_PATH]; + +static struct passwd x_passwd = { + x_passwd_name, /* pw_name */ + x_passwd_passwd, /* pw_passwd */ + -1, /* pw_uid */ + -1, /* pw_gid */ + NULL, /* pw_age */ + NULL, /* pw_comment */ + x_passwd_gecos, /* pw_gecos */ + x_passwd_dir, /* pw_dir */ + x_passwd_shell, /* pw_shell */ + 0, /* pw_audid */ + 0 /* pw_audflg */ +}; + +static char x_group_name[WIN32_LOGIN_LEN]; +static char x_group_passwd[32]; + +static struct group x_group = { + x_group_name, /* gr_name */ + x_group_passwd, /* gr_passwd */ + -1, /* gr_gid */ + NULL +}; + +static void initialise_user(void); +static unsigned RID(PSID sid); /* @@ -67,7 +107,8 @@ __CIDENT_RCSID(gr_w32_user_c,"$Id: w32_user.c,v 1.16 2019/03/15 23:12:22 cvsuser LIBW32_API int w32_getuid (void) { - return 42; + initialise_user(); + return x_passwd.pw_uid; } @@ -93,7 +134,8 @@ w32_getuid (void) int w32_geteuid (void) { - return 42; + initialise_user(); + return x_passwd.pw_uid; } @@ -119,7 +161,8 @@ w32_geteuid (void) LIBW32_API int w32_getgid (void) { - return 42; + initialise_user(); + return x_passwd.pw_gid; } @@ -145,7 +188,8 @@ w32_getgid (void) int w32_getegid (void) { - return 42; + initialise_user(); + return x_passwd.pw_gid; } @@ -159,13 +203,13 @@ w32_getegid (void) // int issetugid(void); // // DESCRIPTION -// The issetugid() function should be used to determine if a path name returned +// The issetugid() function should be used to determine if a path name returned // from a getenv(3C) call can be used safely to open the specified file. It is -// often not safe to open such a file because the status of the effective uid +// often not safe to open such a file because the status of the effective uid // is not known. // // RETURN VALUE -// The issetugid() function returns 1 if the process was made setuid or setgid +// The issetugid() function returns 1 if the process was made setuid or setgid // as the result of the last or a previous call to execve(). Otherwise it returns 0. // // ERRORS @@ -243,48 +287,198 @@ issetugid (void) LIBW32_API const char * getlogin (void) { - static char buffer[100]; /* one-shot */ - DWORD size = sizeof(buffer); - const char *p = buffer; + static char buffer[WIN32_LOGIN_LEN]; + if (getlogin_r(buffer, sizeof(buffer)) > 0) { + return buffer; + } + return NULL; +} + + +LIBW32_API int +getlogin_r (char *name, size_t namesize) +{ + int length; + + if (name == NULL || namesize == 0) { + errno = EINVAL; + return -1; + } + + initialise_user(); + length = strlen(x_passwd_name); + if (namesize <= (size_t)length) { + errno = ERANGE; + return -1; + } + memcpy(name, x_passwd_name, length + 1); + return length; +} + + +LIBW32_API const struct passwd * +w32_passwd_user (void) +{ + initialise_user(); + return &x_passwd; +} + + +LIBW32_API const struct group * +w32_group_user (void) +{ + initialise_user(); + return &x_group; +} + + +static void +initialise_user() +{ + char login[WIN32_LOGIN_LEN], group[WIN32_GROUP_LEN]; + char domain[1024 + 1]; + + TOKEN_USER *tu = NULL; + TOKEN_PRIMARY_GROUP *pg = NULL; + HANDLE hToken = NULL; + + login[0] = 0, group[0] = 0, domain[0] = 0; + + if (x_passwd.pw_uid >= 0) { + return; + } - if (!*p) { - p = getenv("USER"); + // defaults + x_passwd.pw_uid = 42; + x_passwd.pw_gid = 42; - if (p == NULL) p = getenv("USERNAME"); /* NT */ + strncpy(x_passwd_name, "user", sizeof(x_passwd_name) - 1); + strncpy(x_passwd_passwd, "*", sizeof(x_passwd_passwd) - 1); + strncpy(x_passwd_gecos, "pcuser", sizeof(x_passwd_gecos) - 1); + strncpy(x_group_name, "user", sizeof(x_group_name) - 1); - if (GetUserNameA(buffer, &size)) /* requires: advapi32.lib */ - p = buffer; + // process identify + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { + SID_NAME_USE user_type = {0}; + DWORD cbSize, cbSize2; + + cbSize = 0; + if (! GetTokenInformation(hToken, TokenUser, NULL, 0, &cbSize) && + GetLastError () == ERROR_INSUFFICIENT_BUFFER && cbSize && + NULL != (tu = alloca(sizeof(char) + (cbSize + 1)))) { + + if (GetTokenInformation(hToken, TokenUser, tu, cbSize, &cbSize2)) { + DWORD ulen = sizeof(login), dlen = sizeof(domain); + + if (! LookupAccountSidA(NULL, tu->User.Sid, login, &ulen, domain, &dlen, &user_type)) { + login[0] = 0; + } + } + } + + cbSize = 0; + if (! GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &cbSize) && + GetLastError () == ERROR_INSUFFICIENT_BUFFER && cbSize && + NULL != (pg = alloca(sizeof(char) + (cbSize + 1)))) { + + if (GetTokenInformation(hToken, TokenPrimaryGroup, pg, cbSize, &cbSize2)) { + DWORD glen = sizeof(group), dlen = sizeof(domain); + + if (! LookupAccountSidA(NULL, pg->PrimaryGroup, group, &glen, NULL, &dlen, &user_type)) { + group[0] = 0; + } + + } else { + pg = NULL; + } + } + + CloseHandle(hToken); + } + + // apply + if (login[0]) { + char *sid = NULL; + + strncpy(x_passwd_name, login, sizeof(x_passwd_name)-1); + + if (0 == _stricmp("Administrator", login)) { + x_passwd.pw_uid = 500; // Built-in admin account. + x_passwd.pw_gid = 513; // PrimaryGroupID. + // + // By default, all Active Directory users have a PrimaryGroupID of 513, + // which is associated with the Domain Users group. + // However, if the user needed to be seen as a Domain Admin for POSIX, + // the PrimaryGroupID needed to be 512, the RID for that group. + // The Enterprise Admins group, 519, is also used to grant this level in POSIX. + // + + } else { + x_passwd.pw_uid = (short) RID(tu->User.Sid); + // Note: Unfortunately st_uid/st_gid are short's resulting in RID truncation. + x_passwd.pw_gid = x_passwd.pw_uid; + if (pg) { + x_passwd.pw_gid = (short) RID(pg->PrimaryGroup); + } + } + + if (ConvertSidToStringSidA(tu->User.Sid, &sid)) { + strncpy(x_passwd_gecos, sid, sizeof(x_passwd_gecos) - 1); + LocalFree(sid); + } + + // old-school + } else { + DWORD cbBuffer = sizeof(x_passwd_name) - 1; - if (p == NULL) - p = "dosuser"; /* default */ + if (! GetUserNameA(x_passwd_name, &cbBuffer)) { + const char *name = NULL; + + if (NULL == name) name = getenv("USER"); + if (NULL == name) name = getenv("USERNAME"); + if (NULL == name) name = "dosuser"; + strncpy(x_passwd_name, name, sizeof(x_passwd_name) - 1); + } - if (p != buffer) { - strncpy(buffer, p, sizeof(buffer)); - buffer[ sizeof(buffer)-1 ] = '\0'; - p = buffer; + if (0 == _stricmp("Administrator", x_passwd_name)) { + x_passwd.pw_uid = 0; } + + x_passwd.pw_gid = x_passwd.pw_uid; + } + + // additional account attributes + _strlwr(x_passwd_name); + strncpy(x_passwd_dir, w32_gethome(FALSE), sizeof(x_passwd_dir) - 1); + strncpy(x_passwd_shell, w32_getshell(), sizeof(x_passwd_shell) - 1); + + // group + if (group[0]) { + strncpy(x_group_name, group, sizeof(x_group_name) - 1); + _strlwr(x_group_name); } - return p; + x_group.gr_gid = x_passwd.pw_gid; + x_group.gr_mem = NULL; } -LIBW32_API int -getlogin_r (char *name, size_t namesize) +static unsigned +RID(PSID sid) { - const char *login = getlogin(); - size_t length = strlen(login); - - if (namesize >= length) { - errno = ERANGE; - return -1; + // Example: S-1-5-32-544 + // Returns the last component, 544. + const int subAuthorities = *GetSidSubAuthorityCount(sid); + if (subAuthorities >= 1) { // last sub-authority value. + return *GetSidSubAuthority(sid, subAuthorities - 1); + // Last component should be the user's relative identifier (RID). + // It uniquely defines this user account to SAM within the domain. } - memcpy(name, login, length + 1); - return (int)length; + return 0; } #if defined(_MSC_VER) && (_MSC_VER < 1500) -#define TokenElevation 20 +#define TokenElevation 20 typedef struct _TOKEN_ELEVATION { DWORD TokenIsElevated; } TOKEN_ELEVATION; @@ -346,5 +540,5 @@ w32_IsAdministrator(void) } return b; } -/*end*/ +/*end*/ diff --git a/libw32/w32_util.c b/libw32/w32_util.c index 69438fad..c047b1e1 100644 --- a/libw32/w32_util.c +++ b/libw32/w32_util.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_util_c,"$Id: w32_util.c,v 1.18 2019/03/15 23:12:22 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_util_c,"$Id: w32_util.c,v 1.20 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 util unix functionality. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_util_c,"$Id: w32_util.c,v 1.18 2019/03/15 23:12:22 cvsuser * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -38,7 +38,10 @@ __CIDENT_RCSID(gr_w32_util_c,"$Id: w32_util.c,v 1.18 2019/03/15 23:12:22 cvsuser #include "win32_internal.h" #include "win32_child.h" #include "win32_misc.h" + #include +#include +#include #pragma comment(lib, "shell32.lib") #pragma comment(lib, "shfolder.lib") @@ -69,6 +72,26 @@ w32_getshell(void) } +LIBW32_API const wchar_t * +w32_getshellW(void) +{ + const wchar_t *shname; + + shname = _wgetenv(L"SHELL"); + if (shname == NULL) + shname = _wgetenv(L"COMSPEC"); + if (shname == NULL) + shname = _wgetenv(L"ComSpec"); + if (shname == NULL) { + if (GetVersion() < 0x80000000) { + shname = L"CMD.EXE"; // Windows NT/2000/XP + } + shname = L"COMMAND.EXE"; // ... others + } + return shname; +} + + /* * w32_gethome --- * Retrieve the default home directory. @@ -148,6 +171,254 @@ w32_gethome(int ignore_env) } +LIBW32_API const wchar_t * +w32_gethomeW(int ignore_env) +{ + static const wchar_t *x_home = NULL; + + if (NULL == x_home) { + wchar_t t_path[MAX_PATH]; + const wchar_t *env; + int len, done = FALSE; + + // + if (!ignore_env && (env = _wgetenv(L"HOME")) != NULL && (len = (int)wcslen(env)) > 0) { + t_path[_countof(t_path) - 1] = 0; + if (0 == _waccess(t_path, 0)) { + t_path[len+1] = 0; + done = TRUE; + } + } + + // Personal settings + // o XP + // X:/Documents and Settings//home/ + // X:/Documents and Settings// + // + // o Windows7+ + // X:/Users//home/ + // X:/Users// + // + if (! done) { + if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, t_path)) && + (len = (int)wcslen(t_path)) > 0) { + t_path[_countof(t_path) - 1] = 0; + if (0 == _waccess(t_path, 0)) { + _snwprintf(t_path + len, _countof(t_path) - len, L"/home/"); + t_path[_countof(t_path) - 1] = 0; + if (0 == _waccess(t_path, 0)) { + len += 6; + } + done = TRUE; + } + } + } + + // + if (! done) { + if ((env = _wgetenv(L"USERPROFILE")) != NULL && (len = (int)wcslen(env)) > 0) { + t_path[_countof(t_path) - 1] = 0; + if (0 == _waccess(t_path, 0)) { + _snwprintf(t_path + len, _countof(t_path) - len, L"/home/"); + t_path[_countof(t_path) - 1] = 0; + if (0 == _waccess(t_path, 0)) { + len += 6; + } + done = TRUE; + } + } + } + + // completion + if (done) { + if (len <= (int)_countof(t_path)) { + if ('/' != t_path[len - 1] && '\\' != t_path[len - 1]) { + t_path[len++] = '/'; + t_path[len] = 0; + } + } + w32_dos2unixW(t_path); + } + + x_home = WIN32_STRDUPW(done ? t_path : L"c:/"); + } + return x_home; +} + + +LIBW32_API int +w32_utf2wc(const char *src, wchar_t *dest, size_t maxlen) +{ + int ret; + + assert(src), assert(dest), assert(maxlen); + + dest[0] = 0; + if ((ret = MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, maxlen)) > 0) { + assert(ret <= (int)maxlen); + if (ret == maxlen) + dest[maxlen - 1] = 0; + + } else { + const DWORD rc = GetLastError(); + + if (dest) dest[0] = 0; + switch (rc) { + case ERROR_INVALID_FLAGS: + case ERROR_INVALID_PARAMETER: + errno = EINVAL; + break; + case ERROR_INSUFFICIENT_BUFFER: + errno = ENAMETOOLONG; + break; + case ERROR_NO_UNICODE_TRANSLATION: + default: + errno = ENOENT; + break; + } + return -1; + } + return ret; +} + + +// If successful, returns the number of bytes including NULL required. +LIBW32_API int +w32_utf2wcl(const char *src) +{ + int ret; + + assert(src); + if ((ret = MultiByteToWideChar(CP_UTF8, 0, src, -1, NULL, 0)) > 0) { + return ret; + } else { + const DWORD rc = GetLastError(); + switch (rc) { + case ERROR_INVALID_FLAGS: + case ERROR_INVALID_PARAMETER: + errno = EINVAL; + break; + case ERROR_INSUFFICIENT_BUFFER: + errno = ENAMETOOLONG; + break; + case ERROR_NO_UNICODE_TRANSLATION: + default: + errno = ENOENT; + break; + } + } + return -1; +} + + +LIBW32_API wchar_t * +w32_utf2wca(const char *src, size_t *len) +{ + int ret; + + assert(src); + if ((ret = MultiByteToWideChar(CP_UTF8, 0, src, -1, NULL, 0)) > 0) { + wchar_t *dest = malloc(sizeof(wchar_t) * ret); + if (dest) { + (void) MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, ret); + if (len) *len = ret; + return dest; + } + + } else { + const DWORD rc = GetLastError(); + switch (rc) { + case ERROR_INVALID_FLAGS: + case ERROR_INVALID_PARAMETER: + errno = EINVAL; + break; + case ERROR_INSUFFICIENT_BUFFER: + errno = ENAMETOOLONG; + break; + case ERROR_NO_UNICODE_TRANSLATION: + default: + errno = ENOENT; + break; + } + } + return NULL; +} + + +LIBW32_API int +w32_wc2utf(const wchar_t *src, char *dest, size_t maxlen) +{ + int ret; + + assert(src), assert(dest), assert(maxlen); + + dest[0] = 0; + if ((ret = WideCharToMultiByte(CP_UTF8, 0, src, -1, dest, maxlen, NULL, NULL)) > 0) { + assert(ret <= (int)maxlen); + if (ret == maxlen) { + dest[maxlen - 1] = 0; + --ret; + } + + } else { + const DWORD rc = GetLastError(); + + if (dest) dest[0] = 0; + switch (rc) { + case ERROR_INVALID_FLAGS: + case ERROR_INVALID_PARAMETER: + errno = EINVAL; + break; + case ERROR_INSUFFICIENT_BUFFER: + errno = ENAMETOOLONG; + break; + case ERROR_NO_UNICODE_TRANSLATION: + default: + errno = ENOENT; + break; + } + return -1; + } + return ret; +} + + +LIBW32_API char * +w32_wc2utfa(const wchar_t *src, size_t *len) +{ + int ret; + + assert(src); + + if ((ret = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL)) > 0) { + char *dest = malloc(sizeof(char) * ret); + if (dest) { + WideCharToMultiByte(CP_UTF8, 0, src, -1, dest, ret, NULL, NULL); + if (len) *len = ret; + return dest; + } + + } else { + const DWORD rc = GetLastError(); + + switch (rc) { + case ERROR_INVALID_FLAGS: + case ERROR_INVALID_PARAMETER: + errno = EINVAL; + break; + case ERROR_INSUFFICIENT_BUFFER: + errno = ENAMETOOLONG; + break; + case ERROR_NO_UNICODE_TRANSLATION: + default: + errno = ENOENT; + break; + } + } + return NULL; +} + + // int // w32_is64bit(void) // { @@ -171,33 +442,59 @@ w32_gethome(int ignore_env) // } -char * +LIBW32_API char * w32_dos2unix(char *path) { if (path) { char *p; for (p = path; *p; ++p) { - if ('\\' == *p) *p = '/'; /* DOS<>Unix */ + if ('\\' == *p) *p = '/'; /* DOS<>Unix */ + } + } + return path; +} + + +LIBW32_API wchar_t * +w32_dos2unixW(wchar_t *path) +{ + if (path) { + wchar_t *p; + for (p = path; *p; ++p) { + if ('\\' == *p) *p = '/'; /* DOS<>Unix */ } } return path; } -char * +LIBW32_API char * w32_unix2dos(char *path) { if (path) { char *p; for (p = path; *p; ++p) { - if ('/' == *p) *p = '\\'; /* Unix<>DOS */ + if ('/' == *p) *p = '\\'; /* Unix<>DOS */ } } return path; } -const char * +LIBW32_API wchar_t * +w32_unix2dosW(wchar_t *path) +{ + if (path) { + wchar_t *p; + for (p = path; *p; ++p) { + if ('/' == *p) *p = '\\'; /* Unix<>DOS */ + } + } + return path; +} + + +LIBW32_API const char * w32_strslash(const char *path) { if (path) { @@ -211,6 +508,20 @@ w32_strslash(const char *path) } +LIBW32_API const wchar_t * +w32_wcsslash(const wchar_t *path) +{ + if (path) { + for (;*path; ++path) { + if (ISSLASH(*path)) { + return path; + } + } + } + return NULL; +} + + LIBW32_API enum w32ostype w32_ostype(void) { @@ -257,18 +568,18 @@ w32_ostype(void) // for Windows 8.1 or Windows 10 will return the Windows 8 OS version value (6.2). To manifest your applications // for Windows 8.1 or Windows 10, refer to Targeting your application for Windows. // - platform = OSTYPE_WIN_NT; // or 2000 + platform = OSTYPE_WIN_NT; // or 2000 if (ovi.dwMajorVersion >= 10) { - platform = OSTYPE_WIN_10; // Windows 10+ + platform = OSTYPE_WIN_10; // Windows 10+ } else if (6 == ovi.dwMajorVersion) { platform = OSTYPE_WIN_VISTA; if (ovi.dwMajorVersion >= 2) { - platform = OSTYPE_WIN_8; // or Server 2012 + platform = OSTYPE_WIN_8; // or Server 2012 } else if (1 == ovi.dwMajorVersion) { - platform = OSTYPE_WIN_7; // or Server 2008 R2 + platform = OSTYPE_WIN_7; // or Server 2008 R2 } } break; @@ -300,4 +611,144 @@ w32_getexedir(char *buf, int maxlen) return -1; } + +LIBW32_API const char * +w32_syserrorA(DWORD dwError, char *buf, int buflen) +{ + return w32_vsyserrorA(dwError, buf, buflen, NULL); +} + + +LIBW32_API const char * +w32_vsyserrorA(DWORD dwError, char *buf, int buflen, ...) +{ + if (buf && buflen > 0) { + const DWORD ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, dwError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, --buflen /*nul*/, NULL); + if (0 == ret) { // error, overflow etc + int len; + + if ((len = buflen) > sizeof("unknown error")) { + len = sizeof("unknown error"); + } + memcpy(buf, "unknown error", len * sizeof(char)); + + } else { + int idx = 1, len = (DWORD)ret; + const char *arg; + va_list ap; + + // remove trailing whitespace + while (--len) { + const char ch = buf[len]; + if (ch == ' ' || ch == '.' || ch == '\n' || ch == '\r') { + continue; // consume + } + break; // done + } + buf[++len] = 0; + + // replace %1...x + va_start(ap, buflen); + while (NULL != (arg = va_arg(ap, const char *)) && idx <= 9 && len < buflen) { + char *cursor = buf; + + while (NULL != (cursor = strchr(cursor, '%'))) { + if (cursor[1] == ('0' + idx)) { + int arglen = strlen(arg); + + len -= 2; // %x being replace + if ((len + arglen) >= buflen) { + arglen = buflen - len; // overflow, truncate + } + memmove(cursor + arglen, cursor + 2, strlen(cursor + 2) + 1 /*nul*/); + memcpy(cursor, arg, arglen); + len += arglen; + break; + } + + if ('%' == *++cursor) { + ++cursor; // %% + } + } + ++idx; + } + va_end(ap); + } + return buf; + } + return NULL; +} + + +LIBW32_API const wchar_t * +w32_syserrorW(DWORD dwError, wchar_t *buf, int buflen) +{ + return w32_vsyserrorW(dwError, buf, buflen, NULL); +} + + +LIBW32_API const wchar_t * +w32_vsyserrorW(DWORD dwError, wchar_t *buf, int buflen, ...) +{ + if (buf && buflen > 0) { + const DWORD ret = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, dwError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, --buflen /*nul*/, NULL); + if (0 == ret) { // error, overflow etc + int len; + + if ((len = buflen) > sizeof("unknown error")) { + len = sizeof("unknown error"); + } + memcpy(buf, L"unknown error", len * sizeof(wchar_t)); + + } else { + int idx = 1, len = (DWORD)ret; + const wchar_t *arg; + va_list ap; + + // remove trailing whitespace + while (--len) { + const wchar_t ch = buf[len]; + if (ch == ' ' || ch == '.' || ch == '\n' || ch == '\r') { + continue; // consume + } + break; // done + } + buf[++len] = 0; // terminate, len inc nul + + // replace %1...x + va_start(ap, buflen); + while (NULL != (arg = va_arg(ap, const wchar_t *)) && idx <= 9 && len < buflen) { + wchar_t *cursor = buf; + + while (NULL != (cursor = wcschr(cursor, '%'))) { + if (cursor[1] == ('0' + idx)) { + int arglen = wcslen(arg); + + len -= 2; // %x being replace + if ((len + arglen) >= buflen) { + arglen = buflen - len; // overflow, truncate + } + wmemmove(cursor + arglen, cursor + 2, wcslen(cursor + 2) + 1 /*nul*/); + wmemcpy(cursor, arg, arglen); + len += arglen; + break; + } + + if ('%' == *++cursor) { + ++cursor; // %% + } + } + ++idx; + } + va_end(ap); + } + return buf; + } + return NULL; +} + /*end*/ diff --git a/libw32/w32_wdirent.c b/libw32/w32_wdirent.c new file mode 100644 index 00000000..979f5699 --- /dev/null +++ b/libw32/w32_wdirent.c @@ -0,0 +1,822 @@ +#include +__CIDENT_RCSID(gr_w32_wdirent_c,"$Id: w32_wdirent.c,v 1.1 2022/03/21 14:29:42 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 directory access services ... + * + * _wopendir, _wclosedir, _wreaddir, _wseekdir, _wrewindir, _wtelldir + * + * Copyright (c) 2021 Adam Young. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + */ + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 /* reparse */ +#endif + +#define _DIRENT_SOURCE +#include "win32_internal.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "win32_io.h" +#include "win32_direct.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#define SIZEOF_WDIRENT (sizeof(struct _wdirent) - sizeof(((struct _wdirent *)0)->d_name)) + +typedef BOOL (WINAPI *Wow64DisableWow64FsRedirection_t)(PVOID *OldValue); +typedef BOOL (WINAPI *Wow64RevertWow64FsRedirection_t)(PVOID OldValue); + +static BOOL isshortcut(const wchar_t *path); + +static _WDIR * unc_populate(const wchar_t *servername); + +static int dir_populate(_WDIR *dp, const wchar_t *path); +static _WDIR * dir_alloc(void); +static void dir_free(_WDIR *dp); +static struct _wdirlist * dir_push(_WDIR *dp, const wchar_t *filename); +static void dir_read(_WDIR *dp, struct _wdirent *entry); +static void dir_list_free(struct _wdirlist *); +static int dir_ishpf(const wchar_t *directory); +static int dir_errno(DWORD rc); + +static BOOL d_Wow64DisableWow64FsRedirection(PVOID *OldValue); +static BOOL d_Wow64RevertWow64FsRedirection(PVOID OldValue); + +static Wow64DisableWow64FsRedirection_t x_Wow64DisableWow64FsRedirection; +static Wow64RevertWow64FsRedirection_t x_Wow64RevertWow64FsRedirection; + + +/* +// NAME +// opendir - open a directory +// +// SYNOPSIS +// #include +// #include +// +// _WDIR *_wopendir(const char *dirname); +*/ + +LIBW32_API _WDIR * +_wopendir(const wchar_t *dirname) +{ + wchar_t fullpath[ MAX_PATH ], symlink[ MAX_PATH ], reparse[ MAX_PATH ], + *path = fullpath; + LPVOID OldValue = NULL; + _WDIR *dp; + int i, len; + + /* Copy to working buffer */ + if (NULL == dirname) { + errno = EFAULT; + return (_WDIR *)NULL; + } else if (0 == (len = wcslen(dirname))) { + errno = ENOTDIR; + return (_WDIR *)NULL; + } + + memset(symlink, 0, sizeof(symlink)); + memset(reparse, 0, sizeof(reparse)); + + /* Convert path (note, UNC safe) */ + if (NULL == w32_realpathW(dirname, fullpath, _countof(fullpath))) { + wchar_t *last; // unknown, assume DOS + + wcsncpy(fullpath, dirname, _countof(fullpath)); + fullpath[_countof(fullpath)-1] = 0; + for (i = 0; fullpath[i]; ++i) { + if (fullpath[i] == '/') { + fullpath[i] = '\\'; // convert + } + } + last = &fullpath[len - 1]; + + /* + * o/s can be very picky about its directory names; the following are valid. + * c:/ c:. c:name/name1 + * + * whereas the following are not valid + * c:name/ + */ + if ((*last == '\\') && (len > 1) && (!((len == 3) && + (fullpath[1] == ':')))) { + *(last--) = 0; + } + } + + /* Is a directory ? */ + if (0 != wcscmp(path, L".")) { + UINT errormode; + DWORD attr; + int rc = 0; + + errormode = SetErrorMode(0); // disable hard errors + if (INVALID_FILE_ATTRIBUTES == (attr = GetFileAttributesW(path))) { + switch(GetLastError()) { + case ERROR_ACCESS_DENIED: + case ERROR_SHARING_VIOLATION: + rc = EACCES; break; + case ERROR_FILE_NOT_FOUND: + rc = ENOENT; break; + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + rc = ENOTDIR; break; + default: + rc = EIO; + } + + } else if (0 == (FILE_ATTRIBUTE_DIRECTORY & attr)) { + rc = ENOTDIR; + if (isshortcut(path)) { // possible shortcut + if (w32_readlinkW(path, symlink, _countof(symlink)) > 0) { + if ((attr = GetFileAttributesW(symlink)) != INVALID_FILE_ATTRIBUTES && + (FILE_ATTRIBUTE_DIRECTORY & attr)) { + path = symlink; // redirect + rc = 0; + } + } + } + } + (void) SetErrorMode(errormode); // restore errors + + if (rc) { + if (w32_unc_rootW(path, NULL)) { // "//servername[/]" + return unc_populate(path); + } + errno = rc; + return (_WDIR *)NULL; + } + + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + if (-1 == w32_reparse_readW(path, reparse, _countof(reparse))) { + errno = EACCES; + return (_WDIR *)NULL; + } + path = reparse; + } + } + + /* Strip trailing slashes, so we can append "\*.*" */ + len = wcslen(path); + while (len > 0) { + --len; + if (path[len] == '\\') { + path[len] = '\0'; // remove slash + } else { + ++len; // end of path + break; + } + } + + path[len++] = '\\'; // insert pattern + path[len++] = '*'; + path[len++] = '.'; + path[len++] = '*'; + path[len++] = 0; + + /* Open directory + * + * If you are writing a 32-bit application to list all the files in a directory and the + * application may be running on a 64-bit computer, you should call Wow64DisableWow64FsRedirection + * before calling FindFirstFileEx and call Wow64RevertWow64FsRedirection after the last call to FindNextFile. + * + * For more information, see File System Redirector. + */ + if (NULL == (dp = dir_alloc())) { + return (_WDIR *)NULL; + } + dp->dd_flags |= DIR_FISUTF8; + + if (d_Wow64DisableWow64FsRedirection(&OldValue)) { + const int ret = dir_populate(dp, path); + + if (! d_Wow64RevertWow64FsRedirection(OldValue) || ret) { + _wclosedir(dp); + errno = (ret ? ret : EIO); + dp = NULL; + } + } + return dp; +} + + +static BOOL +isshortcut(const wchar_t *name) +{ + const size_t len = wcslen(name); + const wchar_t *cursor; + + for (cursor = name + len; --cursor >= name;) { + if (*cursor == '.') { // extension + return (*++cursor && 0 == w32_io_wstricmp(cursor, "lnk")); + } + if (*cursor == '/' || *cursor == '\\') { + break; // delimiter + } + } + return FALSE; +} + + +/* + * populate a unc root directory. + */ +static int +unc_push(void *data, const wchar_t *filename) +{ + if (dir_push((_WDIR *)data, filename)) { + return 0; //success + } + return -1; //error +} + + +static _WDIR * +unc_populate(const wchar_t *servername) +{ + _WDIR *dp; + + if (NULL == (dp = dir_alloc()) || // alloc and populate + -1 == w32_unc_iterateW(servername, unc_push, dp)) { + dir_free(dp); + return (_WDIR *)NULL; + } + + dp->dd_current = dp->dd_contents; // seed cursor + return dp; +} + + +/* + * populate a directory. + */ +static int +dir_populate(_WDIR *dp, const wchar_t *path) +{ + WIN32_FIND_DATAW fd = {0}; + struct _wdirlist *dplist = NULL; + HANDLE hSearch = INVALID_HANDLE_VALUE; + UINT errormode; + BOOL isHPFS = FALSE; + int rc, ret = 0; + + errormode = SetErrorMode(0); // disable hard errors + hSearch = FindFirstFileW(path, &fd); + (void) SetErrorMode(errormode); // restore errors + + if (INVALID_HANDLE_VALUE == hSearch) { + return dir_errno(GetLastError()); + } + + isHPFS = dir_ishpf(path); // extended file system + if (isHPFS) dp->dd_flags |= DIR_FISHPF; + dp->dd_flags |= DIR_FISUTF8; + + do { + +#if defined(FILE_ATTRIBUTE_VOLUME) // skip volume labels + // Not listed by Microsoft but it's there. + // Indicates a directory entry without corresponding file, used only to denote the name of a hard drive volume. + // Was used to 'hack' the long file name system of Windows 95. + if (fd.dwFileAttributes & FILE_ATTRIBUTE_VOLUME) { + continue; + } +#endif + // skip '.' + if ('.' == fd.cFileName[0] && 0 == fd.cFileName[1]) { + continue; + } + + if (NULL == (dplist = dir_push(dp, fd.cFileName))) { + FindClose(hSearch); + return ENOMEM; + } + + dplist->dl_size2 = fd.nFileSizeHigh; + dplist->dl_size = fd.nFileSizeLow; + dplist->dl_attr = fd.dwFileAttributes; + + dplist->dl_type = DT_UNKNOWN; + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + dplist->dl_type = DT_DIR; + } else if ((fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (fd.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT)) { + dplist->dl_type = DT_LNK; + } else { + dplist->dl_type = DT_REG; + } + + } while (FindNextFileW(hSearch, &fd)); + + if ((rc = GetLastError()) == ERROR_NO_MORE_FILES) { + dp->dd_current = dp->dd_contents; // seed cursor + dp->dd_flags |= DIR_FHAVESTATS; + } else { + ret = dir_errno(rc); + } + FindClose(hSearch); + return ret; +} + + +/* + * allocate a directory structure. + */ +static _WDIR * +dir_alloc(void) +{ + const int dd_len = SIZEOF_WDIRENT + (sizeof(wchar_t) * DIRBLKSIZ); /* working dirent storage */ + _WDIR *dp; + +#if defined(NAME_MAX) + assert(MAXNAMLEN >= NAME_MAX); /* POSIX requirement, verify */ +#endif + assert(DIRBLKSIZ > MAXNAMLEN); + + if (NULL == (dp = (_WDIR *)calloc(sizeof(_WDIR), 1)) || + NULL == (dp->dd_buf = (void *)calloc(dd_len, 1))) { + free(dp); + return (_WDIR *)NULL; + } + + dp->dd_magic = DIR_WMAGIC; /* structure magic */ + dp->dd_len = dd_len; /* underlying dd_buf length, in bytes */ + dp->dd_id = w32_dir_identifier(); /* generate unique directory identifier */ + dp->dd_fd = -1; /* file descriptor */ + + return dp; +} + + +/* + * release a directory structure. + */ +static void +dir_free(_WDIR *dp) +{ + if (dp) { + assert(DIR_WMAGIC == dp->dd_magic); + dir_list_free(dp->dd_contents); + free((void *)dp->dd_buf); /* working dirent storage */ + free((void *)dp); + } +} + + +/* + * errno mapping. + */ +static int +dir_errno(DWORD rc) +{ + switch (rc) { +#if defined(ERROR_EMPTY_DIR) + case ERROR_EMPTY_DIR: + return 0; +#endif + case ERROR_NO_MORE_FILES: + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + return ENOENT; + case ERROR_NOT_ENOUGH_MEMORY: + return ENOMEM; + } + return EINVAL; +} + + +/* + * Create a directory list element. + */ +static struct _wdirlist * +dir_push(_WDIR *dp, const wchar_t *filename) +{ + size_t nambytes, namlen = wcslen(filename); + struct _wdirlist *dplist; + + assert(namlen < DIRBLKSIZ); // d_name limit + if (namlen >= DIRBLKSIZ) namlen = DIRBLKSIZ-1; + + nambytes = sizeof(wchar_t) * (namlen + 1 /*nul*/); + if (NULL == (dplist = + (struct _wdirlist *)malloc(sizeof(struct _wdirlist) + nambytes))) { + return NULL; + } + + memset(dplist, 0, sizeof(*dplist)); + if (dp->dd_contents) { + dp->dd_current = + dp->dd_current->dl_next = dplist; + } else { + dp->dd_contents = dp->dd_current = dplist; + } + + dplist->dl_namlen = (unsigned short)namlen; + memcpy(dplist->dl_name, filename, nambytes); + dplist->dl_next = NULL; + return dplist; +} + + +/* + * dir_read --- + * Read the next directory element. + */ +static void +dir_read(_WDIR *dp, struct _wdirent *ent) +{ + struct _wdirlist *dplist = dp->dd_current; + size_t nambytes; + + assert(dplist); + + /* Standard fields */ + assert((dplist->dl_namlen + 1 /*nul*/) <= DIRBLKSIZ); + nambytes = sizeof(wchar_t) * (dplist->dl_namlen + 1 /*nul*/); + memcpy(ent->d_name, dplist->dl_name, nambytes); + ent->d_namlen = dplist->dl_namlen; + ent->d_reclen = (unsigned short)(SIZEOF_WDIRENT + nambytes); + + if (0 == (dp->dd_flags & DIR_FISHPF)) { // not HPFS, convert case. +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__WATCOMC__)) + _wcslwr(ent->d_name); +#else + wcslwr(ent->d_name); +#endif + } + ent->d_fileno = 0; + + /* Extension fields */ + ent->d_ctime = dplist->dl_ctime; + ent->d_mtime = dplist->dl_mtime; + ent->d_size = dplist->dl_size; + ent->d_attr = dplist->dl_attr; + ent->d_type = dplist->dl_type; + + /* Update current location */ + dp->dd_current = dplist->dl_next; + ++dp->dd_loc; +} + + +/* + * dir_list_free --- + * Dispose of the directory list. + */ +static void +dir_list_free(struct _wdirlist *dplist) +{ + struct _wdirlist *odplist; + + while (dplist) { + dplist = (odplist = dplist)->dl_next; + free(odplist); + } +} + + +/* +// NAME +// _wclosedir - close a directory stream +// +// SYNOPSIS +// #include +// +// int _wclosedir(_WDIR *dirp); +// +*/ +LIBW32_API int +_wclosedir(_WDIR *dp) +{ + if (NULL == dp) { + errno = EBADF; + return -1; + } + dir_free(dp); + return 0; +} + + +/* +// NAME +// _wreaddir, readdir_r - read a directory +// +// SYNOPSIS +// #include +// +// struct dirent *_wreaddir(_WDIR *dirp); +// int _wreaddir_r(_WDIR *restrict dirp, struct _wdirent *restrict entry, struct _wdirent **restrict result); +// +*/ +LIBW32_API struct _wdirent * +_wreaddir(_WDIR *dp) +{ + struct _wdirent *entry = (struct _wdirent *)dp->dd_buf; // working buffer. + + if (NULL == dp) { + errno = EBADF; + return (struct _wdirent *)NULL; + } + assert(DIR_WMAGIC == dp->dd_magic); + if (DIR_WMAGIC != dp->dd_magic) { + errno = EBADF; + return (struct _wdirent *)NULL; + } + + if ((struct _wdirlist *)NULL == dp->dd_current) { + errno = ENOENT; + return (struct _wdirent *)NULL; + } + + dir_read(dp, entry); // retrieve next entry. + + return entry; +} + + +LIBW32_API int +_wreaddir_r(_WDIR *dp, struct _wdirent *entry, struct _wdirent **result) +{ + if (NULL == dp) { + return EBADF; + } else if (NULL == entry || NULL == result) { + return EINVAL; + } + assert(DIR_WMAGIC == dp->dd_magic); + if (DIR_WMAGIC != dp->dd_magic) { + *result = NULL; + return EBADF; + } + + if ((struct _wdirlist *)NULL == dp->dd_current) { + *result = NULL; + return ENOENT; + } + + if (dp->dd_current->dl_namlen > MAXNAMLEN) { + *result = NULL; + return ENAMETOOLONG; + } + + dir_read(dp, entry); // retrieve next entry. + *result = entry; + + return 0; +} + + +/* +// NAME +// _wseekdir - set the position of a directory stream +// +// SYNOPSIS +// #include +// +// void _wseekdir(_WDIR *dirp, long loc); [Option End] +// +*/ +LIBW32_API void +_wseekdir(_WDIR *dp, long off) +{ + struct _wdirlist *dplist; + long i = off; + + if (NULL == dp) { + errno = EBADF; + return; + } + assert(DIR_WMAGIC == dp->dd_magic); + + if (off >= 0) { + for (dplist = dp->dd_contents; --i >= 0 && dplist; dplist = dplist->dl_next) { + /*continue*/; + } + dp->dd_loc = off - (i + 1); + dp->dd_current = dplist; + } +} + + +/* +// NAME +// _wrewinddir - reset position of directory stream to the beginning of a directory +// +// SYNOPSIS +// #include +// #include +// +// void _wrewinddir(_WDIR *dirp); +// +*/ +LIBW32_API void +_wrewinddir(_WDIR *dp) +{ + if (NULL == dp) { + errno = EBADF; + return; + } + assert(DIR_WMAGIC == dp->dd_magic); + _wseekdir(dp, 0); +} + + +/* +// NAME +// _wtelldir - current location of a named directory stream +// +// SYNOPSIS +// #include +// +// long _wtelldir(_WDIR *dirp); +// +*/ +LIBW32_API long +_wtelldir(_WDIR *dp) +{ + if (dp == (_WDIR *)NULL) { + errno = EBADF; + return -1; + } + assert(DIR_WMAGIC == dp->dd_magic); + return (dp->dd_loc); +} + + +/* + * Wow64DisableWow64FsRedirection/Wow64RevertWow64FsRedirection -- + * Disables file system redirection for the calling thread. File system + * redirection is enabled by default. + * + * This function is useful for 32-bit applications that want to gain access to the + * native system32 directory. By default, WOW64 file system redirection is enabled. + * + * The Wow64DisableWow64FsRedirection/Wow64RevertWow64FsRedirection function + * pairing is a replacement for the functionality of the + * Wow64EnableWow64FsRedirection function. + * + * To restore file system redirection, call the Wow64RevertWow64FsRedirection + * function. Every successful call to the Wow64DisableWow64FsRedirection function + * must have a matching call to the Wow64RevertWow64FsRedirection function. This + * will ensure redirection is re-enabled and frees associated system resources. + * + * Note The Wow64DisableWow64FsRedirection function affects all file operations + * performed by the current thread, which can have unintended consequences if file + * system redirection is disabled for any length of time. For example, DLL loading + * depends on file system redirection, so disabling file system redirection will + * cause DLL loading to fail. Also, many feature implementations use delayed + * loading and will fail while redirection is disabled. The failure state of the + * initial delay-load operation is persisted, so any subsequent use of the + * delay-load function will fail even after file system redirection is re-enabled. + * To avoid these problems, disable file system redirection immediately before + * calls to specific file I/O functions (such as CreateFile) that must not be + * redirected, and re-enable file system redirection immediately afterward using + * Wow64RevertWow64FsRedirection. + * + * Disabling file system redirection affects only operations made by the current + * thread. Some functions, such as CreateProcessAsUser, do their work on another + * thread, which is not affected by the state of file system redirection in the + * calling thread. + */ + +static BOOL WINAPI +my_Wow64DisableWow64FsRedirection(PVOID *OldValue) +{ + (void)OldValue; + return TRUE; +} + + +static BOOL +d_Wow64DisableWow64FsRedirection(PVOID *OldValue) +{ + if (NULL == x_Wow64DisableWow64FsRedirection) { +#if defined(ENABLE_WOW64) /*11/01/14*/ + HINSTANCE hinst; // Vista+ + + if (0 == (hinst = LoadLibrary("Kernel32")) || + 0 == (x_Wow64DisableWow64FsRedirection = + (Wow64DisableWow64FsRedirection_t) + GetProcAddress(hinst, "Wow64DisableWow64FsRedirection")) || + 0 == (x_Wow64RevertWow64FsRedirection = + (Wow64RevertWow64FsRedirection_t) + GetProcAddress(hinst, "Wow64RevertWow64FsRedirection"))) { + // XP+ + x_Wow64DisableWow64FsRedirection = my_Wow64DisableWow64FsRedirection; + x_Wow64RevertWow64FsRedirection = NULL; + FreeLibrary(hinst); + } +#else + x_Wow64DisableWow64FsRedirection = my_Wow64DisableWow64FsRedirection; + x_Wow64RevertWow64FsRedirection = NULL; +#endif + } + return x_Wow64DisableWow64FsRedirection(OldValue); +} + + +static BOOL +d_Wow64RevertWow64FsRedirection(PVOID OldValue) +{ + if (x_Wow64RevertWow64FsRedirection) { + return x_Wow64RevertWow64FsRedirection(OldValue); + } + return TRUE; +} + + +/* + * IsHPFS --- + * Is High Performance File System. + */ + +static int +dir_ishpf(const wchar_t *directory) +{ + int namelen; + UINT errormode; + DWORD flags = 0, maxname; + BOOL rc = 0; + + if ((namelen = w32_unc_validW(directory)) > 0) { + wchar_t rootdir[MAXHOSTNAMELEN + MAX_PATH], + *cursor = rootdir, *end = cursor + (_countof(rootdir) - 4); + int i; + + directory += 2; // "//" or "\\" + *cursor++ = '\\'; *cursor++ = '\\'; + for (i = namelen; i > 0; --i) { + *cursor++ = *directory++; + } + *cursor++ = '\\'; + if (*directory++) { // component + wchar_t ch; + while (cursor < end && (ch = *directory++) != 0) { + if (IS_PATH_SEP(ch)) break; + *cursor++ = ch; + } + *cursor++ = '\\'; + } + *cursor = 0; + + errormode = SetErrorMode(0); // disable hard errors + rc = GetVolumeInformationW(rootdir, (LPWSTR)NULL, 0, + (LPDWORD)NULL, &maxname, &flags, (LPWSTR)NULL, 0); + (void) SetErrorMode(errormode); // restore errors + + } else { + wchar_t rootdir[4] = L"x:\\"; + int driveno; + + if (directory && + isalpha((unsigned char)directory[0]) && directory[1] == ':') { + driveno = toupper(directory[0]) - 'A'; + } else { + if (0 == (driveno = w32_getdrive())) { + return 0; + } + --driveno; + } + + rootdir[0] = (char)(driveno + 'A'); + errormode = SetErrorMode(0); // disable hard errors + rc = GetVolumeInformationW(rootdir, (LPWSTR)NULL, 0, + (LPDWORD)NULL, &maxname, &flags, (LPWSTR)NULL, 0); + (void) SetErrorMode(errormode); // restore errors + } + + return ((rc) && + (flags & (FS_CASE_SENSITIVE | FS_CASE_IS_PRESERVED))) ? TRUE : FALSE; +} + +/*end*/ diff --git a/libw32/w32_write.c b/libw32/w32_write.c index 4829768c..45ca4460 100644 --- a/libw32/w32_write.c +++ b/libw32/w32_write.c @@ -1,11 +1,11 @@ #include -__CIDENT_RCSID(gr_w32_write_c,"$Id: w32_write.c,v 1.17 2020/06/20 02:00:20 cvsuser Exp $") +__CIDENT_RCSID(gr_w32_write_c,"$Id: w32_write.c,v 1.18 2022/03/21 14:29:42 cvsuser Exp $") /* -*- mode: c; indent-width: 4; -*- */ /* * win32 write() system calls, * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -21,10 +21,10 @@ __CIDENT_RCSID(gr_w32_write_c,"$Id: w32_write.c,v 1.17 2020/06/20 02:00:20 cvsus * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== * * Notice: Portions of this text are reprinted and reproduced in electronic form. from @@ -36,7 +36,7 @@ __CIDENT_RCSID(gr_w32_write_c,"$Id: w32_write.c,v 1.17 2020/06/20 02:00:20 cvsus */ #ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 /* enable xp+ features */ +#define _WIN32_WINNT 0x0501 /* enable xp+ features */ #endif #include "win32_internal.h" @@ -45,7 +45,6 @@ __CIDENT_RCSID(gr_w32_write_c,"$Id: w32_write.c,v 1.17 2020/06/20 02:00:20 cvsus #pragma comment(lib, "Ws2_32.lib") - /* // NAME // @@ -389,4 +388,3 @@ pwrite(int fildes, const void *buf, size_t nbyte, off_t offset) return ret; #endif } - diff --git a/libw32/w32_writev.c b/libw32/w32_writev.c new file mode 100644 index 00000000..1c3a636a --- /dev/null +++ b/libw32/w32_writev.c @@ -0,0 +1,101 @@ +#include +__CIDENT_RCSID(gr_w32_writev_c,"$Id: w32_writev.c,v 1.3 2022/03/21 14:29:42 cvsuser Exp $") + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * win32 writev() system calls, + * + * Copyright (c) 2018 - 2022, Adam Young. + * All rights reserved. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * This project is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * license for more details. + * ==end== + * + * Notice: Portions of this text are reprinted and reproduced in electronic form. from + * IEEE Portable Operating System Interface (POSIX), for reference only. Copyright (C) + * 2001-2003 by the Institute of. Electrical and Electronics Engineers, Inc and The Open + * Group. Copyright remains with the authors and the original Standard can be obtained + * online at http://www.opengroup.org/unix/online.html. + * ==extra== + */ + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 /* enable xp+ features */ +#endif + +#include "win32_internal.h" +#include "win32_misc.h" + +#include +#include + +#pragma comment(lib, "Ws2_32.lib") + + +LIBW32_API int /*ssize_t*/ +writev(int fildes, const struct iovec *iov, int iovcnt) +{ + SOCKET s = (SOCKET)-1; + int i, ret = -1; + + if (fildes < 0) { + errno = EBADF; + + } else if (NULL == iov || iovcnt <= 0){ + errno = EINVAL; + + } else if (w32_issockfd(fildes, &s)) { + ret = 0; + for (i = 0; i < iovcnt; ++i) { +#undef sendto + const int cnt = sendto(s, iov[i].iov_base, iov[i].iov_len, 0, NULL, 0); + if (cnt > 0) { + ret += cnt; + } else if (0 == cnt) { + break; + } else { /*SOCKET_ERROR*/ + if (0 == ret) { + w32_neterrno_set(); + ret = -1; + } + break; + } + ++i; + } + + } else { + ret = 0; + for (i = 0; i < iovcnt; ++i) { + const int cnt = _write(fildes, iov[i].iov_base, iov[i].iov_len); + if (cnt > 0) { + ret += cnt; + } else if (0 == cnt) { + break; + } else if (errno == EINTR) { + continue; + } else { + if (ret == 0) ret = -1; + break; + } + } + } + return ret; +} + +/*end*/ diff --git a/libw32/w32config.hin b/libw32/w32config.hin index 3f3a7ea3..ad76fdcf 100644 --- a/libw32/w32config.hin +++ b/libw32/w32config.hin @@ -1,16 +1,16 @@ #ifndef WIN32_CONFIG_H_INCLUDED #define WIN32_CONFIG_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_w32config_h, "$Id: w32config.hin,v 1.15 2021/04/19 15:17:47 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_w32config_h, "$Id: w32config.hin,v 1.19 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; set-indent: 4; -*- */ -/* $Id: w32config.hin,v 1.15 2021/04/19 15:17:47 cvsuser Exp $ +/* $Id: w32config.hin,v 1.19 2022/03/21 14:29:42 cvsuser Exp $ * Machine configuration. * * System dependent configuration template, * Windows targets (see makelib.pl for details). * - * Copyright (c) 1998 - 2021, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the Grief Editor. @@ -25,7 +25,6 @@ __CPRAGMA_ONCE * ==end== */ - /* * Target compiler */ @@ -115,6 +114,7 @@ __CPRAGMA_ONCE #undef HAVE_STDARG_H #undef HAVE_STDLIB_H #undef HAVE_STDIO_H +#undef HAVE_STDDEF_H #undef HAVE_LIMITS_H /* AC_HEADER_DIRENT */ @@ -336,6 +336,8 @@ __CPRAGMA_ONCE #undef HAVE_UINTMAX_T #undef HAVE_INTPTR_T #undef HAVE_UINTPTR_T +#undef HAVE_PTRDIFF_T +#undef HAVE_LONG_DOUBLE #undef HAVE_LONG_LONG_INT #undef HAVE_UNSIGNED_LONG_LONG_INT #undef HAVE_INT8_T @@ -472,6 +474,7 @@ __CPRAGMA_ONCE #undef HAVE_GETLOGIN_R #undef HAVE_GETPWNAM_R #undef HAVE_GETPWUID_R +#undef HAVE__TZSET #undef HAVE_INDEX #undef HAVE_RINDEX @@ -557,6 +560,7 @@ __CPRAGMA_ONCE #undef HAVE_STRSIGNAL #undef HAVE_PRCTL +#undef HAVE_WCWIDTH #undef HAVE_MBRTOWC #undef HAVE_WCRTOMB #undef HAVE_WCSCMP @@ -726,9 +730,9 @@ __CPRAGMA_ONCE #undef HAVE_LIBCHARSET_H #undef HAVE_LOCALCHARSET_H -#undef HAVE_ICONVL_H -#undef HAVE_LIBICONVL_DLL #undef HAVE_LIBCITRUS +#undef HAVE_ICONV_CITRUS_H +#undef HAVE_LIBICONV_CITRUS_DLL /* compression */ #undef HAVE_ZLIB_H diff --git a/libw32/win32_cdef.h b/libw32/win32_cdef.h index 5b38d010..f43ca81b 100644 --- a/libw32/win32_cdef.h +++ b/libw32/win32_cdef.h @@ -1,8 +1,10 @@ +#ifndef LIBW32_WIN32_CDEF_H_INCLUDED +#define LIBW32_WIN32_CDEF_H_INCLUDED /* -*- mode: c; indent-width: 4; -*- */ /* * internal definitions * - * Copyright (c) 2016 - 2019 Adam Young. + * Copyright (c) 2016 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -17,13 +19,14 @@ * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ #include /*end*/ +#endif /*LIBW32_WIN32_CDEF_H_INCLUDED*/ diff --git a/libw32/win32_child.h b/libw32/win32_child.h index aa7597ae..cccab13e 100644 --- a/libw32/win32_child.h +++ b/libw32/win32_child.h @@ -1,14 +1,14 @@ #ifndef LIBW32_WIN32_CHILD_H_INCLUDED #define LIBW32_WIN32_CHILD_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_win32_child_h,"$Id: win32_child.h,v 1.11 2019/03/15 23:12:22 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_win32_child_h,"$Id: win32_child.h,v 1.12 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * child process support * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -40,14 +40,25 @@ __BEGIN_DECLS typedef struct win32_spawn { const char * cmd; const char ** argv; - const char ** envp; + const char ** envv; const char * dir; #define W32_SPAWNDETACHED 0x01 - int flags; +#define W32_SWHIDE 0x02 /* hide otherwise show child window */ + unsigned flags; unsigned long _dwFlags; /* reserved */ unsigned long _dwProcessId; /* reserved */ } win32_spawn_t; +typedef struct win32_spawnw { + const wchar_t * cmd; + const wchar_t ** argv; + const wchar_t ** envv; + const wchar_t * dir; + unsigned flags; + unsigned long _dwFlags; /* reserved */ + unsigned long _dwProcessId; /* reserved */ +} win32_spawnw_t; + typedef struct { win32_spawn_t spawn; HANDLE hInput; @@ -56,31 +67,56 @@ typedef struct { HANDLE hProc; } win32_exec_t; +typedef struct { + win32_spawnw_t spawn; + HANDLE hInput; + HANDLE hOutput; + HANDLE hError; + HANDLE hProc; +} win32_execw_t; + #if !defined(WNOHANG) #define WNOHANG 1 #endif LIBW32_API const char * w32_getshell (void); +LIBW32_API const wchar_t * w32_getshellW (void); + LIBW32_API const char * w32_gethome (int ignore_env); +LIBW32_API const wchar_t * w32_gethomeW (int ignore_env); LIBW32_API int w32_iscommand (const char *); +LIBW32_API int w32_iscommandA (const char *); +LIBW32_API int w32_iscommandW (const wchar_t *); + LIBW32_API int w32_shell (const char *shell, const char *cmd, const char *fstdin, const char *fstdout, const char *fstderr); +LIBW32_API int w32_shellA (const char *shell, const char *cmd, + const char *fstdin, const char *fstdout, const char *fstderr); +LIBW32_API int w32_shellW (const wchar_t *shell, const wchar_t *cmd, + const wchar_t *fstdin, const wchar_t *fstdout, const wchar_t *fstderr); -LIBW32_API int w32_spawn (win32_spawn_t *args, int Stdout, int Stderr, int *Stdin); -LIBW32_API int w32_spawn2 (win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr); +LIBW32_API int w32_spawnA (win32_spawn_t *args, int Stdout, int Stderr, int *Stdin); +LIBW32_API int w32_spawnW (win32_spawnw_t *args, int Stdout, int Stderr, int *Stdin); +LIBW32_API int w32_spawnA2 (win32_spawn_t *args, int *Stdin, int *Stdout, int *Stderr); +LIBW32_API int w32_spawnW2 (win32_spawnw_t *args, int *Stdin, int *Stdout, int *Stderr); LIBW32_API int w32_exec (win32_exec_t *args); +LIBW32_API int w32_execA (win32_exec_t *args); +LIBW32_API int w32_execW (win32_execw_t *args); -LIBW32_API HANDLE w32_child_exec (struct win32_spawn *args, HANDLE hStdin, HANDLE hStdOut, HANDLE hStdErr); +LIBW32_API HANDLE w32_child_execA (win32_spawn_t *args, HANDLE hStdin, HANDLE hStdOut, HANDLE hStdErr); +LIBW32_API HANDLE w32_child_execW (win32_spawnw_t *args, HANDLE hStdin, HANDLE hStdOut, HANDLE hStdErr); LIBW32_API int w32_child_wait (HANDLE hProc, int *status, int nowait); /*stdio.h*/ LIBW32_API FILE * w32_popen (const char *cmd, const char *mode); +LIBW32_API FILE * w32_popenA (const char *cmd, const char *mode); +LIBW32_API FILE * w32_popenW (const wchar_t *cmd, const char *mode); LIBW32_API int w32_pclose (FILE *file); LIBW32_API int w32_pread_err (FILE *file, char *buf, int length); -/*unistd,h*/ +/*unistd.h*/ LIBW32_API ssize_t pread (int fildes, void *buf, size_t nbyte, off_t offset); LIBW32_API ssize_t pwrite (int fildes, const void *buf, size_t nbyte, off_t offset); diff --git a/libw32/win32_direct.h b/libw32/win32_direct.h new file mode 100644 index 00000000..c0ec404b --- /dev/null +++ b/libw32/win32_direct.h @@ -0,0 +1,71 @@ +#ifndef LIBW32_DIRECT_H_INCLUDED +#define LIBW32_DIRECT_H_INCLUDED + +/* -*- mode: c; indent-width: 4; -*- */ +/* + * Copyright (c) 2021 - 2022, Adam Young. + * + * This file is part of the GRIEF Editor. + * + * The GRIEF Editor is free software: you can redistribute it + * and/or modify it under the terms of the GRIEF Editor License. + * + * Redistributions of source code must retain the above copyright + * notice, and must be distributed with the license document above. + * + * Redistributions in binary form must reproduce the above copyright + * notice, and must include the license document above in + * the documentation and/or other materials provided with the + * distribution. + * + * The GRIEF Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License for more details. + * ==end== + */ + +#include +#include + +__BEGIN_DECLS + +#define DIR_MAGIC 0x57333264 // W32d +#define DIR_WMAGIC 0x57333244 // W32D +#define DIR_UMAGIC 0x57333255 // W32U + +#define DIR_FISHPF 0x0001 +#define DIR_FISUTF8 0x0002 +#define DIR_FHAVESTATS 0x0040 + //#define DIR_FDYNAMICREAD 0x1000 // TODO + +#define PATH_SEP '/' +#define PATH_SEP_STR "/" +#define PATH_SEP2 '\\' +#define PATH_SEP_STR2 "\\" +#define IS_PATH_SEP(c) ((c) == PATH_SEP || (c) == PATH_SEP2) + +DIR * w32_dir_alloc(void); +void w32_dir_free(DIR *dp); +int w32_dir_identifier(void); + +typedef int (*unc_push_t)(void *data, const wchar_t *); + +int w32_unc_iterateA(const char *servername, unc_push_t push, void *data); +int w32_unc_iterateW(const wchar_t *servername, unc_push_t push, void *data); + +DIR * w32_unc_opendirA(const char *dirname); +DIR * w32_unc_opendirW(const wchar_t *dirname); +struct dirent * w32_unc_readdirA(DIR *dp); +struct dirent * w32_unc_readdirW(DIR *dp); +int w32_unc_closedir(DIR *dp); + +int w32_unc_validA(const char *path); +int w32_unc_validW(const wchar_t *path); + +int w32_unc_rootA(const char *path, int *length); +int w32_unc_rootW(const wchar_t *path, int *length); + +__END_DECLS + +#endif /*LIBW32_DIRECT_H_INCLUDED*/ diff --git a/libw32/win32_errno.h b/libw32/win32_errno.h index 61f41568..ed5971aa 100644 --- a/libw32/win32_errno.h +++ b/libw32/win32_errno.h @@ -1,14 +1,14 @@ #ifndef LIBW32_WIN32_ERRNO_H_INCLUDED #define LIBW32_WIN32_ERRNO_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_win32_errno_h,"$Id: win32_errno.h,v 1.8 2020/06/18 13:28:57 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_win32_errno_h,"$Id: win32_errno.h,v 1.10 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * * - * Copyright (c) 2007, 2012 - 2020 Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * * This file is part of the GRIEF Editor. * @@ -23,10 +23,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ diff --git a/libw32/win32_iconv.h b/libw32/win32_iconv.h index ec1e80c9..cdadee8b 100644 --- a/libw32/win32_iconv.h +++ b/libw32/win32_iconv.h @@ -1,14 +1,14 @@ #ifndef LIBW32_WIN32_ICONV_H_INCLUDED #define LIBW32_WIN32_ICONV_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_win32_iconv_h,"$Id: win32_iconv.h,v 1.11 2019/03/15 23:12:22 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_win32_iconv_h,"$Id: win32_iconv.h,v 1.13 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 iconv dynamic loader. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -36,6 +36,8 @@ __CPRAGMA_ONCE __BEGIN_DECLS +LIBW32_API void w32_iconv_dllname(const char *dllname); + LIBW32_API int w32_iconv_connect(int verbose); LIBW32_API void w32_iconv_shutdown(void); diff --git a/libw32/win32_include.h b/libw32/win32_include.h index ef16184f..bc0fb9ab 100644 --- a/libw32/win32_include.h +++ b/libw32/win32_include.h @@ -1,14 +1,14 @@ #ifndef LIBW32_WIN32_INCLUDE_H_INCLUDED #define LIBW32_WIN32_INCLUDE_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_win32_include_h,"$Id: win32_include.h,v 1.9 2019/03/15 23:12:23 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_win32_include_h,"$Id: win32_include.h,v 1.10 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * winsock2.h and windows.h include guard * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ diff --git a/libw32/win32_internal.h b/libw32/win32_internal.h index ea8fe618..f5793c03 100644 --- a/libw32/win32_internal.h +++ b/libw32/win32_internal.h @@ -1,14 +1,14 @@ #ifndef LIBW32_WIN32_INTERNAL_H_INCLUDED #define LIBW32_WIN32_INTERNAL_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_win32_internal_h,"$Id: win32_internal.h,v 1.11 2020/05/04 00:03:53 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_win32_internal_h,"$Id: win32_internal.h,v 1.13 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* - * internal definitions. + * internal definitions * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,73 +24,114 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ - #include "w32config.h" +#if defined(__WATCOMC__) && !defined(__STDC_WANT_LIB_EXT1__) +#define __STDC_WANT_LIB_EXT1__ 1 +#endif + #include #include -#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#if defined(_MSC_VER) && (_MSC_VER >= 1400) || \ + defined(__WATCOMC__) #define WIN32_OPEN _open +#define WIN32_WOPEN _wopen #define WIN32_CLOSE _close #define WIN32_READ _read #define WIN32_WRITE _write #define WIN32_CHMOD _chmod +#define WIN32_WCHMOD _wchmod #define WIN32_LSEEK _lseek #define WIN32_STRICMP _stricmp #define WIN32_STRNICMP _strnicmp #define WIN32_STRDUP _strdup -#define WIN32_GETPID _getpid +#define WIN32_STRDUPW _wcsdup #define WIN32_TZSET _tzset #else #define WIN32_OPEN open +#define WIN32_WOPEN wopen #define WIN32_CLOSE close #define WIN32_READ read #define WIN32_WRITE write #define WIN32_CHMOD chmod +#define WIN32_WCHMOD wchmod #define WIN32_LSEEK lseek #define WIN32_STRICMP stricmp #define WIN32_STRNICMP strnicmp #define WIN32_STRDUP strdup -#define WIN32_GETPID getpid +#define WIN32_STRDUPW wcsdup #define WIN32_TZSET tzset #endif +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define WIN32_GETPID _getpid +#else +#define WIN32_GETPID getpid +#endif + #define SLASHCHAR '\\' #define XSLASHCHAR '/' #define SLASH "\\" +#define LSLASH L"\\" #define DELIMITER ";" +#define LDELIMITER L";" #define ISSLASH(c) (((c) == SLASHCHAR) || ((c) == XSLASHCHAR)) #include __BEGIN_DECLS -#define WIN32_FILDES_MAX 1024 +#define WIN32_FILDES_DEF (512) +#define WIN32_FILDES_MAX (8*1024) /* was 2048, now 8192/2019 */ + +extern int x_w32_cwdn; /* current/last working drive number, A=1 etc */ +extern const char * x_w32_cwdd[26]; /* last directory, prr drive */ +extern const char * x_w32_vfscwd; /* current UNC path, if any */ -extern const char * x_w32_vfscwd; +int w32_io_stricmp (const char *s1, const char *s2); +int w32_io_strnicmp (const char *s1, const char *s2, int slen); +int w32_io_wstricmp (const wchar_t *s1, const char *s2); +int w32_io_wstrnicmp (const wchar_t *s1, const char *s2, int slen); -extern const char * x_w32_cwdd[26]; +LIBW32_API int w32_utf8filenames (int state); +LIBW32_API int w32_utf8filenames_state (void); LIBW32_API ino_t w32_ino_hash (const char *name); +LIBW32_API ino_t w32_ino_whash (const wchar_t *name); LIBW32_API ino_t w32_ino_gen (const DWORD fileIndexLow, const DWORD fileIndexHigh); LIBW32_API ino_t w32_ino_handle (HANDLE handle); LIBW32_API ino_t w32_ino_fildes (int fildes); LIBW32_API ino_t w32_ino_file (const char *name); +LIBW32_API ino_t w32_ino_wfile(const wchar_t *name); + +LIBW32_API int w32_utf2wc (const char *src, wchar_t *dest, size_t max); +LIBW32_API int w32_utf2wcl (const char *src); +LIBW32_API wchar_t * w32_utf2wca (const char *src, size_t *len); +LIBW32_API int w32_wc2utf (const wchar_t *src, char *dest, size_t max); +LIBW32_API char * w32_wc2utfa (const wchar_t *src, size_t *len); + +//User account names are limited to 20 characters and group names are limited to 256 characters. +#define WIN32_GROUP_LEN (256) +#define WIN32_LOGIN_LEN (32) + +LIBW32_API const struct passwd *w32_passwd_user (void); +LIBW32_API const struct group *w32_group_user (void); LIBW32_API char * w32_dos2unix (char *path); +LIBW32_API wchar_t * w32_dos2unixW (wchar_t *path); LIBW32_API char * w32_unix2dos (char *path); - -LIBW32_API int w32_root_unc (const char *path); +LIBW32_API wchar_t * w32_unix2dosW (wchar_t *path); LIBW32_API const char * w32_strslash (const char *path); +LIBW32_API const wchar_t * w32_wcsslash (const wchar_t *path); LIBW32_API int w32_neterrno_map (int nerrno); LIBW32_API int w32_neterrno_set (void); @@ -107,7 +148,8 @@ LIBW32_API SOCKET w32_sockfd_get (int fd); LIBW32_API void w32_sockfd_close (int fd, SOCKET s); LIBW32_API int w32_issockfd (int fd, SOCKET *s); -LIBW32_API int w32_reparse_read(const char *name, char *buf, int maxlen); +LIBW32_API int w32_reparse_readA (const char *name, char *buf, int maxlen); +LIBW32_API int w32_reparse_readW (const wchar_t *name, wchar_t *buf, int maxlen); __END_DECLS diff --git a/libw32/win32_io.h b/libw32/win32_io.h index ee061e30..e998a001 100644 --- a/libw32/win32_io.h +++ b/libw32/win32_io.h @@ -1,14 +1,14 @@ #ifndef LIBW32_WIN32_IO_H_INCLUDED #define LIBW32_WIN32_IO_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_win32_io_h,"$Id: win32_io.h,v 1.32 2021/04/07 16:15:41 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_win32_io_h,"$Id: win32_io.h,v 1.36 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 io functionality. * - * Copyright (c) 1998 - 2021, Adam Young. + * Copyright (c) 2007, 2012 - 2022 Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,33 +24,16 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ #undef DATADIR /* namespace issue */ #if defined(_MSC_VER) -#if (_MSC_VER != 1200) /* MSVC 6 */ -#if (_MSC_VER != 1400) /* MSVC 8/2005 */ -#if (_MSC_VER != 1500) /* MSVC 9/2008 */ -#if (_MSC_VER != 1600) /* MSVC 10/2010 */ -#if (_MSC_VER != 1900) /* MSVC 19/2015 */ -#if (_MSC_VER < 1910 || _MSC_VER > 1916) /* MSVC 19.10 .. 16/2017 */ -#if (_MSC_VER > 1928) /* MSVC 19.20 / 2019.08 */ -#error unistd.h: untested MSVC Version (2005 -- 2019.08) only ... - //see: https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B -#endif //2019 -#endif //2017 -#endif //2015 -#endif //2010 -#endif //2008 -#endif //2005 -#endif //_MSC_VER - #pragma warning(disable:4115) #elif defined(__WATCOMC__) @@ -90,37 +73,81 @@ LIBW32_API int w32_fsync (int fildes); /*io.h*/ struct stat; -LIBW32_API int w32_open (const char *name, int, ...); -LIBW32_API int w32_stat (const char *name, struct stat *sb); +LIBW32_API int w32_open (const char *path, int, ...); +LIBW32_API int w32_openA (const char *path, int, int); +LIBW32_API int w32_openW (const wchar_t *path, int, int); + +LIBW32_API int w32_stat (const char *path, struct stat *sb); +LIBW32_API int w32_statA (const char *path, struct stat *sb); +LIBW32_API int w32_statW (const wchar_t *path, struct stat *sb); +LIBW32_API int w32_lstat (const char *path, struct stat *sb); +LIBW32_API int w32_lstatA (const char *path, struct stat *sb); +LIBW32_API int w32_lstatW (const wchar_t *path, struct stat *sb); + LIBW32_API int w32_read (int fildes, void *buf, size_t nbyte); LIBW32_API int w32_write (int fildes, const void *buf, size_t nbyte); LIBW32_API int w32_close (int fildes); LIBW32_API const char * w32_strerror (int errnum); -LIBW32_API int w32_unlink (const char *fname); LIBW32_API int w32_mkstemp (char *path); +LIBW32_API int w32_mkstempA (char *path); +LIBW32_API int w32_mkstempW (wchar_t *path); + +LIBW32_API int w32_mkstemps (char *path, int suffixlen); +LIBW32_API int w32_mkstempsA (char *path, int suffixlen); +LIBW32_API int w32_mkstempsW (wchar_t *path, int suffixlen); + LIBW32_API int w32_mkstempx (char *path); +LIBW32_API int w32_mkstempxA (char *path); +LIBW32_API int w32_mkstempxW (wchar_t *path); -LIBW32_API int w32_link (const char *, const char *); -LIBW32_API int w32_lstat (const char *, struct stat *); +LIBW32_API int w32_link (const char *path1, const char *path2); +LIBW32_API int w32_linkA (const char *path1, const char *path2); +LIBW32_API int w32_linkW (const wchar_t *path1, const wchar_t *path2); + +LIBW32_API int w32_unlink (const char *fname); +LIBW32_API int w32_unlinkA (const char *fname); +LIBW32_API int w32_unlinkW (const wchar_t *fname); + +LIBW32_API int w32_rename (const char *ofile, const char *nfile); +LIBW32_API int w32_renameA (const char *ofile, const char *nfile); +LIBW32_API int w32_renameW (const wchar_t *ofile, const wchar_t *nfile); LIBW32_API char * w32_getcwd (char *buffer, int size); -LIBW32_API char * w32_getcwdd (char drive, char *buffer, int size); +LIBW32_API char * w32_getcwdA (char *buffer, int size); +LIBW32_API wchar_t * w32_getcwdW (wchar_t *buffer, int size); + +LIBW32_API char * w32_getcwdd (char drive, char *path, int size); +LIBW32_API char * w32_getcwddA (char drive, char *path, int size); +LIBW32_API wchar_t * w32_getcwddW (char drive, wchar_t *path, int size); + +LIBW32_API int w32_getdrive (void); +LIBW32_API int w32_getsystemdrive (void); +LIBW32_API int w32_getlastdrive (void); + +LIBW32_API int w32_mkdir (const char *path, int mode); +LIBW32_API int w32_mkdirA (const char *path, int mode); +LIBW32_API int w32_mkdirW (const wchar_t *path, int mode); + +LIBW32_API int w32_chdir (const char *path); +LIBW32_API int w32_chdirA (const char *path); +LIBW32_API int w32_chdirW (const wchar_t *path); -LIBW32_API int w32_mkdir (const char *fname, int mode); -LIBW32_API int w32_chdir (const char *fname); -LIBW32_API int w32_rmdir (const char *fname); +LIBW32_API int w32_rmdir (const char *path); +LIBW32_API int w32_rmdirA (const char *path); +LIBW32_API int w32_rmdirW (const wchar_t *path); /*support functions*/ -LIBW32_API int w32_root_unc (const char *path); #define SHORTCUT_TRAILING 0x01 #define SHORTCUT_COMPONENT 0x02 -LIBW32_API int w32_shortcut_expand(const char *name, char *buf, size_t buflen, unsigned flags); +LIBW32_API int w32_lnkexpandA (const char *name, char *buf, size_t buflen, unsigned flags); +LIBW32_API int w32_lnkexpandW (const wchar_t *name, wchar_t *buf, size_t buflen, unsigned flags); LIBW32_API const char * w32_strslash (const char *path); +LIBW32_API const wchar_t *w32_wcsslash (const wchar_t *path); LIBW32_API int w32_errno_set (void); LIBW32_API int w32_errno_setas (unsigned nerrno); diff --git a/libw32/win32_ioctl.h b/libw32/win32_ioctl.h index 6842376e..4dfdd1f6 100644 --- a/libw32/win32_ioctl.h +++ b/libw32/win32_ioctl.h @@ -1,7 +1,7 @@ #ifndef LIBW32_WIN32_IOCTL_H_INCLUDED #define LIBW32_WIN32_IOCTL_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_win32_ioctl_h,"$Id: win32_ioctl.h,v 1.2 2018/10/18 13:08:59 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_win32_ioctl_h,"$Id: win32_ioctl.h,v 1.3 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details.th this program. + * license for more details. * ==end== */ diff --git a/libw32/win32_misc.h b/libw32/win32_misc.h index f47e1c45..ecfdc186 100644 --- a/libw32/win32_misc.h +++ b/libw32/win32_misc.h @@ -1,14 +1,14 @@ #ifndef LIBW32_WIN32_MISC_H_INCLUDED #define LIBW32_WIN32_MISC_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_win32_misc_h,"$Id: win32_misc.h,v 1.11 2019/03/15 23:12:23 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_win32_misc_h,"$Id: win32_misc.h,v 1.13 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 public interface. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ @@ -46,23 +46,36 @@ enum w32ostype { /* generalised machine types, ignoring server */ }; #define SYSDIR_TEMP 0x000001 +#define SYSDIR_WINDOWS 0x000002 +#define SYSDIR_SYSTEM 0x000003 +#define SYSDIR_PROGRAM_FILES 0x000004 #define WIN32_PATH_MAX 1024 /* 255, unless UNC names are used */ #define WIN32_LINK_DEPTH 8 -LIBW32_API enum w32ostype w32_ostype (void); -LIBW32_API int w32_getexedir (char *buf, int maxlen); -LIBW32_API int w32_getsysdir (int id, char *buf, int maxlen); +LIBW32_API enum w32ostype w32_ostype(void); +LIBW32_API int w32_getexedir(char *buf, int maxlen); + +LIBW32_API int w32_getsysdir(int id, char *buf, int maxlen); +LIBW32_API int w32_getsysdirA(int id, char *buf, int maxlen); +LIBW32_API int w32_getsysdirW(int id, wchar_t *buf, int maxlen); LIBW32_API int w32_regstrget(const char *subkey, const char *valuename, char *buf, int len); LIBW32_API int w32_regstrgetx(HKEY hkey, const char *subkey, const char *valuename, char *buf, int len); LIBW32_API const char * w32_getlanguage(char *buffer, int len); -LIBW32_API const char * w32_selectfolder(const char *strMessage, char *szBuffer); +LIBW32_API const char * w32_selectfolder(const char *message, char *path, int buflen); +LIBW32_API const char * w32_selectfolderA(const char *message, char *path, int buflen); +LIBW32_API const wchar_t * w32_selectfolderW(const wchar_t *message, wchar_t *path, int buflen); LIBW32_API int w32_IsElevated(void); LIBW32_API int w32_IsAdministrator(void); +LIBW32_API const char * w32_syserrorA(DWORD dwError, char *buf, int bufien); +LIBW32_API const char * w32_vsyserrorA(DWORD dwError, char *buf, int bufien, ...); +LIBW32_API const wchar_t * w32_syserrorW(DWORD dwError, wchar_t *buf, int buflen); +LIBW32_API const wchar_t * w32_vsyserrorW(DWORD dwError, wchar_t *buf, int buflen, ...); + __END_DECLS #endif /*LIBW32_WIN32_MISC_H_INCLUDED*/ diff --git a/libw32/win32_time.h b/libw32/win32_time.h index 8d9c034d..a5e3ed95 100644 --- a/libw32/win32_time.h +++ b/libw32/win32_time.h @@ -1,14 +1,14 @@ #ifndef LIBW32_WIN32_TIME_H_INCLUDED #define LIBW32_WIN32_TIME_H_INCLUDED #include -__CIDENT_RCSID(gr_libw32_win32_time_h,"$Id: win32_time.h,v 1.12 2020/06/18 13:29:15 cvsuser Exp $") +__CIDENT_RCSID(gr_libw32_win32_time_h,"$Id: win32_time.h,v 1.13 2022/03/21 14:29:42 cvsuser Exp $") __CPRAGMA_ONCE /* -*- mode: c; indent-width: 4; -*- */ /* * win32 time functionality. * - * Copyright (c) 1998 - 2019, Adam Young. + * Copyright (c) 1998 - 2022, Adam Young. * All rights reserved. * * This file is part of the GRIEF Editor. @@ -24,10 +24,10 @@ __CPRAGMA_ONCE * the documentation and/or other materials provided with the * distribution. * - * The GRIEF Editor is distributed in the hope that it will be useful, + * This project is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * License for more details. + * license for more details. * ==end== */ diff --git a/libwidechar/.cvsignore b/libwidechar/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/libwidechar/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/libwidechar/Makefile.in b/libwidechar/Makefile.in new file mode 100644 index 00000000..ecaca3b2 --- /dev/null +++ b/libwidechar/Makefile.in @@ -0,0 +1,187 @@ +# -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- +# $Id: Makefile.in,v 1.3 2021/08/01 15:40:21 cvsuser Exp $ +# libwidechar makefile. +# +# +# Copyright (c) 2021, Adam Young. +# All rights reserved. +# +# This file is part of the GRIEF Editor. +# +# The GRIEF Editor is free software: you can redistribute it +# and/or modify it under the terms of the GRIEF Editor License. +# +# Redistributions of source code must retain the above copyright +# notice, and must be distributed with the license document above. +# +# Redistributions in binary form must reproduce the above copyright +# notice, and must include the license document above in +# the documentation and/or other materials provided with the +# distribution. +# +# The GRIEF Editor is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# License for more details. +# ==end== +# + +@SET_MAKE@ +ROOT= @abs_top_builddir@ +top_builddir= @abs_top_builddir@ +top_srcdir= @abs_top_srcdir@ + +# File extensions + +C= .c +O= .o +H= .h +A= .a +LP= lib + +CLEAN= *.bak *~ *.BAK *.swp *.tmp core *.core a.out +XCLEAN= + +# Compilers, programs + +CC= @CC@ +AR= @AR@ +RANLIB= @RANLIB@ +RM= @RM@ +PERL= @PERL@ +LIBTOOL= @LIBTOOL@ +LT_OBJDIR= @LT_OBJDIR@ +WGET= @WGET@ + +# Configuration + +ifeq ("$(BUILD_TYPE)","") #default +BUILD_TYPE= debug +MAKEFLAGS+= BUILD_TYPE=debug +endif +ifneq ("$(BUILD_TYPE)","release") +RTSUFFIX=d +endif + +# Directories + +D_INC= $(ROOT)/include +D_BIN= $(ROOT)/bin@TOOLCHAINEXT@/$(BUILD_TYPE) +D_BINCTBL= $(ROOT)/bin@TOOLCHAINEXT@/$(BUILD_TYPE)/ctbl +D_OBJ= $(ROOT)/objects@TOOLCHAINEXT@/$(BUILD_TYPE)/libwidechar +D_LIB= $(ROOT)/lib@TOOLCHAINEXT@/$(BUILD_TYPE) + +OBJMKDIR := $(shell test -d $(ROOT)/objects) || mkdir $(ROOT)/objects) +LIBMKDIR := $(shell test -d $(ROOT)/lib) || mkdir $(ROOT)/lib) + +# Common flags + +XFLAGS= +CFLAGS= @CFLAGS@ +CWARN= @CWARN@ +CDEBUG= @CDEBUG@ +CRELEASE= @CRELEASE@ +LDDEBUG= @LDDEBUG@ +LDRELEASE= @LDRELEASE@ + +CINCLUDE= -I. -I$(D_INC) @CINCLUDE@ +##ifeq ("mingw32","@build_os@") +##CINCLUDE+= -I../libw32 +##endif +CEXTRA= @DEFS@ + +ifeq ("$(BUILD_TYPE)","release") +CFLAGS+= $(CRELEASE) $(CWARN) $(CINCLUDE) $(CEXTRA) $(XFLAGS) +LDFLAGS= $(LDRELEASE) @LDFLAGS@ +else +CFLAGS+= $(CDEBUG) $(CWARN) $(CINCLUDE) $(CEXTRA) $(XFLAGS) +LDFLAGS= $(LDDEBUG) @LDFLAGS@ +endif + +LDLIBS= -L$(D_LIB) @LIBS@ -lmisc @LIBMALLOC@ @LIBTHREAD@ @EXTRALIBS@ +##ifeq ("mingw32","@build_os@") +##LDLIBS+= -lw32 -lshlwapi -lpsapi -lole32 -luuid -lgdi32 -luserenv -lnetapi32 -ladvapi32 -lWs2_32 +##endif + +YFLAGS= -d +ARFLAGS= rcv +RMFLAGS= -f +RMDFLAGS= -rf + + +######################################################################################### +# Targets + +WIDECHARLIB= $(D_LIB)/$(LP)widechar$(A) + +WIDECHAROBJS=\ + $(D_OBJ)/ucswidth$(O) \ + \ + $(D_OBJ)/wcscasecmp$(O) \ + $(D_OBJ)/wcscat$(O) \ + $(D_OBJ)/wcschr$(O) \ + $(D_OBJ)/wcscmp$(O) \ + $(D_OBJ)/wcscpy$(O) \ + $(D_OBJ)/wcslcat$(O) \ + $(D_OBJ)/wcslcpy$(O) \ + $(D_OBJ)/wcslen$(O) \ + $(D_OBJ)/wcsncat$(O) \ + $(D_OBJ)/wcsncmp$(O) \ + $(D_OBJ)/wcsncpy$(O) \ + $(D_OBJ)/wcspbrk$(O) \ + $(D_OBJ)/wcsrchr$(O) \ + $(D_OBJ)/wcsspn$(O) \ + $(D_OBJ)/wcsstr$(O) \ + $(D_OBJ)/wcstod$(O) \ + $(D_OBJ)/wcstok$(O) \ + $(D_OBJ)/wcswcs$(O) \ + $(D_OBJ)/wcswidth$(O) \ + $(D_OBJ)/wcwidth$(O) \ + $(D_OBJ)/wmemchr$(O) \ + $(D_OBJ)/wmemcmp$(O) \ + $(D_OBJ)/wmemcpy$(O) \ + $(D_OBJ)/wmemmove$(O) \ + $(D_OBJ)/wmemset$(O) \ + $(D_OBJ)/wsnprintf$(O) \ + $(D_OBJ)/wcutf8$(O) + +OBJS= $(WIDECHAROBJS) +LIBS= $(WIDECHARLIB) +TSKS= + + +######################################################################################### +# Rules + +.PHONY: build release debug +build: $(WIDECHARLIB) + +release: + $(MAKE) BUILD_TYPE=release $(filter-out release, $(MAKECMDGOALS)) +debug: + $(MAKE) BUILD_TYPE=debug $(filter-out debug, $(MAKECMDGOALS)) + +$(WIDECHARLIB): $(D_OBJ)/.created \ + $(WIDECHAROBJS) + $(RM) $(RMFLAGS) $@ + $(AR) $(ARFLAGS) $@ $(WIDECHAROBJS) + $(RANLIB) $@ + +XCLEAN+= + +clean: + -@$(RM) $(RMFLAGS) $(BAK) $(TSKS) $(LIBS) $(OBJS) $(CLEAN) $(XCLEAN) >/dev/null 2>&1 + +%/.created: + -@mkdir $(@D) + @echo "++ do not delete, managed directory ++" > $@ + +$(D_LIB)/%.la: %.lo + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(D_OBJ)/$< \ + -module -avoid-version -bindir $(D_BINWIDECHAR) $(LDLIBS) + +$(D_OBJ)/%$(O): %.c + $(CC) $(CFLAGS) -o $@ -c $< + +#end + diff --git a/libwidechar/table_wide.h b/libwidechar/table_wide.h new file mode 100644 index 00000000..38b24d07 --- /dev/null +++ b/libwidechar/table_wide.h @@ -0,0 +1,1134 @@ +/* + * Generated: 2020-06-23T15:58:41.860748 + */ + +static const struct width_interval +width_4_1_0[] = { + // Source: EastAsianWidth-4.1.0.txt + // Date: 2005-03-17, 15:21:00 PST [KW] + // + {0x01100, 0x01159}, // Hangul Choseong Kiyeok ..Hangul Choseong Yeorinhi + {0x0115f, 0x0115f}, // Hangul Choseong Filler ..Hangul Choseong Filler + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312c}, // Bopomofo Letter B ..Bopomofo Letter Gn + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031b7}, // Ideographic Annotation L..Bopomofo Final Letter H + {0x031c0, 0x031cf}, // Cjk Stroke T ..Cjk Stroke N + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03243}, // Parenthesized Ideograph ..Parenthesized Ideograph + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04db5}, // Square Apaato ..Cjk Unified Ideograph-4d + {0x04e00, 0x09fbb}, // Cjk Unified Ideograph-4e..Cjk Unified Ideograph-9f + {0x0a000, 0x0a48c}, // Yi Syllable It ..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0fa2d}, // Cjk Compatibility Ideogr..Cjk Compatibility Ideogr + {0x0fa30, 0x0fa6a}, // Cjk Compatibility Ideogr..Cjk Compatibility Ideogr + {0x0fa70, 0x0fad9}, // Cjk Compatibility Ideogr..Cjk Compatibility Ideogr + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_5_0_0[] = { + // Source: EastAsianWidth-5.0.0.txt + // Date: 2006-02-15, 14:39:00 PST [KW] + // + {0x01100, 0x01159}, // Hangul Choseong Kiyeok ..Hangul Choseong Yeorinhi + {0x0115f, 0x0115f}, // Hangul Choseong Filler ..Hangul Choseong Filler + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312c}, // Bopomofo Letter B ..Bopomofo Letter Gn + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031b7}, // Ideographic Annotation L..Bopomofo Final Letter H + {0x031c0, 0x031cf}, // Cjk Stroke T ..Cjk Stroke N + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03243}, // Parenthesized Ideograph ..Parenthesized Ideograph + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04db5}, // Square Apaato ..Cjk Unified Ideograph-4d + {0x04e00, 0x09fbb}, // Cjk Unified Ideograph-4e..Cjk Unified Ideograph-9f + {0x0a000, 0x0a48c}, // Yi Syllable It ..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0fa2d}, // Cjk Compatibility Ideogr..Cjk Compatibility Ideogr + {0x0fa30, 0x0fa6a}, // Cjk Compatibility Ideogr..Cjk Compatibility Ideogr + {0x0fa70, 0x0fad9}, // Cjk Compatibility Ideogr..Cjk Compatibility Ideogr + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_5_1_0[] = { + // Source: EastAsianWidth-5.1.0.txt + // Date: 2008-03-20, 17:42:00 PDT [KW] + // + {0x01100, 0x01159}, // Hangul Choseong Kiyeok ..Hangul Choseong Yeorinhi + {0x0115f, 0x0115f}, // Hangul Choseong Filler ..Hangul Choseong Filler + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312d}, // Bopomofo Letter B ..Bopomofo Letter Ih + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031b7}, // Ideographic Annotation L..Bopomofo Final Letter H + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03243}, // Parenthesized Ideograph ..Parenthesized Ideograph + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04db5}, // Square Apaato ..Cjk Unified Ideograph-4d + {0x04e00, 0x09fc3}, // Cjk Unified Ideograph-4e..Cjk Unified Ideograph-9f + {0x0a000, 0x0a48c}, // Yi Syllable It ..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0fa2d}, // Cjk Compatibility Ideogr..Cjk Compatibility Ideogr + {0x0fa30, 0x0fa6a}, // Cjk Compatibility Ideogr..Cjk Compatibility Ideogr + {0x0fa70, 0x0fad9}, // Cjk Compatibility Ideogr..Cjk Compatibility Ideogr + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_5_2_0[] = { + // Source: EastAsianWidth-5.2.0.txt + // Date: 2009-06-09, 17:47:00 PDT [KW] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x011a3, 0x011a7}, // Hangul Jungseong A-eu ..Hangul Jungseong O-yae + {0x011fa, 0x011ff}, // Hangul Jongseong Kiyeok-..Hangul Jongseong Ssangni + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312d}, // Bopomofo Letter B ..Bopomofo Letter Ih + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031b7}, // Ideographic Annotation L..Bopomofo Final Letter H + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0d7b0, 0x0d7c6}, // Hangul Jungseong O-yeo ..Hangul Jungseong Araea-e + {0x0d7cb, 0x0d7fb}, // Hangul Jongseong Nieun-r..Hangul Jongseong Phieuph + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x1f200, 0x1f200}, // Square Hiragana Hoka ..Square Hiragana Hoka + {0x1f210, 0x1f231}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_6_0_0[] = { + // Source: EastAsianWidth-6.0.0.txt + // Date: 2010-08-17, 12:17:00 PDT [KW] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x011a3, 0x011a7}, // Hangul Jungseong A-eu ..Hangul Jungseong O-yae + {0x011fa, 0x011ff}, // Hangul Jongseong Kiyeok-..Hangul Jongseong Ssangni + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312d}, // Bopomofo Letter B ..Bopomofo Letter Ih + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0d7b0, 0x0d7c6}, // Hangul Jungseong O-yeo ..Hangul Jungseong Araea-e + {0x0d7cb, 0x0d7fb}, // Hangul Jongseong Nieun-r..Hangul Jongseong Phieuph + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x1b000, 0x1b001}, // Katakana Letter Archaic ..Hiragana Letter Archaic + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23a}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x20000, 0x2f73f}, // Cjk Unified Ideograph-20..(nil) + {0x2b740, 0x2fffd}, // Cjk Unified Ideograph-2b..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_6_1_0[] = { + // Source: EastAsianWidth-6.1.0.txt + // Date: 2011-09-19, 18:46:00 GMT [KW] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x011a3, 0x011a7}, // Hangul Jungseong A-eu ..Hangul Jungseong O-yae + {0x011fa, 0x011ff}, // Hangul Jongseong Kiyeok-..Hangul Jongseong Ssangni + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312d}, // Bopomofo Letter B ..Bopomofo Letter Ih + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0d7b0, 0x0d7c6}, // Hangul Jungseong O-yeo ..Hangul Jungseong Araea-e + {0x0d7cb, 0x0d7fb}, // Hangul Jongseong Nieun-r..Hangul Jongseong Phieuph + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x1b000, 0x1b001}, // Katakana Letter Archaic ..Hiragana Letter Archaic + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23a}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_6_2_0[] = { + // Source: EastAsianWidth-6.2.0.txt + // Date: 2012-05-15, 18:30:00 GMT [KW] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312d}, // Bopomofo Letter B ..Bopomofo Letter Ih + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x1b000, 0x1b001}, // Katakana Letter Archaic ..Hiragana Letter Archaic + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23a}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_6_3_0[] = { + // Source: EastAsianWidth-6.3.0.txt + // Date: 2013-02-05, 20:09:00 GMT [KW, LI] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312d}, // Bopomofo Letter B ..Bopomofo Letter Ih + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x1b000, 0x1b001}, // Katakana Letter Archaic ..Hiragana Letter Archaic + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23a}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_7_0_0[] = { + // Source: EastAsianWidth-7.0.0.txt + // Date: 2014-02-28, 23:15:00 GMT [KW, LI] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312d}, // Bopomofo Letter B ..Bopomofo Letter Ih + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x1b000, 0x1b001}, // Katakana Letter Archaic ..Hiragana Letter Archaic + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23a}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_8_0_0[] = { + // Source: EastAsianWidth-8.0.0.txt + // Date: 2015-02-10, 21:00:00 GMT [KW, LI] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312d}, // Bopomofo Letter B ..Bopomofo Letter Ih + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x1b000, 0x1b001}, // Katakana Letter Archaic ..Hiragana Letter Archaic + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23a}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_9_0_0[] = { + // Source: EastAsianWidth-9.0.0.txt + // Date: 2016-05-27, 17:00:00 GMT [KW, LI] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x0231a, 0x0231b}, // Watch ..Hourglass + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x023e9, 0x023ec}, // Black Right-pointing Dou..Black Down-pointing Doub + {0x023f0, 0x023f0}, // Alarm Clock ..Alarm Clock + {0x023f3, 0x023f3}, // Hourglass With Flowing S..Hourglass With Flowing S + {0x025fd, 0x025fe}, // White Medium Small Squar..Black Medium Small Squar + {0x02614, 0x02615}, // Umbrella With Rain Drops..Hot Beverage + {0x02648, 0x02653}, // Aries ..Pisces + {0x0267f, 0x0267f}, // Wheelchair Symbol ..Wheelchair Symbol + {0x02693, 0x02693}, // Anchor ..Anchor + {0x026a1, 0x026a1}, // High Voltage Sign ..High Voltage Sign + {0x026aa, 0x026ab}, // Medium White Circle ..Medium Black Circle + {0x026bd, 0x026be}, // Soccer Ball ..Baseball + {0x026c4, 0x026c5}, // Snowman Without Snow ..Sun Behind Cloud + {0x026ce, 0x026ce}, // Ophiuchus ..Ophiuchus + {0x026d4, 0x026d4}, // No Entry ..No Entry + {0x026ea, 0x026ea}, // Church ..Church + {0x026f2, 0x026f3}, // Fountain ..Flag In Hole + {0x026f5, 0x026f5}, // Sailboat ..Sailboat + {0x026fa, 0x026fa}, // Tent ..Tent + {0x026fd, 0x026fd}, // Fuel Pump ..Fuel Pump + {0x02705, 0x02705}, // White Heavy Check Mark ..White Heavy Check Mark + {0x0270a, 0x0270b}, // Raised Fist ..Raised Hand + {0x02728, 0x02728}, // Sparkles ..Sparkles + {0x0274c, 0x0274c}, // Cross Mark ..Cross Mark + {0x0274e, 0x0274e}, // Negative Squared Cross M..Negative Squared Cross M + {0x02753, 0x02755}, // Black Question Mark Orna..White Exclamation Mark O + {0x02757, 0x02757}, // Heavy Exclamation Mark S..Heavy Exclamation Mark S + {0x02795, 0x02797}, // Heavy Plus Sign ..Heavy Division Sign + {0x027b0, 0x027b0}, // Curly Loop ..Curly Loop + {0x027bf, 0x027bf}, // Double Curly Loop ..Double Curly Loop + {0x02b1b, 0x02b1c}, // Black Large Square ..White Large Square + {0x02b50, 0x02b50}, // White Medium Star ..White Medium Star + {0x02b55, 0x02b55}, // Heavy Large Circle ..Heavy Large Circle + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312d}, // Bopomofo Letter B ..Bopomofo Letter Ih + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x16fe0, 0x16fe0}, // Tangut Iteration Mark ..Tangut Iteration Mark + {0x17000, 0x187ec}, // (nil) ..(nil) + {0x18800, 0x18af2}, // Tangut Component-001 ..Tangut Component-755 + {0x1b000, 0x1b001}, // Katakana Letter Archaic ..Hiragana Letter Archaic + {0x1f004, 0x1f004}, // Mahjong Tile Red Dragon ..Mahjong Tile Red Dragon + {0x1f0cf, 0x1f0cf}, // Playing Card Black Joker..Playing Card Black Joker + {0x1f18e, 0x1f18e}, // Negative Squared Ab ..Negative Squared Ab + {0x1f191, 0x1f19a}, // Squared Cl ..Squared Vs + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23b}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x1f300, 0x1f320}, // Cyclone ..Shooting Star + {0x1f32d, 0x1f335}, // Hot Dog ..Cactus + {0x1f337, 0x1f37c}, // Tulip ..Baby Bottle + {0x1f37e, 0x1f393}, // Bottle With Popping Cork..Graduation Cap + {0x1f3a0, 0x1f3ca}, // Carousel Horse ..Swimmer + {0x1f3cf, 0x1f3d3}, // Cricket Bat And Ball ..Table Tennis Paddle And + {0x1f3e0, 0x1f3f0}, // House Building ..European Castle + {0x1f3f4, 0x1f3f4}, // Waving Black Flag ..Waving Black Flag + {0x1f3f8, 0x1f43e}, // Badminton Racquet And Sh..Paw Prints + {0x1f440, 0x1f440}, // Eyes ..Eyes + {0x1f442, 0x1f4fc}, // Ear ..Videocassette + {0x1f4ff, 0x1f53d}, // Prayer Beads ..Down-pointing Small Red + {0x1f54b, 0x1f54e}, // Kaaba ..Menorah With Nine Branch + {0x1f550, 0x1f567}, // Clock Face One Oclock ..Clock Face Twelve-thirty + {0x1f57a, 0x1f57a}, // Man Dancing ..Man Dancing + {0x1f595, 0x1f596}, // Reversed Hand With Middl..Raised Hand With Part Be + {0x1f5a4, 0x1f5a4}, // Black Heart ..Black Heart + {0x1f5fb, 0x1f64f}, // Mount Fuji ..Person With Folded Hands + {0x1f680, 0x1f6c5}, // Rocket ..Left Luggage + {0x1f6cc, 0x1f6cc}, // Sleeping Accommodation ..Sleeping Accommodation + {0x1f6d0, 0x1f6d2}, // Place Of Worship ..Shopping Trolley + {0x1f6eb, 0x1f6ec}, // Airplane Departure ..Airplane Arriving + {0x1f6f4, 0x1f6f6}, // Scooter ..Canoe + {0x1f910, 0x1f91e}, // Zipper-mouth Face ..Hand With Index And Midd + {0x1f920, 0x1f927}, // Face With Cowboy Hat ..Sneezing Face + {0x1f930, 0x1f930}, // Pregnant Woman ..Pregnant Woman + {0x1f933, 0x1f93e}, // Selfie ..Handball + {0x1f940, 0x1f94b}, // Wilted Flower ..Martial Arts Uniform + {0x1f950, 0x1f95e}, // Croissant ..Pancakes + {0x1f980, 0x1f991}, // Crab ..Squid + {0x1f9c0, 0x1f9c0}, // Cheese Wedge ..Cheese Wedge + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_10_0_0[] = { + // Source: EastAsianWidth-10.0.0.txt + // Date: 2017-03-08, 02:00:00 GMT [KW, LI] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x0231a, 0x0231b}, // Watch ..Hourglass + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x023e9, 0x023ec}, // Black Right-pointing Dou..Black Down-pointing Doub + {0x023f0, 0x023f0}, // Alarm Clock ..Alarm Clock + {0x023f3, 0x023f3}, // Hourglass With Flowing S..Hourglass With Flowing S + {0x025fd, 0x025fe}, // White Medium Small Squar..Black Medium Small Squar + {0x02614, 0x02615}, // Umbrella With Rain Drops..Hot Beverage + {0x02648, 0x02653}, // Aries ..Pisces + {0x0267f, 0x0267f}, // Wheelchair Symbol ..Wheelchair Symbol + {0x02693, 0x02693}, // Anchor ..Anchor + {0x026a1, 0x026a1}, // High Voltage Sign ..High Voltage Sign + {0x026aa, 0x026ab}, // Medium White Circle ..Medium Black Circle + {0x026bd, 0x026be}, // Soccer Ball ..Baseball + {0x026c4, 0x026c5}, // Snowman Without Snow ..Sun Behind Cloud + {0x026ce, 0x026ce}, // Ophiuchus ..Ophiuchus + {0x026d4, 0x026d4}, // No Entry ..No Entry + {0x026ea, 0x026ea}, // Church ..Church + {0x026f2, 0x026f3}, // Fountain ..Flag In Hole + {0x026f5, 0x026f5}, // Sailboat ..Sailboat + {0x026fa, 0x026fa}, // Tent ..Tent + {0x026fd, 0x026fd}, // Fuel Pump ..Fuel Pump + {0x02705, 0x02705}, // White Heavy Check Mark ..White Heavy Check Mark + {0x0270a, 0x0270b}, // Raised Fist ..Raised Hand + {0x02728, 0x02728}, // Sparkles ..Sparkles + {0x0274c, 0x0274c}, // Cross Mark ..Cross Mark + {0x0274e, 0x0274e}, // Negative Squared Cross M..Negative Squared Cross M + {0x02753, 0x02755}, // Black Question Mark Orna..White Exclamation Mark O + {0x02757, 0x02757}, // Heavy Exclamation Mark S..Heavy Exclamation Mark S + {0x02795, 0x02797}, // Heavy Plus Sign ..Heavy Division Sign + {0x027b0, 0x027b0}, // Curly Loop ..Curly Loop + {0x027bf, 0x027bf}, // Double Curly Loop ..Double Curly Loop + {0x02b1b, 0x02b1c}, // Black Large Square ..White Large Square + {0x02b50, 0x02b50}, // White Medium Star ..White Medium Star + {0x02b55, 0x02b55}, // Heavy Large Circle ..Heavy Large Circle + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312e}, // Bopomofo Letter B ..Bopomofo Letter O With D + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x16fe0, 0x16fe1}, // Tangut Iteration Mark ..Nushu Iteration Mark + {0x17000, 0x187ec}, // (nil) ..(nil) + {0x18800, 0x18af2}, // Tangut Component-001 ..Tangut Component-755 + {0x1b000, 0x1b11e}, // Katakana Letter Archaic ..Hentaigana Letter N-mu-m + {0x1b170, 0x1b2fb}, // Nushu Character-1b170 ..Nushu Character-1b2fb + {0x1f004, 0x1f004}, // Mahjong Tile Red Dragon ..Mahjong Tile Red Dragon + {0x1f0cf, 0x1f0cf}, // Playing Card Black Joker..Playing Card Black Joker + {0x1f18e, 0x1f18e}, // Negative Squared Ab ..Negative Squared Ab + {0x1f191, 0x1f19a}, // Squared Cl ..Squared Vs + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23b}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x1f260, 0x1f265}, // Rounded Symbol For Fu ..Rounded Symbol For Cai + {0x1f300, 0x1f320}, // Cyclone ..Shooting Star + {0x1f32d, 0x1f335}, // Hot Dog ..Cactus + {0x1f337, 0x1f37c}, // Tulip ..Baby Bottle + {0x1f37e, 0x1f393}, // Bottle With Popping Cork..Graduation Cap + {0x1f3a0, 0x1f3ca}, // Carousel Horse ..Swimmer + {0x1f3cf, 0x1f3d3}, // Cricket Bat And Ball ..Table Tennis Paddle And + {0x1f3e0, 0x1f3f0}, // House Building ..European Castle + {0x1f3f4, 0x1f3f4}, // Waving Black Flag ..Waving Black Flag + {0x1f3f8, 0x1f43e}, // Badminton Racquet And Sh..Paw Prints + {0x1f440, 0x1f440}, // Eyes ..Eyes + {0x1f442, 0x1f4fc}, // Ear ..Videocassette + {0x1f4ff, 0x1f53d}, // Prayer Beads ..Down-pointing Small Red + {0x1f54b, 0x1f54e}, // Kaaba ..Menorah With Nine Branch + {0x1f550, 0x1f567}, // Clock Face One Oclock ..Clock Face Twelve-thirty + {0x1f57a, 0x1f57a}, // Man Dancing ..Man Dancing + {0x1f595, 0x1f596}, // Reversed Hand With Middl..Raised Hand With Part Be + {0x1f5a4, 0x1f5a4}, // Black Heart ..Black Heart + {0x1f5fb, 0x1f64f}, // Mount Fuji ..Person With Folded Hands + {0x1f680, 0x1f6c5}, // Rocket ..Left Luggage + {0x1f6cc, 0x1f6cc}, // Sleeping Accommodation ..Sleeping Accommodation + {0x1f6d0, 0x1f6d2}, // Place Of Worship ..Shopping Trolley + {0x1f6eb, 0x1f6ec}, // Airplane Departure ..Airplane Arriving + {0x1f6f4, 0x1f6f8}, // Scooter ..Flying Saucer + {0x1f910, 0x1f93e}, // Zipper-mouth Face ..Handball + {0x1f940, 0x1f94c}, // Wilted Flower ..Curling Stone + {0x1f950, 0x1f96b}, // Croissant ..Canned Food + {0x1f980, 0x1f997}, // Crab ..Cricket + {0x1f9c0, 0x1f9c0}, // Cheese Wedge ..Cheese Wedge + {0x1f9d0, 0x1f9e6}, // Face With Monocle ..Socks + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_11_0_0[] = { + // Source: EastAsianWidth-11.0.0.txt + // Date: 2018-05-14, 09:41:59 GMT [KW, LI] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x0231a, 0x0231b}, // Watch ..Hourglass + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x023e9, 0x023ec}, // Black Right-pointing Dou..Black Down-pointing Doub + {0x023f0, 0x023f0}, // Alarm Clock ..Alarm Clock + {0x023f3, 0x023f3}, // Hourglass With Flowing S..Hourglass With Flowing S + {0x025fd, 0x025fe}, // White Medium Small Squar..Black Medium Small Squar + {0x02614, 0x02615}, // Umbrella With Rain Drops..Hot Beverage + {0x02648, 0x02653}, // Aries ..Pisces + {0x0267f, 0x0267f}, // Wheelchair Symbol ..Wheelchair Symbol + {0x02693, 0x02693}, // Anchor ..Anchor + {0x026a1, 0x026a1}, // High Voltage Sign ..High Voltage Sign + {0x026aa, 0x026ab}, // Medium White Circle ..Medium Black Circle + {0x026bd, 0x026be}, // Soccer Ball ..Baseball + {0x026c4, 0x026c5}, // Snowman Without Snow ..Sun Behind Cloud + {0x026ce, 0x026ce}, // Ophiuchus ..Ophiuchus + {0x026d4, 0x026d4}, // No Entry ..No Entry + {0x026ea, 0x026ea}, // Church ..Church + {0x026f2, 0x026f3}, // Fountain ..Flag In Hole + {0x026f5, 0x026f5}, // Sailboat ..Sailboat + {0x026fa, 0x026fa}, // Tent ..Tent + {0x026fd, 0x026fd}, // Fuel Pump ..Fuel Pump + {0x02705, 0x02705}, // White Heavy Check Mark ..White Heavy Check Mark + {0x0270a, 0x0270b}, // Raised Fist ..Raised Hand + {0x02728, 0x02728}, // Sparkles ..Sparkles + {0x0274c, 0x0274c}, // Cross Mark ..Cross Mark + {0x0274e, 0x0274e}, // Negative Squared Cross M..Negative Squared Cross M + {0x02753, 0x02755}, // Black Question Mark Orna..White Exclamation Mark O + {0x02757, 0x02757}, // Heavy Exclamation Mark S..Heavy Exclamation Mark S + {0x02795, 0x02797}, // Heavy Plus Sign ..Heavy Division Sign + {0x027b0, 0x027b0}, // Curly Loop ..Curly Loop + {0x027bf, 0x027bf}, // Double Curly Loop ..Double Curly Loop + {0x02b1b, 0x02b1c}, // Black Large Square ..White Large Square + {0x02b50, 0x02b50}, // White Medium Star ..White Medium Star + {0x02b55, 0x02b55}, // Heavy Large Circle ..Heavy Large Circle + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312f}, // Bopomofo Letter B ..Bopomofo Letter Nn + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x16fe0, 0x16fe1}, // Tangut Iteration Mark ..Nushu Iteration Mark + {0x17000, 0x187f1}, // (nil) ..(nil) + {0x18800, 0x18af2}, // Tangut Component-001 ..Tangut Component-755 + {0x1b000, 0x1b11e}, // Katakana Letter Archaic ..Hentaigana Letter N-mu-m + {0x1b170, 0x1b2fb}, // Nushu Character-1b170 ..Nushu Character-1b2fb + {0x1f004, 0x1f004}, // Mahjong Tile Red Dragon ..Mahjong Tile Red Dragon + {0x1f0cf, 0x1f0cf}, // Playing Card Black Joker..Playing Card Black Joker + {0x1f18e, 0x1f18e}, // Negative Squared Ab ..Negative Squared Ab + {0x1f191, 0x1f19a}, // Squared Cl ..Squared Vs + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23b}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x1f260, 0x1f265}, // Rounded Symbol For Fu ..Rounded Symbol For Cai + {0x1f300, 0x1f320}, // Cyclone ..Shooting Star + {0x1f32d, 0x1f335}, // Hot Dog ..Cactus + {0x1f337, 0x1f37c}, // Tulip ..Baby Bottle + {0x1f37e, 0x1f393}, // Bottle With Popping Cork..Graduation Cap + {0x1f3a0, 0x1f3ca}, // Carousel Horse ..Swimmer + {0x1f3cf, 0x1f3d3}, // Cricket Bat And Ball ..Table Tennis Paddle And + {0x1f3e0, 0x1f3f0}, // House Building ..European Castle + {0x1f3f4, 0x1f3f4}, // Waving Black Flag ..Waving Black Flag + {0x1f3f8, 0x1f43e}, // Badminton Racquet And Sh..Paw Prints + {0x1f440, 0x1f440}, // Eyes ..Eyes + {0x1f442, 0x1f4fc}, // Ear ..Videocassette + {0x1f4ff, 0x1f53d}, // Prayer Beads ..Down-pointing Small Red + {0x1f54b, 0x1f54e}, // Kaaba ..Menorah With Nine Branch + {0x1f550, 0x1f567}, // Clock Face One Oclock ..Clock Face Twelve-thirty + {0x1f57a, 0x1f57a}, // Man Dancing ..Man Dancing + {0x1f595, 0x1f596}, // Reversed Hand With Middl..Raised Hand With Part Be + {0x1f5a4, 0x1f5a4}, // Black Heart ..Black Heart + {0x1f5fb, 0x1f64f}, // Mount Fuji ..Person With Folded Hands + {0x1f680, 0x1f6c5}, // Rocket ..Left Luggage + {0x1f6cc, 0x1f6cc}, // Sleeping Accommodation ..Sleeping Accommodation + {0x1f6d0, 0x1f6d2}, // Place Of Worship ..Shopping Trolley + {0x1f6eb, 0x1f6ec}, // Airplane Departure ..Airplane Arriving + {0x1f6f4, 0x1f6f9}, // Scooter ..Skateboard + {0x1f910, 0x1f93e}, // Zipper-mouth Face ..Handball + {0x1f940, 0x1f970}, // Wilted Flower ..Smiling Face With Smilin + {0x1f973, 0x1f976}, // Face With Party Horn And..Freezing Face + {0x1f97a, 0x1f97a}, // Face With Pleading Eyes ..Face With Pleading Eyes + {0x1f97c, 0x1f9a2}, // Lab Coat ..Swan + {0x1f9b0, 0x1f9b9}, // Emoji Component Red Hair..Supervillain + {0x1f9c0, 0x1f9c2}, // Cheese Wedge ..Salt Shaker + {0x1f9d0, 0x1f9ff}, // Face With Monocle ..Nazar Amulet + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_12_0_0[] = { + // Source: EastAsianWidth-12.0.0.txt + // Date: 2019-01-21, 14:12:58 GMT [KW, LI] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x0231a, 0x0231b}, // Watch ..Hourglass + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x023e9, 0x023ec}, // Black Right-pointing Dou..Black Down-pointing Doub + {0x023f0, 0x023f0}, // Alarm Clock ..Alarm Clock + {0x023f3, 0x023f3}, // Hourglass With Flowing S..Hourglass With Flowing S + {0x025fd, 0x025fe}, // White Medium Small Squar..Black Medium Small Squar + {0x02614, 0x02615}, // Umbrella With Rain Drops..Hot Beverage + {0x02648, 0x02653}, // Aries ..Pisces + {0x0267f, 0x0267f}, // Wheelchair Symbol ..Wheelchair Symbol + {0x02693, 0x02693}, // Anchor ..Anchor + {0x026a1, 0x026a1}, // High Voltage Sign ..High Voltage Sign + {0x026aa, 0x026ab}, // Medium White Circle ..Medium Black Circle + {0x026bd, 0x026be}, // Soccer Ball ..Baseball + {0x026c4, 0x026c5}, // Snowman Without Snow ..Sun Behind Cloud + {0x026ce, 0x026ce}, // Ophiuchus ..Ophiuchus + {0x026d4, 0x026d4}, // No Entry ..No Entry + {0x026ea, 0x026ea}, // Church ..Church + {0x026f2, 0x026f3}, // Fountain ..Flag In Hole + {0x026f5, 0x026f5}, // Sailboat ..Sailboat + {0x026fa, 0x026fa}, // Tent ..Tent + {0x026fd, 0x026fd}, // Fuel Pump ..Fuel Pump + {0x02705, 0x02705}, // White Heavy Check Mark ..White Heavy Check Mark + {0x0270a, 0x0270b}, // Raised Fist ..Raised Hand + {0x02728, 0x02728}, // Sparkles ..Sparkles + {0x0274c, 0x0274c}, // Cross Mark ..Cross Mark + {0x0274e, 0x0274e}, // Negative Squared Cross M..Negative Squared Cross M + {0x02753, 0x02755}, // Black Question Mark Orna..White Exclamation Mark O + {0x02757, 0x02757}, // Heavy Exclamation Mark S..Heavy Exclamation Mark S + {0x02795, 0x02797}, // Heavy Plus Sign ..Heavy Division Sign + {0x027b0, 0x027b0}, // Curly Loop ..Curly Loop + {0x027bf, 0x027bf}, // Double Curly Loop ..Double Curly Loop + {0x02b1b, 0x02b1c}, // Black Large Square ..White Large Square + {0x02b50, 0x02b50}, // White Medium Star ..White Medium Star + {0x02b55, 0x02b55}, // Heavy Large Circle ..Heavy Large Circle + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312f}, // Bopomofo Letter B ..Bopomofo Letter Nn + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x032fe}, // Partnership Sign ..Circled Katakana Wo + {0x03300, 0x04dbf}, // Square Apaato ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x16fe0, 0x16fe3}, // Tangut Iteration Mark ..Old Chinese Iteration Ma + {0x17000, 0x187f7}, // (nil) ..(nil) + {0x18800, 0x18af2}, // Tangut Component-001 ..Tangut Component-755 + {0x1b000, 0x1b11e}, // Katakana Letter Archaic ..Hentaigana Letter N-mu-m + {0x1b150, 0x1b152}, // Hiragana Letter Small Wi..Hiragana Letter Small Wo + {0x1b164, 0x1b167}, // Katakana Letter Small Wi..Katakana Letter Small N + {0x1b170, 0x1b2fb}, // Nushu Character-1b170 ..Nushu Character-1b2fb + {0x1f004, 0x1f004}, // Mahjong Tile Red Dragon ..Mahjong Tile Red Dragon + {0x1f0cf, 0x1f0cf}, // Playing Card Black Joker..Playing Card Black Joker + {0x1f18e, 0x1f18e}, // Negative Squared Ab ..Negative Squared Ab + {0x1f191, 0x1f19a}, // Squared Cl ..Squared Vs + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23b}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x1f260, 0x1f265}, // Rounded Symbol For Fu ..Rounded Symbol For Cai + {0x1f300, 0x1f320}, // Cyclone ..Shooting Star + {0x1f32d, 0x1f335}, // Hot Dog ..Cactus + {0x1f337, 0x1f37c}, // Tulip ..Baby Bottle + {0x1f37e, 0x1f393}, // Bottle With Popping Cork..Graduation Cap + {0x1f3a0, 0x1f3ca}, // Carousel Horse ..Swimmer + {0x1f3cf, 0x1f3d3}, // Cricket Bat And Ball ..Table Tennis Paddle And + {0x1f3e0, 0x1f3f0}, // House Building ..European Castle + {0x1f3f4, 0x1f3f4}, // Waving Black Flag ..Waving Black Flag + {0x1f3f8, 0x1f43e}, // Badminton Racquet And Sh..Paw Prints + {0x1f440, 0x1f440}, // Eyes ..Eyes + {0x1f442, 0x1f4fc}, // Ear ..Videocassette + {0x1f4ff, 0x1f53d}, // Prayer Beads ..Down-pointing Small Red + {0x1f54b, 0x1f54e}, // Kaaba ..Menorah With Nine Branch + {0x1f550, 0x1f567}, // Clock Face One Oclock ..Clock Face Twelve-thirty + {0x1f57a, 0x1f57a}, // Man Dancing ..Man Dancing + {0x1f595, 0x1f596}, // Reversed Hand With Middl..Raised Hand With Part Be + {0x1f5a4, 0x1f5a4}, // Black Heart ..Black Heart + {0x1f5fb, 0x1f64f}, // Mount Fuji ..Person With Folded Hands + {0x1f680, 0x1f6c5}, // Rocket ..Left Luggage + {0x1f6cc, 0x1f6cc}, // Sleeping Accommodation ..Sleeping Accommodation + {0x1f6d0, 0x1f6d2}, // Place Of Worship ..Shopping Trolley + {0x1f6d5, 0x1f6d5}, // Hindu Temple ..Hindu Temple + {0x1f6eb, 0x1f6ec}, // Airplane Departure ..Airplane Arriving + {0x1f6f4, 0x1f6fa}, // Scooter ..Auto Rickshaw + {0x1f7e0, 0x1f7eb}, // Large Orange Circle ..Large Brown Square + {0x1f90d, 0x1f971}, // White Heart ..Yawning Face + {0x1f973, 0x1f976}, // Face With Party Horn And..Freezing Face + {0x1f97a, 0x1f9a2}, // Face With Pleading Eyes ..Swan + {0x1f9a5, 0x1f9aa}, // Sloth ..Oyster + {0x1f9ae, 0x1f9ca}, // Guide Dog ..Ice Cube + {0x1f9cd, 0x1f9ff}, // Standing Person ..Nazar Amulet + {0x1fa70, 0x1fa73}, // Ballet Shoes ..Shorts + {0x1fa78, 0x1fa7a}, // Drop Of Blood ..Stethoscope + {0x1fa80, 0x1fa82}, // Yo-yo ..Parachute + {0x1fa90, 0x1fa95}, // Ringed Planet ..Banjo + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_12_1_0[] = { + // Source: EastAsianWidth-12.1.0.txt + // Date: 2019-03-31, 22:01:58 GMT [KW, LI] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x0231a, 0x0231b}, // Watch ..Hourglass + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x023e9, 0x023ec}, // Black Right-pointing Dou..Black Down-pointing Doub + {0x023f0, 0x023f0}, // Alarm Clock ..Alarm Clock + {0x023f3, 0x023f3}, // Hourglass With Flowing S..Hourglass With Flowing S + {0x025fd, 0x025fe}, // White Medium Small Squar..Black Medium Small Squar + {0x02614, 0x02615}, // Umbrella With Rain Drops..Hot Beverage + {0x02648, 0x02653}, // Aries ..Pisces + {0x0267f, 0x0267f}, // Wheelchair Symbol ..Wheelchair Symbol + {0x02693, 0x02693}, // Anchor ..Anchor + {0x026a1, 0x026a1}, // High Voltage Sign ..High Voltage Sign + {0x026aa, 0x026ab}, // Medium White Circle ..Medium Black Circle + {0x026bd, 0x026be}, // Soccer Ball ..Baseball + {0x026c4, 0x026c5}, // Snowman Without Snow ..Sun Behind Cloud + {0x026ce, 0x026ce}, // Ophiuchus ..Ophiuchus + {0x026d4, 0x026d4}, // No Entry ..No Entry + {0x026ea, 0x026ea}, // Church ..Church + {0x026f2, 0x026f3}, // Fountain ..Flag In Hole + {0x026f5, 0x026f5}, // Sailboat ..Sailboat + {0x026fa, 0x026fa}, // Tent ..Tent + {0x026fd, 0x026fd}, // Fuel Pump ..Fuel Pump + {0x02705, 0x02705}, // White Heavy Check Mark ..White Heavy Check Mark + {0x0270a, 0x0270b}, // Raised Fist ..Raised Hand + {0x02728, 0x02728}, // Sparkles ..Sparkles + {0x0274c, 0x0274c}, // Cross Mark ..Cross Mark + {0x0274e, 0x0274e}, // Negative Squared Cross M..Negative Squared Cross M + {0x02753, 0x02755}, // Black Question Mark Orna..White Exclamation Mark O + {0x02757, 0x02757}, // Heavy Exclamation Mark S..Heavy Exclamation Mark S + {0x02795, 0x02797}, // Heavy Plus Sign ..Heavy Division Sign + {0x027b0, 0x027b0}, // Curly Loop ..Curly Loop + {0x027bf, 0x027bf}, // Double Curly Loop ..Double Curly Loop + {0x02b1b, 0x02b1c}, // Black Large Square ..White Large Square + {0x02b50, 0x02b50}, // White Medium Star ..White Medium Star + {0x02b55, 0x02b55}, // Heavy Large Circle ..Heavy Large Circle + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312f}, // Bopomofo Letter B ..Bopomofo Letter Nn + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031ba}, // Ideographic Annotation L..Bopomofo Letter Zy + {0x031c0, 0x031e3}, // Cjk Stroke T ..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x04dbf}, // Partnership Sign ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x16fe0, 0x16fe3}, // Tangut Iteration Mark ..Old Chinese Iteration Ma + {0x17000, 0x187f7}, // (nil) ..(nil) + {0x18800, 0x18af2}, // Tangut Component-001 ..Tangut Component-755 + {0x1b000, 0x1b11e}, // Katakana Letter Archaic ..Hentaigana Letter N-mu-m + {0x1b150, 0x1b152}, // Hiragana Letter Small Wi..Hiragana Letter Small Wo + {0x1b164, 0x1b167}, // Katakana Letter Small Wi..Katakana Letter Small N + {0x1b170, 0x1b2fb}, // Nushu Character-1b170 ..Nushu Character-1b2fb + {0x1f004, 0x1f004}, // Mahjong Tile Red Dragon ..Mahjong Tile Red Dragon + {0x1f0cf, 0x1f0cf}, // Playing Card Black Joker..Playing Card Black Joker + {0x1f18e, 0x1f18e}, // Negative Squared Ab ..Negative Squared Ab + {0x1f191, 0x1f19a}, // Squared Cl ..Squared Vs + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23b}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x1f260, 0x1f265}, // Rounded Symbol For Fu ..Rounded Symbol For Cai + {0x1f300, 0x1f320}, // Cyclone ..Shooting Star + {0x1f32d, 0x1f335}, // Hot Dog ..Cactus + {0x1f337, 0x1f37c}, // Tulip ..Baby Bottle + {0x1f37e, 0x1f393}, // Bottle With Popping Cork..Graduation Cap + {0x1f3a0, 0x1f3ca}, // Carousel Horse ..Swimmer + {0x1f3cf, 0x1f3d3}, // Cricket Bat And Ball ..Table Tennis Paddle And + {0x1f3e0, 0x1f3f0}, // House Building ..European Castle + {0x1f3f4, 0x1f3f4}, // Waving Black Flag ..Waving Black Flag + {0x1f3f8, 0x1f43e}, // Badminton Racquet And Sh..Paw Prints + {0x1f440, 0x1f440}, // Eyes ..Eyes + {0x1f442, 0x1f4fc}, // Ear ..Videocassette + {0x1f4ff, 0x1f53d}, // Prayer Beads ..Down-pointing Small Red + {0x1f54b, 0x1f54e}, // Kaaba ..Menorah With Nine Branch + {0x1f550, 0x1f567}, // Clock Face One Oclock ..Clock Face Twelve-thirty + {0x1f57a, 0x1f57a}, // Man Dancing ..Man Dancing + {0x1f595, 0x1f596}, // Reversed Hand With Middl..Raised Hand With Part Be + {0x1f5a4, 0x1f5a4}, // Black Heart ..Black Heart + {0x1f5fb, 0x1f64f}, // Mount Fuji ..Person With Folded Hands + {0x1f680, 0x1f6c5}, // Rocket ..Left Luggage + {0x1f6cc, 0x1f6cc}, // Sleeping Accommodation ..Sleeping Accommodation + {0x1f6d0, 0x1f6d2}, // Place Of Worship ..Shopping Trolley + {0x1f6d5, 0x1f6d5}, // Hindu Temple ..Hindu Temple + {0x1f6eb, 0x1f6ec}, // Airplane Departure ..Airplane Arriving + {0x1f6f4, 0x1f6fa}, // Scooter ..Auto Rickshaw + {0x1f7e0, 0x1f7eb}, // Large Orange Circle ..Large Brown Square + {0x1f90d, 0x1f971}, // White Heart ..Yawning Face + {0x1f973, 0x1f976}, // Face With Party Horn And..Freezing Face + {0x1f97a, 0x1f9a2}, // Face With Pleading Eyes ..Swan + {0x1f9a5, 0x1f9aa}, // Sloth ..Oyster + {0x1f9ae, 0x1f9ca}, // Guide Dog ..Ice Cube + {0x1f9cd, 0x1f9ff}, // Standing Person ..Nazar Amulet + {0x1fa70, 0x1fa73}, // Ballet Shoes ..Shorts + {0x1fa78, 0x1fa7a}, // Drop Of Blood ..Stethoscope + {0x1fa80, 0x1fa82}, // Yo-yo ..Parachute + {0x1fa90, 0x1fa95}, // Ringed Planet ..Banjo + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + +static const struct width_interval +width_13_0_0[] = { + // Source: EastAsianWidth-13.0.0.txt + // Date: 2029-01-21, 18:14:00 GMT [KW, LI] + // + {0x01100, 0x0115f}, // Hangul Choseong Kiyeok ..Hangul Choseong Filler + {0x0231a, 0x0231b}, // Watch ..Hourglass + {0x02329, 0x0232a}, // Left-pointing Angle Brac..Right-pointing Angle Bra + {0x023e9, 0x023ec}, // Black Right-pointing Dou..Black Down-pointing Doub + {0x023f0, 0x023f0}, // Alarm Clock ..Alarm Clock + {0x023f3, 0x023f3}, // Hourglass With Flowing S..Hourglass With Flowing S + {0x025fd, 0x025fe}, // White Medium Small Squar..Black Medium Small Squar + {0x02614, 0x02615}, // Umbrella With Rain Drops..Hot Beverage + {0x02648, 0x02653}, // Aries ..Pisces + {0x0267f, 0x0267f}, // Wheelchair Symbol ..Wheelchair Symbol + {0x02693, 0x02693}, // Anchor ..Anchor + {0x026a1, 0x026a1}, // High Voltage Sign ..High Voltage Sign + {0x026aa, 0x026ab}, // Medium White Circle ..Medium Black Circle + {0x026bd, 0x026be}, // Soccer Ball ..Baseball + {0x026c4, 0x026c5}, // Snowman Without Snow ..Sun Behind Cloud + {0x026ce, 0x026ce}, // Ophiuchus ..Ophiuchus + {0x026d4, 0x026d4}, // No Entry ..No Entry + {0x026ea, 0x026ea}, // Church ..Church + {0x026f2, 0x026f3}, // Fountain ..Flag In Hole + {0x026f5, 0x026f5}, // Sailboat ..Sailboat + {0x026fa, 0x026fa}, // Tent ..Tent + {0x026fd, 0x026fd}, // Fuel Pump ..Fuel Pump + {0x02705, 0x02705}, // White Heavy Check Mark ..White Heavy Check Mark + {0x0270a, 0x0270b}, // Raised Fist ..Raised Hand + {0x02728, 0x02728}, // Sparkles ..Sparkles + {0x0274c, 0x0274c}, // Cross Mark ..Cross Mark + {0x0274e, 0x0274e}, // Negative Squared Cross M..Negative Squared Cross M + {0x02753, 0x02755}, // Black Question Mark Orna..White Exclamation Mark O + {0x02757, 0x02757}, // Heavy Exclamation Mark S..Heavy Exclamation Mark S + {0x02795, 0x02797}, // Heavy Plus Sign ..Heavy Division Sign + {0x027b0, 0x027b0}, // Curly Loop ..Curly Loop + {0x027bf, 0x027bf}, // Double Curly Loop ..Double Curly Loop + {0x02b1b, 0x02b1c}, // Black Large Square ..White Large Square + {0x02b50, 0x02b50}, // White Medium Star ..White Medium Star + {0x02b55, 0x02b55}, // Heavy Large Circle ..Heavy Large Circle + {0x02e80, 0x02e99}, // Cjk Radical Repeat ..Cjk Radical Rap + {0x02e9b, 0x02ef3}, // Cjk Radical Choke ..Cjk Radical C-simplified + {0x02f00, 0x02fd5}, // Kangxi Radical One ..Kangxi Radical Flute + {0x02ff0, 0x02ffb}, // Ideographic Description ..Ideographic Description + {0x03000, 0x0303e}, // Ideographic Space ..Ideographic Variation In + {0x03041, 0x03096}, // Hiragana Letter Small A ..Hiragana Letter Small Ke + {0x03099, 0x030ff}, // Combining Katakana-hirag..Katakana Digraph Koto + {0x03105, 0x0312f}, // Bopomofo Letter B ..Bopomofo Letter Nn + {0x03131, 0x0318e}, // Hangul Letter Kiyeok ..Hangul Letter Araeae + {0x03190, 0x031e3}, // Ideographic Annotation L..Cjk Stroke Q + {0x031f0, 0x0321e}, // Katakana Letter Small Ku..Parenthesized Korean Cha + {0x03220, 0x03247}, // Parenthesized Ideograph ..Circled Ideograph Koto + {0x03250, 0x04dbf}, // Partnership Sign ..(nil) + {0x04e00, 0x0a48c}, // Cjk Unified Ideograph-4e..Yi Syllable Yyr + {0x0a490, 0x0a4c6}, // Yi Radical Qot ..Yi Radical Ke + {0x0a960, 0x0a97c}, // Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo + {0x0ac00, 0x0d7a3}, // Hangul Syllable Ga ..Hangul Syllable Hih + {0x0f900, 0x0faff}, // Cjk Compatibility Ideogr..(nil) + {0x0fe10, 0x0fe19}, // Presentation Form For Ve..Presentation Form For Ve + {0x0fe30, 0x0fe52}, // Presentation Form For Ve..Small Full Stop + {0x0fe54, 0x0fe66}, // Small Semicolon ..Small Equals Sign + {0x0fe68, 0x0fe6b}, // Small Reverse Solidus ..Small Commercial At + {0x0ff01, 0x0ff60}, // Fullwidth Exclamation Ma..Fullwidth Right White Pa + {0x0ffe0, 0x0ffe6}, // Fullwidth Cent Sign ..Fullwidth Won Sign + {0x16fe0, 0x16fe4}, // Tangut Iteration Mark ..(nil) + {0x16ff0, 0x16ff1}, // (nil) ..(nil) + {0x17000, 0x187f7}, // (nil) ..(nil) + {0x18800, 0x18cd5}, // Tangut Component-001 ..(nil) + {0x18d00, 0x18d08}, // (nil) ..(nil) + {0x1b000, 0x1b11e}, // Katakana Letter Archaic ..Hentaigana Letter N-mu-m + {0x1b150, 0x1b152}, // Hiragana Letter Small Wi..Hiragana Letter Small Wo + {0x1b164, 0x1b167}, // Katakana Letter Small Wi..Katakana Letter Small N + {0x1b170, 0x1b2fb}, // Nushu Character-1b170 ..Nushu Character-1b2fb + {0x1f004, 0x1f004}, // Mahjong Tile Red Dragon ..Mahjong Tile Red Dragon + {0x1f0cf, 0x1f0cf}, // Playing Card Black Joker..Playing Card Black Joker + {0x1f18e, 0x1f18e}, // Negative Squared Ab ..Negative Squared Ab + {0x1f191, 0x1f19a}, // Squared Cl ..Squared Vs + {0x1f200, 0x1f202}, // Square Hiragana Hoka ..Squared Katakana Sa + {0x1f210, 0x1f23b}, // Squared Cjk Unified Ideo..Squared Cjk Unified Ideo + {0x1f240, 0x1f248}, // Tortoise Shell Bracketed..Tortoise Shell Bracketed + {0x1f250, 0x1f251}, // Circled Ideograph Advant..Circled Ideograph Accept + {0x1f260, 0x1f265}, // Rounded Symbol For Fu ..Rounded Symbol For Cai + {0x1f300, 0x1f320}, // Cyclone ..Shooting Star + {0x1f32d, 0x1f335}, // Hot Dog ..Cactus + {0x1f337, 0x1f37c}, // Tulip ..Baby Bottle + {0x1f37e, 0x1f393}, // Bottle With Popping Cork..Graduation Cap + {0x1f3a0, 0x1f3ca}, // Carousel Horse ..Swimmer + {0x1f3cf, 0x1f3d3}, // Cricket Bat And Ball ..Table Tennis Paddle And + {0x1f3e0, 0x1f3f0}, // House Building ..European Castle + {0x1f3f4, 0x1f3f4}, // Waving Black Flag ..Waving Black Flag + {0x1f3f8, 0x1f43e}, // Badminton Racquet And Sh..Paw Prints + {0x1f440, 0x1f440}, // Eyes ..Eyes + {0x1f442, 0x1f4fc}, // Ear ..Videocassette + {0x1f4ff, 0x1f53d}, // Prayer Beads ..Down-pointing Small Red + {0x1f54b, 0x1f54e}, // Kaaba ..Menorah With Nine Branch + {0x1f550, 0x1f567}, // Clock Face One Oclock ..Clock Face Twelve-thirty + {0x1f57a, 0x1f57a}, // Man Dancing ..Man Dancing + {0x1f595, 0x1f596}, // Reversed Hand With Middl..Raised Hand With Part Be + {0x1f5a4, 0x1f5a4}, // Black Heart ..Black Heart + {0x1f5fb, 0x1f64f}, // Mount Fuji ..Person With Folded Hands + {0x1f680, 0x1f6c5}, // Rocket ..Left Luggage + {0x1f6cc, 0x1f6cc}, // Sleeping Accommodation ..Sleeping Accommodation + {0x1f6d0, 0x1f6d2}, // Place Of Worship ..Shopping Trolley + {0x1f6d5, 0x1f6d7}, // Hindu Temple ..(nil) + {0x1f6eb, 0x1f6ec}, // Airplane Departure ..Airplane Arriving + {0x1f6f4, 0x1f6fc}, // Scooter ..(nil) + {0x1f7e0, 0x1f7eb}, // Large Orange Circle ..Large Brown Square + {0x1f90c, 0x1f93a}, // (nil) ..Fencer + {0x1f93c, 0x1f945}, // Wrestlers ..Goal Net + {0x1f947, 0x1f978}, // First Place Medal ..(nil) + {0x1f97a, 0x1f9cb}, // Face With Pleading Eyes ..(nil) + {0x1f9cd, 0x1f9ff}, // Standing Person ..Nazar Amulet + {0x1fa70, 0x1fa74}, // Ballet Shoes ..(nil) + {0x1fa78, 0x1fa7a}, // Drop Of Blood ..Stethoscope + {0x1fa80, 0x1fa86}, // Yo-yo ..(nil) + {0x1fa90, 0x1faa8}, // Ringed Planet ..(nil) + {0x1fab0, 0x1fab6}, // (nil) ..(nil) + {0x1fac0, 0x1fac2}, // (nil) ..(nil) + {0x1fad0, 0x1fad6}, // (nil) ..(nil) + {0x20000, 0x2fffd}, // Cjk Unified Ideograph-20..(nil) + {0x30000, 0x3fffd}, // (nil) ..(nil) + }; + diff --git a/libwidechar/table_zero.h b/libwidechar/table_zero.h new file mode 100644 index 00000000..57d383f4 --- /dev/null +++ b/libwidechar/table_zero.h @@ -0,0 +1,3942 @@ +/* + * Generated: 2020-06-23T15:58:43.900697 + */ + +static const struct width_interval +zero_4_1_0[] = { + // Source: DerivedGeneralCategory-4.1.0.txt + // Date: 2005-02-26, 02:35:50 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00486}, // Combining Cyrillic Titlo..Combining Cyrillic Psili + {0x00488, 0x00489}, // Combining Cyrillic Hundr..Combining Cyrillic Milli + {0x00591, 0x005b9}, // Hebrew Accent Etnahta ..Hebrew Point Holam + {0x005bb, 0x005bd}, // Hebrew Point Qubuts ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x00615}, // Arabic Sign Sallallahou ..Arabic Small High Tah + {0x0064b, 0x0065e}, // Arabic Fathatan ..Arabic Fatha With Two Do + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006de, 0x006e4}, // Arabic Start Of Rub El H..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x00901, 0x00902}, // Devanagari Sign Candrabi..Devanagari Sign Anusvara + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00954}, // Devanagari Stress Sign U..Devanagari Acute Accent + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b43}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00d41, 0x00d43}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f90, 0x00f97}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01032}, // Myanmar Vowel Sign Ai ..Myanmar Vowel Sign Ai + {0x01036, 0x01037}, // Myanmar Sign Anusvara ..Myanmar Sign Dot Below + {0x01039, 0x01039}, // Myanmar Sign Virama ..Myanmar Sign Virama + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0135f, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01dc0, 0x01dc3}, // Combining Dotted Grave A..Combining Suspension Mar + {0x020d0, 0x020eb}, // Combining Left Harpoon A..Combining Long Double So + {0x0302a, 0x0302f}, // Ideographic Level Tone M..Hangul Double Dot Tone M + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe23}, // Combining Ligature Left ..Combining Double Tilde R + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_5_0_0[] = { + // Source: DerivedGeneralCategory-5.0.0.txt + // Date: 2006-02-27, 23:41:27 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00486}, // Combining Cyrillic Titlo..Combining Cyrillic Psili + {0x00488, 0x00489}, // Combining Cyrillic Hundr..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x00615}, // Arabic Sign Sallallahou ..Arabic Small High Tah + {0x0064b, 0x0065e}, // Arabic Fathatan ..Arabic Fatha With Two Do + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006de, 0x006e4}, // Arabic Start Of Rub El H..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00901, 0x00902}, // Devanagari Sign Candrabi..Devanagari Sign Anusvara + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00954}, // Devanagari Stress Sign U..Devanagari Acute Accent + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b43}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d41, 0x00d43}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f90, 0x00f97}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01032}, // Myanmar Vowel Sign Ai ..Myanmar Vowel Sign Ai + {0x01036, 0x01037}, // Myanmar Sign Anusvara ..Myanmar Sign Dot Below + {0x01039, 0x01039}, // Myanmar Sign Virama ..Myanmar Sign Virama + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0135f, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01dc0, 0x01dca}, // Combining Dotted Grave A..Combining Latin Small Le + {0x01dfe, 0x01dff}, // Combining Left Arrowhead..Combining Right Arrowhea + {0x020d0, 0x020ef}, // Combining Left Harpoon A..Combining Right Arrow Be + {0x0302a, 0x0302f}, // Ideographic Level Tone M..Hangul Double Dot Tone M + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe23}, // Combining Ligature Left ..Combining Double Tilde R + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_5_1_0[] = { + // Source: DerivedGeneralCategory-5.1.0.txt + // Date: 2008-03-20, 17:54:57 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065e}, // Arabic Fathatan ..Arabic Fatha With Two Do + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006de, 0x006e4}, // Arabic Start Of Rub El H..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00901, 0x00902}, // Devanagari Sign Candrabi..Devanagari Sign Anusvara + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00954}, // Devanagari Stress Sign U..Devanagari Acute Accent + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f90, 0x00f97}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0135f, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01dc0, 0x01de6}, // Combining Dotted Grave A..Combining Latin Small Le + {0x01dfe, 0x01dff}, // Combining Left Arrowhead..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302f}, // Ideographic Level Tone M..Hangul Double Dot Tone M + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a67c, 0x0a67d}, // Combining Cyrillic Kavyk..Combining Cyrillic Payer + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c4}, // Saurashtra Sign Virama ..Saurashtra Sign Virama + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe26}, // Combining Ligature Left ..Combining Conjoining Mac + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_5_2_0[] = { + // Source: DerivedGeneralCategory-5.2.0.txt + // Date: 2009-08-22, 04:58:21 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065e}, // Arabic Fathatan ..Arabic Fatha With Two Do + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006de, 0x006e4}, // Arabic Start Of Rub El H..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00900, 0x00902}, // Devanagari Sign Inverted..Devanagari Sign Anusvara + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00955}, // Devanagari Stress Sign U..Devanagari Vowel Sign Ca + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f90, 0x00f97}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135f, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01dc0, 0x01de6}, // Combining Dotted Grave A..Combining Latin Small Le + {0x01dfd, 0x01dff}, // Combining Almost Equal T..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302f}, // Ideographic Level Tone M..Hangul Double Dot Tone M + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a67c, 0x0a67d}, // Combining Cyrillic Kavyk..Combining Cyrillic Payer + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c4}, // Saurashtra Sign Virama ..Saurashtra Sign Virama + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe26}, // Combining Ligature Left ..Combining Conjoining Mac + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x11080, 0x11081}, // Kaithi Sign Candrabindu ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_6_0_0[] = { + // Source: DerivedGeneralCategory-6.0.0.txt + // Date: 2010-08-19, 00:48:09 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x00900, 0x00902}, // Devanagari Sign Inverted..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01dc0, 0x01de6}, // Combining Dotted Grave A..Combining Latin Small Le + {0x01dfc, 0x01dff}, // Combining Double Inverte..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302f}, // Ideographic Level Tone M..Hangul Double Dot Tone M + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a67c, 0x0a67d}, // Combining Cyrillic Kavyk..Combining Cyrillic Payer + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c4}, // Saurashtra Sign Virama ..Saurashtra Sign Virama + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe26}, // Combining Ligature Left ..Combining Conjoining Mac + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x11080, 0x11081}, // Kaithi Sign Candrabindu ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_6_1_0[] = { + // Source: DerivedGeneralCategory-6.1.0.txt + // Date: 2011-11-27, 05:10:22 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008e4, 0x008fe}, // Arabic Curly Fatha ..Arabic Damma With Dot + {0x00900, 0x00902}, // Devanagari Sign Inverted..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bab}, // Sundanese Sign Virama ..Sundanese Sign Virama + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01dc0, 0x01de6}, // Combining Dotted Grave A..Combining Latin Small Le + {0x01dfc, 0x01dff}, // Combining Double Inverte..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69f, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c4}, // Saurashtra Sign Virama ..Saurashtra Sign Virama + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe26}, // Combining Ligature Left ..Combining Conjoining Mac + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x11080, 0x11081}, // Kaithi Sign Candrabindu ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_6_2_0[] = { + // Source: DerivedGeneralCategory-6.2.0.txt + // Date: 2012-05-20, 00:42:34 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008e4, 0x008fe}, // Arabic Curly Fatha ..Arabic Damma With Dot + {0x00900, 0x00902}, // Devanagari Sign Inverted..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bab}, // Sundanese Sign Virama ..Sundanese Sign Virama + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01dc0, 0x01de6}, // Combining Dotted Grave A..Combining Latin Small Le + {0x01dfc, 0x01dff}, // Combining Double Inverte..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69f, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c4}, // Saurashtra Sign Virama ..Saurashtra Sign Virama + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe26}, // Combining Ligature Left ..Combining Conjoining Mac + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x11080, 0x11081}, // Kaithi Sign Candrabindu ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_6_3_0[] = { + // Source: DerivedGeneralCategory-6.3.0.txt + // Date: 2013-07-05, 14:08:45 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008e4, 0x008fe}, // Arabic Curly Fatha ..Arabic Damma With Dot + {0x00900, 0x00902}, // Devanagari Sign Inverted..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bab}, // Sundanese Sign Virama ..Sundanese Sign Virama + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01dc0, 0x01de6}, // Combining Dotted Grave A..Combining Latin Small Le + {0x01dfc, 0x01dff}, // Combining Double Inverte..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69f, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c4}, // Saurashtra Sign Virama ..Saurashtra Sign Virama + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe26}, // Combining Ligature Left ..Combining Conjoining Mac + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x11080, 0x11081}, // Kaithi Sign Candrabindu ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_7_0_0[] = { + // Source: DerivedGeneralCategory-7.0.0.txt + // Date: 2014-02-07, 18:42:12 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008e4, 0x00902}, // Arabic Curly Fatha ..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d01, 0x00d01}, // Malayalam Sign Candrabin..Malayalam Sign Candrabin + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01abe}, // Combining Doubled Circum..Combining Parentheses Ov + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df5}, // Combining Dotted Grave A..Combining Up Tack Above + {0x01dfc, 0x01dff}, // Combining Double Inverte..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69f, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c4}, // Saurashtra Sign Virama ..Saurashtra Sign Virama + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2d}, // Combining Ligature Left ..Combining Conjoining Mac + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11301, 0x11301}, // Grantha Sign Candrabindu..Grantha Sign Candrabindu + {0x1133c, 0x1133c}, // Grantha Sign Nukta ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_8_0_0[] = { + // Source: DerivedGeneralCategory-8.0.0.txt + // Date: 2015-02-13, 13:47:11 GMT [MD] + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d01, 0x00d01}, // Malayalam Sign Candrabin..Malayalam Sign Candrabin + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01abe}, // Combining Doubled Circum..Combining Parentheses Ov + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df5}, // Combining Dotted Grave A..Combining Up Tack Above + {0x01dfc, 0x01dff}, // Combining Double Inverte..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c4}, // Saurashtra Sign Virama ..Saurashtra Sign Virama + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111ca, 0x111cc}, // Sharada Sign Nukta ..Sharada Extra Short Vowe + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133c, 0x1133c}, // Grantha Sign Nukta ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_9_0_0[] = { + // Source: DerivedGeneralCategory-9.0.0.txt + // Date: 2016-06-01, 10:34:26 GMT + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008d4, 0x008e1}, // Arabic Small High Word A..Arabic Small High Sign S + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d01, 0x00d01}, // Malayalam Sign Candrabin..Malayalam Sign Candrabin + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x01885, 0x01886}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01abe}, // Combining Doubled Circum..Combining Parentheses Ov + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df5}, // Combining Dotted Grave A..Combining Up Tack Above + {0x01dfb, 0x01dff}, // Combining Deletion Mark ..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c5}, // Saurashtra Sign Virama ..Saurashtra Sign Candrabi + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111ca, 0x111cc}, // Sharada Sign Nukta ..Sharada Extra Short Vowe + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x1123e, 0x1123e}, // Khojki Sign Sukun ..Khojki Sign Sukun + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133c, 0x1133c}, // Grantha Sign Nukta ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x11438, 0x1143f}, // Newa Vowel Sign U ..Newa Vowel Sign Ai + {0x11442, 0x11444}, // Newa Sign Virama ..Newa Sign Anusvara + {0x11446, 0x11446}, // Newa Sign Nukta ..Newa Sign Nukta + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x11c30, 0x11c36}, // Bhaiksuki Vowel Sign I ..Bhaiksuki Vowel Sign Voc + {0x11c38, 0x11c3d}, // Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Anusvara + {0x11c3f, 0x11c3f}, // Bhaiksuki Sign Virama ..Bhaiksuki Sign Virama + {0x11c92, 0x11ca7}, // Marchen Subjoined Letter..Marchen Subjoined Letter + {0x11caa, 0x11cb0}, // Marchen Subjoined Letter..Marchen Vowel Sign Aa + {0x11cb2, 0x11cb3}, // Marchen Vowel Sign U ..Marchen Vowel Sign E + {0x11cb5, 0x11cb6}, // Marchen Sign Anusvara ..Marchen Sign Candrabindu + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e000, 0x1e006}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e008, 0x1e018}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e01b, 0x1e021}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e023, 0x1e024}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e026, 0x1e02a}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0x1e944, 0x1e94a}, // Adlam Alif Lengthener ..Adlam Nukta + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_10_0_0[] = { + // Source: DerivedGeneralCategory-10.0.0.txt + // Date: 2017-03-08, 08:41:49 GMT + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008d4, 0x008e1}, // Arabic Small High Word A..Arabic Small High Sign S + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00afa, 0x00aff}, // Gujarati Sign Sukun ..Gujarati Sign Two-circle + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d00, 0x00d01}, // Malayalam Sign Combining..Malayalam Sign Candrabin + {0x00d3b, 0x00d3c}, // Malayalam Sign Vertical ..Malayalam Sign Circular + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x01885, 0x01886}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01abe}, // Combining Doubled Circum..Combining Parentheses Ov + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df9}, // Combining Dotted Grave A..Combining Wide Inverted + {0x01dfb, 0x01dff}, // Combining Deletion Mark ..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c5}, // Saurashtra Sign Virama ..Saurashtra Sign Candrabi + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111ca, 0x111cc}, // Sharada Sign Nukta ..Sharada Extra Short Vowe + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x1123e, 0x1123e}, // Khojki Sign Sukun ..Khojki Sign Sukun + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133c, 0x1133c}, // Grantha Sign Nukta ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x11438, 0x1143f}, // Newa Vowel Sign U ..Newa Vowel Sign Ai + {0x11442, 0x11444}, // Newa Sign Virama ..Newa Sign Anusvara + {0x11446, 0x11446}, // Newa Sign Nukta ..Newa Sign Nukta + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x11a01, 0x11a06}, // Zanabazar Square Vowel S..Zanabazar Square Vowel S + {0x11a09, 0x11a0a}, // Zanabazar Square Vowel S..Zanabazar Square Vowel L + {0x11a33, 0x11a38}, // Zanabazar Square Final C..Zanabazar Square Sign An + {0x11a3b, 0x11a3e}, // Zanabazar Square Cluster..Zanabazar Square Cluster + {0x11a47, 0x11a47}, // Zanabazar Square Subjoin..Zanabazar Square Subjoin + {0x11a51, 0x11a56}, // Soyombo Vowel Sign I ..Soyombo Vowel Sign Oe + {0x11a59, 0x11a5b}, // Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar + {0x11a8a, 0x11a96}, // Soyombo Final Consonant ..Soyombo Sign Anusvara + {0x11a98, 0x11a99}, // Soyombo Gemination Mark ..Soyombo Subjoiner + {0x11c30, 0x11c36}, // Bhaiksuki Vowel Sign I ..Bhaiksuki Vowel Sign Voc + {0x11c38, 0x11c3d}, // Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Anusvara + {0x11c3f, 0x11c3f}, // Bhaiksuki Sign Virama ..Bhaiksuki Sign Virama + {0x11c92, 0x11ca7}, // Marchen Subjoined Letter..Marchen Subjoined Letter + {0x11caa, 0x11cb0}, // Marchen Subjoined Letter..Marchen Vowel Sign Aa + {0x11cb2, 0x11cb3}, // Marchen Vowel Sign U ..Marchen Vowel Sign E + {0x11cb5, 0x11cb6}, // Marchen Sign Anusvara ..Marchen Sign Candrabindu + {0x11d31, 0x11d36}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3a, 0x11d3a}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3c, 0x11d3d}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3f, 0x11d45}, // Masaram Gondi Vowel Sign..Masaram Gondi Virama + {0x11d47, 0x11d47}, // Masaram Gondi Ra-kara ..Masaram Gondi Ra-kara + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e000, 0x1e006}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e008, 0x1e018}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e01b, 0x1e021}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e023, 0x1e024}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e026, 0x1e02a}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0x1e944, 0x1e94a}, // Adlam Alif Lengthener ..Adlam Nukta + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_11_0_0[] = { + // Source: DerivedGeneralCategory-11.0.0.txt + // Date: 2018-02-21, 05:34:04 GMT + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x007fd, 0x007fd}, // Nko Dantayalan ..Nko Dantayalan + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008d3, 0x008e1}, // Arabic Small Low Waw ..Arabic Small High Sign S + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x009fe, 0x009fe}, // Bengali Sandhi Mark ..Bengali Sandhi Mark + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00afa, 0x00aff}, // Gujarati Sign Sukun ..Gujarati Sign Two-circle + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c04, 0x00c04}, // Telugu Sign Combining An..Telugu Sign Combining An + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d00, 0x00d01}, // Malayalam Sign Combining..Malayalam Sign Candrabin + {0x00d3b, 0x00d3c}, // Malayalam Sign Vertical ..Malayalam Sign Circular + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00eb9}, // Lao Vowel Sign I ..Lao Vowel Sign Uu + {0x00ebb, 0x00ebc}, // Lao Vowel Sign Mai Kon ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x01885, 0x01886}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01abe}, // Combining Doubled Circum..Combining Parentheses Ov + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df9}, // Combining Dotted Grave A..Combining Wide Inverted + {0x01dfb, 0x01dff}, // Combining Deletion Mark ..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c5}, // Saurashtra Sign Virama ..Saurashtra Sign Candrabi + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a8ff, 0x0a8ff}, // Devanagari Vowel Sign Ay..Devanagari Vowel Sign Ay + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bc}, // Javanese Vowel Sign Pepe..Javanese Vowel Sign Pepe + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x10d24, 0x10d27}, // Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas + {0x10f46, 0x10f50}, // Sogdian Combining Dot Be..Sogdian Combining Stroke + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111c9, 0x111cc}, // Sharada Sandhi Mark ..Sharada Extra Short Vowe + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x1123e, 0x1123e}, // Khojki Sign Sukun ..Khojki Sign Sukun + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133b, 0x1133c}, // Combining Bindu Below ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x11438, 0x1143f}, // Newa Vowel Sign U ..Newa Vowel Sign Ai + {0x11442, 0x11444}, // Newa Sign Virama ..Newa Sign Anusvara + {0x11446, 0x11446}, // Newa Sign Nukta ..Newa Sign Nukta + {0x1145e, 0x1145e}, // Newa Sandhi Mark ..Newa Sandhi Mark + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x1182f, 0x11837}, // Dogra Vowel Sign U ..Dogra Sign Anusvara + {0x11839, 0x1183a}, // Dogra Sign Virama ..Dogra Sign Nukta + {0x11a01, 0x11a0a}, // Zanabazar Square Vowel S..Zanabazar Square Vowel L + {0x11a33, 0x11a38}, // Zanabazar Square Final C..Zanabazar Square Sign An + {0x11a3b, 0x11a3e}, // Zanabazar Square Cluster..Zanabazar Square Cluster + {0x11a47, 0x11a47}, // Zanabazar Square Subjoin..Zanabazar Square Subjoin + {0x11a51, 0x11a56}, // Soyombo Vowel Sign I ..Soyombo Vowel Sign Oe + {0x11a59, 0x11a5b}, // Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar + {0x11a8a, 0x11a96}, // Soyombo Final Consonant ..Soyombo Sign Anusvara + {0x11a98, 0x11a99}, // Soyombo Gemination Mark ..Soyombo Subjoiner + {0x11c30, 0x11c36}, // Bhaiksuki Vowel Sign I ..Bhaiksuki Vowel Sign Voc + {0x11c38, 0x11c3d}, // Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Anusvara + {0x11c3f, 0x11c3f}, // Bhaiksuki Sign Virama ..Bhaiksuki Sign Virama + {0x11c92, 0x11ca7}, // Marchen Subjoined Letter..Marchen Subjoined Letter + {0x11caa, 0x11cb0}, // Marchen Subjoined Letter..Marchen Vowel Sign Aa + {0x11cb2, 0x11cb3}, // Marchen Vowel Sign U ..Marchen Vowel Sign E + {0x11cb5, 0x11cb6}, // Marchen Sign Anusvara ..Marchen Sign Candrabindu + {0x11d31, 0x11d36}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3a, 0x11d3a}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3c, 0x11d3d}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3f, 0x11d45}, // Masaram Gondi Vowel Sign..Masaram Gondi Virama + {0x11d47, 0x11d47}, // Masaram Gondi Ra-kara ..Masaram Gondi Ra-kara + {0x11d90, 0x11d91}, // Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign + {0x11d95, 0x11d95}, // Gunjala Gondi Sign Anusv..Gunjala Gondi Sign Anusv + {0x11d97, 0x11d97}, // Gunjala Gondi Virama ..Gunjala Gondi Virama + {0x11ef3, 0x11ef4}, // Makasar Vowel Sign I ..Makasar Vowel Sign U + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e000, 0x1e006}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e008, 0x1e018}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e01b, 0x1e021}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e023, 0x1e024}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e026, 0x1e02a}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0x1e944, 0x1e94a}, // Adlam Alif Lengthener ..Adlam Nukta + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_12_0_0[] = { + // Source: DerivedGeneralCategory-12.0.0.txt + // Date: 2019-01-22, 08:18:28 GMT + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x007fd, 0x007fd}, // Nko Dantayalan ..Nko Dantayalan + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008d3, 0x008e1}, // Arabic Small Low Waw ..Arabic Small High Sign S + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x009fe, 0x009fe}, // Bengali Sandhi Mark ..Bengali Sandhi Mark + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00afa, 0x00aff}, // Gujarati Sign Sukun ..Gujarati Sign Two-circle + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c04, 0x00c04}, // Telugu Sign Combining An..Telugu Sign Combining An + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d00, 0x00d01}, // Malayalam Sign Combining..Malayalam Sign Candrabin + {0x00d3b, 0x00d3c}, // Malayalam Sign Vertical ..Malayalam Sign Circular + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00ebc}, // Lao Vowel Sign I ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x01885, 0x01886}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01abe}, // Combining Doubled Circum..Combining Parentheses Ov + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df9}, // Combining Dotted Grave A..Combining Wide Inverted + {0x01dfb, 0x01dff}, // Combining Deletion Mark ..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c5}, // Saurashtra Sign Virama ..Saurashtra Sign Candrabi + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a8ff, 0x0a8ff}, // Devanagari Vowel Sign Ay..Devanagari Vowel Sign Ay + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bd}, // Javanese Vowel Sign Pepe..Javanese Consonant Sign + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x10d24, 0x10d27}, // Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas + {0x10f46, 0x10f50}, // Sogdian Combining Dot Be..Sogdian Combining Stroke + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111c9, 0x111cc}, // Sharada Sandhi Mark ..Sharada Extra Short Vowe + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x1123e, 0x1123e}, // Khojki Sign Sukun ..Khojki Sign Sukun + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133b, 0x1133c}, // Combining Bindu Below ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x11438, 0x1143f}, // Newa Vowel Sign U ..Newa Vowel Sign Ai + {0x11442, 0x11444}, // Newa Sign Virama ..Newa Sign Anusvara + {0x11446, 0x11446}, // Newa Sign Nukta ..Newa Sign Nukta + {0x1145e, 0x1145e}, // Newa Sandhi Mark ..Newa Sandhi Mark + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x1182f, 0x11837}, // Dogra Vowel Sign U ..Dogra Sign Anusvara + {0x11839, 0x1183a}, // Dogra Sign Virama ..Dogra Sign Nukta + {0x119d4, 0x119d7}, // Nandinagari Vowel Sign U..Nandinagari Vowel Sign V + {0x119da, 0x119db}, // Nandinagari Vowel Sign E..Nandinagari Vowel Sign A + {0x119e0, 0x119e0}, // Nandinagari Sign Virama ..Nandinagari Sign Virama + {0x11a01, 0x11a0a}, // Zanabazar Square Vowel S..Zanabazar Square Vowel L + {0x11a33, 0x11a38}, // Zanabazar Square Final C..Zanabazar Square Sign An + {0x11a3b, 0x11a3e}, // Zanabazar Square Cluster..Zanabazar Square Cluster + {0x11a47, 0x11a47}, // Zanabazar Square Subjoin..Zanabazar Square Subjoin + {0x11a51, 0x11a56}, // Soyombo Vowel Sign I ..Soyombo Vowel Sign Oe + {0x11a59, 0x11a5b}, // Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar + {0x11a8a, 0x11a96}, // Soyombo Final Consonant ..Soyombo Sign Anusvara + {0x11a98, 0x11a99}, // Soyombo Gemination Mark ..Soyombo Subjoiner + {0x11c30, 0x11c36}, // Bhaiksuki Vowel Sign I ..Bhaiksuki Vowel Sign Voc + {0x11c38, 0x11c3d}, // Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Anusvara + {0x11c3f, 0x11c3f}, // Bhaiksuki Sign Virama ..Bhaiksuki Sign Virama + {0x11c92, 0x11ca7}, // Marchen Subjoined Letter..Marchen Subjoined Letter + {0x11caa, 0x11cb0}, // Marchen Subjoined Letter..Marchen Vowel Sign Aa + {0x11cb2, 0x11cb3}, // Marchen Vowel Sign U ..Marchen Vowel Sign E + {0x11cb5, 0x11cb6}, // Marchen Sign Anusvara ..Marchen Sign Candrabindu + {0x11d31, 0x11d36}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3a, 0x11d3a}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3c, 0x11d3d}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3f, 0x11d45}, // Masaram Gondi Vowel Sign..Masaram Gondi Virama + {0x11d47, 0x11d47}, // Masaram Gondi Ra-kara ..Masaram Gondi Ra-kara + {0x11d90, 0x11d91}, // Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign + {0x11d95, 0x11d95}, // Gunjala Gondi Sign Anusv..Gunjala Gondi Sign Anusv + {0x11d97, 0x11d97}, // Gunjala Gondi Virama ..Gunjala Gondi Virama + {0x11ef3, 0x11ef4}, // Makasar Vowel Sign I ..Makasar Vowel Sign U + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f4f, 0x16f4f}, // Miao Sign Consonant Modi..Miao Sign Consonant Modi + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e000, 0x1e006}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e008, 0x1e018}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e01b, 0x1e021}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e023, 0x1e024}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e026, 0x1e02a}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e130, 0x1e136}, // Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T + {0x1e2ec, 0x1e2ef}, // Wancho Tone Tup ..Wancho Tone Koini + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0x1e944, 0x1e94a}, // Adlam Alif Lengthener ..Adlam Nukta + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_12_1_0[] = { + // Source: DerivedGeneralCategory-12.1.0.txt + // Date: 2019-03-10, 10:53:08 GMT + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x007fd, 0x007fd}, // Nko Dantayalan ..Nko Dantayalan + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008d3, 0x008e1}, // Arabic Small Low Waw ..Arabic Small High Sign S + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x009fe, 0x009fe}, // Bengali Sandhi Mark ..Bengali Sandhi Mark + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00afa, 0x00aff}, // Gujarati Sign Sukun ..Gujarati Sign Two-circle + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b56, 0x00b56}, // Oriya Ai Length Mark ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c04, 0x00c04}, // Telugu Sign Combining An..Telugu Sign Combining An + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d00, 0x00d01}, // Malayalam Sign Combining..Malayalam Sign Candrabin + {0x00d3b, 0x00d3c}, // Malayalam Sign Vertical ..Malayalam Sign Circular + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00ebc}, // Lao Vowel Sign I ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x01885, 0x01886}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01abe}, // Combining Doubled Circum..Combining Parentheses Ov + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df9}, // Combining Dotted Grave A..Combining Wide Inverted + {0x01dfb, 0x01dff}, // Combining Deletion Mark ..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a8c4, 0x0a8c5}, // Saurashtra Sign Virama ..Saurashtra Sign Candrabi + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a8ff, 0x0a8ff}, // Devanagari Vowel Sign Ay..Devanagari Vowel Sign Ay + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bd}, // Javanese Vowel Sign Pepe..Javanese Consonant Sign + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x10d24, 0x10d27}, // Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas + {0x10f46, 0x10f50}, // Sogdian Combining Dot Be..Sogdian Combining Stroke + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111c9, 0x111cc}, // Sharada Sandhi Mark ..Sharada Extra Short Vowe + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x1123e, 0x1123e}, // Khojki Sign Sukun ..Khojki Sign Sukun + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133b, 0x1133c}, // Combining Bindu Below ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x11438, 0x1143f}, // Newa Vowel Sign U ..Newa Vowel Sign Ai + {0x11442, 0x11444}, // Newa Sign Virama ..Newa Sign Anusvara + {0x11446, 0x11446}, // Newa Sign Nukta ..Newa Sign Nukta + {0x1145e, 0x1145e}, // Newa Sandhi Mark ..Newa Sandhi Mark + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x1182f, 0x11837}, // Dogra Vowel Sign U ..Dogra Sign Anusvara + {0x11839, 0x1183a}, // Dogra Sign Virama ..Dogra Sign Nukta + {0x119d4, 0x119d7}, // Nandinagari Vowel Sign U..Nandinagari Vowel Sign V + {0x119da, 0x119db}, // Nandinagari Vowel Sign E..Nandinagari Vowel Sign A + {0x119e0, 0x119e0}, // Nandinagari Sign Virama ..Nandinagari Sign Virama + {0x11a01, 0x11a0a}, // Zanabazar Square Vowel S..Zanabazar Square Vowel L + {0x11a33, 0x11a38}, // Zanabazar Square Final C..Zanabazar Square Sign An + {0x11a3b, 0x11a3e}, // Zanabazar Square Cluster..Zanabazar Square Cluster + {0x11a47, 0x11a47}, // Zanabazar Square Subjoin..Zanabazar Square Subjoin + {0x11a51, 0x11a56}, // Soyombo Vowel Sign I ..Soyombo Vowel Sign Oe + {0x11a59, 0x11a5b}, // Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar + {0x11a8a, 0x11a96}, // Soyombo Final Consonant ..Soyombo Sign Anusvara + {0x11a98, 0x11a99}, // Soyombo Gemination Mark ..Soyombo Subjoiner + {0x11c30, 0x11c36}, // Bhaiksuki Vowel Sign I ..Bhaiksuki Vowel Sign Voc + {0x11c38, 0x11c3d}, // Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Anusvara + {0x11c3f, 0x11c3f}, // Bhaiksuki Sign Virama ..Bhaiksuki Sign Virama + {0x11c92, 0x11ca7}, // Marchen Subjoined Letter..Marchen Subjoined Letter + {0x11caa, 0x11cb0}, // Marchen Subjoined Letter..Marchen Vowel Sign Aa + {0x11cb2, 0x11cb3}, // Marchen Vowel Sign U ..Marchen Vowel Sign E + {0x11cb5, 0x11cb6}, // Marchen Sign Anusvara ..Marchen Sign Candrabindu + {0x11d31, 0x11d36}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3a, 0x11d3a}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3c, 0x11d3d}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3f, 0x11d45}, // Masaram Gondi Vowel Sign..Masaram Gondi Virama + {0x11d47, 0x11d47}, // Masaram Gondi Ra-kara ..Masaram Gondi Ra-kara + {0x11d90, 0x11d91}, // Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign + {0x11d95, 0x11d95}, // Gunjala Gondi Sign Anusv..Gunjala Gondi Sign Anusv + {0x11d97, 0x11d97}, // Gunjala Gondi Virama ..Gunjala Gondi Virama + {0x11ef3, 0x11ef4}, // Makasar Vowel Sign I ..Makasar Vowel Sign U + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f4f, 0x16f4f}, // Miao Sign Consonant Modi..Miao Sign Consonant Modi + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e000, 0x1e006}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e008, 0x1e018}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e01b, 0x1e021}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e023, 0x1e024}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e026, 0x1e02a}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e130, 0x1e136}, // Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T + {0x1e2ec, 0x1e2ef}, // Wancho Tone Tup ..Wancho Tone Koini + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0x1e944, 0x1e94a}, // Adlam Alif Lengthener ..Adlam Nukta + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + +static const struct width_interval +zero_13_0_0[] = { + // Source: DerivedGeneralCategory-13.0.0.txt + // Date: 2019-10-21, 14:30:32 GMT + // + {0x00300, 0x0036f}, // Combining Grave Accent ..Combining Latin Small Le + {0x00483, 0x00489}, // Combining Cyrillic Titlo..Combining Cyrillic Milli + {0x00591, 0x005bd}, // Hebrew Accent Etnahta ..Hebrew Point Meteg + {0x005bf, 0x005bf}, // Hebrew Point Rafe ..Hebrew Point Rafe + {0x005c1, 0x005c2}, // Hebrew Point Shin Dot ..Hebrew Point Sin Dot + {0x005c4, 0x005c5}, // Hebrew Mark Upper Dot ..Hebrew Mark Lower Dot + {0x005c7, 0x005c7}, // Hebrew Point Qamats Qata..Hebrew Point Qamats Qata + {0x00610, 0x0061a}, // Arabic Sign Sallallahou ..Arabic Small Kasra + {0x0064b, 0x0065f}, // Arabic Fathatan ..Arabic Wavy Hamza Below + {0x00670, 0x00670}, // Arabic Letter Superscrip..Arabic Letter Superscrip + {0x006d6, 0x006dc}, // Arabic Small High Ligatu..Arabic Small High Seen + {0x006df, 0x006e4}, // Arabic Small High Rounde..Arabic Small High Madda + {0x006e7, 0x006e8}, // Arabic Small High Yeh ..Arabic Small High Noon + {0x006ea, 0x006ed}, // Arabic Empty Centre Low ..Arabic Small Low Meem + {0x00711, 0x00711}, // Syriac Letter Superscrip..Syriac Letter Superscrip + {0x00730, 0x0074a}, // Syriac Pthaha Above ..Syriac Barrekh + {0x007a6, 0x007b0}, // Thaana Abafili ..Thaana Sukun + {0x007eb, 0x007f3}, // Nko Combining Short High..Nko Combining Double Dot + {0x007fd, 0x007fd}, // Nko Dantayalan ..Nko Dantayalan + {0x00816, 0x00819}, // Samaritan Mark In ..Samaritan Mark Dagesh + {0x0081b, 0x00823}, // Samaritan Mark Epentheti..Samaritan Vowel Sign A + {0x00825, 0x00827}, // Samaritan Vowel Sign Sho..Samaritan Vowel Sign U + {0x00829, 0x0082d}, // Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa + {0x00859, 0x0085b}, // Mandaic Affrication Mark..Mandaic Gemination Mark + {0x008d3, 0x008e1}, // Arabic Small Low Waw ..Arabic Small High Sign S + {0x008e3, 0x00902}, // Arabic Turned Damma Belo..Devanagari Sign Anusvara + {0x0093a, 0x0093a}, // Devanagari Vowel Sign Oe..Devanagari Vowel Sign Oe + {0x0093c, 0x0093c}, // Devanagari Sign Nukta ..Devanagari Sign Nukta + {0x00941, 0x00948}, // Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai + {0x0094d, 0x0094d}, // Devanagari Sign Virama ..Devanagari Sign Virama + {0x00951, 0x00957}, // Devanagari Stress Sign U..Devanagari Vowel Sign Uu + {0x00962, 0x00963}, // Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo + {0x00981, 0x00981}, // Bengali Sign Candrabindu..Bengali Sign Candrabindu + {0x009bc, 0x009bc}, // Bengali Sign Nukta ..Bengali Sign Nukta + {0x009c1, 0x009c4}, // Bengali Vowel Sign U ..Bengali Vowel Sign Vocal + {0x009cd, 0x009cd}, // Bengali Sign Virama ..Bengali Sign Virama + {0x009e2, 0x009e3}, // Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal + {0x009fe, 0x009fe}, // Bengali Sandhi Mark ..Bengali Sandhi Mark + {0x00a01, 0x00a02}, // Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi + {0x00a3c, 0x00a3c}, // Gurmukhi Sign Nukta ..Gurmukhi Sign Nukta + {0x00a41, 0x00a42}, // Gurmukhi Vowel Sign U ..Gurmukhi Vowel Sign Uu + {0x00a47, 0x00a48}, // Gurmukhi Vowel Sign Ee ..Gurmukhi Vowel Sign Ai + {0x00a4b, 0x00a4d}, // Gurmukhi Vowel Sign Oo ..Gurmukhi Sign Virama + {0x00a51, 0x00a51}, // Gurmukhi Sign Udaat ..Gurmukhi Sign Udaat + {0x00a70, 0x00a71}, // Gurmukhi Tippi ..Gurmukhi Addak + {0x00a75, 0x00a75}, // Gurmukhi Sign Yakash ..Gurmukhi Sign Yakash + {0x00a81, 0x00a82}, // Gujarati Sign Candrabind..Gujarati Sign Anusvara + {0x00abc, 0x00abc}, // Gujarati Sign Nukta ..Gujarati Sign Nukta + {0x00ac1, 0x00ac5}, // Gujarati Vowel Sign U ..Gujarati Vowel Sign Cand + {0x00ac7, 0x00ac8}, // Gujarati Vowel Sign E ..Gujarati Vowel Sign Ai + {0x00acd, 0x00acd}, // Gujarati Sign Virama ..Gujarati Sign Virama + {0x00ae2, 0x00ae3}, // Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca + {0x00afa, 0x00aff}, // Gujarati Sign Sukun ..Gujarati Sign Two-circle + {0x00b01, 0x00b01}, // Oriya Sign Candrabindu ..Oriya Sign Candrabindu + {0x00b3c, 0x00b3c}, // Oriya Sign Nukta ..Oriya Sign Nukta + {0x00b3f, 0x00b3f}, // Oriya Vowel Sign I ..Oriya Vowel Sign I + {0x00b41, 0x00b44}, // Oriya Vowel Sign U ..Oriya Vowel Sign Vocalic + {0x00b4d, 0x00b4d}, // Oriya Sign Virama ..Oriya Sign Virama + {0x00b55, 0x00b56}, // (nil) ..Oriya Ai Length Mark + {0x00b62, 0x00b63}, // Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic + {0x00b82, 0x00b82}, // Tamil Sign Anusvara ..Tamil Sign Anusvara + {0x00bc0, 0x00bc0}, // Tamil Vowel Sign Ii ..Tamil Vowel Sign Ii + {0x00bcd, 0x00bcd}, // Tamil Sign Virama ..Tamil Sign Virama + {0x00c00, 0x00c00}, // Telugu Sign Combining Ca..Telugu Sign Combining Ca + {0x00c04, 0x00c04}, // Telugu Sign Combining An..Telugu Sign Combining An + {0x00c3e, 0x00c40}, // Telugu Vowel Sign Aa ..Telugu Vowel Sign Ii + {0x00c46, 0x00c48}, // Telugu Vowel Sign E ..Telugu Vowel Sign Ai + {0x00c4a, 0x00c4d}, // Telugu Vowel Sign O ..Telugu Sign Virama + {0x00c55, 0x00c56}, // Telugu Length Mark ..Telugu Ai Length Mark + {0x00c62, 0x00c63}, // Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali + {0x00c81, 0x00c81}, // Kannada Sign Candrabindu..Kannada Sign Candrabindu + {0x00cbc, 0x00cbc}, // Kannada Sign Nukta ..Kannada Sign Nukta + {0x00cbf, 0x00cbf}, // Kannada Vowel Sign I ..Kannada Vowel Sign I + {0x00cc6, 0x00cc6}, // Kannada Vowel Sign E ..Kannada Vowel Sign E + {0x00ccc, 0x00ccd}, // Kannada Vowel Sign Au ..Kannada Sign Virama + {0x00ce2, 0x00ce3}, // Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal + {0x00d00, 0x00d01}, // Malayalam Sign Combining..Malayalam Sign Candrabin + {0x00d3b, 0x00d3c}, // Malayalam Sign Vertical ..Malayalam Sign Circular + {0x00d41, 0x00d44}, // Malayalam Vowel Sign U ..Malayalam Vowel Sign Voc + {0x00d4d, 0x00d4d}, // Malayalam Sign Virama ..Malayalam Sign Virama + {0x00d62, 0x00d63}, // Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc + {0x00d81, 0x00d81}, // (nil) ..(nil) + {0x00dca, 0x00dca}, // Sinhala Sign Al-lakuna ..Sinhala Sign Al-lakuna + {0x00dd2, 0x00dd4}, // Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti + {0x00dd6, 0x00dd6}, // Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga + {0x00e31, 0x00e31}, // Thai Character Mai Han-a..Thai Character Mai Han-a + {0x00e34, 0x00e3a}, // Thai Character Sara I ..Thai Character Phinthu + {0x00e47, 0x00e4e}, // Thai Character Maitaikhu..Thai Character Yamakkan + {0x00eb1, 0x00eb1}, // Lao Vowel Sign Mai Kan ..Lao Vowel Sign Mai Kan + {0x00eb4, 0x00ebc}, // Lao Vowel Sign I ..Lao Semivowel Sign Lo + {0x00ec8, 0x00ecd}, // Lao Tone Mai Ek ..Lao Niggahita + {0x00f18, 0x00f19}, // Tibetan Astrological Sig..Tibetan Astrological Sig + {0x00f35, 0x00f35}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f37, 0x00f37}, // Tibetan Mark Ngas Bzung ..Tibetan Mark Ngas Bzung + {0x00f39, 0x00f39}, // Tibetan Mark Tsa -phru ..Tibetan Mark Tsa -phru + {0x00f71, 0x00f7e}, // Tibetan Vowel Sign Aa ..Tibetan Sign Rjes Su Nga + {0x00f80, 0x00f84}, // Tibetan Vowel Sign Rever..Tibetan Mark Halanta + {0x00f86, 0x00f87}, // Tibetan Sign Lci Rtags ..Tibetan Sign Yang Rtags + {0x00f8d, 0x00f97}, // Tibetan Subjoined Sign L..Tibetan Subjoined Letter + {0x00f99, 0x00fbc}, // Tibetan Subjoined Letter..Tibetan Subjoined Letter + {0x00fc6, 0x00fc6}, // Tibetan Symbol Padma Gda..Tibetan Symbol Padma Gda + {0x0102d, 0x01030}, // Myanmar Vowel Sign I ..Myanmar Vowel Sign Uu + {0x01032, 0x01037}, // Myanmar Vowel Sign Ai ..Myanmar Sign Dot Below + {0x01039, 0x0103a}, // Myanmar Sign Virama ..Myanmar Sign Asat + {0x0103d, 0x0103e}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01058, 0x01059}, // Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal + {0x0105e, 0x01060}, // Myanmar Consonant Sign M..Myanmar Consonant Sign M + {0x01071, 0x01074}, // Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah + {0x01082, 0x01082}, // Myanmar Consonant Sign S..Myanmar Consonant Sign S + {0x01085, 0x01086}, // Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan + {0x0108d, 0x0108d}, // Myanmar Sign Shan Counci..Myanmar Sign Shan Counci + {0x0109d, 0x0109d}, // Myanmar Vowel Sign Aiton..Myanmar Vowel Sign Aiton + {0x0135d, 0x0135f}, // Ethiopic Combining Gemin..Ethiopic Combining Gemin + {0x01712, 0x01714}, // Tagalog Vowel Sign I ..Tagalog Sign Virama + {0x01732, 0x01734}, // Hanunoo Vowel Sign I ..Hanunoo Sign Pamudpod + {0x01752, 0x01753}, // Buhid Vowel Sign I ..Buhid Vowel Sign U + {0x01772, 0x01773}, // Tagbanwa Vowel Sign I ..Tagbanwa Vowel Sign U + {0x017b4, 0x017b5}, // Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa + {0x017b7, 0x017bd}, // Khmer Vowel Sign I ..Khmer Vowel Sign Ua + {0x017c6, 0x017c6}, // Khmer Sign Nikahit ..Khmer Sign Nikahit + {0x017c9, 0x017d3}, // Khmer Sign Muusikatoan ..Khmer Sign Bathamasat + {0x017dd, 0x017dd}, // Khmer Sign Atthacan ..Khmer Sign Atthacan + {0x0180b, 0x0180d}, // Mongolian Free Variation..Mongolian Free Variation + {0x01885, 0x01886}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x018a9, 0x018a9}, // Mongolian Letter Ali Gal..Mongolian Letter Ali Gal + {0x01920, 0x01922}, // Limbu Vowel Sign A ..Limbu Vowel Sign U + {0x01927, 0x01928}, // Limbu Vowel Sign E ..Limbu Vowel Sign O + {0x01932, 0x01932}, // Limbu Small Letter Anusv..Limbu Small Letter Anusv + {0x01939, 0x0193b}, // Limbu Sign Mukphreng ..Limbu Sign Sa-i + {0x01a17, 0x01a18}, // Buginese Vowel Sign I ..Buginese Vowel Sign U + {0x01a1b, 0x01a1b}, // Buginese Vowel Sign Ae ..Buginese Vowel Sign Ae + {0x01a56, 0x01a56}, // Tai Tham Consonant Sign ..Tai Tham Consonant Sign + {0x01a58, 0x01a5e}, // Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign + {0x01a60, 0x01a60}, // Tai Tham Sign Sakot ..Tai Tham Sign Sakot + {0x01a62, 0x01a62}, // Tai Tham Vowel Sign Mai ..Tai Tham Vowel Sign Mai + {0x01a65, 0x01a6c}, // Tai Tham Vowel Sign I ..Tai Tham Vowel Sign Oa B + {0x01a73, 0x01a7c}, // Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue + {0x01a7f, 0x01a7f}, // Tai Tham Combining Crypt..Tai Tham Combining Crypt + {0x01ab0, 0x01ac0}, // Combining Doubled Circum..(nil) + {0x01b00, 0x01b03}, // Balinese Sign Ulu Ricem ..Balinese Sign Surang + {0x01b34, 0x01b34}, // Balinese Sign Rerekan ..Balinese Sign Rerekan + {0x01b36, 0x01b3a}, // Balinese Vowel Sign Ulu ..Balinese Vowel Sign Ra R + {0x01b3c, 0x01b3c}, // Balinese Vowel Sign La L..Balinese Vowel Sign La L + {0x01b42, 0x01b42}, // Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe + {0x01b6b, 0x01b73}, // Balinese Musical Symbol ..Balinese Musical Symbol + {0x01b80, 0x01b81}, // Sundanese Sign Panyecek ..Sundanese Sign Panglayar + {0x01ba2, 0x01ba5}, // Sundanese Consonant Sign..Sundanese Vowel Sign Pan + {0x01ba8, 0x01ba9}, // Sundanese Vowel Sign Pam..Sundanese Vowel Sign Pan + {0x01bab, 0x01bad}, // Sundanese Sign Virama ..Sundanese Consonant Sign + {0x01be6, 0x01be6}, // Batak Sign Tompi ..Batak Sign Tompi + {0x01be8, 0x01be9}, // Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee + {0x01bed, 0x01bed}, // Batak Vowel Sign Karo O ..Batak Vowel Sign Karo O + {0x01bef, 0x01bf1}, // Batak Vowel Sign U For S..Batak Consonant Sign H + {0x01c2c, 0x01c33}, // Lepcha Vowel Sign E ..Lepcha Consonant Sign T + {0x01c36, 0x01c37}, // Lepcha Sign Ran ..Lepcha Sign Nukta + {0x01cd0, 0x01cd2}, // Vedic Tone Karshana ..Vedic Tone Prenkha + {0x01cd4, 0x01ce0}, // Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash + {0x01ce2, 0x01ce8}, // Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda + {0x01ced, 0x01ced}, // Vedic Sign Tiryak ..Vedic Sign Tiryak + {0x01cf4, 0x01cf4}, // Vedic Tone Candra Above ..Vedic Tone Candra Above + {0x01cf8, 0x01cf9}, // Vedic Tone Ring Above ..Vedic Tone Double Ring A + {0x01dc0, 0x01df9}, // Combining Dotted Grave A..Combining Wide Inverted + {0x01dfb, 0x01dff}, // Combining Deletion Mark ..Combining Right Arrowhea + {0x020d0, 0x020f0}, // Combining Left Harpoon A..Combining Asterisk Above + {0x02cef, 0x02cf1}, // Coptic Combining Ni Abov..Coptic Combining Spiritu + {0x02d7f, 0x02d7f}, // Tifinagh Consonant Joine..Tifinagh Consonant Joine + {0x02de0, 0x02dff}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0302a, 0x0302d}, // Ideographic Level Tone M..Ideographic Entering Ton + {0x03099, 0x0309a}, // Combining Katakana-hirag..Combining Katakana-hirag + {0x0a66f, 0x0a672}, // Combining Cyrillic Vzmet..Combining Cyrillic Thous + {0x0a674, 0x0a67d}, // Combining Cyrillic Lette..Combining Cyrillic Payer + {0x0a69e, 0x0a69f}, // Combining Cyrillic Lette..Combining Cyrillic Lette + {0x0a6f0, 0x0a6f1}, // Bamum Combining Mark Koq..Bamum Combining Mark Tuk + {0x0a802, 0x0a802}, // Syloti Nagri Sign Dvisva..Syloti Nagri Sign Dvisva + {0x0a806, 0x0a806}, // Syloti Nagri Sign Hasant..Syloti Nagri Sign Hasant + {0x0a80b, 0x0a80b}, // Syloti Nagri Sign Anusva..Syloti Nagri Sign Anusva + {0x0a825, 0x0a826}, // Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign + {0x0a82c, 0x0a82c}, // (nil) ..(nil) + {0x0a8c4, 0x0a8c5}, // Saurashtra Sign Virama ..Saurashtra Sign Candrabi + {0x0a8e0, 0x0a8f1}, // Combining Devanagari Dig..Combining Devanagari Sig + {0x0a8ff, 0x0a8ff}, // Devanagari Vowel Sign Ay..Devanagari Vowel Sign Ay + {0x0a926, 0x0a92d}, // Kayah Li Vowel Ue ..Kayah Li Tone Calya Plop + {0x0a947, 0x0a951}, // Rejang Vowel Sign I ..Rejang Consonant Sign R + {0x0a980, 0x0a982}, // Javanese Sign Panyangga ..Javanese Sign Layar + {0x0a9b3, 0x0a9b3}, // Javanese Sign Cecak Telu..Javanese Sign Cecak Telu + {0x0a9b6, 0x0a9b9}, // Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku + {0x0a9bc, 0x0a9bd}, // Javanese Vowel Sign Pepe..Javanese Consonant Sign + {0x0a9e5, 0x0a9e5}, // Myanmar Sign Shan Saw ..Myanmar Sign Shan Saw + {0x0aa29, 0x0aa2e}, // Cham Vowel Sign Aa ..Cham Vowel Sign Oe + {0x0aa31, 0x0aa32}, // Cham Vowel Sign Au ..Cham Vowel Sign Ue + {0x0aa35, 0x0aa36}, // Cham Consonant Sign La ..Cham Consonant Sign Wa + {0x0aa43, 0x0aa43}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa4c, 0x0aa4c}, // Cham Consonant Sign Fina..Cham Consonant Sign Fina + {0x0aa7c, 0x0aa7c}, // Myanmar Sign Tai Laing T..Myanmar Sign Tai Laing T + {0x0aab0, 0x0aab0}, // Tai Viet Mai Kang ..Tai Viet Mai Kang + {0x0aab2, 0x0aab4}, // Tai Viet Vowel I ..Tai Viet Vowel U + {0x0aab7, 0x0aab8}, // Tai Viet Mai Khit ..Tai Viet Vowel Ia + {0x0aabe, 0x0aabf}, // Tai Viet Vowel Am ..Tai Viet Tone Mai Ek + {0x0aac1, 0x0aac1}, // Tai Viet Tone Mai Tho ..Tai Viet Tone Mai Tho + {0x0aaec, 0x0aaed}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0aaf6, 0x0aaf6}, // Meetei Mayek Virama ..Meetei Mayek Virama + {0x0abe5, 0x0abe5}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abe8, 0x0abe8}, // Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign + {0x0abed, 0x0abed}, // Meetei Mayek Apun Iyek ..Meetei Mayek Apun Iyek + {0x0fb1e, 0x0fb1e}, // Hebrew Point Judeo-spani..Hebrew Point Judeo-spani + {0x0fe00, 0x0fe0f}, // Variation Selector-1 ..Variation Selector-16 + {0x0fe20, 0x0fe2f}, // Combining Ligature Left ..Combining Cyrillic Titlo + {0x101fd, 0x101fd}, // Phaistos Disc Sign Combi..Phaistos Disc Sign Combi + {0x102e0, 0x102e0}, // Coptic Epact Thousands M..Coptic Epact Thousands M + {0x10376, 0x1037a}, // Combining Old Permic Let..Combining Old Permic Let + {0x10a01, 0x10a03}, // Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo + {0x10a05, 0x10a06}, // Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O + {0x10a0c, 0x10a0f}, // Kharoshthi Vowel Length ..Kharoshthi Sign Visarga + {0x10a38, 0x10a3a}, // Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo + {0x10a3f, 0x10a3f}, // Kharoshthi Virama ..Kharoshthi Virama + {0x10ae5, 0x10ae6}, // Manichaean Abbreviation ..Manichaean Abbreviation + {0x10d24, 0x10d27}, // Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas + {0x10eab, 0x10eac}, // (nil) ..(nil) + {0x10f46, 0x10f50}, // Sogdian Combining Dot Be..Sogdian Combining Stroke + {0x11001, 0x11001}, // Brahmi Sign Anusvara ..Brahmi Sign Anusvara + {0x11038, 0x11046}, // Brahmi Vowel Sign Aa ..Brahmi Virama + {0x1107f, 0x11081}, // Brahmi Number Joiner ..Kaithi Sign Anusvara + {0x110b3, 0x110b6}, // Kaithi Vowel Sign U ..Kaithi Vowel Sign Ai + {0x110b9, 0x110ba}, // Kaithi Sign Virama ..Kaithi Sign Nukta + {0x11100, 0x11102}, // Chakma Sign Candrabindu ..Chakma Sign Visarga + {0x11127, 0x1112b}, // Chakma Vowel Sign A ..Chakma Vowel Sign Uu + {0x1112d, 0x11134}, // Chakma Vowel Sign Ai ..Chakma Maayyaa + {0x11173, 0x11173}, // Mahajani Sign Nukta ..Mahajani Sign Nukta + {0x11180, 0x11181}, // Sharada Sign Candrabindu..Sharada Sign Anusvara + {0x111b6, 0x111be}, // Sharada Vowel Sign U ..Sharada Vowel Sign O + {0x111c9, 0x111cc}, // Sharada Sandhi Mark ..Sharada Extra Short Vowe + {0x111cf, 0x111cf}, // (nil) ..(nil) + {0x1122f, 0x11231}, // Khojki Vowel Sign U ..Khojki Vowel Sign Ai + {0x11234, 0x11234}, // Khojki Sign Anusvara ..Khojki Sign Anusvara + {0x11236, 0x11237}, // Khojki Sign Nukta ..Khojki Sign Shadda + {0x1123e, 0x1123e}, // Khojki Sign Sukun ..Khojki Sign Sukun + {0x112df, 0x112df}, // Khudawadi Sign Anusvara ..Khudawadi Sign Anusvara + {0x112e3, 0x112ea}, // Khudawadi Vowel Sign U ..Khudawadi Sign Virama + {0x11300, 0x11301}, // Grantha Sign Combining A..Grantha Sign Candrabindu + {0x1133b, 0x1133c}, // Combining Bindu Below ..Grantha Sign Nukta + {0x11340, 0x11340}, // Grantha Vowel Sign Ii ..Grantha Vowel Sign Ii + {0x11366, 0x1136c}, // Combining Grantha Digit ..Combining Grantha Digit + {0x11370, 0x11374}, // Combining Grantha Letter..Combining Grantha Letter + {0x11438, 0x1143f}, // Newa Vowel Sign U ..Newa Vowel Sign Ai + {0x11442, 0x11444}, // Newa Sign Virama ..Newa Sign Anusvara + {0x11446, 0x11446}, // Newa Sign Nukta ..Newa Sign Nukta + {0x1145e, 0x1145e}, // Newa Sandhi Mark ..Newa Sandhi Mark + {0x114b3, 0x114b8}, // Tirhuta Vowel Sign U ..Tirhuta Vowel Sign Vocal + {0x114ba, 0x114ba}, // Tirhuta Vowel Sign Short..Tirhuta Vowel Sign Short + {0x114bf, 0x114c0}, // Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara + {0x114c2, 0x114c3}, // Tirhuta Sign Virama ..Tirhuta Sign Nukta + {0x115b2, 0x115b5}, // Siddham Vowel Sign U ..Siddham Vowel Sign Vocal + {0x115bc, 0x115bd}, // Siddham Sign Candrabindu..Siddham Sign Anusvara + {0x115bf, 0x115c0}, // Siddham Sign Virama ..Siddham Sign Nukta + {0x115dc, 0x115dd}, // Siddham Vowel Sign Alter..Siddham Vowel Sign Alter + {0x11633, 0x1163a}, // Modi Vowel Sign U ..Modi Vowel Sign Ai + {0x1163d, 0x1163d}, // Modi Sign Anusvara ..Modi Sign Anusvara + {0x1163f, 0x11640}, // Modi Sign Virama ..Modi Sign Ardhacandra + {0x116ab, 0x116ab}, // Takri Sign Anusvara ..Takri Sign Anusvara + {0x116ad, 0x116ad}, // Takri Vowel Sign Aa ..Takri Vowel Sign Aa + {0x116b0, 0x116b5}, // Takri Vowel Sign U ..Takri Vowel Sign Au + {0x116b7, 0x116b7}, // Takri Sign Nukta ..Takri Sign Nukta + {0x1171d, 0x1171f}, // Ahom Consonant Sign Medi..Ahom Consonant Sign Medi + {0x11722, 0x11725}, // Ahom Vowel Sign I ..Ahom Vowel Sign Uu + {0x11727, 0x1172b}, // Ahom Vowel Sign Aw ..Ahom Sign Killer + {0x1182f, 0x11837}, // Dogra Vowel Sign U ..Dogra Sign Anusvara + {0x11839, 0x1183a}, // Dogra Sign Virama ..Dogra Sign Nukta + {0x1193b, 0x1193c}, // (nil) ..(nil) + {0x1193e, 0x1193e}, // (nil) ..(nil) + {0x11943, 0x11943}, // (nil) ..(nil) + {0x119d4, 0x119d7}, // Nandinagari Vowel Sign U..Nandinagari Vowel Sign V + {0x119da, 0x119db}, // Nandinagari Vowel Sign E..Nandinagari Vowel Sign A + {0x119e0, 0x119e0}, // Nandinagari Sign Virama ..Nandinagari Sign Virama + {0x11a01, 0x11a0a}, // Zanabazar Square Vowel S..Zanabazar Square Vowel L + {0x11a33, 0x11a38}, // Zanabazar Square Final C..Zanabazar Square Sign An + {0x11a3b, 0x11a3e}, // Zanabazar Square Cluster..Zanabazar Square Cluster + {0x11a47, 0x11a47}, // Zanabazar Square Subjoin..Zanabazar Square Subjoin + {0x11a51, 0x11a56}, // Soyombo Vowel Sign I ..Soyombo Vowel Sign Oe + {0x11a59, 0x11a5b}, // Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar + {0x11a8a, 0x11a96}, // Soyombo Final Consonant ..Soyombo Sign Anusvara + {0x11a98, 0x11a99}, // Soyombo Gemination Mark ..Soyombo Subjoiner + {0x11c30, 0x11c36}, // Bhaiksuki Vowel Sign I ..Bhaiksuki Vowel Sign Voc + {0x11c38, 0x11c3d}, // Bhaiksuki Vowel Sign E ..Bhaiksuki Sign Anusvara + {0x11c3f, 0x11c3f}, // Bhaiksuki Sign Virama ..Bhaiksuki Sign Virama + {0x11c92, 0x11ca7}, // Marchen Subjoined Letter..Marchen Subjoined Letter + {0x11caa, 0x11cb0}, // Marchen Subjoined Letter..Marchen Vowel Sign Aa + {0x11cb2, 0x11cb3}, // Marchen Vowel Sign U ..Marchen Vowel Sign E + {0x11cb5, 0x11cb6}, // Marchen Sign Anusvara ..Marchen Sign Candrabindu + {0x11d31, 0x11d36}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3a, 0x11d3a}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3c, 0x11d3d}, // Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign + {0x11d3f, 0x11d45}, // Masaram Gondi Vowel Sign..Masaram Gondi Virama + {0x11d47, 0x11d47}, // Masaram Gondi Ra-kara ..Masaram Gondi Ra-kara + {0x11d90, 0x11d91}, // Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign + {0x11d95, 0x11d95}, // Gunjala Gondi Sign Anusv..Gunjala Gondi Sign Anusv + {0x11d97, 0x11d97}, // Gunjala Gondi Virama ..Gunjala Gondi Virama + {0x11ef3, 0x11ef4}, // Makasar Vowel Sign I ..Makasar Vowel Sign U + {0x16af0, 0x16af4}, // Bassa Vah Combining High..Bassa Vah Combining High + {0x16b30, 0x16b36}, // Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta + {0x16f4f, 0x16f4f}, // Miao Sign Consonant Modi..Miao Sign Consonant Modi + {0x16f8f, 0x16f92}, // Miao Tone Right ..Miao Tone Below + {0x16fe4, 0x16fe4}, // (nil) ..(nil) + {0x1bc9d, 0x1bc9e}, // Duployan Thick Letter Se..Duployan Double Mark + {0x1d167, 0x1d169}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d17b, 0x1d182}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d185, 0x1d18b}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d1aa, 0x1d1ad}, // Musical Symbol Combining..Musical Symbol Combining + {0x1d242, 0x1d244}, // Combining Greek Musical ..Combining Greek Musical + {0x1da00, 0x1da36}, // Signwriting Head Rim ..Signwriting Air Sucking + {0x1da3b, 0x1da6c}, // Signwriting Mouth Closed..Signwriting Excitement + {0x1da75, 0x1da75}, // Signwriting Upper Body T..Signwriting Upper Body T + {0x1da84, 0x1da84}, // Signwriting Location Hea..Signwriting Location Hea + {0x1da9b, 0x1da9f}, // Signwriting Fill Modifie..Signwriting Fill Modifie + {0x1daa1, 0x1daaf}, // Signwriting Rotation Mod..Signwriting Rotation Mod + {0x1e000, 0x1e006}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e008, 0x1e018}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e01b, 0x1e021}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e023, 0x1e024}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e026, 0x1e02a}, // Combining Glagolitic Let..Combining Glagolitic Let + {0x1e130, 0x1e136}, // Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T + {0x1e2ec, 0x1e2ef}, // Wancho Tone Tup ..Wancho Tone Koini + {0x1e8d0, 0x1e8d6}, // Mende Kikakui Combining ..Mende Kikakui Combining + {0x1e944, 0x1e94a}, // Adlam Alif Lengthener ..Adlam Nukta + {0xe0100, 0xe01ef}, // Variation Selector-17 ..Variation Selector-256 + }; + diff --git a/libwidechar/ucswidth.c b/libwidechar/ucswidth.c new file mode 100644 index 00000000..b36c4b27 --- /dev/null +++ b/libwidechar/ucswidth.c @@ -0,0 +1,205 @@ +#include +__CIDENT_RCSID(gr_wcwidth_c,"$Id: ucswidth.c,v 1.2 2021/07/05 15:40:38 cvsuser Exp $") + +/* + ------------------------------------------------------------------------------ + The MIT License (MIT) + + Copyright (c) 2014 Jeff Quast + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + ------------------------------------------------------------------------------ + + Markus Kuhn -- 2007-05-26 (Unicode 5.0) + + Permission to use, copy, modify, and distribute this software + for any purpose and without fee is hereby granted. The author + disclaims all warranties with regard to this software. + + ------------------------------------------------------------------------------ + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#if defined(HAVE_WCHAR_H) +#if defined(HAVE_WCWIDTH) +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 1 +#endif +#endif + +#include +#include "widechar.h" + +#if defined(HAVE_WCHAR_H) +#if defined(HAVE_WCWIDTH) +#include +#endif +#endif + +struct width_interval { + int start; + int end; +}; + +#include "table_wide.h" +#include "table_zero.h" + +#define _elementsof(__type) (sizeof(__type)/sizeof(__type[0])) + +struct width_version { + const char *label; + unsigned long value; + const struct width_interval *zero; + int zero_elements; + const struct width_interval *width; + int width_elements; +}; + + +static const struct width_version +VERSIONS[] = { + { "4.1.0", 40100, zero_4_1_0, _elementsof(zero_4_1_0), width_4_1_0, _elementsof(width_4_1_0) }, + { "5.0.0", 50000, zero_5_0_0, _elementsof(zero_5_0_0), width_5_0_0, _elementsof(width_5_0_0) }, + { "5.1.0", 50100, zero_5_1_0, _elementsof(zero_5_1_0), width_5_1_0, _elementsof(width_5_1_0) }, + { "5.2.0", 50200, zero_5_2_0, _elementsof(zero_5_2_0), width_5_2_0, _elementsof(width_5_2_0) }, + { "6.0.0", 60000, zero_6_0_0, _elementsof(zero_6_0_0), width_6_0_0, _elementsof(width_6_0_0) }, + { "6.1.0", 60100, zero_6_1_0, _elementsof(zero_6_1_0), width_6_1_0, _elementsof(width_6_1_0) }, + { "6.2.0", 60200, zero_6_2_0, _elementsof(zero_6_2_0), width_6_2_0, _elementsof(width_6_2_0) }, + { "6.3.0", 60300, zero_6_3_0, _elementsof(zero_6_3_0), width_6_3_0, _elementsof(width_6_3_0) }, + { "7.0.0", 70000, zero_7_0_0, _elementsof(zero_7_0_0), width_7_0_0, _elementsof(width_7_0_0) }, + { "8.0.0", 80000, zero_8_0_0, _elementsof(zero_8_0_0), width_8_0_0, _elementsof(width_8_0_0) }, + { "9.0.0", 90000, zero_9_0_0, _elementsof(zero_9_0_0), width_9_0_0, _elementsof(width_9_0_0) }, + { "10.0.0", 100000, zero_10_0_0, _elementsof(zero_10_0_0), width_10_0_0, _elementsof(width_10_0_0) }, + { "11.0.0", 110000, zero_11_0_0, _elementsof(zero_11_0_0), width_11_0_0, _elementsof(width_11_0_0) }, + { "12.1.0", 120100, zero_12_1_0, _elementsof(zero_12_1_0), width_12_1_0, _elementsof(width_12_1_0) }, + { "13.0.0", 130000, zero_13_0_0, _elementsof(zero_13_0_0), width_13_0_0, _elementsof(width_13_0_0) } + }; + +static const struct width_version *version = VERSIONS + (_elementsof(VERSIONS) - 1); + + +static int intable(const struct width_interval *table, int table_length, int c) { + // Binary search in table. + int bot = 0; + int top = table_length - 1; + + // First quick check for Latin1 etc. characters. + if (c < table[0].start) return false; + + while (top >= bot) { + int mid = (bot + top) / 2; + if (table[mid].end < c) { + bot = mid + 1; + } else if (table[mid].start > c) { + top = mid - 1; + } else { + return true; + } + } + return false; +} + + +int +ucs_width_set(const char *label) +{ + if (label) { + const struct width_version *cursor, + *end = VERSIONS + _elementsof(VERSIONS); + unsigned a = 0, b = 0, c = 0; + + if (0 == strcmp(label, "system")) { +#if defined(HAVE_WCWIDTH) + version = NULL; + return 1; +#else + return -1; +#endif + + } + + for (cursor = VERSIONS; cursor != end; ++cursor) { + if (0 == strcmp(label, cursor->label)) { //match + version = cursor; + return version->value; + } + } + + if (sscanf(label, "%2u.%2u.%2u", &a, &b, &c) >= 1) { //closest match + const unsigned value = (a * 10000) + (b * 100) + c; + if (value) { + for (cursor = end; cursor-- != VERSIONS;) { + if (value >= cursor->value) { + version = cursor; + return version->value; + } + } + } + } + } + return 0; +} + + +const char * +ucs_width_version(void) +{ + return version->label; +} + + +int +ucs_width(int32_t ucs) +{ +#if defined(HAVE_WCWIDTH) + // Behavior of wcwidth() depends on the LC_CTYPE category of the current locale. + if (NULL == version) { + return wcwidth(ucs); + } +#endif + + // NOTE: created by hand, there isn't anything identifiable other than + // general Cf category code to identify these, and some characters in Cf + // category code are of non-zero width. + if (ucs == 0 || + ucs == 0x034F || + (0x200B <= ucs && ucs <= 0x200F) || + ucs == 0x2028 || + ucs == 0x2029 || + (0x202A <= ucs && ucs <= 0x202E) || + (0x2060 <= ucs && ucs <= 0x2063)) { + return 0; + } + + // C0/C1 control characters. + if (ucs < 32 || (0x07F <= ucs && ucs < 0x0A0)) + return -1; + + // Combining characters with zero width. + if (intable(version->zero, version->zero_elements, ucs)) + return 0; + + return intable(version->width, version->width_elements, ucs) ? 2 : 1; +} + +/*end*/ diff --git a/libwidechar/wcscasecmp.c b/libwidechar/wcscasecmp.c new file mode 100644 index 00000000..82eb9ac4 --- /dev/null +++ b/libwidechar/wcscasecmp.c @@ -0,0 +1,57 @@ +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" +#include + +int +Wcscasecmp(const WChar_t *s1, const WChar_t *s2) +{ + WChar_t l1, l2; + + while ((l1 = towlower(*s1++)) == (l2 = towlower(*s2++))) { //FIXME + if (l1 == 0) + return (0); + } + return ((int)l1 - (int)l2); +} + +int +Wcsncasecmp(const WChar_t *s1, const WChar_t *s2, size_t n) +{ + WChar_t l1, l2; + + if (n == 0) + return (0); + do { + if (((l1 = towlower(*s1++))) != (l2 = towlower(*s2++))) { //FIXME + return ((int)l1 - (int)l2); + } + if (l1 == 0) + break; + } while (--n != 0); + return (0); +} diff --git a/libwidechar/wcscat.c b/libwidechar/wcscat.c new file mode 100644 index 00000000..050068b6 --- /dev/null +++ b/libwidechar/wcscat.c @@ -0,0 +1,53 @@ +/* $OpenBSD: wcscat.c,v 1.5 2017/11/28 06:55:49 tb Exp $ */ +/* $NetBSD: wcscat.c,v 1.2 2001/01/03 14:29:36 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +#if defined(APIWARN) +__warn_references(wcscat, + "wcscat() is almost always misused, please use wcslcat()"); +#endif + +WChar_t * +Wcscat(WChar_t *s1, const WChar_t *s2) +{ + WChar_t *p; + WChar_t *q; + const WChar_t *r; + + p = s1; + while (*p) + p++; + q = p; + r = s2; + while (*r) + *q++ = *r++; + *q = '\0'; + return s1; +} diff --git a/libwidechar/wcschr.c b/libwidechar/wcschr.c new file mode 100644 index 00000000..a6b8f24a --- /dev/null +++ b/libwidechar/wcschr.c @@ -0,0 +1,47 @@ +/* $OpenBSD: wcschr.c,v 1.6 2015/10/01 02:32:07 guenther Exp $ */ +/* $NetBSD: wcschr.c,v 1.2 2001/01/03 14:29:36 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +WChar_t * +Wcschr(const WChar_t *s, WChar_t c) +{ + const WChar_t *p; + + p = s; + for (;;) { + if (*p == c) { + return (WChar_t *)p; + } + if (!*p) + return NULL; + p++; + } + /* NOTREACHED */ +} diff --git a/libwidechar/wcscmp.c b/libwidechar/wcscmp.c new file mode 100644 index 00000000..a1b7b629 --- /dev/null +++ b/libwidechar/wcscmp.c @@ -0,0 +1,44 @@ +/* $OpenBSD: wcscmp.c,v 1.5 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wcscmp.c,v 1.5 2003/08/07 16:43:54 agc Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +/* + * Compare strings. + */ +int +Wcscmp(const WChar_t *s1, const WChar_t *s2) +{ + + while (*s1 == *s2++) + if (*s1++ == 0) + return (0); + return (*(const int *)s1 - *(const int *)--s2); +} + diff --git a/libwidechar/wcscpy.c b/libwidechar/wcscpy.c new file mode 100644 index 00000000..ff7b9f48 --- /dev/null +++ b/libwidechar/wcscpy.c @@ -0,0 +1,50 @@ +/* $OpenBSD: wcscpy.c,v 1.5 2017/11/28 06:55:49 tb Exp $ */ +/* $NetBSD: wcscpy.c,v 1.2 2001/01/03 14:29:36 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +#if defined(APIWARN) +__warn_references(wcscpy, + "wcscpy() is almost always misused, please use wcslcpy()"); +#endif + +WChar_t * +Wcscpy(WChar_t *s1, const WChar_t *s2) +{ + WChar_t *p; + const WChar_t *q; + + p = s1; + q = s2; + while (*q) + *p++ = *q++; + *p = '\0'; + + return s1; +} diff --git a/libwidechar/wcslcat.c b/libwidechar/wcslcat.c new file mode 100644 index 00000000..f93b80b6 --- /dev/null +++ b/libwidechar/wcslcat.c @@ -0,0 +1,55 @@ +/* $OpenBSD: wcslcat.c,v 1.7 2019/01/25 00:19:25 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "widechar.h" + + +/* + * Appends src to string dst of size dsize (unlike strncat, dsize is the + * full size of dst, not space left). At most dsize-1 characters + * will be copied. Always NUL terminates (unless dsize <= wcslen(dst)). + * Returns wcslen(src) + MIN(dsize, wcslen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +Wcslcat(WChar_t *dst, const WChar_t *src, size_t dsize) +{ + const WChar_t *odst = dst; + const WChar_t *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != L'\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return(dlen + Wcslen(src)); + while (*src != L'\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = L'\0'; + + return(dlen + (src - osrc)); /* count does not include NUL */ +} diff --git a/libwidechar/wcslcpy.c b/libwidechar/wcslcpy.c new file mode 100644 index 00000000..0748df67 --- /dev/null +++ b/libwidechar/wcslcpy.c @@ -0,0 +1,49 @@ +/* $OpenBSD: wcslcpy.c,v 1.8 2019/01/25 00:19:25 millert Exp $ */ + +/* + * Copyright (c) 1998, 2015 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "widechar.h" + +/* + * Copy string src to buffer dst of size dsize. At most dsize-1 + * chars will be copied. Always NUL terminates (unless dsize == 0). + * Returns wcslen(src); if retval >= dsize, truncation occurred. + */ +size_t +Wcslcpy(WChar_t *dst, const WChar_t *src, size_t dsize) +{ + const WChar_t *osrc = src; + size_t nleft = dsize; + + /* Copy as many bytes as will fit. */ + if (nleft != 0) { + while (--nleft != 0) { + if ((*dst++ = *src++) == L'\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src. */ + if (nleft == 0) { + if (dsize != 0) + *dst = L'\0'; /* NUL-terminate dst */ + while (*src++) + ; + } + + return(src - osrc - 1); /* count does not include NUL */ +} diff --git a/libwidechar/wcslen.c b/libwidechar/wcslen.c new file mode 100644 index 00000000..99246766 --- /dev/null +++ b/libwidechar/wcslen.c @@ -0,0 +1,42 @@ +/* $OpenBSD: wcslen.c,v 1.4 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wcslen.c,v 1.2 2001/01/03 14:29:36 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +size_t +Wcslen(const WChar_t *s) +{ + const WChar_t *p; + + p = s; + while (*p) + p++; + + return p - s; +} diff --git a/libwidechar/wcsncat.c b/libwidechar/wcsncat.c new file mode 100644 index 00000000..f6f5d678 --- /dev/null +++ b/libwidechar/wcsncat.c @@ -0,0 +1,50 @@ +/* $OpenBSD: wcsncat.c,v 1.4 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wcsncat.c,v 1.2 2001/01/03 14:29:36 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +WChar_t * +Wcsncat(WChar_t *s1, const WChar_t *s2, size_t n) +{ + WChar_t *p; + WChar_t *q; + const WChar_t *r; + + p = s1; + while (*p) + p++; + q = p; + r = s2; + while (*r && n) { + *q++ = *r++; + n--; + } + *q = '\0'; + return s1; +} diff --git a/libwidechar/wcsncmp.c b/libwidechar/wcsncmp.c new file mode 100644 index 00000000..db6b57f7 --- /dev/null +++ b/libwidechar/wcsncmp.c @@ -0,0 +1,48 @@ +/* $OpenBSD: wcsncmp.c,v 1.5 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wcsncmp.c,v 1.5 2003/08/07 16:43:54 agc Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +int +Wcsncmp(const WChar_t *s1, const WChar_t *s2, size_t n) +{ + if (n == 0) + return (0); + do { + if (*s1 != *s2++) { /* XXX assumes WChar_t = int */ + return (*(const int *)s1 - *(const int *)--s2); + } + if (*s1++ == 0) + break; + } while (--n != 0); + return (0); +} diff --git a/libwidechar/wcsncpy.c b/libwidechar/wcsncpy.c new file mode 100644 index 00000000..ec2259d9 --- /dev/null +++ b/libwidechar/wcsncpy.c @@ -0,0 +1,48 @@ +/* $OpenBSD: wcsncpy.c,v 1.5 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wcsncpy.c,v 1.2 2001/01/03 14:29:37 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +WChar_t * +Wcsncpy(WChar_t *s1, const WChar_t *s2, size_t n) +{ + WChar_t *p; + + p = s1; + while (n && *s2) { + *p++ = *s2++; + n--; + } + while (n) { + *p++ = L'\0'; + n--; + } + + return s1; +} diff --git a/libwidechar/wcspbrk.c b/libwidechar/wcspbrk.c new file mode 100644 index 00000000..b229ae87 --- /dev/null +++ b/libwidechar/wcspbrk.c @@ -0,0 +1,50 @@ +/* $OpenBSD: wcspbrk.c,v 1.5 2015/10/01 02:32:07 guenther Exp $ */ +/* $NetBSD: wcspbrk.c,v 1.2 2001/01/03 14:29:37 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +WChar_t * +Wcspbrk(const WChar_t *s, const WChar_t *set) +{ + const WChar_t *p; + const WChar_t *q; + + p = s; + while (*p) { + q = set; + while (*q) { + if (*p == *q) { + return (WChar_t *)p; + } + q++; + } + p++; + } + return NULL; +} diff --git a/libwidechar/wcsrchr.c b/libwidechar/wcsrchr.c new file mode 100644 index 00000000..d9a0875c --- /dev/null +++ b/libwidechar/wcsrchr.c @@ -0,0 +1,47 @@ +/* $OpenBSD: wcsrchr.c,v 1.5 2015/10/01 02:32:07 guenther Exp $ */ +/* $NetBSD: wcsrchr.c,v 1.2 2001/01/03 14:29:37 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +WChar_t * +Wcsrchr(const WChar_t *s, WChar_t c) +{ + const WChar_t *p; + + p = s; + while (*p) + p++; + while (s <= p) { + if (*p == c) { + return (WChar_t *)p; + } + p--; + } + return NULL; +} diff --git a/libwidechar/wcsspn.c b/libwidechar/wcsspn.c new file mode 100644 index 00000000..09da46a0 --- /dev/null +++ b/libwidechar/wcsspn.c @@ -0,0 +1,53 @@ +/* $OpenBSD: wcsspn.c,v 1.4 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wcsspn.c,v 1.3 2001/09/21 16:09:15 yamt Exp $ */ + +/*- + * Copyright (c)1999,2001 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +size_t +Wcsspn(const WChar_t *s, const WChar_t *set) +{ + const WChar_t *p; + const WChar_t *q; + + p = s; + while (*p) { + q = set; + while (*q) { + if (*p == *q) + break; + q++; + } + if (!*q) + goto done; + p++; + } + +done: + return (p - s); +} diff --git a/libwidechar/wcsstr.c b/libwidechar/wcsstr.c new file mode 100644 index 00000000..2f03e403 --- /dev/null +++ b/libwidechar/wcsstr.c @@ -0,0 +1,66 @@ +/* $OpenBSD: wcsstr.c,v 1.5 2015/10/01 02:32:07 guenther Exp $ */ +/* $NetBSD: wcsstr.c,v 1.3 2003/03/05 20:18:17 tshiozak Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +WChar_t * +#ifdef WCSWCS +Wcswcs(const WChar_t *big, const WChar_t *little) +#else +Wcsstr(const WChar_t *big, const WChar_t *little) +#endif +{ + const WChar_t *p; + const WChar_t *q; + const WChar_t *r; + + if (!*little) { + return (WChar_t *)big; + } + if (Wcslen(big) < Wcslen(little)) + return NULL; + + p = big; + q = little; + while (*p) { + q = little; + r = p; + while (*q) { + if (*r != *q) + break; + q++; + r++; + } + if (!*q) { + return (WChar_t *)p; + } + p++; + } + return NULL; +} diff --git a/libwidechar/wcstod.c b/libwidechar/wcstod.c new file mode 100644 index 00000000..792789c1 --- /dev/null +++ b/libwidechar/wcstod.c @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2002 Tim J. Robbins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "widechar.h" + +#include +#include + +double +Wcstod(const WChar_t *nptr, WChar_t **endptr) +{ + const WChar_t *norg = nptr; + char *buf, *end = NULL; + double val; + int len; + + while (*nptr < 0xff && isspace(*nptr)) { + ++nptr; + } + + /* + * Convert the supplied wide char string to multibyte. + * Note: could be optimised to limit converted text. + */ + if ((len = Wcstoutf8(nptr, NULL, 0)) <= 0 || + NULL == (buf = (char *)malloc(len + 1/*+nul*/))) { + if (endptr != NULL) + *endptr = (WChar_t *)nptr; + return 0.0; + } + + (void) Wcstoutf8(nptr, buf, len + 1); + + /* + * conversion + */ + val = strtod(buf, &end); + + /* + * Convert position, numeric are never multi-byte, hence 1:1 + */ + if (endptr != NULL) { + if (end == buf) { + *endptr = (WChar_t *)norg; + } else { + *endptr = (WChar_t *)(nptr + (end - buf)); + } + } + free(buf); + + return val; +} diff --git a/libwidechar/wcstok.c b/libwidechar/wcstok.c new file mode 100644 index 00000000..1fe45ad3 --- /dev/null +++ b/libwidechar/wcstok.c @@ -0,0 +1,92 @@ +/* $OpenBSD: wcstok.c,v 1.3 2005/08/08 08:05:37 espie Exp $ */ +/* $NetBSD: wcstok.c,v 1.3 2003/07/10 08:50:48 tshiozak Exp $ */ + +/*- + * Copyright (c) 1998 Softweyr LLC. All rights reserved. + * + * strtok_r, from Berkeley strtok + * Oct 13, 1998 by Wes Peters + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notices, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notices, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Softweyr LLC, the + * University of California, Berkeley, and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE + * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Original version ID: + * FreeBSD: src/lib/libc/string/wcstok.c,v 1.1 2002/09/07 08:16:57 tjr Exp + */ + +#include "widechar.h" + +WChar_t * +Wcstok(WChar_t * s, const WChar_t * delim, WChar_t ** last) +{ + const WChar_t *spanp; + WChar_t c, sc; + WChar_t *tok; + + if (s == NULL && (s = *last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += wcsspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = delim; (sc = *spanp++) != L'\0';) { + if (c == sc) + goto cont; + } + + if (c == L'\0') { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += wcscspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == L'\0') + s = NULL; + else + s[-1] = L'\0'; + *last = s; + return (tok); + } + } while (sc != L'\0'); + } + /* NOTREACHED */ +} diff --git a/libwidechar/wcswcs.c b/libwidechar/wcswcs.c new file mode 100644 index 00000000..9c451eff --- /dev/null +++ b/libwidechar/wcswcs.c @@ -0,0 +1,5 @@ +/* $OpenBSD: wcswcs.c,v 1.1 2005/04/13 16:35:58 espie Exp $ */ +/* $NetBSD: wcswcs.c,v 1.1 2003/03/05 20:18:17 tshiozak Exp $ */ + +#define WCSWCS +#include "wcsstr.c" diff --git a/libwidechar/wcswidth.c b/libwidechar/wcswidth.c new file mode 100644 index 00000000..19e25262 --- /dev/null +++ b/libwidechar/wcswidth.c @@ -0,0 +1,23 @@ +/* + * wcswidth - determine columns needed for a fixed-size wide-character string. + */ + +#include "widechar.h" + +int +Wcswidth(const WChar_t *s, size_t n) +{ + int w, q; + + w = 0; + while (n && *s) { + q = ucs_width(*s); + if (q == -1) + return (-1); + w += q; + s++; + n--; + } + + return w; +} diff --git a/libwidechar/wcutf8.c b/libwidechar/wcutf8.c new file mode 100644 index 00000000..beb291bd --- /dev/null +++ b/libwidechar/wcutf8.c @@ -0,0 +1,130 @@ +/* + * UTF-8 support + */ + +#include "widechar.h" +#include "../libchartable/libchartable.h" + +#include +#include + +// Multibyte string width. +int +utf8_width(const void *src, const void *cpend) +{ + int width, result = 0; + const void *end; + int32_t wch; + + while (src < cpend) { + if ((end = charset_utf8_decode_safe(src, cpend, &wch)) > src && + (width = ucs_width(wch)) >= 0) { + result += width; + src = end; + continue; + } + break; + } + return result; +} + + +// Multibyte string width. +int +utf8_nwidth(const void *src, size_t len) +{ + return utf8_width(src, (const char *)src + len); +} + + +// Multibyte string width. +int +utf8_swidth(const void *src) +{ + return utf8_width(src, (const char *)src + strlen(src)); +} + + +// Convert multibyte string to wide-character string. +int +Wcsfromutf8(const char *mbstr, WChar_t *buf, int buflen) +{ + int remaining = buflen; + WChar_t *cursor = buf; + const char *cend; + int32_t ch; + + assert(mbstr && buf && buflen > 0); + for (--remaining /*nul*/; remaining && *mbstr;) { + if ((cend = charset_utf8_decode(mbstr, mbstr + 6, &ch)) <= mbstr || ch <= 0) { + break; + } + *cursor++ = ch; + --remaining; + mbstr = cend; + } + assert(cursor < (buf + buflen)); + *cursor = 0; + return cursor - buf; +} + + +// Convert wide-character string to multibyte string. +int +Wcstoutf8(const WChar_t *wstr, char *buf, int buflen) +{ + WChar_t ch; + int len = 0; + + if (NULL == buf) { + assert(wstr); + while (0 != (ch = *wstr++)) { + len += charset_utf8_length(ch); + } + } else { + int remaining = buflen; + char *cursor = buf; + + assert(wstr && buflen > 0); + for (--remaining /*nul*/; remaining && 0 != (ch = *wstr++);) { + const int t_len = charset_utf8_length(ch); + if (t_len > remaining) { + break; + } + cursor += charset_utf8_encode(ch, cursor); + remaining -= t_len; + } + assert(cursor < (buf + buflen)); + *cursor = 0; + len = (cursor - buf); + } + return len; +} + + +// Convert multibyte character to wide-character. +int +Wcfromutf8(const char *mbstr, WChar_t *wc) +{ + const char *cend; + int32_t ch; + + assert(mbstr && wc); + if ((cend = charset_utf8_decode(mbstr, mbstr + 6, &ch)) <= mbstr || ch <= 0) { + return -1; + } + *wc = ch; + return cend - mbstr; +} + + +// Convert wide-character character to multibyte string. +int +Wctoutf8(WChar_t wch, char *buf, int buflen) +{ + const int len = charset_utf8_length(wch); + if (len > buflen) { + return -1; + } + return charset_utf8_encode(wch, buf); +} diff --git a/libwidechar/wcwidth.c b/libwidechar/wcwidth.c new file mode 100644 index 00000000..41f8305b --- /dev/null +++ b/libwidechar/wcwidth.c @@ -0,0 +1,11 @@ +/* + * wcwidth - determine columns needed for a wide character. + */ + +#include "widechar.h" + +int +Wcwidth(WChar_t wch) +{ + return ucs_width(wch); +} diff --git a/libwidechar/widechar.h b/libwidechar/widechar.h new file mode 100644 index 00000000..3a4867d4 --- /dev/null +++ b/libwidechar/widechar.h @@ -0,0 +1,83 @@ +/* + * Compat wide character. + * + * The wchar_t type is an implementation-defined wide character type. For example under the + * Microsoft compiler, it represents a 16-bit wide character used to store Unicode encoded as + * UTF-16LE, the native character type on Windows operating systems. Characters that cannot b + * represented in just one wide character are represented in a Unicode pair by using the + * Unicode surrogate pair feature. + * + * Whereas other implementations including this use UTF-32 need not manage wide-character strings + * without special handling for surrogates. + * + * Furthermore the behaviour of several standard functions are influenced by the current locale. + * + * These functions provide uniform behaviour independent of run-time environment and the locale. + */ + +#include +#include +#include +#include + + //#define MB_LEN_MAX 6 +typedef int WChar_t; + +#ifdef __cplusplus +extern "C" { +#endif + +WChar_t * Wcscat(WChar_t *s1, const WChar_t *s2); +WChar_t * Wcschr(const WChar_t *s, WChar_t c); +int Wcscmp(const WChar_t *s1, const WChar_t *s2); +WChar_t * Wcscpy(WChar_t *s1, const WChar_t *s2); +size_t Wcslen(const WChar_t *s); +WChar_t * Wcsncat(WChar_t *s1, const WChar_t *s2, size_t n); +int Wcsncmp(const WChar_t *s1, const WChar_t *s2, size_t n); +WChar_t * Wcsncpy(WChar_t *s1, const WChar_t *s2, size_t n); +WChar_t * Wcspbrk(const WChar_t *s, const WChar_t *set); +WChar_t * Wcsrchr(const WChar_t *s, WChar_t c); +WChar_t * Wcstok(WChar_t * s, const WChar_t * delim, WChar_t ** last); + +int Wcscasecmp(const WChar_t *s1, const WChar_t *s2); +int Wcsncasecmp(const WChar_t *s1, const WChar_t *s2, size_t n); + +double Wcstod(const WChar_t *nptr, WChar_t **endptr); + +WChar_t * Wmemchr(const WChar_t *s, WChar_t c, size_t n); +int Wmemcmp(const WChar_t *s1, const WChar_t *s2, size_t n); +WChar_t * Wmemcpy(WChar_t *d, const WChar_t *s, size_t n); +WChar_t * Wmemmove(WChar_t *d, const WChar_t *s, size_t n); +WChar_t * Wmemset(WChar_t *s, WChar_t c, size_t n); + +size_t Wcslcat(WChar_t *dst, const WChar_t *src, size_t dsize); +size_t Wcslcpy(WChar_t *dst, const WChar_t *src, size_t dsize); +size_t Wcsspn(const WChar_t *s, const WChar_t *set); +int Wcswidth(const WChar_t *s, size_t n); + +int Wcfromutf8(const char *str, WChar_t *wc); +int Wctoutf8(WChar_t wch, char *buf, int buflen); + +int Wcsfromutf8(const char *str, WChar_t *buf, int buflen); +int Wcstoutf8(const WChar_t *str, char *buf, int buflen); + +int Wcwidth(WChar_t ucs); +int Wcswidth(const WChar_t *s, size_t n); + +int Wvsnprintf(WChar_t *str, size_t size, const char *format, va_list args); +int Wsnprintf(WChar_t *str, size_t size, const char *format, ...); +int Wasprintf(WChar_t **ret, const char *format, ...); + +int utf8_width(const void *src, const void *cpend); +int utf8_nwidth(const void *src, size_t len); +int utf8_swidth(const void *src); + +int ucs_width_set(const char *label); +const char *ucs_width_version(void); +int ucs_width(int32_t ucs); + +#ifdef __cplusplus +} +#endif + +/*end*/ diff --git a/libwidechar/wmemchr.c b/libwidechar/wmemchr.c new file mode 100644 index 00000000..4e864708 --- /dev/null +++ b/libwidechar/wmemchr.c @@ -0,0 +1,46 @@ +/* $OpenBSD: wmemchr.c,v 1.5 2015/10/01 02:32:07 guenther Exp $ */ +/* $NetBSD: wmemchr.c,v 1.2 2001/01/03 14:29:37 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * citrus Id: wmemchr.c,v 1.2 2000/12/20 14:08:31 itojun Exp + */ + +#include "widechar.h" + +WChar_t * +Wmemchr(const WChar_t *s, WChar_t c, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) { + if (*s == c) { + return (WChar_t *)s; + } + s++; + } + return NULL; +} diff --git a/libwidechar/wmemcmp.c b/libwidechar/wmemcmp.c new file mode 100644 index 00000000..b1367152 --- /dev/null +++ b/libwidechar/wmemcmp.c @@ -0,0 +1,47 @@ +/* $OpenBSD: wmemcmp.c,v 1.5 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wmemcmp.c,v 1.3 2003/04/06 18:33:23 tshiozak Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * citrus Id: wmemcmp.c,v 1.2 2000/12/20 14:08:31 itojun Exp + */ + +#include "widechar.h" + +int +Wmemcmp(const WChar_t *s1, const WChar_t *s2, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) { + if (*s1 != *s2) { /* wchar might be unsigned */ + return *(const int *)s1 > *(const int *)s2 ? 1 : -1; + } + s1++; + s2++; + } + return 0; +} diff --git a/libwidechar/wmemcpy.c b/libwidechar/wmemcpy.c new file mode 100644 index 00000000..b751f077 --- /dev/null +++ b/libwidechar/wmemcpy.c @@ -0,0 +1,41 @@ +/* $OpenBSD: wmemcpy.c,v 1.4 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wmemcpy.c,v 1.2 2001/01/03 14:29:37 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * citrus Id: wmemcpy.c,v 1.2 2000/12/20 14:08:31 itojun Exp + */ + +#include "widechar.h" +#include + +WChar_t * +Wmemcpy(WChar_t *d, const WChar_t *s, size_t n) +{ + + return (WChar_t *)memcpy(d, s, n * sizeof(WChar_t)); +} + diff --git a/libwidechar/wmemmove.c b/libwidechar/wmemmove.c new file mode 100644 index 00000000..1a4cae11 --- /dev/null +++ b/libwidechar/wmemmove.c @@ -0,0 +1,40 @@ +/* $OpenBSD: wmemmove.c,v 1.4 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wmemmove.c,v 1.2 2001/01/03 14:29:37 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * citrus Id: wmemmove.c,v 1.2 2000/12/20 14:08:31 itojun Exp + */ + +#include "widechar.h" +#include + +WChar_t * +Wmemmove(WChar_t *d, const WChar_t *s, size_t n) +{ + + return (WChar_t *)memmove(d, s, n * sizeof(WChar_t)); +} diff --git a/libwidechar/wmemset.c b/libwidechar/wmemset.c new file mode 100644 index 00000000..21be3a3f --- /dev/null +++ b/libwidechar/wmemset.c @@ -0,0 +1,46 @@ +/* $OpenBSD: wmemset.c,v 1.4 2015/09/12 16:23:14 guenther Exp $ */ +/* $NetBSD: wmemset.c,v 1.2 2001/01/03 14:29:37 lukem Exp $ */ + +/*- + * Copyright (c)1999 Citrus Project, + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * citrus Id: wmemset.c,v 1.2 2000/12/20 14:08:31 itojun Exp + */ + +#include "widechar.h" + +WChar_t * +Wmemset(WChar_t *s, WChar_t c, size_t n) +{ + size_t i; + WChar_t *p; + + p = s; + for (i = 0; i < n; i++) { + *p = c; + p++; + } + return s; +} diff --git a/libwidechar/wsnprintf.c b/libwidechar/wsnprintf.c new file mode 100644 index 00000000..6a6aaf8a --- /dev/null +++ b/libwidechar/wsnprintf.c @@ -0,0 +1,2248 @@ +/* + * + + Conversion Explanation Expected Argument Type + Specifier + Length + Modifier hh h none l ll j z t L + + % writes literal %. The full conversion specification + must be %%. N/A N/A N/A N/A N/A N/A N/A N/A N/A + + c writes a single character. N/A N/A N/A N/A N/A N/A N/A N/A N/A + + s writes a character string N/A N/A char wchar N/A N/A N/A N/A N/A + + S writes a character string N/A N/A WChar N/A N/A N/A N/A N/A N/A + + d,i converts a signed integer into decimal "[-]dddd". signed short int long long intmax size_t ptrdiff N/A + char long + + unsigned + o converts an unsigned integer into octal signed short int long long intmax size_t ptrdiff N/A + representation oooo. char long + + x,X converts an unsigned integer into hexadecimal : : : : : : : : : + representation hhhh. + + For the x conversion letters abcdef are used. + For the X conversion letters ABCDEF are used. + + u converts an unsigned integer into decimal "dddd". : : : : : : : : : + + f,f converts floating-point number to the decimal notation N/A N/A double double N/A N/A N/A N/A N/A + in the style [-]ddd.ddd. + + e,E converts floating-point number to the decimal : : : : : : : : : + exponent notation. + + For the e conversion style [-]d.ddde±dd is used. + For the E conversion style [-]d.dddE±dd is used. + + a,A converts floating-point number to the hexadecimal : : : : : : : : : + exponent notation. -- NOT SUPPORTED -- + + For the a conversion style [-]0xh.hhhp±d is used. + For the A conversion style [-]0Xh.hhhP±d is used. + + g,G converts floating-point number to decimal or decimal : : : : : : : : : + exponent notation depending on the value and the precision. + + For the g conversion style conversion with style e or f will be performed. + For the G conversion style conversion with style E or F will be performed. + + n returns the number of characters written so far by this signed short int long long intmax size_t ptrdiff N/A + call to the function. char * long + + The result is written to the value pointed to by the argument. + The specification may not contain any flag, field width, or precision. + + p writes an implementation defined character sequence N/A N/A void* N/A N/A N/A N/A N/A N/A + defining a pointer. + + */ + +/* + * Source: https://github.com/weiss/c99-snprintf + */ + +/* + * Copyright (c) 1995 Patrick Powell. + * + * This code is based on code written by Patrick Powell . + * It may be used for any purpose as long as this notice remains intact on all + * source code distributions. + */ + +/* + * Copyright (c) 2008 Holger Weiss. + * + * This version of the code is maintained by Holger Weiss . + * My changes to the code may freely be used, modified and/or redistributed for + * any purpose. It would be nice if additions and fixes to this file (including + * trivial code cleanups) would be sent back in order to let me include them in + * the version available at . + * However, this is not a requirement for using or redistributing (possibly + * modified) versions of this file, nor is leaving this notice intact mandatory. + */ + +/* + * History + * + * 2021-06-01 + * + * Wide-character reason. + * + * 2008-01-20 Holger Weiss for C99-snprintf 1.1: + * + * Fixed the detection of infinite floating point values on IRIX (and + * possibly other systems) and applied another few minor cleanups. + * + * 2008-01-06 Holger Weiss for C99-snprintf 1.0: + * + * Added a lot of new features, fixed many bugs, and incorporated various + * improvements done by Andrew Tridgell , Russ Allbery + * , Hrvoje Niksic , Damien Miller + * , and others for the Samba, INN, Wget, and OpenSSH + * projects. The additions include: support the "e", "E", "g", "G", and + * "F" conversion specifiers (and use conversion style "f" or "F" for the + * still unsupported "a" and "A" specifiers); support the "hh", "ll", "j", + * "t", and "z" length modifiers; support the "#" flag and the (non-C99) + * "'" flag; use localeconv(3) (if available) to get both the current + * locale's decimal point character and the separator between groups of + * digits; fix the handling of various corner cases of field width and + * precision specifications; fix various floating point conversion bugs; + * handle infinite and NaN floating point values; don't attempt to write to + * the output buffer (which may be NULL) if a size of zero was specified; + * check for integer overflow of the field width, precision, and return + * values and during the floating point conversion; use the OUTCHAR() macro + * instead of a function for better performance; provide asprintf(3) and + * vasprintf(3) functions; add new test cases. The replacement functions + * have been renamed to use an "rpl_" prefix, the function calls in the + * main project (and in this file) must be redefined accordingly for each + * replacement function which is needed (by using Autoconf or other means). + * Various other minor improvements have been applied and the coding style + * was cleaned up for consistency. + * + * 2007-07-23 Holger Weiss for Mutt 1.5.13: + * + * C99 compliant snprintf(3) and vsnprintf(3) functions return the number + * of characters that would have been written to a sufficiently sized + * buffer (excluding the '\0'). The original code simply returned the + * length of the resulting output string, so that's been fixed. + * + * 1998-03-05 Michael Elkins for Mutt 0.90.8: + * + * The original code assumed that both snprintf(3) and vsnprintf(3) were + * missing. Some systems only have snprintf(3) but not vsnprintf(3), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + * 1998-01-27 Thomas Roessler for Mutt 0.89i: + * + * The PGP code was using unsigned hexadecimal formats. Unfortunately, + * unsigned formats simply didn't work. + * + * 1997-10-22 Brandon Long for Mutt 0.87.1: + * + * Ok, added some minimal floating point support, which means this probably + * requires libm on most operating systems. Don't yet support the exponent + * (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just + * wasn't being exercised in ways which showed it, so that's been fixed. + * Also, formatted the code to Mutt conventions, and removed dead code left + * over from the original. Also, there is now a builtin-test, run with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf + * + * 2996-09-15 Brandon Long for Mutt 0.43: + * + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything from the + * normal C string format, at least as far as I can tell from the Solaris + * 2.5 printf(3S) man page. + */ + +/* + * ToDo + * + * - Add wide character support. + * - Add support for "%a" and "%A" conversions. + * - Create test routines which predefine the expected results. Our test cases + * usually expose bugs in system implementations rather than in ours :-) + */ + +/* + * Usage + * + * 1) The following preprocessor macros should be defined to 1 if the feature or + * file in question is available on the target system (by using Autoconf or + * other means), though basic functionality should be available as long as + * HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly: + * + * HAVE_VSNPRINTF + * HAVE_SNPRINTF + * HAVE_VASPRINTF + * HAVE_ASPRINTF + * HAVE_STDARG_H + * HAVE_STDDEF_H + * HAVE_STDINT_H + * HAVE_STDLIB_H + * HAVE_FLOAT_H + * HAVE_INTTYPES_H + * HAVE_LOCALE_H + * HAVE_LOCALECONV + * HAVE_LCONV_DECIMAL_POINT + * HAVE_LCONV_THOUSANDS_SEP + * HAVE_LONG_DOUBLE + * HAVE_LONG_LONG_INT + * HAVE_UNSIGNED_LONG_LONG_INT + * HAVE_INTMAX_T + * HAVE_UINTMAX_T + * HAVE_UINTPTR_T + * HAVE_PTRDIFF_T + * HAVE_VA_COPY + * HAVE___VA_COPY + * + * 2) The calls to the functions which should be replaced must be redefined + * throughout the project files (by using Autoconf or other means): + * + * #define vsnprintf rpl_vsnprintf + * #define snprintf rpl_snprintf + * #define vasprintf rpl_vasprintf + * #define asprintf rpl_asprintf + * + * 3) The required replacement functions should be declared in some header file + * included throughout the project files: + * + * #if HAVE_CONFIG_H + * #include + * #endif + * #if HAVE_STDARG_H + * #include + * #if !HAVE_VSNPRINTF + * int rpl_vsnprintf(WChar_t *, size_t, const WChar_t *, va_list); + * #endif + * #if !HAVE_SNPRINTF + * int rpl_snprintf(WChar_t *, size_t, const WChar_t *, ...); + * #endif + * #if !HAVE_VASPRINTF + * int rpl_vasprintf(WChar_t **, const WChar_t *, va_list); + * #endif + * #if !HAVE_ASPRINTF + * int rpl_asprintf(WChar_t **, const WChar_t *, ...); + * #endif + * #endif + * + * Autoconf macros for handling step 1 and step 2 are available at + * . + */ + +#if HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include "widechar.h" + +#if TEST_SNPRINTF +#include /* For pow(3), NAN, and INFINITY. */ +#include /* For strcmp(3). */ +#if defined(__NetBSD__) || \ + defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NeXT__) || \ + defined(__bsd__) +#define OS_BSD 1 +#elif defined(sgi) || defined(__sgi) +#ifndef __c99 +#define __c99 /* Force C99 mode to get included on IRIX 6.5.30. */ +#endif /* !defined(__c99) */ +#define OS_IRIX 1 +#define OS_SYSV 1 +#elif defined(__svr4__) +#define OS_SYSV 1 +#elif defined(__linux__) +#define OS_LINUX 1 +#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */ +#if HAVE_CONFIG_H /* Undefine definitions possibly done in config.h. */ +//#ifdef HAVE_SNPRINTF +//#undef HAVE_SNPRINTF +//#endif /* defined(HAVE_SNPRINTF) */ +//#ifdef HAVE_VSNPRINTF +//#undef HAVE_VSNPRINTF +//#endif /* defined(HAVE_VSNPRINTF) */ +//#ifdef HAVE_ASPRINTF +//#undef HAVE_ASPRINTF +//#endif /* defined(HAVE_ASPRINTF) */ +//#ifdef HAVE_VASPRINTF +//#undef HAVE_VASPRINTF +//#endif /* defined(HAVE_VASPRINTF) */ +#ifdef snprintf +#undef snprintf +#endif /* defined(snprintf) */ +#ifdef vsnprintf +#undef vsnprintf +#endif /* defined(vsnprintf) */ +#ifdef asprintf +#undef asprintf +#endif /* defined(asprintf) */ +#ifdef vasprintf +#undef vasprintf +#endif /* defined(vasprintf) */ +#else /* By default, we assume a modern system for testing. */ +#ifndef HAVE_STDARG_H +#define HAVE_STDARG_H 1 +#endif /* HAVE_STDARG_H */ +#ifndef HAVE_STDDEF_H +#define HAVE_STDDEF_H 1 +#endif /* HAVE_STDDEF_H */ +#ifndef HAVE_STDINT_H +#define HAVE_STDINT_H 1 +#endif /* HAVE_STDINT_H */ +#ifndef HAVE_STDLIB_H +#define HAVE_STDLIB_H 1 +#endif /* HAVE_STDLIB_H */ +#ifndef HAVE_FLOAT_H +#define HAVE_FLOAT_H 1 +#endif /* HAVE_FLOAT_H */ +#ifndef HAVE_INTTYPES_H +#define HAVE_INTTYPES_H 1 +#endif /* HAVE_INTTYPES_H */ +#ifndef HAVE_LOCALE_H +#define HAVE_LOCALE_H 1 +#endif /* HAVE_LOCALE_H */ +#ifndef HAVE_LOCALECONV +#define HAVE_LOCALECONV 1 +#endif /* !defined(HAVE_LOCALECONV) */ +#ifndef HAVE_LCONV_DECIMAL_POINT +#define HAVE_LCONV_DECIMAL_POINT 1 +#endif /* HAVE_LCONV_DECIMAL_POINT */ +#ifndef HAVE_LCONV_THOUSANDS_SEP +#define HAVE_LCONV_THOUSANDS_SEP 1 +#endif /* HAVE_LCONV_THOUSANDS_SEP */ +#ifndef HAVE_LONG_DOUBLE +#define HAVE_LONG_DOUBLE 1 +#endif /* !defined(HAVE_LONG_DOUBLE) */ +#ifndef HAVE_LONG_LONG_INT +#define HAVE_LONG_LONG_INT 1 +#endif /* !defined(HAVE_LONG_LONG_INT) */ +#ifndef HAVE_UNSIGNED_LONG_LONG_INT +#define HAVE_UNSIGNED_LONG_LONG_INT 1 +#endif /* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */ +#ifndef HAVE_INTMAX_T +#define HAVE_INTMAX_T 1 +#endif /* !defined(HAVE_INTMAX_T) */ +#ifndef HAVE_UINTMAX_T +#define HAVE_UINTMAX_T 1 +#endif /* !defined(HAVE_UINTMAX_T) */ +#ifndef HAVE_UINTPTR_T +#define HAVE_UINTPTR_T 1 +#endif /* !defined(HAVE_UINTPTR_T) */ +#ifndef HAVE_PTRDIFF_T +#define HAVE_PTRDIFF_T 1 +#endif /* !defined(HAVE_PTRDIFF_T) */ +#ifndef HAVE_VA_COPY +#define HAVE_VA_COPY 1 +#endif /* !defined(HAVE_VA_COPY) */ +#ifndef HAVE___VA_COPY +#define HAVE___VA_COPY 1 +#endif /* !defined(HAVE___VA_COPY) */ +#endif /* HAVE_CONFIG_H */ + //#define snprintf rpl_snprintf + //#define vsnprintf rpl_vsnprintf + //#define asprintf rpl_asprintf + //#define vasprintf rpl_vasprintf +#endif /* TEST_SNPRINTF */ + +#if !HAVE_WSNPRINTF || !HAVE_WVSNPRINTF || !HAVE_WASPRINTF || !HAVE_WVASPRINTF +#include /* For NULL, size_t, vsnprintf(3), and vasprintf(3). */ +#ifdef VA_START +#undef VA_START +#endif /* defined(VA_START) */ +#ifdef VA_SHIFT +#undef VA_SHIFT +#endif /* defined(VA_SHIFT) */ +#if HAVE_STDARG_H +#include +#define VA_START(ap, last) va_start(ap, last) +#define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */ +#else /* Assume is available. */ +#include +#define VA_START(ap, last) va_start(ap) /* "last" is ignored. */ +#define VA_SHIFT(ap, value, type) value = va_arg(ap, type) +#endif /* HAVE_STDARG_H */ + +#if !HAVE_WVASPRINTF +#if HAVE_STDLIB_H +#include /* For malloc(3). */ +#endif /* HAVE_STDLIB_H */ +#ifdef VA_COPY +#undef VA_COPY +#endif /* defined(VA_COPY) */ +#ifdef VA_END_COPY +#undef VA_END_COPY +#endif /* defined(VA_END_COPY) */ +#if HAVE_VA_COPY +#define VA_COPY(dest, src) va_copy(dest, src) +#define VA_END_COPY(ap) va_end(ap) +#elif HAVE___VA_COPY +#define VA_COPY(dest, src) __va_copy(dest, src) +#define VA_END_COPY(ap) va_end(ap) +#else +#define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list)) +#define VA_END_COPY(ap) /* No-op. */ +#define NEED_MYMEMCPY 1 +static void *mymemcpy(void *, void *, size_t); +#endif /* HAVE_VA_COPY */ +#endif /* !HAVE_WVASPRINTF */ + +#if !HAVE_WVSNPRINTF +#include /* For ERANGE and errno. */ +#include /* For *_MAX. */ +#if HAVE_FLOAT_H +#include /* For *DBL_{MIN,MAX}_10_EXP. */ +#endif /* HAVE_FLOAT_H */ +#if HAVE_INTTYPES_H +#include /* For intmax_t (if not defined in ). */ +#endif /* HAVE_INTTYPES_H */ +#if HAVE_LOCALE_H +#include /* For localeconv(3). */ +#endif /* HAVE_LOCALE_H */ +#if HAVE_STDDEF_H +#include /* For ptrdiff_t. */ +#endif /* HAVE_STDDEF_H */ +#if HAVE_STDINT_H +#include /* For intmax_t. */ +#endif /* HAVE_STDINT_H */ + +/* Support for unsigned long long int. We may also need ULLONG_MAX. */ +#ifndef ULONG_MAX /* We may need ULONG_MAX as a fallback. */ +#ifdef UINT_MAX +#define ULONG_MAX UINT_MAX +#else +#define ULONG_MAX INT_MAX +#endif /* defined(UINT_MAX) */ +#endif /* !defined(ULONG_MAX) */ +#ifdef ULLONG +#undef ULLONG +#endif /* defined(ULLONG) */ +#if HAVE_UNSIGNED_LONG_LONG_INT +#define ULLONG unsigned long long int +#ifndef ULLONG_MAX +#define ULLONG_MAX ULONG_MAX +#endif /* !defined(ULLONG_MAX) */ +#else +#define ULLONG unsigned long int +#ifdef ULLONG_MAX +#undef ULLONG_MAX +#endif /* defined(ULLONG_MAX) */ +#define ULLONG_MAX ULONG_MAX +#endif /* HAVE_LONG_LONG_INT */ + +/* Support for uintmax_t. We also need UINTMAX_MAX. */ +#ifdef UINTMAX_T +#undef UINTMAX_T +#endif /* defined(UINTMAX_T) */ +#if HAVE_UINTMAX_T || defined(uintmax_t) +#define UINTMAX_T uintmax_t +#ifndef UINTMAX_MAX +#define UINTMAX_MAX ULLONG_MAX +#endif /* !defined(UINTMAX_MAX) */ +#else +#define UINTMAX_T ULLONG +#ifdef UINTMAX_MAX +#undef UINTMAX_MAX +#endif /* defined(UINTMAX_MAX) */ +#define UINTMAX_MAX ULLONG_MAX +#endif /* HAVE_UINTMAX_T || defined(uintmax_t) */ + +/* Support for long double. */ +#ifndef LDOUBLE +#if HAVE_LONG_DOUBLE +#define LDOUBLE long double +#define LDOUBLE_MIN_10_EXP LDBL_MIN_10_EXP +#define LDOUBLE_MAX_10_EXP LDBL_MAX_10_EXP +#else +#define LDOUBLE double +#define LDOUBLE_MIN_10_EXP DBL_MIN_10_EXP +#define LDOUBLE_MAX_10_EXP DBL_MAX_10_EXP +#endif /* HAVE_LONG_DOUBLE */ +#endif /* !defined(LDOUBLE) */ + +/* Support for long long int. */ +#ifndef LLONG +#if HAVE_LONG_LONG_INT +#define LLONG long long int +#else +#define LLONG long int +#endif /* HAVE_LONG_LONG_INT */ +#endif /* !defined(LLONG) */ + +/* Support for intmax_t. */ +#ifndef INTMAX_T +#if HAVE_INTMAX_T || defined(intmax_t) +#define INTMAX_T intmax_t +#else +#define INTMAX_T LLONG +#endif /* HAVE_INTMAX_T || defined(intmax_t) */ +#endif /* !defined(INTMAX_T) */ + +/* Support for uintptr_t. */ +#ifndef UINTPTR_T +#if HAVE_UINTPTR_T || defined(uintptr_t) +#define UINTPTR_T uintptr_t +#else +#define UINTPTR_T unsigned long int +#endif /* HAVE_UINTPTR_T || defined(uintptr_t) */ +#endif /* !defined(UINTPTR_T) */ + +/* Support for ptrdiff_t. */ +#ifndef PTRDIFF_T +#if HAVE_PTRDIFF_T || defined(ptrdiff_t) +#define PTRDIFF_T ptrdiff_t +#else +#define PTRDIFF_T long int +#endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */ +#endif /* !defined(PTRDIFF_T) */ + +/* + * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99: + * 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an + * unsigned type if necessary. This should work just fine in practice. + */ +#ifndef UPTRDIFF_T +#define UPTRDIFF_T PTRDIFF_T +#endif /* !defined(UPTRDIFF_T) */ + +/* + * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7). + * However, we'll simply use size_t and convert it to a signed type if + * necessary. This should work just fine in practice. + */ +#ifndef SSIZE_T +#define SSIZE_T size_t +#endif /* !defined(SSIZE_T) */ + +/* Either ERANGE or E2BIG should be available everywhere. */ +#ifndef ERANGE +#define ERANGE E2BIG +#endif /* !defined(ERANGE) */ +#ifndef EOVERFLOW +#define EOVERFLOW ERANGE +#endif /* !defined(EOVERFLOW) */ + +/* + * Buffer size to hold the octal string representation of UINT128_MAX without + * nul-termination ("3777777777777777777777777777777777777777777"). + */ +#ifdef MAX_CONVERT_LENGTH +#undef MAX_CONVERT_LENGTH +#endif /* defined(MAX_CONVERT_LENGTH) */ +#define MAX_CONVERT_LENGTH 43 + +/* Format read states. */ +#define PRINT_S_DEFAULT 0 +#define PRINT_S_FLAGS 1 +#define PRINT_S_WIDTH 2 +#define PRINT_S_DOT 3 +#define PRINT_S_PRECISION 4 +#define PRINT_S_MOD 5 +#define PRINT_S_CONV 6 + +/* Format flags. */ +#define PRINT_F_MINUS (1 << 0) +#define PRINT_F_PLUS (1 << 1) +#define PRINT_F_SPACE (1 << 2) +#define PRINT_F_NUM (1 << 3) +#define PRINT_F_ZERO (1 << 4) +#define PRINT_F_QUOTE (1 << 5) +#define PRINT_F_UP (1 << 6) +#define PRINT_F_UNSIGNED (1 << 7) +#define PRINT_F_TYPE_G (1 << 8) +#define PRINT_F_TYPE_E (1 << 9) + +/* Conversion flags. */ +#define PRINT_C_CHAR 1 +#define PRINT_C_SHORT 2 +#define PRINT_C_LONG 3 +#define PRINT_C_LLONG 4 +#define PRINT_C_LDOUBLE 5 +#define PRINT_C_SIZE 6 +#define PRINT_C_PTRDIFF 7 +#define PRINT_C_INTMAX 8 + +#ifndef MAX +#define MAX(x, y) ((x >= y) ? x : y) +#endif /* !defined(MAX) */ +#ifndef CHARTOINT +#define CHARTOINT(ch) (ch - '0') +#endif /* !defined(CHARTOINT) */ +#ifndef ISDIGIT +#define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9') +#endif /* !defined(ISDIGIT) */ +#ifndef ISNAN +#define ISNAN(x) (x != x) +#endif /* !defined(ISNAN) */ +#ifndef ISINF +#define ISINF(x) ((x < -1 || x > 1) && x + x == x) +#endif /* !defined(ISINF) */ + +#ifdef OUTCHAR +#undef OUTCHAR +#endif /* defined(OUTCHAR) */ +#define OUTCHAR(str, len, size, ch) \ +do { \ + if (len + 1 < size) \ + str[len] = ch; \ + (len)++; \ +} while (/* CONSTCOND */ 0) + +static const WChar_t nil[6] = {'(', 'n', 'i', 'l', ')', 0}; +static const WChar_t null[7] = {'(', 'n', 'u', 'l', 'l', ')', 0}; +static const WChar_t NAN[4] = {'N', 'A', 'N', 0}; +static const WChar_t nan[4] = {'n', 'a', 'n', 0}; +static const WChar_t INF[4] = {'I', 'N', 'F', 0}; +static const WChar_t inf[4] = {'i', 'n', 'f', 0}; +static const WChar_t HEX[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 0}; +static const WChar_t hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 0}; + +static void fmtstrw(WChar_t *, size_t *, size_t, const WChar_t *, int, int, int); +static void fmtstrW(WChar_t *, size_t *, size_t, const wchar_t *, int, int, int); +static void fmtstr(WChar_t *, size_t *, size_t, const char *, int, int, int); +static void fmtint(WChar_t *, size_t *, size_t, INTMAX_T, int, int, int, int); +static void fmtflt(WChar_t *, size_t *, size_t, LDOUBLE, int, int, int, int *); +static void printsep(WChar_t *, size_t *, size_t); +static int getnumsep(int); +static int getexponent(LDOUBLE); +static int convert(UINTMAX_T, WChar_t *, size_t, int, int); +static UINTMAX_T cast(LDOUBLE); +static UINTMAX_T myround(LDOUBLE); +static LDOUBLE mypow10(int); + +//extern int errno; + +int +Wvsnprintf(WChar_t *str, size_t size, const char *format, va_list args) +{ + LDOUBLE fvalue; + INTMAX_T value; + /*unsigned*/ WChar_t cvalue; + const WChar_t *strvalue; + INTMAX_T *intmaxptr; + PTRDIFF_T *ptrdiffptr; + SSIZE_T *sizeptr; + LLONG *llongptr; + long int *longptr; + int *intptr; + short int *shortptr; + /*signed*/ WChar_t *charptr; + size_t len = 0; + int overflow = 0; + int base = 0; + int cflags = 0; + int flags = 0; + int width = 0; + int precision = -1; + int state = PRINT_S_DEFAULT; + WChar_t ch = *format++; + + /* + * C99 says: "If `n' is zero, nothing is written, and `s' may be a null + * pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer + * even if a size larger than zero was specified. At least NetBSD's + * snprintf(3) does the same, as well as other versions of this file. + * (Though some of these versions will write to a non-NULL buffer even + * if a size of zero was specified, which violates the standard.) + */ + if (str == NULL && size != 0) + size = 0; + + while (ch != '\0') + switch (state) { + case PRINT_S_DEFAULT: + if (ch == '%') + state = PRINT_S_FLAGS; + else + OUTCHAR(str, len, size, ch); + ch = *format++; + break; + case PRINT_S_FLAGS: + switch (ch) { + case '-': + flags |= PRINT_F_MINUS; + ch = *format++; + break; + case '+': + flags |= PRINT_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= PRINT_F_SPACE; + ch = *format++; + break; + case '#': + flags |= PRINT_F_NUM; + ch = *format++; + break; + case '0': + flags |= PRINT_F_ZERO; + ch = *format++; + break; + case '\'': /* SUSv2 flag (not in C99). */ + flags |= PRINT_F_QUOTE; + ch = *format++; + break; + default: + state = PRINT_S_WIDTH; + break; + } + break; + case PRINT_S_WIDTH: + if (ISDIGIT(ch)) { + ch = CHARTOINT(ch); + if (width > (INT_MAX - ch) / 10) { + overflow = 1; + goto out; + } + width = 10 * width + ch; + ch = *format++; + } else if (ch == '*') { + /* + * C99 says: "A negative field width argument is + * taken as a `-' flag followed by a positive + * field width." (7.19.6.1, 5) + */ + if ((width = va_arg(args, int)) < 0) { + flags |= PRINT_F_MINUS; + width = -width; + } + ch = *format++; + state = PRINT_S_DOT; + } else + state = PRINT_S_DOT; + break; + case PRINT_S_DOT: + if (ch == '.') { + state = PRINT_S_PRECISION; + ch = *format++; + } else + state = PRINT_S_MOD; + break; + case PRINT_S_PRECISION: + if (precision == -1) + precision = 0; + if (ISDIGIT(ch)) { + ch = CHARTOINT(ch); + if (precision > (INT_MAX - ch) / 10) { + overflow = 1; + goto out; + } + precision = 10 * precision + ch; + ch = *format++; + } else if (ch == '*') { + /* + * C99 says: "A negative precision argument is + * taken as if the precision were omitted." + * (7.19.6.1, 5) + */ + if ((precision = va_arg(args, int)) < 0) + precision = -1; + ch = *format++; + state = PRINT_S_MOD; + } else + state = PRINT_S_MOD; + break; + case PRINT_S_MOD: + switch (ch) { + case 'h': + ch = *format++; + if (ch == 'h') { /* It's a char. */ + ch = *format++; + cflags = PRINT_C_CHAR; + } else + cflags = PRINT_C_SHORT; + break; + case 'l': + ch = *format++; + if (ch == 'l') { /* It's a long long. */ + ch = *format++; + cflags = PRINT_C_LLONG; + } else + cflags = PRINT_C_LONG; + break; + case 'L': + cflags = PRINT_C_LDOUBLE; + ch = *format++; + break; + case 'j': + cflags = PRINT_C_INTMAX; + ch = *format++; + break; + case 't': + cflags = PRINT_C_PTRDIFF; + ch = *format++; + break; + case 'z': + cflags = PRINT_C_SIZE; + ch = *format++; + break; + } + state = PRINT_S_CONV; + break; + case PRINT_S_CONV: + switch (ch) { + case 'd': + /* FALLTHROUGH */ + case 'i': + switch (cflags) { + case PRINT_C_CHAR: + value = (signed char)va_arg(args, int); + break; + case PRINT_C_SHORT: + value = (short int)va_arg(args, int); + break; + case PRINT_C_LONG: + value = va_arg(args, long int); + break; + case PRINT_C_LLONG: + value = va_arg(args, LLONG); + break; + case PRINT_C_SIZE: + value = va_arg(args, SSIZE_T); + break; + case PRINT_C_INTMAX: + value = va_arg(args, INTMAX_T); + break; + case PRINT_C_PTRDIFF: + value = va_arg(args, PTRDIFF_T); + break; + default: + value = va_arg(args, int); + break; + } + fmtint(str, &len, size, value, 10, width, + precision, flags); + break; + case 'X': + flags |= PRINT_F_UP; + /* FALLTHROUGH */ + case 'x': + base = 16; + /* FALLTHROUGH */ + case 'o': + if (base == 0) + base = 8; + /* FALLTHROUGH */ + case 'u': + if (base == 0) + base = 10; + flags |= PRINT_F_UNSIGNED; + switch (cflags) { + case PRINT_C_CHAR: + value = (unsigned char)va_arg(args, unsigned int); + break; + case PRINT_C_SHORT: + value = (unsigned short int)va_arg(args, unsigned int); + break; + case PRINT_C_LONG: + value = va_arg(args, unsigned long int); + break; + case PRINT_C_LLONG: + value = va_arg(args, ULLONG); + break; + case PRINT_C_SIZE: + value = va_arg(args, size_t); + break; + case PRINT_C_INTMAX: + value = va_arg(args, UINTMAX_T); + break; + case PRINT_C_PTRDIFF: + value = va_arg(args, UPTRDIFF_T); + break; + default: + value = va_arg(args, unsigned int); + break; + } + fmtint(str, &len, size, value, base, width, + precision, flags); + break; + case 'A': + /* Not yet supported, we'll use "%F". */ + /* FALLTHROUGH */ + case 'E': + if (ch == 'E') + flags |= PRINT_F_TYPE_E; + /* FALLTHROUGH */ + case 'G': + if (ch == 'G') + flags |= PRINT_F_TYPE_G; + /* FALLTHROUGH */ + case 'F': + flags |= PRINT_F_UP; + /* FALLTHROUGH */ + case 'a': + /* Not yet supported, we'll use "%f". */ + /* FALLTHROUGH */ + case 'e': + if (ch == 'e') + flags |= PRINT_F_TYPE_E; + /* FALLTHROUGH */ + case 'g': + if (ch == 'g') + flags |= PRINT_F_TYPE_G; + /* FALLTHROUGH */ + case 'f': + if (cflags == PRINT_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + fmtflt(str, &len, size, fvalue, width, + precision, flags, &overflow); + if (overflow) + goto out; + break; + case 'c': + cvalue = va_arg(args, int); + OUTCHAR(str, len, size, cvalue); + break; + case 's': + switch (cflags) { + case PRINT_C_LONG: + fmtstrW(str, &len, size, va_arg(args, wchar_t *), width, precision, flags); + break; + default: + fmtstr(str, &len, size, va_arg(args, char *), width, precision, flags); + break; + } + case 'S': + fmtstrw(str, &len, size, va_arg(args, WChar_t *), width, precision, flags); + break; + case 'p': + /* + * C99 says: "The value of the pointer is + * converted to a sequence of printing + * characters, in an implementation-defined + * manner." (C99: 7.19.6.1, 8) + */ + if ((strvalue = va_arg(args, void *)) == NULL) + /* + * We use the glibc format. BSD prints + * "0x0", SysV "0". + */ + fmtstrw(str, &len, size, nil, width, -1, flags); + else { + /* + * We use the BSD/glibc format. SysV + * omits the "0x" prefix (which we emit + * using the PRINT_F_NUM flag). + */ + flags |= PRINT_F_NUM; + flags |= PRINT_F_UNSIGNED; + fmtint(str, &len, size, + (UINTPTR_T)strvalue, 16, width, + precision, flags); + } + break; + case 'n': + switch (cflags) { + case PRINT_C_CHAR: + charptr = va_arg(args, /*signed*/ WChar_t *); + *charptr = len; + break; + case PRINT_C_SHORT: + shortptr = va_arg(args, short int *); + *shortptr = (short)len; + break; + case PRINT_C_LONG: + longptr = va_arg(args, long int *); + *longptr = len; + break; + case PRINT_C_LLONG: + llongptr = va_arg(args, LLONG *); + *llongptr = len; + break; + case PRINT_C_SIZE: + /* + * C99 says that with the "z" length + * modifier, "a following `n' conversion + * specifier applies to a pointer to a + * signed integer type corresponding to + * size_t argument." (7.19.6.1, 7) + */ + sizeptr = va_arg(args, SSIZE_T *); + *sizeptr = len; + break; + case PRINT_C_INTMAX: + intmaxptr = va_arg(args, INTMAX_T *); + *intmaxptr = len; + break; + case PRINT_C_PTRDIFF: + ptrdiffptr = va_arg(args, PTRDIFF_T *); + *ptrdiffptr = len; + break; + default: + intptr = va_arg(args, int *); + *intptr = len; + break; + } + break; + case '%': /* Print a "%" character verbatim. */ + OUTCHAR(str, len, size, ch); + break; + default: /* Skip other characters. */ + break; + } + ch = *format++; + state = PRINT_S_DEFAULT; + base = cflags = flags = width = 0; + precision = -1; + break; + } +out: + if (len < size) + str[len] = '\0'; + else if (size > 0) + str[size - 1] = '\0'; + + if (overflow || len > INT_MAX) { + errno = EOVERFLOW; + return -1; + } + return (int)len; +} + +static void +fmtstrw(WChar_t *str, size_t *len, size_t size, const WChar_t *value, int width, int precision, int flags) +{ + int padlen, strln; /* Amount to pad. */ + int noprecision = (precision == -1); + + if (value == NULL) /* We're forgiving. */ + value = null; + + /* If a precision was specified, don't read the string past it. */ + for (strln = 0; value[strln] != '\0' && + (noprecision || strln < precision); strln++) + continue; + + if ((padlen = width - strln) < 0) + padlen = 0; + if (flags & PRINT_F_MINUS) /* Left justify. */ + padlen = -padlen; + + while (padlen > 0) { /* Leading spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen--; + } + while (*value != '\0' && (noprecision || precision-- > 0)) { + OUTCHAR(str, *len, size, *value); + value++; + } + while (padlen < 0) { /* Trailing spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen++; + } +} + +static void +fmtstrW(WChar_t *str, size_t *len, size_t size, const wchar_t *value, int width, int precision, int flags) +{ + int padlen, strln; /* Amount to pad. */ + int noprecision = (precision == -1); + + if (value == NULL) /* We're forgiving. */ + value = L"(null)"; + + /* If a precision was specified, don't read the string past it. */ + for (strln = 0; value[strln] != '\0' && + (noprecision || strln < precision); strln++) + continue; + + if ((padlen = width - strln) < 0) + padlen = 0; + if (flags & PRINT_F_MINUS) /* Left justify. */ + padlen = -padlen; + + while (padlen > 0) { /* Leading spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen--; + } + while (*value != '\0' && (noprecision || precision-- > 0)) { + OUTCHAR(str, *len, size, *value); + value++; + } + while (padlen < 0) { /* Trailing spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen++; + } +} + +static void +fmtstr(WChar_t *str, size_t *len, size_t size, const char *value, int width, int precision, int flags) +{ + int padlen, strln; /* Amount to pad. */ + int noprecision = (precision == -1); + + if (value == NULL) /* We're forgiving. */ + value = "(null)"; + + /* If a precision was specified, don't read the string past it. */ + for (strln = 0; value[strln] != '\0' && + (noprecision || strln < precision); strln++) + continue; + + if ((padlen = width - strln) < 0) + padlen = 0; + if (flags & PRINT_F_MINUS) /* Left justify. */ + padlen = -padlen; + + while (padlen > 0) { /* Leading spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen--; + } + while (*value != '\0' && (noprecision || precision-- > 0)) { + OUTCHAR(str, *len, size, *value); + value++; + } + while (padlen < 0) { /* Trailing spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen++; + } +} + +static void +fmtint(WChar_t *str, size_t *len, size_t size, INTMAX_T value, int base, int width, + int precision, int flags) +{ + UINTMAX_T uvalue; + WChar_t iconvert[MAX_CONVERT_LENGTH]; + WChar_t sign = 0; + WChar_t hexprefix = 0; + int spadlen = 0; /* Amount to space pad. */ + int zpadlen = 0; /* Amount to zero pad. */ + int pos; + int separators = (flags & PRINT_F_QUOTE); + int noprecision = (precision == -1); + + if (flags & PRINT_F_UNSIGNED) + uvalue = value; + else { + uvalue = (value >= 0) ? value : -value; + if (value < 0) + sign = '-'; + else if (flags & PRINT_F_PLUS) /* Do a sign. */ + sign = '+'; + else if (flags & PRINT_F_SPACE) + sign = ' '; + } + + pos = convert(uvalue, iconvert, sizeof(iconvert), base, flags & PRINT_F_UP); + + if (flags & PRINT_F_NUM && uvalue != 0) { + /* + * C99 says: "The result is converted to an `alternative form'. + * For `o' conversion, it increases the precision, if and only + * if necessary, to force the first digit of the result to be a + * zero (if the value and precision are both 0, a single 0 is + * printed). For `x' (or `X') conversion, a nonzero result has + * `0x' (or `0X') prefixed to it." (7.19.6.1, 6) + */ + switch (base) { + case 8: + if (precision <= pos) + precision = pos + 1; + break; + case 16: + hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x'; + break; + } + } + + if (separators) /* Get the number of group separators we'll print. */ + separators = getnumsep(pos); + + zpadlen = precision - pos - separators; + spadlen = width /* Minimum field width. */ + - separators /* Number of separators. */ + - MAX(precision, pos) /* Number of integer digits. */ + - ((sign != 0) ? 1 : 0) /* Will we print a sign? */ + - ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */ + + if (zpadlen < 0) + zpadlen = 0; + if (spadlen < 0) + spadlen = 0; + + /* + * C99 says: "If the `0' and `-' flags both appear, the `0' flag is + * ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a + * precision is specified, the `0' flag is ignored." (7.19.6.1, 6) + */ + if (flags & PRINT_F_MINUS) /* Left justify. */ + spadlen = -spadlen; + else if (flags & PRINT_F_ZERO && noprecision) { + zpadlen += spadlen; + spadlen = 0; + } + while (spadlen > 0) { /* Leading spaces. */ + OUTCHAR(str, *len, size, ' '); + spadlen--; + } + if (sign != 0) /* Sign. */ + OUTCHAR(str, *len, size, sign); + if (hexprefix != 0) { /* A "0x" or "0X" prefix. */ + OUTCHAR(str, *len, size, '0'); + OUTCHAR(str, *len, size, hexprefix); + } + while (zpadlen > 0) { /* Leading zeros. */ + OUTCHAR(str, *len, size, '0'); + zpadlen--; + } + while (pos > 0) { /* The actual digits. */ + pos--; + OUTCHAR(str, *len, size, iconvert[pos]); + if (separators > 0 && pos > 0 && pos % 3 == 0) + printsep(str, len, size); + } + while (spadlen < 0) { /* Trailing spaces. */ + OUTCHAR(str, *len, size, ' '); + spadlen++; + } +} + +static void +fmtflt(WChar_t *str, size_t *len, size_t size, LDOUBLE fvalue, int width, int precision, int flags, int *overflow) +{ + LDOUBLE ufvalue; + UINTMAX_T intpart; + UINTMAX_T fracpart; + UINTMAX_T mask; + const WChar_t *infnan = NULL; + WChar_t iconvert[MAX_CONVERT_LENGTH]; + WChar_t fconvert[MAX_CONVERT_LENGTH]; + WChar_t econvert[5]; /* "e-300" (without nul-termination). */ + WChar_t esign = 0; + WChar_t sign = 0; + int leadfraczeros = 0; + int exponent = 0; + int emitpoint = 0; + int omitzeros = 0; + int omitcount = 0; + int padlen = 0; + int epos = 0; + int fpos = 0; + int ipos = 0; + int separators = (flags & PRINT_F_QUOTE); + int estyle = (flags & PRINT_F_TYPE_E); +#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT + struct lconv *lc = localeconv(); +#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ + + /* + * AIX' man page says the default is 0, but C99 and at least Solaris' + * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX + * defaults to 6. + */ + if (precision == -1) + precision = 6; + + if (fvalue < 0.0) + sign = '-'; + else if (flags & PRINT_F_PLUS) /* Do a sign. */ + sign = '+'; + else if (flags & PRINT_F_SPACE) + sign = ' '; + + if (ISNAN(fvalue)) + infnan = (flags & PRINT_F_UP) ? NAN : nan; + else if (ISINF(fvalue)) + infnan = (flags & PRINT_F_UP) ? INF : inf; + + if (infnan != NULL) { + if (sign != 0) + iconvert[ipos++] = sign; + while (*infnan != '\0') + iconvert[ipos++] = *infnan++; + fmtstrw(str, len, size, iconvert, width, ipos, flags); + return; + } + + /* "%e" (or "%E") or "%g" (or "%G") conversion. */ + if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) { + if (flags & PRINT_F_TYPE_G) { + /* + * If the precision is zero, it is treated as one (cf. + * C99: 7.19.6.1, 8). + */ + if (precision == 0) + precision = 1; + /* + * For "%g" (and "%G") conversions, the precision + * specifies the number of significant digits, which + * includes the digits in the integer part. The + * conversion will or will not be using "e-style" (like + * "%e" or "%E" conversions) depending on the precision + * and on the exponent. However, the exponent can be + * affected by rounding the converted value, so we'll + * leave this decision for later. Until then, we'll + * assume that we're going to do an "e-style" conversion + * (in order to get the exponent calculated). For + * "e-style", the precision must be decremented by one. + */ + precision--; + /* + * For "%g" (and "%G") conversions, trailing zeros are + * removed from the fractional portion of the result + * unless the "#" flag was specified. + */ + if (!(flags & PRINT_F_NUM)) + omitzeros = 1; + } + exponent = getexponent(fvalue); + estyle = 1; + } + +again: + /* + * Sorry, we only support 9, 19, or 38 digits (that is, the number of + * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value + * minus one) past the decimal point due to our conversion method. + */ + switch (sizeof(UINTMAX_T)) { + case 16: + if (precision > 38) + precision = 38; + break; + case 8: + if (precision > 19) + precision = 19; + break; + default: + if (precision > 9) + precision = 9; + break; + } + + ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue; + if (estyle) /* We want exactly one integer digit. */ + ufvalue /= mypow10(exponent); + + if ((intpart = cast(ufvalue)) == UINTMAX_MAX) { + *overflow = 1; + return; + } + + /* + * Factor of ten with the number of digits needed for the fractional + * part. For example, if the precision is 3, the mask will be 1000. + */ + mask = (UINTMAX_T)mypow10(precision); + /* + * We "cheat" by converting the fractional part to integer by + * multiplying by a factor of ten. + */ + if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) { + /* + * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000 + * (because precision = 3). Now, myround(1000 * 0.99962) will + * return 1000. So, the integer part must be incremented by one + * and the fractional part must be set to zero. + */ + intpart++; + fracpart = 0; + if (estyle && intpart == 10) { + /* + * The value was rounded up to ten, but we only want one + * integer digit if using "e-style". So, the integer + * part must be set to one and the exponent must be + * incremented by one. + */ + intpart = 1; + exponent++; + } + } + + /* + * Now that we know the real exponent, we can check whether or not to + * use "e-style" for "%g" (and "%G") conversions. If we don't need + * "e-style", the precision must be adjusted and the integer and + * fractional parts must be recalculated from the original value. + * + * C99 says: "Let P equal the precision if nonzero, 6 if the precision + * is omitted, or 1 if the precision is zero. Then, if a conversion + * with style `E' would have an exponent of X: + * + * - if P > X >= -4, the conversion is with style `f' (or `F') and + * precision P - (X + 1). + * + * - otherwise, the conversion is with style `e' (or `E') and precision + * P - 1." (7.19.6.1, 8) + * + * Note that we had decremented the precision by one. + */ + if (flags & PRINT_F_TYPE_G && estyle && + precision + 1 > exponent && exponent >= -4) { + precision -= exponent; + estyle = 0; + goto again; + } + + if (estyle) { + if (exponent < 0) { + exponent = -exponent; + esign = '-'; + } else + esign = '+'; + + /* + * Convert the exponent. The sizeof(econvert) is 5. So, the + * econvert buffer can hold e.g. "e+999" and "e-999". We don't + * support an exponent which contains more than three digits. + * Therefore, the following stores are safe. + */ + epos = convert(exponent, econvert, 3, 10, 0); + /* + * C99 says: "The exponent always contains at least two digits, + * and only as many more digits as necessary to represent the + * exponent." (7.19.6.1, 8) + */ + if (epos == 1) + econvert[epos++] = '0'; + econvert[epos++] = esign; + econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e'; + } + + /* Convert the integer part and the fractional part. */ + ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0); + if (fracpart != 0) /* convert() would return 1 if fracpart == 0. */ + fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0); + + leadfraczeros = precision - fpos; + + if (omitzeros) { + if (fpos > 0) /* Omit trailing fractional part zeros. */ + while (omitcount < fpos && fconvert[omitcount] == '0') + omitcount++; + else { /* The fractional part is zero, omit it completely. */ + omitcount = precision; + leadfraczeros = 0; + } + precision -= omitcount; + } + + /* + * Print a decimal point if either the fractional part is non-zero + * and/or the "#" flag was specified. + */ + if (precision > 0 || flags & PRINT_F_NUM) + emitpoint = 1; + if (separators) /* Get the number of group separators we'll print. */ + separators = getnumsep(ipos); + + padlen = width /* Minimum field width. */ + - ipos /* Number of integer digits. */ + - epos /* Number of exponent characters. */ + - precision /* Number of fractional digits. */ + - separators /* Number of group separators. */ + - (emitpoint ? 1 : 0) /* Will we print a decimal point? */ + - ((sign != 0) ? 1 : 0); /* Will we print a sign character? */ + + if (padlen < 0) + padlen = 0; + + /* + * C99 says: "If the `0' and `-' flags both appear, the `0' flag is + * ignored." (7.19.6.1, 6) + */ + if (flags & PRINT_F_MINUS) /* Left justifty. */ + padlen = -padlen; + else if (flags & PRINT_F_ZERO && padlen > 0) { + if (sign != 0) { /* Sign. */ + OUTCHAR(str, *len, size, sign); + sign = 0; + } + while (padlen > 0) { /* Leading zeros. */ + OUTCHAR(str, *len, size, '0'); + padlen--; + } + } + while (padlen > 0) { /* Leading spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen--; + } + if (sign != 0) /* Sign. */ + OUTCHAR(str, *len, size, sign); + while (ipos > 0) { /* Integer part. */ + ipos--; + OUTCHAR(str, *len, size, iconvert[ipos]); + if (separators > 0 && ipos > 0 && ipos % 3 == 0) + printsep(str, len, size); + } + if (emitpoint) { /* Decimal point. */ +#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT + if (lc->decimal_point != NULL && *lc->decimal_point != '\0') + OUTCHAR(str, *len, size, *lc->decimal_point); + else /* We'll always print some decimal point character. */ +#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ + OUTCHAR(str, *len, size, '.'); + } + while (leadfraczeros > 0) { /* Leading fractional part zeros. */ + OUTCHAR(str, *len, size, '0'); + leadfraczeros--; + } + while (fpos > omitcount) { /* The remaining fractional part. */ + fpos--; + OUTCHAR(str, *len, size, fconvert[fpos]); + } + while (epos > 0) { /* Exponent. */ + epos--; + OUTCHAR(str, *len, size, econvert[epos]); + } + while (padlen < 0) { /* Trailing spaces. */ + OUTCHAR(str, *len, size, ' '); + padlen++; + } +} + +static void +printsep(WChar_t *str, size_t *len, size_t size) +{ +#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP + struct lconv *lc = localeconv(); + int i; + + if (lc->thousands_sep != NULL) + for (i = 0; lc->thousands_sep[i] != '\0'; i++) + OUTCHAR(str, *len, size, lc->thousands_sep[i]); + else +#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ + OUTCHAR(str, *len, size, ','); +} + +static int +getnumsep(int digits) +{ + int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3; +#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP + int strln; + struct lconv *lc = localeconv(); + + /* We support an arbitrary separator length (including zero). */ + if (lc->thousands_sep != NULL) { + for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++) + continue; + separators *= strln; + } +#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ + return separators; +} + +static int +getexponent(LDOUBLE value) +{ + LDOUBLE tmp = (value >= 0.0) ? value : -value; + int exponent = 0; + + /* + * We check for LDOUBLE_MAX_10_EXP >= exponent >= LDOUBLE_MIN_10_EXP in + * order to work around possible endless loops which could happen (at + * least) in the second loop (at least) if we're called with an infinite + * value. However, we checked for infinity before calling this function + * using our ISINF() macro, so this might be somewhat paranoid. + */ + while (tmp < 1.0 && tmp > 0.0 && --exponent >= LDOUBLE_MIN_10_EXP) + tmp *= 10; + while (tmp >= 10.0 && ++exponent <= LDOUBLE_MAX_10_EXP) + tmp /= 10; + + return exponent; +} + +static int +convert(UINTMAX_T value, WChar_t *buf, size_t size, int base, int caps) +{ + const WChar_t *digits = caps ? HEX : hex; + size_t pos = 0; + + /* We return an unterminated buffer with the digits in reverse order. */ + do { + buf[pos++] = digits[value % base]; + value /= base; + } while (value != 0 && pos < size); + + return (int)pos; +} + +static UINTMAX_T +cast(LDOUBLE value) +{ + UINTMAX_T result; + + /* + * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be + * represented exactly as an LDOUBLE value (but is less than LDBL_MAX), + * it may be increased to the nearest higher representable value for the + * comparison (cf. C99: 6.3.1.4, 2). It might then equal the LDOUBLE + * value although converting the latter to UINTMAX_T would overflow. + */ + if (value >= UINTMAX_MAX) + return UINTMAX_MAX; + + result = (UINTMAX_T)value; + /* + * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to + * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates + * the standard). Sigh. + */ + return (result <= value) ? result : result - 1; +} + +static UINTMAX_T +myround(LDOUBLE value) +{ + UINTMAX_T intpart = cast(value); + + return ((value -= intpart) < 0.5) ? intpart : intpart + 1; +} + +static LDOUBLE +mypow10(int exponent) +{ + LDOUBLE result = 1; + + while (exponent > 0) { + result *= 10; + exponent--; + } + while (exponent < 0) { + result /= 10; + exponent++; + } + return result; +} +#endif /* !HAVE_WVSNPRINTF */ + +#if !HAVE_WVASPRINTF +#if NEED_MYMEMCPY +void * +mymemcpy(void *dst, void *src, size_t len) +{ + const WChar_t *from = src; + WChar_t *to = dst; + + /* No need for optimization, we use this only to replace va_copy(3). */ + while (len-- > 0) + *to++ = *from++; + return dst; +} +#endif /* NEED_MYMEMCPY */ + +int +Wvasprintf(WChar_t **ret, const char *format, va_list ap) +{ + size_t size; + int len; + va_list aq; + + VA_COPY(aq, ap); + len = Wvsnprintf(NULL, 0, format, aq); + VA_END_COPY(aq); + if (len < 0 || (*ret = malloc(size = len + 1)) == NULL) + return -1; + return Wvsnprintf(*ret, size, format, ap); +} +#endif /* !HAVE_WVASPRINTF */ + +#if !HAVE_WSNPRINTF +#if HAVE_STDARG_H +int +Wsnprintf(WChar_t *str, size_t size, const char *format, ...) +#else +int +Wsnprintf(va_alist) va_dcl +#endif /* HAVE_STDARG_H */ +{ +#if !HAVE_STDARG_H + WChar_t *str; + size_t size; + WChar_t *format; +#endif /* HAVE_STDARG_H */ + va_list ap; + int len; + + VA_START(ap, format); + VA_SHIFT(ap, str, WChar_t *); + VA_SHIFT(ap, size, size_t); + VA_SHIFT(ap, format, const WChar_t *); + len = Wvsnprintf(str, size, format, ap); + va_end(ap); + return len; +} +#endif /* !HAVE_WSNPRINTF */ + +#if !HAVE_WASPRINTF +#if HAVE_STDARG_H +int +Wasprintf(WChar_t **ret, const char *format, ...) +#else +int +Wasprintf(va_alist) va_dcl +#endif /* HAVE_STDARG_H */ +{ +#if !HAVE_STDARG_H + WChar_t **ret; + WChar_t *format; +#endif /* HAVE_STDARG_H */ + va_list ap; + int len; + + VA_START(ap, format); + VA_SHIFT(ap, ret, WChar_t **); + VA_SHIFT(ap, format, const WChar_t *); + len = Wvasprintf(ret, format, ap); + va_end(ap); + return len; +} +#endif /* !HAVE_WASPRINTF */ +#else /* Dummy declaration to avoid empty translation unit warnings. */ +int main(int argc, WChar_t **argv); +#endif /* !HAVE_WSNPRINTF || !HAVE_WVSNPRINTF || !HAVE_WASPRINTF || [...] */ + +#if TEST_SNPRINTF +int +main(void) +{ + const WChar_t *float_fmt[] = { + /* "%E" and "%e" formats. */ +#if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX + "%.16e", + "%22.16e", + "%022.16e", + "%-22.16e", + "%#+'022.16e", +#endif /* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */ + "foo|%#+0123.9E|bar", + "%-123.9e", + "%123.9e", + "%+23.9e", + "%+05.8e", + "%-05.8e", + "%05.8e", + "%+5.8e", + "%-5.8e", + "% 5.8e", + "%5.8e", + "%+4.9e", +#if !OS_LINUX /* glibc sometimes gets these wrong. */ + "%+#010.0e", + "%#10.1e", + "%10.5e", + "% 10.5e", + "%5.0e", + "%5.e", + "%#5.0e", + "%#5.e", + "%3.2e", + "%3.1e", + "%-1.5e", + "%1.5e", + "%01.3e", + "%1.e", + "%.1e", + "%#.0e", + "%+.0e", + "% .0e", + "%.0e", + "%#.e", + "%+.e", + "% .e", + "%.e", + "%4e", + "%e", + "%E", +#endif /* !OS_LINUX */ + /* "%F" and "%f" formats. */ +#if !OS_BSD && !OS_IRIX + "% '022f", + "%+'022f", + "%-'22f", + "%'22f", +#if HAVE_LONG_LONG_INT + "%.16f", + "%22.16f", + "%022.16f", + "%-22.16f", + "%#+'022.16f", +#endif /* HAVE_LONG_LONG_INT */ +#endif /* !OS_BSD && !OS_IRIX */ + "foo|%#+0123.9F|bar", + "%-123.9f", + "%123.9f", + "%+23.9f", + "%+#010.0f", + "%#10.1f", + "%10.5f", + "% 10.5f", + "%+05.8f", + "%-05.8f", + "%05.8f", + "%+5.8f", + "%-5.8f", + "% 5.8f", + "%5.8f", + "%5.0f", + "%5.f", + "%#5.0f", + "%#5.f", + "%+4.9f", + "%3.2f", + "%3.1f", + "%-1.5f", + "%1.5f", + "%01.3f", + "%1.f", + "%.1f", + "%#.0f", + "%+.0f", + "% .0f", + "%.0f", + "%#.f", + "%+.f", + "% .f", + "%.f", + "%4f", + "%f", + "%F", + /* "%G" and "%g" formats. */ +#if !OS_BSD && !OS_IRIX && !OS_LINUX + "% '022g", + "%+'022g", + "%-'22g", + "%'22g", +#if HAVE_LONG_LONG_INT + "%.16g", + "%22.16g", + "%022.16g", + "%-22.16g", + "%#+'022.16g", +#endif /* HAVE_LONG_LONG_INT */ +#endif /* !OS_BSD && !OS_IRIX && !OS_LINUX */ + "foo|%#+0123.9G|bar", + "%-123.9g", + "%123.9g", + "%+23.9g", + "%+05.8g", + "%-05.8g", + "%05.8g", + "%+5.8g", + "%-5.8g", + "% 5.8g", + "%5.8g", + "%+4.9g", +#if !OS_LINUX /* glibc sometimes gets these wrong. */ + "%+#010.0g", + "%#10.1g", + "%10.5g", + "% 10.5g", + "%5.0g", + "%5.g", + "%#5.0g", + "%#5.g", + "%3.2g", + "%3.1g", + "%-1.5g", + "%1.5g", + "%01.3g", + "%1.g", + "%.1g", + "%#.0g", + "%+.0g", + "% .0g", + "%.0g", + "%#.g", + "%+.g", + "% .g", + "%.g", + "%4g", + "%g", + "%G", +#endif /* !OS_LINUX */ + NULL + }; + double float_val[] = { + -4.136, + -134.52, + -5.04030201, + -3410.01234, + -999999.999999, + -913450.29876, + -913450.2, + -91345.2, + -9134.2, + -913.2, + -91.2, + -9.2, + -9.9, + 4.136, + 134.52, + 5.04030201, + 3410.01234, + 999999.999999, + 913450.29876, + 913450.2, + 91345.2, + 9134.2, + 913.2, + 91.2, + 9.2, + 9.9, + 9.96, + 9.996, + 9.9996, + 9.99996, + 9.999996, + 9.9999996, + 9.99999996, + 0.99999996, + 0.99999999, + 0.09999999, + 0.00999999, + 0.00099999, + 0.00009999, + 0.00000999, + 0.00000099, + 0.00000009, + 0.00000001, + 0.0000001, + 0.000001, + 0.00001, + 0.0001, + 0.001, + 0.01, + 0.1, + 1.0, + 1.5, + -1.5, + -1.0, + -0.1, +#if !OS_BSD /* BSD sometimes gets these wrong. */ +#ifdef INFINITY + INFINITY, + -INFINITY, +#endif /* defined(INFINITY) */ +#ifdef NAN + NAN, +#endif /* defined(NAN) */ +#endif /* !OS_BSD */ + 0 + }; + const WChar_t *long_fmt[] = { + "foo|%0123ld|bar", +#if !OS_IRIX + "% '0123ld", + "%+'0123ld", + "%-'123ld", + "%'123ld", +#endif /* !OS_IRiX */ + "%123.9ld", + "% 123.9ld", + "%+123.9ld", + "%-123.9ld", + "%0123ld", + "% 0123ld", + "%+0123ld", + "%-0123ld", + "%10.5ld", + "% 10.5ld", + "%+10.5ld", + "%-10.5ld", + "%010ld", + "% 010ld", + "%+010ld", + "%-010ld", + "%4.2ld", + "% 4.2ld", + "%+4.2ld", + "%-4.2ld", + "%04ld", + "% 04ld", + "%+04ld", + "%-04ld", + "%5.5ld", + "%+22.33ld", + "%01.3ld", + "%1.5ld", + "%-1.5ld", + "%44ld", + "%4ld", + "%4.0ld", + "%4.ld", + "%.44ld", + "%.4ld", + "%.0ld", + "%.ld", + "%ld", + NULL + }; + long int long_val[] = { +#ifdef LONG_MAX + LONG_MAX, +#endif /* LONG_MAX */ +#ifdef LONG_MIN + LONG_MIN, +#endif /* LONG_MIN */ + -91340, + 91340, + 341, + 134, + 0203, + -1, + 1, + 0 + }; + const WChar_t *ulong_fmt[] = { + /* "%u" formats. */ + "foo|%0123lu|bar", +#if !OS_IRIX + "% '0123lu", + "%+'0123lu", + "%-'123lu", + "%'123lu", +#endif /* !OS_IRiX */ + "%123.9lu", + "% 123.9lu", + "%+123.9lu", + "%-123.9lu", + "%0123lu", + "% 0123lu", + "%+0123lu", + "%-0123lu", + "%5.5lu", + "%+22.33lu", + "%01.3lu", + "%1.5lu", + "%-1.5lu", + "%44lu", + "%lu", + /* "%o" formats. */ + "foo|%#0123lo|bar", + "%#123.9lo", + "%# 123.9lo", + "%#+123.9lo", + "%#-123.9lo", + "%#0123lo", + "%# 0123lo", + "%#+0123lo", + "%#-0123lo", + "%#5.5lo", + "%#+22.33lo", + "%#01.3lo", + "%#1.5lo", + "%#-1.5lo", + "%#44lo", + "%#lo", + "%123.9lo", + "% 123.9lo", + "%+123.9lo", + "%-123.9lo", + "%0123lo", + "% 0123lo", + "%+0123lo", + "%-0123lo", + "%5.5lo", + "%+22.33lo", + "%01.3lo", + "%1.5lo", + "%-1.5lo", + "%44lo", + "%lo", + /* "%X" and "%x" formats. */ + "foo|%#0123lX|bar", + "%#123.9lx", + "%# 123.9lx", + "%#+123.9lx", + "%#-123.9lx", + "%#0123lx", + "%# 0123lx", + "%#+0123lx", + "%#-0123lx", + "%#5.5lx", + "%#+22.33lx", + "%#01.3lx", + "%#1.5lx", + "%#-1.5lx", + "%#44lx", + "%#lx", + "%#lX", + "%123.9lx", + "% 123.9lx", + "%+123.9lx", + "%-123.9lx", + "%0123lx", + "% 0123lx", + "%+0123lx", + "%-0123lx", + "%5.5lx", + "%+22.33lx", + "%01.3lx", + "%1.5lx", + "%-1.5lx", + "%44lx", + "%lx", + "%lX", + NULL + }; + unsigned long int ulong_val[] = { +#ifdef ULONG_MAX + ULONG_MAX, +#endif /* ULONG_MAX */ + 91340, + 341, + 134, + 0203, + 1, + 0 + }; + const WChar_t *llong_fmt[] = { + "foo|%0123lld|bar", + "%123.9lld", + "% 123.9lld", + "%+123.9lld", + "%-123.9lld", + "%0123lld", + "% 0123lld", + "%+0123lld", + "%-0123lld", + "%5.5lld", + "%+22.33lld", + "%01.3lld", + "%1.5lld", + "%-1.5lld", + "%44lld", + "%lld", + NULL + }; + LLONG llong_val[] = { +#ifdef LLONG_MAX + LLONG_MAX, +#endif /* LLONG_MAX */ +#ifdef LLONG_MIN + LLONG_MIN, +#endif /* LLONG_MIN */ + -91340, + 91340, + 341, + 134, + 0203, + -1, + 1, + 0 + }; + const WChar_t *string_fmt[] = { + "foo|%10.10s|bar", + "%-10.10s", + "%10.10s", + "%10.5s", + "%5.10s", + "%10.1s", + "%1.10s", + "%10.0s", + "%0.10s", + "%-42.5s", + "%2.s", + "%.10s", + "%.1s", + "%.0s", + "%.s", + "%4s", + "%s", + NULL + }; + const WChar_t *string_val[] = { + "Hello", + "Hello, world!", + "Sound check: One, two, three.", + "This string is a little longer than the other strings.", + "1", + "", + NULL + }; +#if !OS_SYSV /* SysV uses a different format than we do. */ + const WChar_t *pointer_fmt[] = { + "foo|%p|bar", + "%42p", + "%p", + NULL + }; + const WChar_t *pointer_val[] = { + *pointer_fmt, + *string_fmt, + *string_val, + NULL + }; +#endif /* !OS_SYSV */ + WChar_t buf1[1024], buf2[1024]; + double value, digits = 9.123456789012345678901234567890123456789; + int i, j, r1, r2, failed = 0, num = 0; + +/* + * Use -DTEST_NILS in order to also test the conversion of nil values. Might + * segfault on systems which don't support converting a NULL pointer with "%s" + * and lets some test cases fail against BSD and glibc due to bugs in their + * implementations. + */ +#ifndef TEST_NILS +#define TEST_NILS 0 +#elif TEST_NILS +#undef TEST_NILS +#define TEST_NILS 1 +#endif /* !defined(TEST_NILS) */ +#ifdef TEST +#undef TEST +#endif /* defined(TEST) */ +#define TEST(fmt, val) \ +do { \ + for (i = 0; fmt[i] != NULL; i++) \ + for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) { \ + r1 = sprintf(buf1, fmt[i], val[j]); \ + r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]); \ + if (strcmp(buf1, buf2) != 0 || r1 != r2) { \ + (void)printf("Results don't match, " \ + "format string: %s\n" \ + "\t sprintf(3): [%s] (%d)\n" \ + "\tsnprintf(3): [%s] (%d)\n", \ + fmt[i], buf1, r1, buf2, r2); \ + failed++; \ + } \ + num++; \ + } \ +} while (/* CONSTCOND */ 0) + +#if HAVE_LOCALE_H + (void)setlocale(LC_ALL, ""); +#endif /* HAVE_LOCALE_H */ + + (void)puts("Testing our snprintf(3) against your system's sprintf(3)."); + TEST(float_fmt, float_val); + TEST(long_fmt, long_val); + TEST(ulong_fmt, ulong_val); + TEST(llong_fmt, llong_val); + TEST(string_fmt, string_val); +#if !OS_SYSV /* SysV uses a different format than we do. */ + TEST(pointer_fmt, pointer_val); +#endif /* !OS_SYSV */ + (void)printf("Result: %d out of %d tests failed.\n", failed, num); + + (void)fputs("Checking how many digits we support: ", stdout); + for (i = 0; i < 100; i++) { + value = pow(10, i) * digits; + (void)sprintf(buf1, "%.1f", value); + (void)snprintf(buf2, sizeof(buf2), "%.1f", value); + if (strcmp(buf1, buf2) != 0) { + (void)printf("apparently %d.\n", i); + break; + } + } + return (failed == 0) ? 0 : 1; +} +#endif /* TEST_SNPRINTF */ + +/* vim: set joinspaces noexpandtab textwidth=80 cinoptions=(4,u0: */ + diff --git a/macsrc/Makefile.in b/macsrc/Makefile.in index 56f91f24..2d4b7fc4 100644 --- a/macsrc/Makefile.in +++ b/macsrc/Makefile.in @@ -1,9 +1,9 @@ # -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- -# $Id: Makefile.in,v 1.20 2020/06/18 20:35:18 cvsuser Exp $ +# $Id: Makefile.in,v 1.21 2021/04/23 12:16:03 cvsuser Exp $ # GRIEF macro library makefile. # # -# Copyright (c) 1998 - 2020, Adam Young. +# Copyright (c) 1998 - 2021, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. diff --git a/macsrc/alt.h b/macsrc/alt.h index 53dce467..d1c71627 100644 --- a/macsrc/alt.h +++ b/macsrc/alt.h @@ -1,4 +1,4 @@ -/* $Id: alt.h,v 1.9 2011/11/03 23:41:50 cvsuser Exp $ +/* $Id: alt.h,v 1.12 2021/07/12 15:55:11 cvsuser Exp $ * Key definitions * */ @@ -7,144 +7,173 @@ #define __ALT_H /*--export--*/ -/* The following scheme is used for encoding function keys. This - * scheme is used because it simplifies converting ASCII key - * names to the internal codes and vice-versa. Also we keep the - * internal keycodes out of the ASCII range so users are free to - * use those for input if necessary, e.g. on foreign language - * keyboards. +/* + * The following scheme is used for encoding function keys. * - * 0x000..0x0ff ASCII ASCII range. - * 0x100..0x1ff Fn keys Support for upto 256 - * unshifted function keys - * 0x200..0x2ff Keypad Upto 256 keypad keys. - * 0x300..0x3ff Misc Miscellaneous - * 0x400..0x7ff Multikey Used when user does something - * like: assign_to_key("xyz", .. - * i.e. a multi-key stroke. - * 0x800..0x8ff Private Private key definitions for - * users. - * 0x900..0x91f Button down Mouse buttons - * 0x920..0x93f Button up Mouse buttons - * 0x940..0x95f Pointer motion Mouse buttons + * Unicode defines a codespace for 1,114,112 code points in range + * 0 to 10FFFF leaving the top bits. * - * These ranges can be OR'ed with the following bits to indicate - * a modifier key is in operation. + * These are utilised for attributes are used to create seperate + * namespaces for UNICODE, FUNCTION and others. * - * 0x1000 SHIFT - * 0x2000 CTRL (Not used for ASCII range) - * 0x4000 META + * Within these ranges can be OR'ed with the modifiers SHIFT, CTRL and META. * - * Hopefully there is more than enough room for expansion - * purposes and any new keys which appear on the keyboard. If - * you use your own encodings you may or may not have trouble - * with the int_to_key() and key_to_int() primitives which - * understand this encoding scheme. + * ----------------------------------------------------------------- + * | attributes | character | + * ----------------------------------------------------------------- + * 4 3 2 1 4 3 2 1 4 3 2 1 4 2 3 1 4 3 2 1 4 2 3 1 4 3 2 1 4 2 3 1 + * 1 f . . . f . . . f . . . f . . . f . . . + * + * x Shift - MOD_SHIFT + * x Ctrl/control - MOD_CTRL + * x Meta - MOD_META + * x App - MOD_APP + * s . r r r r . Character ranges/namespaces - RANGE_MASK + * + * RANGE_CHARACTER, RANGE_FUNCTION, RANGE_KEYPAD, + * RANGE_MISC, RANGE_MULTIKEY, RANGE_PRIVATE, RANGE_BUTTON + * + * s = sign/reserved. + * . = reserved/unused. * */ -#if defined(WIN32) -#undef MOD_SHIFT -#undef MOS_CTRL +#if defined(_WIN32) || defined(WIN32) +#undef MOD_SHIFT +#undef MOS_CTRL #endif #if defined(KEY_DOWN) || defined(KEY_END) || /* [n]curses.h refinitions */ \ - defined(KEY_UNDO) || defined(KEY_COPY) -#undef KEY_DOWN -#undef KEY_LEFT -#undef KEY_RIGHT -#undef KEY_HOME -#undef KEY_UP -#undef KEY_END -#undef KEY_DEL -#undef KEY_COPY -#undef KEY_UNDO -#undef KEY_SEARCH -#undef KEY_REPLACE -#undef KEY_CANCEL -#undef KEY_COMMAND -#undef KEY_EXIT + defined(KEY_HELP) || defined(KEY_UNDO) || defined(KEY_COPY) +#undef KEY_COMMAND +#undef KEY_HELP +#undef KEY_MENU +#undef KEY_EXIT +#undef KEY_CANCEL +#undef KEY_COPY +#undef KEY_DEL +#undef KEY_UP +#undef KEY_DOWN +#undef KEY_HOME +#undef KEY_END +#undef KEY_LEFT +#undef KEY_RIGHT +#undef KEY_NEXT +#undef KEY_PREV +#undef KEY_OPEN +#undef KEY_SAVE +#undef KEY_CLOSE +#undef KEY_UNDO +#undef KEY_REDO +#undef KEY_SEARCH +#undef KEY_REPLACE +#undef KEY_ENTER +#undef KEY_BACKSPACE #endif -/* Standard names - */ -#define ESC 0x1b -#define BACKSPACE 0x08 -#define TAB '\t' -#define ENTER '\r' - -/* Macro to check whether key is a normal ASCII key. +/* + * Standard names */ -#define IS_ASCII(x) ((x & ~KEY_MASK) == 0) -#define IS_MULTIKEY(x) ((x) >= RANGE_MULTIKEY && (x) <= RANGE_MULTIKEY + MULTIKEY_SIZE) -#define KEY_MASK 0xff - - -/* Define the modifier bits. +#define __ESC 0x1b +#define __BACKSPACE 0x08 +#define __TAB '\t' +#define __ENTER '\r' + +#define KEY_ESC __ESC +#define KEY_BACKSPACE __BACKSPACE +#define KEY_TAB __TAB +#define KEY_ENTER __ENTER +#define KEY_NEWLINE '\n' + +/* + * Namespaces and modifiers. */ -#define MOD_SHIFT 0x1000 -#define MOD_CTRL 0x2000 -#define MOD_META 0x4000 - - -/* Define the ranges for the keys. +#define KEY_MASK 0x001fffff // 0..10ffff +#define RANGE_CHARACTER 0x00000000 // namespaces +#define RANGE_FUNCTION (1 << 26) +#define RANGE_KEYPAD (2 << 26) +#define RANGE_MISC (3 << 26) +#define RANGE_MULTIKEY (4 << 26) +#define RANGE_PRIVATE (5 << 26) +#define RANGE_BUTTON (6 << 26) +#define RANGE_MAX (15 << 26) +#define RANGE_MASK 0x3c000000 + +#define MULTIKEY_SIZE 0x0400 +#define IS_CHARACTER(x) (((x) & ~KEY_MASK) == 0) // unmodified character. +#define IS_FUNCTION(x) (((x) & RANGE_MASK) == RANGE_FUNCTION) // function key. +#define IS_MULTIKEY(x) ((x) >= RANGE_MULTIKEY && (x) <= (RANGE_MULTIKEY + MULTIKEY_SIZE)) +#define IS_BUTTON(x) (((x) & RANGE_MASK) == RANGE_BUTTON) // mouse button. + +#define MOD_SHIFT 0x00200000 // modifiers +#define MOD_CTRL 0x00400000 +#define MOD_META 0x00800000 +#define MOD_APP 0x01000000 // reserved +#define MOD_MASK 0x01e00000 + +/* + * Specials */ -#define RANGE_ASCII 0x000 -#define RANGE_FN 0x100 -#define RANGE_KEYPAD 0x200 -#define RANGE_MISC 0x300 -#define RANGE_MULTIKEY 0x400 /* 0x400 .. 0x7ff */ -#define RANGE_PRIVATE 0x800 /* 0x800 .. 0x8ff */ -#define RANGE_BUTTON 0x900 -#define RANGE_MASK 0xf00 - -#define MULTIKEY_SIZE 0x400 +#define KEY_VOID 0x001fffff // null +#define KEY_WINCH 0x001ffffe // winch/resize event +#define KEY_UNICODE 0x001ffff0 // keyboard special - -/* Define some ASCII characters which we use in the code. +/* + * Control characters */ -#define CCHR(x) ((x) & 0x1f) -#define __CTRL(x) ((x) & 0x1f) /*???*/ - -#define CTRL_A CCHR('a') -#define CTRL_B CCHR('b') -#define CTRL_C CCHR('c') -#define CTRL_D CCHR('d') -#define CTRL_E CCHR('e') -#define CTRL_F CCHR('f') -#define CTRL_G CCHR('g') -#define CTRL_H CCHR('h') -#define CTRL_I CCHR('i') -#define CTRL_J CCHR('j') -#define CTRL_K CCHR('k') -#define CTRL_L CCHR('l') -#define CTRL_M CCHR('m') -#define CTRL_N CCHR('n') -#define CTRL_O CCHR('o') -#define CTRL_P CCHR('p') -#define CTRL_Q CCHR('q') -#define CTRL_R CCHR('r') -#define CTRL_S CCHR('s') -#define CTRL_T CCHR('t') -#define CTRL_U CCHR('u') -#define CTRL_V CCHR('v') -#define CTRL_W CCHR('w') -#define CTRL_X CCHR('x') -#define CTRL_Y CCHR('y') -#define CTRL_Z CCHR('z') - - -/* Function key definitions. +#define __CTRLAZ(__x) ((__x) & 0x1f) /* Ctrl A-Z */ +#define __CTRL(__x) (MOD_CTRL | (__x)) + +#define CTRL_A __CTRLAZ('a') +#define CTRL_B __CTRLAZ('b') +#define CTRL_C __CTRLAZ('c') +#define CTRL_D __CTRLAZ('d') +#define CTRL_E __CTRLAZ('e') +#define CTRL_F __CTRLAZ('f') +#define CTRL_G __CTRLAZ('g') +#define CTRL_H __CTRLAZ('h') +#define CTRL_I __CTRLAZ('i') +#define CTRL_J __CTRLAZ('j') +#define CTRL_K __CTRLAZ('k') +#define CTRL_L __CTRLAZ('l') +#define CTRL_M __CTRLAZ('m') +#define CTRL_N __CTRLAZ('n') +#define CTRL_O __CTRLAZ('o') +#define CTRL_P __CTRLAZ('p') +#define CTRL_Q __CTRLAZ('q') +#define CTRL_R __CTRLAZ('r') +#define CTRL_S __CTRLAZ('s') +#define CTRL_T __CTRLAZ('t') +#define CTRL_U __CTRLAZ('u') +#define CTRL_V __CTRLAZ('v') +#define CTRL_W __CTRLAZ('w') +#define CTRL_X __CTRLAZ('x') +#define CTRL_Y __CTRLAZ('y') +#define CTRL_Z __CTRLAZ('z') + +#define CTRL_0 __CTRL('0') +#define CTRL_1 __CTRL('1') +#define CTRL_2 __CTRL('2') +#define CTRL_3 __CTRL('3') +#define CTRL_4 __CTRL('4') +#define CTRL_5 __CTRL('5') +#define CTRL_6 __CTRL('6') +#define CTRL_7 __CTRL('7') +#define CTRL_8 __CTRL('8') +#define CTRL_9 __CTRL('9') + +/* + * Function key definitions. */ -#define F(x) (RANGE_FN + x - 1) -#define SF(x) (MOD_SHIFT | (RANGE_FN + x - 1)) -#define CF(x) (MOD_CTRL | (RANGE_FN + x - 1)) -#define CSF(x) (MOD_CTRL | MOD_SHIFT | (RANGE_FN + x - 1)) -#define AF(x) (MOD_META | (RANGE_FN + x - 1)) - - -/* Alt-letter definitions. +#define F(__x) (RANGE_FUNCTION + (__x) - 1) +#define SF(__x) (MOD_SHIFT | (RANGE_FUNCTION + (__x) - 1)) +#define CF(__x) (MOD_CTRL | (RANGE_FUNCTION + (__x) - 1)) +#define CSF(__x) (MOD_CTRL | MOD_SHIFT | (RANGE_FUNCTION + (__x) - 1)) +#define AF(__x) (MOD_META | (RANGE_FUNCTION + (__x) - 1)) + +/* + * Alt-letter definitions. */ -#define __ALT(x) (MOD_META | x) +#define __ALT(__x) (MOD_META | (__x)) #define ALT_A __ALT('A') #define ALT_B __ALT('B') @@ -173,8 +202,8 @@ #define ALT_Y __ALT('Y') #define ALT_Z __ALT('Z') - -/* Alt and normal digit key. +/* + * Alt and normal digit key. */ #define ALT_0 __ALT('0') #define ALT_1 __ALT('1') @@ -187,16 +216,16 @@ #define ALT_8 __ALT('8') #define ALT_9 __ALT('9') - -/* Alt and normal digit key. +/* + * Alt and normal digit key. */ #define ALT_MINUS __ALT('-') #define ALT_EQUALS __ALT('=') - -/* Keypad keys. +/* + * Keypad keys. */ -#define __KEYPAD(x) (RANGE_KEYPAD | x) +#define __KEYPAD(__x) (RANGE_KEYPAD | (__x)) #define KEYPAD_0 __KEYPAD(0) #define KEYPAD_1 __KEYPAD(1) #define KEYPAD_2 __KEYPAD(2) @@ -219,8 +248,8 @@ #define KEYPAD_SCROLL __KEYPAD(19) #define KEYPAD_NUMLOCK __KEYPAD(20) - -/* Aliases for the keypad keys. PC keyboard layout. +/* + * Aliases for the keypad keys, PC keyboard layout. */ #define KEY_INS KEYPAD_0 #define KEY_END KEYPAD_1 @@ -237,9 +266,10 @@ #define KEY_UNDO KEYPAD_STAR -/* Control keypad keys. +/* + * Control keypad keys. */ -#define __CTRL_KEYPAD(x) (MOD_CTRL | RANGE_KEYPAD | x) +#define __CTRL_KEYPAD(__x) (MOD_CTRL | RANGE_KEYPAD | (__x)) #define CTRL_KEYPAD_0 __CTRL_KEYPAD(0) #define CTRL_KEYPAD_1 __CTRL_KEYPAD(1) #define CTRL_KEYPAD_2 __CTRL_KEYPAD(2) @@ -262,7 +292,7 @@ #define CTRL_KEYPAD_SCROLL __CTRL_KEYPAD(19) #define CTRL_KEYPAD_NUMLOCK __CTRL_KEYPAD(20) -#define __ALT_KEYPAD(x) (MOD_META | RANGE_KEYPAD | x) +#define __ALT_KEYPAD(__x) (MOD_META | RANGE_KEYPAD | (__x)) #define ALT_KEYPAD_0 __ALT_KEYPAD(0) #define ALT_KEYPAD_1 __ALT_KEYPAD(1) #define ALT_KEYPAD_2 __ALT_KEYPAD(2) @@ -290,10 +320,10 @@ #define ALT_KEYPAD_SCROLL __ALT_KEYPAD(19) #define ALT_KEYPAD_NUMLOCK __ALT_KEYPAD(20) - -/* Shift keypad keys. +/* + * Shift keypad keys. */ -#define __SHIFT_KEYPAD(x) (MOD_SHIFT | RANGE_KEYPAD | x) +#define __SHIFT_KEYPAD(__x) (MOD_SHIFT | RANGE_KEYPAD | (__x)) #define SHIFT_KEYPAD_0 __SHIFT_KEYPAD(0) #define SHIFT_KEYPAD_1 __SHIFT_KEYPAD(1) #define SHIFT_KEYPAD_2 __SHIFT_KEYPAD(2) @@ -316,19 +346,21 @@ #define SHIFT_KEYPAD_SCROLL __SHIFT_KEYPAD(19) #define SHIFT_KEYPAD_NUMLOCK __SHIFT_KEYPAD(20) - -/* Aliases +/* + * Aliases. */ #define KEY_WDOWN SHIFT_KEYPAD_2 #define KEY_WLEFT SHIFT_KEYPAD_4 #define KEY_WRIGHT SHIFT_KEYPAD_6 #define KEY_WUP SHIFT_KEYPAD_8 +#define KEY_WDOWN2 CTRL_KEYPAD_2 #define KEY_WLEFT2 CTRL_KEYPAD_4 #define KEY_WRIGHT2 CTRL_KEYPAD_6 +#define KEY_WUP2 CTRL_KEYPAD_8 - -/* Miscellaneous keys. +/* + * Miscellaneous keys. */ #define MOUSE_KEY (RANGE_MISC | 0) /* Xterm Mouse, not really a key. */ #define BACK_TAB (RANGE_MISC | 1) @@ -349,11 +381,17 @@ #define KEY_CANCEL (RANGE_MISC | 15) #define KEY_COMMAND (RANGE_MISC | 16) #define KEY_EXIT (RANGE_MISC | 17) +#define KEY_NEXT (RANGE_MISC | 18) +#define KEY_PREV (RANGE_MISC | 19) +#define KEY_OPEN (RANGE_MISC | 20) +#define KEY_SAVE (RANGE_MISC | 21) +#define KEY_MENU (RANGE_MISC | 22) #define WHEEL_UP (RANGE_MISC | 31) /* Mouse scroll wheel */ #define WHEEL_DOWN (RANGE_MISC | 32) -/* Following are like 'events' for mouse key trapping. +/* + * Mouse events. */ #define BUTTON1_DOWN (RANGE_BUTTON | 0x00) #define BUTTON2_DOWN (RANGE_BUTTON | 0x01) diff --git a/macsrc/ascii.cr b/macsrc/ascii.cr index 95ecb5bb..5ed29f43 100644 --- a/macsrc/ascii.cr +++ b/macsrc/ascii.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: ascii.cr,v 1.13 2014/10/27 23:28:16 ayoung Exp $ +/* $Id: ascii.cr,v 1.14 2021/06/10 12:58:11 cvsuser Exp $ * Display an ASCII and UNICODE table display. * * @@ -176,10 +176,9 @@ chart(int radix, int unicode) while ((ch < 0x20 && c1_mode) || (ch < 0x01 && !c0_mode)) { insertf(fmt, ch); insert(c0[ch]); + insert(unicode ? " |" : "|"); if (7 == (ch & 7)) { insert("\n"); - } else { - insert(unicode ? " |" : "|"); } ++ch; } @@ -188,10 +187,9 @@ chart(int radix, int unicode) while (ch < 0xa0 && ch < ascii_mode) { insertf(fmt, ch); insert(c1[ch - 0x7f]); + insert(unicode ? " |" : "|"); if (7 == (ch & 7)) { insert("\n"); - } else { - insert(unicode ? " |" : "|"); } ++ch; } @@ -203,10 +201,9 @@ chart(int radix, int unicode) insertf(fmt + " ", ch); insert(ch); } + insert(unicode ? " |" : " |"); if (7 == (ch & 7)) { insert("\n"); - } else { - insert(unicode ? " |" : " |"); } ++ch; } @@ -225,7 +222,6 @@ chart(int radix, int unicode) 0x18B0, 0x18ff, // Undefined 0x1980, 0x1cff, // Undefined 0x1d80, 0x1dff, // Undefined - // 0x2c00, 0x2e7f, // Undefined, UNICODE 6.0 available 0x2fe0, 0x2fef, // Undefined 0x31c0, 0x31ef, // Undefined 0x9fb0, 0x9fff, // Undefined @@ -250,11 +246,13 @@ chart(int radix, int unicode) while (ch < last) { // export characters insertf(fmt + " ", ch); insert(ch); + switch (wcwidth(ch, 0)) { + case 0: insert(" |"); break; + case 1: insert(" |"); break; + case 2: insert(" |"); break; + } if (7 == (ch & 7)) { insert("\n"); - } else { - move_abs(NULL, ((ch & 7) + 1) * len); - insert("|"); } ++ch; } @@ -265,10 +263,9 @@ chart(int radix, int unicode) } else { while (ch <= last) { // pad area insertf(fmt, ch); + insert(" |"); if (7 == (ch & 7)) { insert("\n"); - } else { - insert(" |"); } ++ch; } diff --git a/macsrc/colors/atom_dark.cr b/macsrc/colors/atom_dark.cr new file mode 100644 index 00000000..12ccbbc9 --- /dev/null +++ b/macsrc/colors/atom_dark.cr @@ -0,0 +1,1335 @@ +/* -*- mode: cr; indent-width: 8; -*- */ +/* $Id: atom_dark.cr,v 1.1 2021/04/23 12:21:18 cvsuser Exp $ + * atom-dark, GRIEF port. + * + * Original: + * Authors: Created by CSApproxSnapshot, 03 dic 2014 + * Source: https://github.com/gosukiwi/vim-atom-dark + */ + +#include "../grief.h" + +static list /*vim style coloriser specification*/ +atom_kconsole = { + "set background=dark", + "hi Normal term=NONE cterm=NONE ctermbg=234 ctermfg=231 gui=NONE guibg=#1D1F21 guifg=#F8F8F2", + "hi vimFiletype term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimExecute term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFunction term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0_tabsel term=bold cterm=bold ctermbg=235 ctermfg=148 gui=bold guibg=#262626 guifg=#afdf00", + "hi LightLineLeft_normal_tabsel_0 term=bold cterm=bold ctermbg=148 ctermfg=235 gui=bold guibg=#afdf00 guifg=#262626", + "hi LightLineLeft_normal_1 term=NONE cterm=NONE ctermbg=240 ctermfg=231 gui=NONE guibg=#585858 guifg=#ffffff", + "hi LightLineLeft_normal_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineLeft_normal_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_normal_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineMiddle_normal term=NONE cterm=NONE ctermbg=236 ctermfg=245 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_normal_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=252 gui=NONE guibg=#585858 guifg=#d0d0d0", + "hi LightLineRight_normal_0 term=NONE cterm=NONE ctermbg=252 ctermfg=241 gui=NONE guibg=#d0d0d0 guifg=#606060", + "hi LightLineRight_normal_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=252 gui=NONE guibg=#262626 guifg=#d0d0d0", + "hi SpecialKey term=bold cterm=NONE ctermbg=bg ctermfg=66 gui=NONE guibg=bg guifg=#465457", + "hi NonText term=bold cterm=bold ctermbg=bg ctermfg=66 gui=bold guibg=bg guifg=#465457", + "hi Directory term=bold cterm=NONE ctermbg=bg ctermfg=248 gui=NONE guibg=bg guifg=#AAAAAA", + "hi ErrorMsg term=NONE cterm=NONE ctermbg=235 ctermfg=153 gui=NONE guibg=#232526 guifg=#92C5F7", + "hi IncSearch term=reverse cterm=reverse ctermbg=187 ctermfg=16 gui=reverse guibg=#000000 guifg=#C4BE89", + "hi Search term=reverse cterm=NONE ctermbg=193 ctermfg=16 gui=NONE guibg=#B4EC85 guifg=#000000", + "hi MoreMsg term=bold cterm=bold ctermbg=bg ctermfg=156 gui=bold guibg=bg guifg=#A8FF60", + "hi ModeMsg term=bold cterm=bold ctermbg=bg ctermfg=156 gui=bold guibg=bg guifg=#A8FF60", + "hi LineNr term=underline cterm=NONE ctermbg=235 ctermfg=66 gui=NONE guibg=#232526 guifg=#465457", + "hi LightLineRight_insert_0 term=NONE cterm=NONE ctermbg=153 ctermfg=30 gui=NONE guibg=#87dfff guifg=#005f5f", + "hi LightLineRight_insert_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=153 gui=NONE guibg=#262626 guifg=#87dfff", + "hi LightLineRight_insert_tabsel_0 term=NONE cterm=NONE ctermbg=153 ctermfg=235 gui=NONE guibg=#87dfff guifg=#262626", + "hi LightLineRight_insert_1_2 term=NONE cterm=NONE ctermbg=31 ctermfg=37 gui=NONE guibg=#005f87 guifg=#0087af", + "hi LightLineRight_insert_1 term=NONE cterm=NONE ctermbg=37 ctermfg=153 gui=NONE guibg=#0087af guifg=#87dfff", + "hi LightLineRight_insert_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=37 gui=NONE guibg=#262626 guifg=#0087af", + "hi LightLineRight_insert_tabsel_1 term=NONE cterm=NONE ctermbg=37 ctermfg=235 gui=NONE guibg=#0087af guifg=#262626", + "hi LightLineRight_insert_2_3 term=NONE cterm=NONE ctermbg=31 ctermfg=31 gui=NONE guibg=#005f87 guifg=#005f87", + "hi LightLineRight_insert_2 term=NONE cterm=NONE ctermbg=31 ctermfg=153 gui=NONE guibg=#005f87 guifg=#87dfff", + "hi LightLineRight_insert_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=31 gui=NONE guibg=#262626 guifg=#005f87", + "hi vimClusterName term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi SpellRare term=reverse cterm=undercurl ctermbg=bg ctermfg=231 gui=undercurl guibg=bg guifg=fg guisp=#FFFFFF", + "hi SpellLocal term=underline cterm=undercurl ctermbg=bg ctermfg=123 gui=undercurl guibg=bg guifg=fg guisp=#70F0F0", + "hi Pmenu term=NONE cterm=NONE ctermbg=16 ctermfg=117 gui=NONE guibg=#000000 guifg=#66D9EF", + "hi PmenuSel term=NONE cterm=NONE ctermbg=244 ctermfg=fg gui=NONE guibg=#808080 guifg=fg", + "hi vimSynKeyRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi PmenuThumb term=NONE cterm=NONE ctermbg=16 ctermfg=117 gui=NONE guibg=Black guifg=#66D9EF", + "hi TabLine term=underline cterm=NONE ctermbg=234 ctermfg=244 gui=NONE guibg=#1D1F21 guifg=#808080", + "hi TabLineSel term=bold cterm=bold ctermbg=bg ctermfg=fg gui=bold guibg=bg guifg=fg", + "hi TabLineFill term=reverse cterm=reverse ctermbg=234 ctermfg=234 gui=reverse guibg=#1D1F21 guifg=#1D1F21", + "hi CursorColumn term=reverse cterm=NONE ctermbg=59 ctermfg=fg gui=NONE guibg=#293739 guifg=fg", + "hi Identifier term=underline cterm=NONE ctermbg=bg ctermfg=189 gui=NONE guibg=bg guifg=#B6B7EB", + "hi NERDTreeLink term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimOperParen term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynLine term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel_0 term=NONE cterm=NONE ctermbg=252 ctermfg=235 gui=NONE guibg=#d0d0d0 guifg=#262626", + "hi LightLineRight_normal_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineRight_normal_1 term=NONE cterm=NONE ctermbg=240 ctermfg=250 gui=NONE guibg=#585858 guifg=#bcbcbc", + "hi LightLineRight_normal_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_normal_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineRight_normal_2_3 term=NONE cterm=NONE ctermbg=236 ctermfg=236 gui=NONE guibg=#303030 guifg=#303030", + "hi LightLineRight_normal_2 term=NONE cterm=NONE ctermbg=236 ctermfg=247 gui=NONE guibg=#303030 guifg=#9e9e9e", + "hi LightLineRight_normal_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_normal_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_normal_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_insert_tabsel_2 term=NONE cterm=NONE ctermbg=31 ctermfg=235 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineLeft_insert_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_insert_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_insert_tabsel_2 term=NONE cterm=NONE ctermbg=31 ctermfg=235 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineLeft_insert_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=31 gui=NONE guibg=#262626 guifg=#005f87", + "hi LightLineRight_insert_tabsel_3 term=NONE cterm=NONE ctermbg=31 ctermfg=235 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineRight_insert_3_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=31 gui=NONE guibg=#262626 guifg=#005f87", + "hi LightLineLeft_insert_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_insert_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_insert_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMatchRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMtchCchar term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMtchGroup term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi ColorColumn term=reverse cterm=NONE ctermbg=252 ctermfg=fg gui=NONE guibg=lightgray guifg=fg", + "hi MatchParen term=reverse cterm=NONE ctermbg=238 ctermfg=188 gui=NONE guibg=#444444 guifg=#B7B9B8", + "hi Comment term=bold cterm=NONE ctermbg=bg ctermfg=244 gui=NONE guibg=bg guifg=#7C7C7C", + "hi Constant term=underline cterm=NONE ctermbg=bg ctermfg=151 gui=NONE guibg=bg guifg=#99CC99", + "hi Special term=bold cterm=NONE ctermbg=234 ctermfg=117 gui=NONE guibg=bg guifg=#66D9EF", + "hi vimSynRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Statement term=bold cterm=NONE ctermbg=bg ctermfg=153 gui=NONE guibg=bg guifg=#92C5F7", + "hi PreProc term=underline cterm=NONE ctermbg=bg ctermfg=187 gui=NONE guibg=bg guifg=#DAD085", + "hi Type term=underline cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#66D9EF", + "hi LightLineLeft_inactive_0 term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_inactive_0_1 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi vimMenuRhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroup term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroupError term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_normal_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_normal_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_normal_tabsel_3 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_normal_3_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_normal_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_normal_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi Repeat term=NONE cterm=NONE ctermbg=bg ctermfg=153 gui=NONE guibg=bg guifg=#92C5F7", + "hi LightLineLeft_insert_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiBang term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynPatMod term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncLines term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Underlined term=underline cterm=underline ctermbg=bg ctermfg=244 gui=underline guibg=bg guifg=#808080", + "hi Ignore term=NONE cterm=NONE ctermbg=234 ctermfg=244 gui=NONE guibg=bg guifg=#808080", + "hi Error term=reverse cterm=NONE ctermbg=52 ctermfg=156 gui=NONE guibg=#1E0010 guifg=#A8FF60", + "hi vimSyncLinecont term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi String term=NONE cterm=NONE ctermbg=bg ctermfg=156 gui=NONE guibg=bg guifg=#A8FF60", + "hi Character term=NONE cterm=NONE ctermbg=bg ctermfg=156 gui=NONE guibg=bg guifg=#A8FF60", + "hi Number term=NONE cterm=NONE ctermbg=bg ctermfg=151 gui=NONE guibg=bg guifg=#99CC99", + "hi Boolean term=NONE cterm=NONE ctermbg=bg ctermfg=151 gui=NONE guibg=bg guifg=#99CC99", + "hi Float term=NONE cterm=NONE ctermbg=bg ctermfg=151 gui=NONE guibg=bg guifg=#99CC99", + "hi Function term=NONE cterm=NONE ctermbg=bg ctermfg=187 gui=NONE guibg=bg guifg=#DAD085", + "hi vimMenuMap term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_inactive_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_inactive_tabsel_0 term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineMiddle_inactive term=NONE cterm=NONE ctermbg=236 ctermfg=245 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_inactive_0_1 term=NONE cterm=NONE ctermbg=235 ctermfg=241 gui=NONE guibg=#262626 guifg=#606060", + "hi LightLineRight_inactive_0 term=NONE cterm=NONE ctermbg=241 ctermfg=235 gui=NONE guibg=#606060 guifg=#262626", + "hi LightLineRight_inactive_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=241 gui=NONE guibg=#262626 guifg=#606060", + "hi LightLineRight_inactive_tabsel_0 term=NONE cterm=NONE ctermbg=241 ctermfg=235 gui=NONE guibg=#606060 guifg=#262626", + "hi LightLineRight_inactive_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_inactive_1 term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_inactive_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi vimEcho term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimIf term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiLink term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Conditional term=NONE cterm=NONE ctermbg=bg ctermfg=153 gui=NONE guibg=bg guifg=#92C5F7", + "hi vimHiKeyList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Label term=NONE cterm=NONE ctermbg=bg ctermfg=156 gui=NONE guibg=bg guifg=#A8FF60", + "hi Operator term=NONE cterm=NONE ctermbg=bg ctermfg=153 gui=NONE guibg=bg guifg=#92C5F7", + "hi Keyword term=NONE cterm=NONE ctermbg=bg ctermfg=153 gui=NONE guibg=bg guifg=#92C5F7", + "hi Exception term=NONE cterm=NONE ctermbg=bg ctermfg=187 gui=NONE guibg=bg guifg=#DAD085", + "hi Define term=NONE cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#66D9EF", + "hi Macro term=NONE cterm=NONE ctermbg=bg ctermfg=187 gui=NONE guibg=bg guifg=#C4BE89", + "hi PreCondit term=NONE cterm=NONE ctermbg=bg ctermfg=187 gui=NONE guibg=bg guifg=#DAD085", + "hi LightLineRight_inactive_tabsel_1 term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_inactive_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_inactive_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_inactive_tabsel_1 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_inactive_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_inactive_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_inactive_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_inactive_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_inactive_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_command_0 term=bold cterm=bold ctermbg=148 ctermfg=28 gui=bold guibg=#afdf00 guifg=#005f00", + "hi vimFuncBody term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFuncBlank term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimEscapeBrace term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSetEqual term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRep term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRange term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiTermcap term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi CursorLine term=underline cterm=NONE ctermbg=59 ctermfg=fg gui=NONE guibg=#293739 guifg=fg", + "hi LightLineRight_insert_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiCtermColor term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiFontname term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiGuiFontname term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Structure term=NONE cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#66D9EF", + "hi Typedef term=NONE cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#66D9EF", + "hi Tag term=NONE cterm=NONE ctermbg=bg ctermfg=153 gui=NONE guibg=bg guifg=#92C5F7", + "hi SpecialChar term=NONE cterm=NONE ctermbg=bg ctermfg=153 gui=NONE guibg=bg guifg=#92C5F7", + "hi Delimiter term=NONE cterm=NONE ctermbg=bg ctermfg=245 gui=NONE guibg=bg guifg=#8F8F8F", + "hi SpecialComment term=NONE cterm=NONE ctermbg=bg ctermfg=244 gui=NONE guibg=bg guifg=#7C7C7C", + "hi Debug term=NONE cterm=NONE ctermbg=bg ctermfg=181 gui=NONE guibg=bg guifg=#BCA3A3", + "hi Cursor term=NONE cterm=NONE ctermbg=243 ctermfg=255 gui=NONE guibg=#777777 guifg=#F1F1F1", + "hi iCursor term=NONE cterm=NONE ctermbg=243 ctermfg=255 gui=NONE guibg=#777777 guifg=#F1F1F1", + "hi PmenuSbar term=NONE cterm=NONE ctermbg=232 ctermfg=fg gui=NONE guibg=#080808 guifg=fg", + "hi LightLineLeft_command_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=148 gui=NONE guibg=#585858 guifg=#afdf00", + "hi LightLineLeft_command_0_tabsel term=bold cterm=bold ctermbg=235 ctermfg=148 gui=bold guibg=#262626 guifg=#afdf00", + "hi LightLineLeft_command_tabsel_0 term=bold cterm=bold ctermbg=148 ctermfg=235 gui=bold guibg=#afdf00 guifg=#262626", + "hi LightLineLeft_command_1 term=NONE cterm=NONE ctermbg=240 ctermfg=231 gui=NONE guibg=#585858 guifg=#ffffff", + "hi LightLineLeft_command_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineLeft_command_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_command_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineMiddle_command term=NONE cterm=NONE ctermbg=236 ctermfg=245 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_command_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=252 gui=NONE guibg=#585858 guifg=#d0d0d0", + "hi LightLineRight_command_0 term=NONE cterm=NONE ctermbg=252 ctermfg=241 gui=NONE guibg=#d0d0d0 guifg=#606060", + "hi LightLineRight_normal_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCommentTitleLeader term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimGlobal term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=252 gui=NONE guibg=#262626 guifg=#d0d0d0", + "hi LightLineRight_command_tabsel_0 term=NONE cterm=NONE ctermbg=252 ctermfg=235 gui=NONE guibg=#d0d0d0 guifg=#262626", + "hi LightLineRight_command_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineRight_command_1 term=NONE cterm=NONE ctermbg=240 ctermfg=250 gui=NONE guibg=#585858 guifg=#bcbcbc", + "hi LightLineRight_command_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_command_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineRight_command_2_3 term=NONE cterm=NONE ctermbg=236 ctermfg=236 gui=NONE guibg=#303030 guifg=#303030", + "hi LightLineRight_command_2 term=NONE cterm=NONE ctermbg=236 ctermfg=247 gui=NONE guibg=#303030 guifg=#9e9e9e", + "hi LightLineRight_command_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_command_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_command_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimPatRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCollection term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstPat term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRep4 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncMatch term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncLinebreak term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Todo term=NONE cterm=NONE ctermbg=234 ctermfg=231 gui=NONE guibg=bg guifg=#FFFFFF", + "hi vimSyncRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimExtCmd term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFilter term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSet term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_command_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_command_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_command_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_command_tabsel_3 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_command_3_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_command_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_command_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_command_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCollClass term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi pythonSpaceError term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi pythonSync term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapLhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoCmdSpace term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoEventList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoCmdSfxList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapRhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapRhsExtend term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi StorageClass term=NONE cterm=NONE ctermbg=bg ctermfg=189 gui=NONE guibg=bg guifg=#B6B7EB", + "hi LightLineLeft_normal_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimPythonRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroupSyncA term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimGroupList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMenuBang term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMenuPriority term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi CursorLineNr term=bold cterm=NONE ctermbg=bg ctermfg=189 gui=NONE guibg=bg guifg=#B6B7EB", + "hi Question term=NONE cterm=bold ctermbg=bg ctermfg=117 gui=bold guibg=bg guifg=#66D9EF", + "hi StatusLine term=bold,reverse cterm=NONE ctermbg=231 ctermfg=66 gui=NONE guibg=fg guifg=#455354", + "hi StatusLineNC term=reverse cterm=reverse ctermbg=244 ctermfg=232 gui=reverse guibg=#080808 guifg=#808080", + "hi VertSplit term=reverse cterm=reverse ctermbg=244 ctermfg=232 gui=reverse guibg=#080808 guifg=#808080", + "hi Title term=bold cterm=NONE ctermbg=bg ctermfg=189 gui=NONE guibg=bg guifg=#B6B7EB", + "hi Visual term=reverse cterm=NONE ctermbg=59 ctermfg=fg gui=NONE guibg=#403D3D guifg=fg", + "hi VisualNOS term=NONE cterm=NONE ctermbg=59 ctermfg=fg gui=NONE guibg=#403D3D guifg=fg", + "hi WarningMsg term=NONE cterm=NONE ctermbg=59 ctermfg=231 gui=NONE guibg=#333333 guifg=#FFFFFF", + "hi WildMenu term=NONE cterm=NONE ctermbg=16 ctermfg=117 gui=NONE guibg=#000000 guifg=#66D9EF", + "hi LightLineLeft_normal_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAuSyntax term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimUserCmd term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCmdSep term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimIsCommand term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0 term=bold cterm=bold ctermbg=148 ctermfg=28 gui=bold guibg=#afdf00 guifg=#005f00", + "hi LightLineLeft_normal_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=148 gui=NONE guibg=#585858 guifg=#afdf00", + "hi LightLineLeft_insert_0 term=bold cterm=bold ctermbg=231 ctermfg=30 gui=bold guibg=#ffffff guifg=#005f5f", + "hi LightLineLeft_insert_0_1 term=NONE cterm=NONE ctermbg=37 ctermfg=231 gui=NONE guibg=#0087af guifg=#ffffff", + "hi LightLineLeft_insert_0_tabsel term=bold cterm=bold ctermbg=235 ctermfg=231 gui=bold guibg=#262626 guifg=#ffffff", + "hi LightLineLeft_insert_tabsel_0 term=bold cterm=bold ctermbg=231 ctermfg=235 gui=bold guibg=#ffffff guifg=#262626", + "hi LightLineLeft_insert_1 term=NONE cterm=NONE ctermbg=37 ctermfg=231 gui=NONE guibg=#0087af guifg=#ffffff", + "hi LightLineLeft_insert_1_2 term=NONE cterm=NONE ctermbg=31 ctermfg=37 gui=NONE guibg=#005f87 guifg=#0087af", + "hi LightLineLeft_insert_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=37 gui=NONE guibg=#262626 guifg=#0087af", + "hi LightLineLeft_insert_tabsel_1 term=NONE cterm=NONE ctermbg=37 ctermfg=235 gui=NONE guibg=#0087af guifg=#262626", + "hi LightLineMiddle_insert term=NONE cterm=NONE ctermbg=31 ctermfg=153 gui=NONE guibg=#005f87 guifg=#87dfff", + "hi LightLineRight_insert_0_1 term=NONE cterm=NONE ctermbg=37 ctermfg=153 gui=NONE guibg=#0087af guifg=#87dfff", + "hi vimNormCmds term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Folded term=NONE cterm=NONE ctermbg=16 ctermfg=66 gui=NONE guibg=#000000 guifg=#465457", + "hi FoldColumn term=NONE cterm=NONE ctermbg=16 ctermfg=66 gui=NONE guibg=#000000 guifg=#465457", + "hi DiffAdd term=bold cterm=NONE ctermbg=23 ctermfg=fg gui=NONE guibg=#13354A guifg=fg", + "hi DiffChange term=bold cterm=NONE ctermbg=59 ctermfg=144 gui=NONE guibg=#4C4745 guifg=#89807D", + "hi DiffDelete term=bold cterm=bold ctermbg=52 ctermfg=126 gui=bold guibg=#1E0010 guifg=#960050", + "hi DiffText term=reverse cterm=NONE ctermbg=59 ctermfg=fg gui=NONE guibg=#4C4745 guifg=fg", + "hi SignColumn term=NONE cterm=NONE ctermbg=235 ctermfg=187 gui=NONE guibg=#232526 guifg=#DAD085", + "hi Conceal term=NONE cterm=NONE ctermbg=248 ctermfg=252 gui=NONE guibg=DarkGrey guifg=LightGrey", + "hi SpellBad term=reverse cterm=undercurl ctermbg=bg ctermfg=196 gui=undercurl guibg=bg guifg=fg guisp=#FF0000", + "hi SpellCap term=reverse cterm=undercurl ctermbg=bg ctermfg=105 gui=undercurl guibg=bg guifg=fg guisp=#7070F0" + }; + + +static list /*vim style coloriser specification*/ +atom_eterm = { + "set background=dark", + "hi Normal term=NONE cterm=NONE ctermbg=234 ctermfg=255 gui=NONE guibg=#1D1F21 guifg=#F8F8F2", + "hi vimFiletype term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimExecute term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFunction term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0_tabsel term=bold cterm=bold ctermbg=235 ctermfg=190 gui=bold guibg=#262626 guifg=#afdf00", + "hi LightLineLeft_normal_tabsel_0 term=bold cterm=bold ctermbg=190 ctermfg=235 gui=bold guibg=#afdf00 guifg=#262626", + "hi LightLineLeft_normal_1 term=NONE cterm=NONE ctermbg=240 ctermfg=255 gui=NONE guibg=#585858 guifg=#ffffff", + "hi LightLineLeft_normal_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineLeft_normal_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_normal_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineMiddle_normal term=NONE cterm=NONE ctermbg=236 ctermfg=245 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_normal_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=252 gui=NONE guibg=#585858 guifg=#d0d0d0", + "hi LightLineRight_normal_0 term=NONE cterm=NONE ctermbg=252 ctermfg=241 gui=NONE guibg=#d0d0d0 guifg=#606060", + "hi LightLineRight_normal_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=252 gui=NONE guibg=#262626 guifg=#d0d0d0", + "hi SpecialKey term=bold cterm=NONE ctermbg=bg ctermfg=102 gui=NONE guibg=bg guifg=#465457", + "hi NonText term=bold cterm=bold ctermbg=bg ctermfg=102 gui=bold guibg=bg guifg=#465457", + "hi Directory term=bold cterm=NONE ctermbg=bg ctermfg=188 gui=NONE guibg=bg guifg=#AAAAAA", + "hi ErrorMsg term=NONE cterm=NONE ctermbg=235 ctermfg=159 gui=NONE guibg=#232526 guifg=#92C5F7", + "hi IncSearch term=reverse cterm=reverse ctermbg=223 ctermfg=16 gui=reverse guibg=#000000 guifg=#C4BE89", + "hi Search term=reverse cterm=NONE ctermbg=193 ctermfg=16 gui=NONE guibg=#B4EC85 guifg=#000000", + "hi MoreMsg term=bold cterm=bold ctermbg=bg ctermfg=192 gui=bold guibg=bg guifg=#A8FF60", + "hi ModeMsg term=bold cterm=bold ctermbg=bg ctermfg=192 gui=bold guibg=bg guifg=#A8FF60", + "hi LineNr term=underline cterm=NONE ctermbg=235 ctermfg=102 gui=NONE guibg=#232526 guifg=#465457", + "hi LightLineRight_insert_0 term=NONE cterm=NONE ctermbg=159 ctermfg=30 gui=NONE guibg=#87dfff guifg=#005f5f", + "hi LightLineRight_insert_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=159 gui=NONE guibg=#262626 guifg=#87dfff", + "hi LightLineRight_insert_tabsel_0 term=NONE cterm=NONE ctermbg=159 ctermfg=235 gui=NONE guibg=#87dfff guifg=#262626", + "hi LightLineRight_insert_1_2 term=NONE cterm=NONE ctermbg=31 ctermfg=38 gui=NONE guibg=#005f87 guifg=#0087af", + "hi LightLineRight_insert_1 term=NONE cterm=NONE ctermbg=38 ctermfg=159 gui=NONE guibg=#0087af guifg=#87dfff", + "hi LightLineRight_insert_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=38 gui=NONE guibg=#262626 guifg=#0087af", + "hi LightLineRight_insert_tabsel_1 term=NONE cterm=NONE ctermbg=38 ctermfg=235 gui=NONE guibg=#0087af guifg=#262626", + "hi LightLineRight_insert_2_3 term=NONE cterm=NONE ctermbg=31 ctermfg=31 gui=NONE guibg=#005f87 guifg=#005f87", + "hi LightLineRight_insert_2 term=NONE cterm=NONE ctermbg=31 ctermfg=159 gui=NONE guibg=#005f87 guifg=#87dfff", + "hi LightLineRight_insert_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=31 gui=NONE guibg=#262626 guifg=#005f87", + "hi vimClusterName term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi SpellRare term=reverse cterm=undercurl ctermbg=bg ctermfg=255 gui=undercurl guibg=bg guifg=fg guisp=#FFFFFF", + "hi SpellLocal term=underline cterm=undercurl ctermbg=bg ctermfg=159 gui=undercurl guibg=bg guifg=fg guisp=#70F0F0", + "hi Pmenu term=NONE cterm=NONE ctermbg=16 ctermfg=123 gui=NONE guibg=#000000 guifg=#66D9EF", + "hi PmenuSel term=NONE cterm=NONE ctermbg=244 ctermfg=fg gui=NONE guibg=#808080 guifg=fg", + "hi vimSynKeyRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi PmenuThumb term=NONE cterm=NONE ctermbg=16 ctermfg=123 gui=NONE guibg=Black guifg=#66D9EF", + "hi TabLine term=underline cterm=NONE ctermbg=234 ctermfg=244 gui=NONE guibg=#1D1F21 guifg=#808080", + "hi TabLineSel term=bold cterm=bold ctermbg=bg ctermfg=fg gui=bold guibg=bg guifg=fg", + "hi TabLineFill term=reverse cterm=reverse ctermbg=234 ctermfg=234 gui=reverse guibg=#1D1F21 guifg=#1D1F21", + "hi CursorColumn term=reverse cterm=NONE ctermbg=59 ctermfg=fg gui=NONE guibg=#293739 guifg=fg", + "hi Identifier term=underline cterm=NONE ctermbg=bg ctermfg=189 gui=NONE guibg=bg guifg=#B6B7EB", + "hi NERDTreeLink term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimOperParen term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynLine term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel_0 term=NONE cterm=NONE ctermbg=252 ctermfg=235 gui=NONE guibg=#d0d0d0 guifg=#262626", + "hi LightLineRight_normal_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineRight_normal_1 term=NONE cterm=NONE ctermbg=240 ctermfg=250 gui=NONE guibg=#585858 guifg=#bcbcbc", + "hi LightLineRight_normal_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_normal_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineRight_normal_2_3 term=NONE cterm=NONE ctermbg=236 ctermfg=236 gui=NONE guibg=#303030 guifg=#303030", + "hi LightLineRight_normal_2 term=NONE cterm=NONE ctermbg=236 ctermfg=247 gui=NONE guibg=#303030 guifg=#9e9e9e", + "hi LightLineRight_normal_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_normal_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_normal_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_insert_tabsel_2 term=NONE cterm=NONE ctermbg=31 ctermfg=235 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineLeft_insert_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_insert_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_insert_tabsel_2 term=NONE cterm=NONE ctermbg=31 ctermfg=235 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineLeft_insert_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=31 gui=NONE guibg=#262626 guifg=#005f87", + "hi LightLineRight_insert_tabsel_3 term=NONE cterm=NONE ctermbg=31 ctermfg=235 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineRight_insert_3_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=31 gui=NONE guibg=#262626 guifg=#005f87", + "hi LightLineLeft_insert_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_insert_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_insert_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMatchRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMtchCchar term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMtchGroup term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi ColorColumn term=reverse cterm=NONE ctermbg=231 ctermfg=fg gui=NONE guibg=lightgray guifg=fg", + "hi MatchParen term=reverse cterm=NONE ctermbg=238 ctermfg=188 gui=NONE guibg=#444444 guifg=#B7B9B8", + "hi Comment term=bold cterm=NONE ctermbg=bg ctermfg=145 gui=NONE guibg=bg guifg=#7C7C7C", + "hi Constant term=underline cterm=NONE ctermbg=bg ctermfg=194 gui=NONE guibg=bg guifg=#99CC99", + "hi Special term=bold cterm=NONE ctermbg=234 ctermfg=123 gui=NONE guibg=bg guifg=#66D9EF", + "hi vimSynRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Statement term=bold cterm=NONE ctermbg=bg ctermfg=159 gui=NONE guibg=bg guifg=#92C5F7", + "hi PreProc term=underline cterm=NONE ctermbg=bg ctermfg=229 gui=NONE guibg=bg guifg=#DAD085", + "hi Type term=underline cterm=NONE ctermbg=bg ctermfg=123 gui=NONE guibg=bg guifg=#66D9EF", + "hi LightLineLeft_inactive_0 term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_inactive_0_1 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi vimMenuRhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroup term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroupError term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_normal_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_normal_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_normal_tabsel_3 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_normal_3_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_normal_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_normal_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi Repeat term=NONE cterm=NONE ctermbg=bg ctermfg=159 gui=NONE guibg=bg guifg=#92C5F7", + "hi LightLineLeft_insert_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiBang term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynPatMod term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncLines term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Underlined term=underline cterm=underline ctermbg=bg ctermfg=244 gui=underline guibg=bg guifg=#808080", + "hi Ignore term=NONE cterm=NONE ctermbg=234 ctermfg=244 gui=NONE guibg=bg guifg=#808080", + "hi Error term=reverse cterm=NONE ctermbg=52 ctermfg=192 gui=NONE guibg=#1E0010 guifg=#A8FF60", + "hi vimSyncLinecont term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi String term=NONE cterm=NONE ctermbg=bg ctermfg=192 gui=NONE guibg=bg guifg=#A8FF60", + "hi Character term=NONE cterm=NONE ctermbg=bg ctermfg=192 gui=NONE guibg=bg guifg=#A8FF60", + "hi Number term=NONE cterm=NONE ctermbg=bg ctermfg=194 gui=NONE guibg=bg guifg=#99CC99", + "hi Boolean term=NONE cterm=NONE ctermbg=bg ctermfg=194 gui=NONE guibg=bg guifg=#99CC99", + "hi Float term=NONE cterm=NONE ctermbg=bg ctermfg=194 gui=NONE guibg=bg guifg=#99CC99", + "hi Function term=NONE cterm=NONE ctermbg=bg ctermfg=229 gui=NONE guibg=bg guifg=#DAD085", + "hi vimMenuMap term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_inactive_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_inactive_tabsel_0 term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineMiddle_inactive term=NONE cterm=NONE ctermbg=236 ctermfg=245 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_inactive_0_1 term=NONE cterm=NONE ctermbg=235 ctermfg=241 gui=NONE guibg=#262626 guifg=#606060", + "hi LightLineRight_inactive_0 term=NONE cterm=NONE ctermbg=241 ctermfg=235 gui=NONE guibg=#606060 guifg=#262626", + "hi LightLineRight_inactive_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=241 gui=NONE guibg=#262626 guifg=#606060", + "hi LightLineRight_inactive_tabsel_0 term=NONE cterm=NONE ctermbg=241 ctermfg=235 gui=NONE guibg=#606060 guifg=#262626", + "hi LightLineRight_inactive_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_inactive_1 term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_inactive_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi vimEcho term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimIf term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiLink term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Conditional term=NONE cterm=NONE ctermbg=bg ctermfg=159 gui=NONE guibg=bg guifg=#92C5F7", + "hi vimHiKeyList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Label term=NONE cterm=NONE ctermbg=bg ctermfg=192 gui=NONE guibg=bg guifg=#A8FF60", + "hi Operator term=NONE cterm=NONE ctermbg=bg ctermfg=159 gui=NONE guibg=bg guifg=#92C5F7", + "hi Keyword term=NONE cterm=NONE ctermbg=bg ctermfg=159 gui=NONE guibg=bg guifg=#92C5F7", + "hi Exception term=NONE cterm=NONE ctermbg=bg ctermfg=229 gui=NONE guibg=bg guifg=#DAD085", + "hi Define term=NONE cterm=NONE ctermbg=bg ctermfg=123 gui=NONE guibg=bg guifg=#66D9EF", + "hi Macro term=NONE cterm=NONE ctermbg=bg ctermfg=223 gui=NONE guibg=bg guifg=#C4BE89", + "hi PreCondit term=NONE cterm=NONE ctermbg=bg ctermfg=229 gui=NONE guibg=bg guifg=#DAD085", + "hi LightLineRight_inactive_tabsel_1 term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_inactive_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_inactive_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_inactive_tabsel_1 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_inactive_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_inactive_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_inactive_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_inactive_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_inactive_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_command_0 term=bold cterm=bold ctermbg=190 ctermfg=28 gui=bold guibg=#afdf00 guifg=#005f00", + "hi vimFuncBody term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFuncBlank term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimEscapeBrace term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSetEqual term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRep term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRange term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiTermcap term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi CursorLine term=underline cterm=NONE ctermbg=60 ctermfg=fg gui=NONE guibg=#293739 guifg=fg", + "hi LightLineRight_insert_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiCtermColor term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiFontname term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiGuiFontname term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Structure term=NONE cterm=NONE ctermbg=bg ctermfg=123 gui=NONE guibg=bg guifg=#66D9EF", + "hi Typedef term=NONE cterm=NONE ctermbg=bg ctermfg=123 gui=NONE guibg=bg guifg=#66D9EF", + "hi Tag term=NONE cterm=NONE ctermbg=bg ctermfg=159 gui=NONE guibg=bg guifg=#92C5F7", + "hi SpecialChar term=NONE cterm=NONE ctermbg=bg ctermfg=159 gui=NONE guibg=bg guifg=#92C5F7", + "hi Delimiter term=NONE cterm=NONE ctermbg=bg ctermfg=245 gui=NONE guibg=bg guifg=#8F8F8F", + "hi SpecialComment term=NONE cterm=NONE ctermbg=bg ctermfg=145 gui=NONE guibg=bg guifg=#7C7C7C", + "hi Debug term=NONE cterm=NONE ctermbg=bg ctermfg=188 gui=NONE guibg=bg guifg=#BCA3A3", + "hi Cursor term=NONE cterm=NONE ctermbg=243 ctermfg=255 gui=NONE guibg=#777777 guifg=#F1F1F1", + "hi iCursor term=NONE cterm=NONE ctermbg=243 ctermfg=255 gui=NONE guibg=#777777 guifg=#F1F1F1", + "hi PmenuSbar term=NONE cterm=NONE ctermbg=232 ctermfg=fg gui=NONE guibg=#080808 guifg=fg", + "hi LightLineLeft_command_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=190 gui=NONE guibg=#585858 guifg=#afdf00", + "hi LightLineLeft_command_0_tabsel term=bold cterm=bold ctermbg=235 ctermfg=190 gui=bold guibg=#262626 guifg=#afdf00", + "hi LightLineLeft_command_tabsel_0 term=bold cterm=bold ctermbg=190 ctermfg=235 gui=bold guibg=#afdf00 guifg=#262626", + "hi LightLineLeft_command_1 term=NONE cterm=NONE ctermbg=240 ctermfg=255 gui=NONE guibg=#585858 guifg=#ffffff", + "hi LightLineLeft_command_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineLeft_command_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_command_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineMiddle_command term=NONE cterm=NONE ctermbg=236 ctermfg=245 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_command_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=252 gui=NONE guibg=#585858 guifg=#d0d0d0", + "hi LightLineRight_command_0 term=NONE cterm=NONE ctermbg=252 ctermfg=241 gui=NONE guibg=#d0d0d0 guifg=#606060", + "hi LightLineRight_normal_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCommentTitleLeader term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimGlobal term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=252 gui=NONE guibg=#262626 guifg=#d0d0d0", + "hi LightLineRight_command_tabsel_0 term=NONE cterm=NONE ctermbg=252 ctermfg=235 gui=NONE guibg=#d0d0d0 guifg=#262626", + "hi LightLineRight_command_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineRight_command_1 term=NONE cterm=NONE ctermbg=240 ctermfg=250 gui=NONE guibg=#585858 guifg=#bcbcbc", + "hi LightLineRight_command_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_command_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineRight_command_2_3 term=NONE cterm=NONE ctermbg=236 ctermfg=236 gui=NONE guibg=#303030 guifg=#303030", + "hi LightLineRight_command_2 term=NONE cterm=NONE ctermbg=236 ctermfg=247 gui=NONE guibg=#303030 guifg=#9e9e9e", + "hi LightLineRight_command_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_command_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_command_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimPatRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCollection term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstPat term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRep4 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncMatch term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncLinebreak term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Todo term=NONE cterm=NONE ctermbg=234 ctermfg=255 gui=NONE guibg=bg guifg=#FFFFFF", + "hi vimSyncRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimExtCmd term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFilter term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSet term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_command_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_command_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_command_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_command_tabsel_3 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_command_3_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_command_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_command_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_command_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCollClass term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi pythonSpaceError term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi pythonSync term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapLhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoCmdSpace term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoEventList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoCmdSfxList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapRhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapRhsExtend term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi StorageClass term=NONE cterm=NONE ctermbg=bg ctermfg=189 gui=NONE guibg=bg guifg=#B6B7EB", + "hi LightLineLeft_normal_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimPythonRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroupSyncA term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimGroupList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMenuBang term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMenuPriority term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi CursorLineNr term=bold cterm=NONE ctermbg=bg ctermfg=189 gui=NONE guibg=bg guifg=#B6B7EB", + "hi Question term=NONE cterm=bold ctermbg=bg ctermfg=123 gui=bold guibg=bg guifg=#66D9EF", + "hi StatusLine term=bold,reverse cterm=NONE ctermbg=255 ctermfg=102 gui=NONE guibg=fg guifg=#455354", + "hi StatusLineNC term=reverse cterm=reverse ctermbg=244 ctermfg=232 gui=reverse guibg=#080808 guifg=#808080", + "hi VertSplit term=reverse cterm=reverse ctermbg=244 ctermfg=232 gui=reverse guibg=#080808 guifg=#808080", + "hi Title term=bold cterm=NONE ctermbg=bg ctermfg=189 gui=NONE guibg=bg guifg=#B6B7EB", + "hi Visual term=reverse cterm=NONE ctermbg=95 ctermfg=fg gui=NONE guibg=#403D3D guifg=fg", + "hi VisualNOS term=NONE cterm=NONE ctermbg=95 ctermfg=fg gui=NONE guibg=#403D3D guifg=fg", + "hi WarningMsg term=NONE cterm=NONE ctermbg=236 ctermfg=255 gui=NONE guibg=#333333 guifg=#FFFFFF", + "hi WildMenu term=NONE cterm=NONE ctermbg=16 ctermfg=123 gui=NONE guibg=#000000 guifg=#66D9EF", + "hi LightLineLeft_normal_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAuSyntax term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimUserCmd term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCmdSep term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimIsCommand term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0 term=bold cterm=bold ctermbg=190 ctermfg=28 gui=bold guibg=#afdf00 guifg=#005f00", + "hi LightLineLeft_normal_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=190 gui=NONE guibg=#585858 guifg=#afdf00", + "hi LightLineLeft_insert_0 term=bold cterm=bold ctermbg=255 ctermfg=30 gui=bold guibg=#ffffff guifg=#005f5f", + "hi LightLineLeft_insert_0_1 term=NONE cterm=NONE ctermbg=38 ctermfg=255 gui=NONE guibg=#0087af guifg=#ffffff", + "hi LightLineLeft_insert_0_tabsel term=bold cterm=bold ctermbg=235 ctermfg=255 gui=bold guibg=#262626 guifg=#ffffff", + "hi LightLineLeft_insert_tabsel_0 term=bold cterm=bold ctermbg=255 ctermfg=235 gui=bold guibg=#ffffff guifg=#262626", + "hi LightLineLeft_insert_1 term=NONE cterm=NONE ctermbg=38 ctermfg=255 gui=NONE guibg=#0087af guifg=#ffffff", + "hi LightLineLeft_insert_1_2 term=NONE cterm=NONE ctermbg=31 ctermfg=38 gui=NONE guibg=#005f87 guifg=#0087af", + "hi LightLineLeft_insert_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=38 gui=NONE guibg=#262626 guifg=#0087af", + "hi LightLineLeft_insert_tabsel_1 term=NONE cterm=NONE ctermbg=38 ctermfg=235 gui=NONE guibg=#0087af guifg=#262626", + "hi LightLineMiddle_insert term=NONE cterm=NONE ctermbg=31 ctermfg=159 gui=NONE guibg=#005f87 guifg=#87dfff", + "hi LightLineRight_insert_0_1 term=NONE cterm=NONE ctermbg=38 ctermfg=159 gui=NONE guibg=#0087af guifg=#87dfff", + "hi vimNormCmds term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Folded term=NONE cterm=NONE ctermbg=16 ctermfg=102 gui=NONE guibg=#000000 guifg=#465457", + "hi FoldColumn term=NONE cterm=NONE ctermbg=16 ctermfg=102 gui=NONE guibg=#000000 guifg=#465457", + "hi DiffAdd term=bold cterm=NONE ctermbg=24 ctermfg=fg gui=NONE guibg=#13354A guifg=fg", + "hi DiffChange term=bold cterm=NONE ctermbg=102 ctermfg=145 gui=NONE guibg=#4C4745 guifg=#89807D", + "hi DiffDelete term=bold cterm=bold ctermbg=52 ctermfg=162 gui=bold guibg=#1E0010 guifg=#960050", + "hi DiffText term=reverse cterm=NONE ctermbg=102 ctermfg=fg gui=NONE guibg=#4C4745 guifg=fg", + "hi SignColumn term=NONE cterm=NONE ctermbg=235 ctermfg=229 gui=NONE guibg=#232526 guifg=#DAD085", + "hi Conceal term=NONE cterm=NONE ctermbg=248 ctermfg=231 gui=NONE guibg=DarkGrey guifg=LightGrey", + "hi SpellBad term=reverse cterm=undercurl ctermbg=bg ctermfg=196 gui=undercurl guibg=bg guifg=fg guisp=#FF0000", + "hi SpellCap term=reverse cterm=undercurl ctermbg=bg ctermfg=147 gui=undercurl guibg=bg guifg=fg guisp=#7070F0" + }; + + +static list /*vim style coloriser specification*/ +atom_256 = { + "set background=dark", + "hi Normal term=NONE cterm=NONE ctermbg=234 ctermfg=231 gui=NONE guibg=#1D1F21 guifg=#F8F8F2", + "hi vimFiletype term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimExecute term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFunction term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0_tabsel term=bold cterm=bold ctermbg=235 ctermfg=148 gui=bold guibg=#262626 guifg=#afdf00", + "hi LightLineLeft_normal_tabsel_0 term=bold cterm=bold ctermbg=148 ctermfg=235 gui=bold guibg=#afdf00 guifg=#262626", + "hi LightLineLeft_normal_1 term=NONE cterm=NONE ctermbg=240 ctermfg=231 gui=NONE guibg=#585858 guifg=#ffffff", + "hi LightLineLeft_normal_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineLeft_normal_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_normal_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineMiddle_normal term=NONE cterm=NONE ctermbg=236 ctermfg=245 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_normal_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=252 gui=NONE guibg=#585858 guifg=#d0d0d0", + "hi LightLineRight_normal_0 term=NONE cterm=NONE ctermbg=252 ctermfg=59 gui=NONE guibg=#d0d0d0 guifg=#606060", + "hi LightLineRight_normal_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=252 gui=NONE guibg=#262626 guifg=#d0d0d0", + "hi SpecialKey term=bold cterm=NONE ctermbg=bg ctermfg=59 gui=NONE guibg=bg guifg=#465457", + "hi NonText term=bold cterm=bold ctermbg=bg ctermfg=59 gui=bold guibg=bg guifg=#465457", + "hi Directory term=bold cterm=NONE ctermbg=bg ctermfg=248 gui=NONE guibg=bg guifg=#AAAAAA", + "hi ErrorMsg term=NONE cterm=NONE ctermbg=235 ctermfg=117 gui=NONE guibg=#232526 guifg=#92C5F7", + "hi IncSearch term=reverse cterm=reverse ctermbg=180 ctermfg=16 gui=reverse guibg=#000000 guifg=#C4BE89", + "hi Search term=reverse cterm=NONE ctermbg=156 ctermfg=16 gui=NONE guibg=#B4EC85 guifg=#000000", + "hi MoreMsg term=bold cterm=bold ctermbg=bg ctermfg=155 gui=bold guibg=bg guifg=#A8FF60", + "hi ModeMsg term=bold cterm=bold ctermbg=bg ctermfg=155 gui=bold guibg=bg guifg=#A8FF60", + "hi LineNr term=underline cterm=NONE ctermbg=235 ctermfg=59 gui=NONE guibg=#232526 guifg=#465457", + "hi LightLineRight_insert_0 term=NONE cterm=NONE ctermbg=117 ctermfg=23 gui=NONE guibg=#87dfff guifg=#005f5f", + "hi LightLineRight_insert_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=117 gui=NONE guibg=#262626 guifg=#87dfff", + "hi LightLineRight_insert_tabsel_0 term=NONE cterm=NONE ctermbg=117 ctermfg=235 gui=NONE guibg=#87dfff guifg=#262626", + "hi LightLineRight_insert_1_2 term=NONE cterm=NONE ctermbg=24 ctermfg=31 gui=NONE guibg=#005f87 guifg=#0087af", + "hi LightLineRight_insert_1 term=NONE cterm=NONE ctermbg=31 ctermfg=117 gui=NONE guibg=#0087af guifg=#87dfff", + "hi LightLineRight_insert_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=31 gui=NONE guibg=#262626 guifg=#0087af", + "hi LightLineRight_insert_tabsel_1 term=NONE cterm=NONE ctermbg=31 ctermfg=235 gui=NONE guibg=#0087af guifg=#262626", + "hi LightLineRight_insert_2_3 term=NONE cterm=NONE ctermbg=24 ctermfg=24 gui=NONE guibg=#005f87 guifg=#005f87", + "hi LightLineRight_insert_2 term=NONE cterm=NONE ctermbg=24 ctermfg=117 gui=NONE guibg=#005f87 guifg=#87dfff", + "hi LightLineRight_insert_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=24 gui=NONE guibg=#262626 guifg=#005f87", + "hi vimClusterName term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi SpellRare term=reverse cterm=undercurl ctermbg=bg ctermfg=231 gui=undercurl guibg=bg guifg=fg guisp=#FFFFFF", + "hi SpellLocal term=underline cterm=undercurl ctermbg=bg ctermfg=87 gui=undercurl guibg=bg guifg=fg guisp=#70F0F0", + "hi Pmenu term=NONE cterm=NONE ctermbg=16 ctermfg=81 gui=NONE guibg=#000000 guifg=#66D9EF", + "hi PmenuSel term=NONE cterm=NONE ctermbg=244 ctermfg=fg gui=NONE guibg=#808080 guifg=fg", + "hi vimSynKeyRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi PmenuThumb term=NONE cterm=NONE ctermbg=16 ctermfg=81 gui=NONE guibg=Black guifg=#66D9EF", + "hi TabLine term=underline cterm=NONE ctermbg=234 ctermfg=244 gui=NONE guibg=#1D1F21 guifg=#808080", + "hi TabLineSel term=bold cterm=bold ctermbg=bg ctermfg=fg gui=bold guibg=bg guifg=fg", + "hi TabLineFill term=reverse cterm=reverse ctermbg=234 ctermfg=234 gui=reverse guibg=#1D1F21 guifg=#1D1F21", + "hi CursorColumn term=reverse cterm=NONE ctermbg=23 ctermfg=fg gui=NONE guibg=#293739 guifg=fg", + "hi Identifier term=underline cterm=NONE ctermbg=bg ctermfg=146 gui=NONE guibg=bg guifg=#B6B7EB", + "hi NERDTreeLink term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimOperParen term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynLine term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel_0 term=NONE cterm=NONE ctermbg=252 ctermfg=235 gui=NONE guibg=#d0d0d0 guifg=#262626", + "hi LightLineRight_normal_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineRight_normal_1 term=NONE cterm=NONE ctermbg=240 ctermfg=250 gui=NONE guibg=#585858 guifg=#bcbcbc", + "hi LightLineRight_normal_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_normal_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineRight_normal_2_3 term=NONE cterm=NONE ctermbg=236 ctermfg=236 gui=NONE guibg=#303030 guifg=#303030", + "hi LightLineRight_normal_2 term=NONE cterm=NONE ctermbg=236 ctermfg=247 gui=NONE guibg=#303030 guifg=#9e9e9e", + "hi LightLineRight_normal_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_normal_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_normal_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_insert_tabsel_2 term=NONE cterm=NONE ctermbg=24 ctermfg=235 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineLeft_insert_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_insert_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_insert_tabsel_2 term=NONE cterm=NONE ctermbg=24 ctermfg=235 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineLeft_insert_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=24 gui=NONE guibg=#262626 guifg=#005f87", + "hi LightLineRight_insert_tabsel_3 term=NONE cterm=NONE ctermbg=24 ctermfg=235 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineRight_insert_3_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=24 gui=NONE guibg=#262626 guifg=#005f87", + "hi LightLineLeft_insert_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_insert_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_insert_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMatchRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMtchCchar term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMtchGroup term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi ColorColumn term=reverse cterm=NONE ctermbg=235 ctermfg=160 gui=NONE guibg=lightgray guifg=fg", + "hi MatchParen term=reverse cterm=NONE ctermbg=238 ctermfg=145 gui=NONE guibg=#444444 guifg=#B7B9B8", + "hi Comment term=bold cterm=NONE ctermbg=bg ctermfg=244 gui=NONE guibg=bg guifg=#7C7C7C", + "hi Constant term=underline cterm=NONE ctermbg=bg ctermfg=114 gui=NONE guibg=bg guifg=#99CC99", + "hi Special term=bold cterm=NONE ctermbg=234 ctermfg=81 gui=NONE guibg=bg guifg=#66D9EF", + "hi vimSynRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Statement term=bold cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#92C5F7", + "hi PreProc term=underline cterm=NONE ctermbg=bg ctermfg=186 gui=NONE guibg=bg guifg=#DAD085", + "hi Type term=underline cterm=NONE ctermbg=bg ctermfg=81 gui=NONE guibg=bg guifg=#66D9EF", + "hi LightLineLeft_inactive_0 term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_inactive_0_1 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi vimMenuRhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroup term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroupError term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_normal_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_normal_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_normal_tabsel_3 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_normal_3_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_normal_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_normal_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi Repeat term=NONE cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#92C5F7", + "hi LightLineLeft_insert_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiBang term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynPatMod term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncLines term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Underlined term=underline cterm=underline ctermbg=bg ctermfg=244 gui=underline guibg=bg guifg=#808080", + "hi Ignore term=NONE cterm=NONE ctermbg=234 ctermfg=244 gui=NONE guibg=bg guifg=#808080", + "hi Error term=reverse cterm=NONE ctermbg=16 ctermfg=155 gui=NONE guibg=#1E0010 guifg=#A8FF60", + "hi vimSyncLinecont term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi String term=NONE cterm=NONE ctermbg=bg ctermfg=155 gui=NONE guibg=bg guifg=#A8FF60", + "hi Character term=NONE cterm=NONE ctermbg=bg ctermfg=155 gui=NONE guibg=bg guifg=#A8FF60", + "hi Number term=NONE cterm=NONE ctermbg=bg ctermfg=114 gui=NONE guibg=bg guifg=#99CC99", + "hi Boolean term=NONE cterm=NONE ctermbg=bg ctermfg=114 gui=NONE guibg=bg guifg=#99CC99", + "hi Float term=NONE cterm=NONE ctermbg=bg ctermfg=114 gui=NONE guibg=bg guifg=#99CC99", + "hi Function term=NONE cterm=NONE ctermbg=bg ctermfg=186 gui=NONE guibg=bg guifg=#DAD085", + "hi vimMenuMap term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_inactive_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_inactive_tabsel_0 term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineMiddle_inactive term=NONE cterm=NONE ctermbg=236 ctermfg=245 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_inactive_0_1 term=NONE cterm=NONE ctermbg=235 ctermfg=59 gui=NONE guibg=#262626 guifg=#606060", + "hi LightLineRight_inactive_0 term=NONE cterm=NONE ctermbg=59 ctermfg=235 gui=NONE guibg=#606060 guifg=#262626", + "hi LightLineRight_inactive_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=59 gui=NONE guibg=#262626 guifg=#606060", + "hi LightLineRight_inactive_tabsel_0 term=NONE cterm=NONE ctermbg=59 ctermfg=235 gui=NONE guibg=#606060 guifg=#262626", + "hi LightLineRight_inactive_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_inactive_1 term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_inactive_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi vimEcho term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimIf term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiLink term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Conditional term=NONE cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#92C5F7", + "hi vimHiKeyList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Label term=NONE cterm=NONE ctermbg=bg ctermfg=155 gui=NONE guibg=bg guifg=#A8FF60", + "hi Operator term=NONE cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#92C5F7", + "hi Keyword term=NONE cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#92C5F7", + "hi Exception term=NONE cterm=NONE ctermbg=bg ctermfg=186 gui=NONE guibg=bg guifg=#DAD085", + "hi Define term=NONE cterm=NONE ctermbg=bg ctermfg=81 gui=NONE guibg=bg guifg=#66D9EF", + "hi Macro term=NONE cterm=NONE ctermbg=bg ctermfg=180 gui=NONE guibg=bg guifg=#C4BE89", + "hi PreCondit term=NONE cterm=NONE ctermbg=bg ctermfg=186 gui=NONE guibg=bg guifg=#DAD085", + "hi LightLineRight_inactive_tabsel_1 term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_inactive_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_inactive_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_inactive_tabsel_1 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_inactive_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_inactive_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_inactive_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_inactive_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_inactive_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_command_0 term=bold cterm=bold ctermbg=148 ctermfg=22 gui=bold guibg=#afdf00 guifg=#005f00", + "hi vimFuncBody term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFuncBlank term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimEscapeBrace term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSetEqual term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRep term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRange term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiTermcap term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi CursorLine term=NONE cterm=NONE ctermbg=238 ctermfg=NONE gui=NONE guibg=#293739 guifg=fg", + "hi LightLineRight_insert_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiCtermColor term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiFontname term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiGuiFontname term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Structure term=NONE cterm=NONE ctermbg=bg ctermfg=81 gui=NONE guibg=bg guifg=#66D9EF", + "hi Typedef term=NONE cterm=NONE ctermbg=bg ctermfg=81 gui=NONE guibg=bg guifg=#66D9EF", + "hi Tag term=NONE cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#92C5F7", + "hi SpecialChar term=NONE cterm=NONE ctermbg=bg ctermfg=117 gui=NONE guibg=bg guifg=#92C5F7", + "hi Delimiter term=NONE cterm=NONE ctermbg=bg ctermfg=245 gui=NONE guibg=bg guifg=#8F8F8F", + "hi SpecialComment term=NONE cterm=NONE ctermbg=bg ctermfg=244 gui=NONE guibg=bg guifg=#7C7C7C", + "hi Debug term=NONE cterm=NONE ctermbg=bg ctermfg=145 gui=NONE guibg=bg guifg=#BCA3A3", + "hi Cursor term=NONE cterm=NONE ctermbg=243 ctermfg=255 gui=NONE guibg=#777777 guifg=#F1F1F1", + "hi iCursor term=NONE cterm=NONE ctermbg=243 ctermfg=255 gui=NONE guibg=#777777 guifg=#F1F1F1", + "hi PmenuSbar term=NONE cterm=NONE ctermbg=232 ctermfg=fg gui=NONE guibg=#080808 guifg=fg", + "hi LightLineLeft_command_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=148 gui=NONE guibg=#585858 guifg=#afdf00", + "hi LightLineLeft_command_0_tabsel term=bold cterm=bold ctermbg=235 ctermfg=148 gui=bold guibg=#262626 guifg=#afdf00", + "hi LightLineLeft_command_tabsel_0 term=bold cterm=bold ctermbg=148 ctermfg=235 gui=bold guibg=#afdf00 guifg=#262626", + "hi LightLineLeft_command_1 term=NONE cterm=NONE ctermbg=240 ctermfg=231 gui=NONE guibg=#585858 guifg=#ffffff", + "hi LightLineLeft_command_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineLeft_command_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_command_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineMiddle_command term=NONE cterm=NONE ctermbg=236 ctermfg=245 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_command_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=252 gui=NONE guibg=#585858 guifg=#d0d0d0", + "hi LightLineRight_command_0 term=NONE cterm=NONE ctermbg=252 ctermfg=59 gui=NONE guibg=#d0d0d0 guifg=#606060", + "hi LightLineRight_normal_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCommentTitleLeader term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimGlobal term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_0_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=252 gui=NONE guibg=#262626 guifg=#d0d0d0", + "hi LightLineRight_command_tabsel_0 term=NONE cterm=NONE ctermbg=252 ctermfg=235 gui=NONE guibg=#d0d0d0 guifg=#262626", + "hi LightLineRight_command_1_2 term=NONE cterm=NONE ctermbg=236 ctermfg=240 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineRight_command_1 term=NONE cterm=NONE ctermbg=240 ctermfg=250 gui=NONE guibg=#585858 guifg=#bcbcbc", + "hi LightLineRight_command_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=240 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_command_tabsel_1 term=NONE cterm=NONE ctermbg=240 ctermfg=235 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineRight_command_2_3 term=NONE cterm=NONE ctermbg=236 ctermfg=236 gui=NONE guibg=#303030 guifg=#303030", + "hi LightLineRight_command_2 term=NONE cterm=NONE ctermbg=236 ctermfg=247 gui=NONE guibg=#303030 guifg=#9e9e9e", + "hi LightLineRight_command_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_command_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_command_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimPatRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCollection term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstPat term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRep4 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncMatch term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncLinebreak term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Todo term=NONE cterm=NONE ctermbg=234 ctermfg=231 gui=NONE guibg=bg guifg=#FFFFFF", + "hi vimSyncRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimExtCmd term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFilter term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSet term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_command_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=250 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_command_tabsel_2 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_command_2_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_command_tabsel_3 term=NONE cterm=NONE ctermbg=236 ctermfg=235 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_command_3_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=236 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_command_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_command_tabsel_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=235 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_command_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCollClass term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi pythonSpaceError term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi pythonSync term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapLhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoCmdSpace term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoEventList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoCmdSfxList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapRhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapRhsExtend term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi StorageClass term=NONE cterm=NONE ctermbg=bg ctermfg=146 gui=NONE guibg=bg guifg=#B6B7EB", + "hi LightLineLeft_normal_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimPythonRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroupSyncA term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimGroupList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMenuBang term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMenuPriority term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi CursorLineNr term=bold cterm=NONE ctermbg=bg ctermfg=146 gui=NONE guibg=bg guifg=#B6B7EB", + "hi Question term=NONE cterm=bold ctermbg=bg ctermfg=81 gui=bold guibg=bg guifg=#66D9EF", + "hi StatusLine term=bold,reverse cterm=NONE ctermbg=231 ctermfg=59 gui=NONE guibg=fg guifg=#455354", + "hi StatusLineNC term=reverse cterm=reverse ctermbg=244 ctermfg=232 gui=reverse guibg=#080808 guifg=#808080", + "hi VertSplit term=reverse cterm=reverse ctermbg=244 ctermfg=232 gui=reverse guibg=#080808 guifg=#808080", + "hi Title term=bold cterm=NONE ctermbg=bg ctermfg=146 gui=NONE guibg=bg guifg=#B6B7EB", + "hi Visual term=reverse cterm=NONE ctermbg=59 ctermfg=fg gui=NONE guibg=#403D3D guifg=fg", + "hi VisualNOS term=NONE cterm=NONE ctermbg=59 ctermfg=fg gui=NONE guibg=#403D3D guifg=fg", + "hi WarningMsg term=NONE cterm=NONE ctermbg=236 ctermfg=231 gui=NONE guibg=#333333 guifg=#FFFFFF", + "hi WildMenu term=NONE cterm=NONE ctermbg=16 ctermfg=81 gui=NONE guibg=#000000 guifg=#66D9EF", + "hi LightLineLeft_normal_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAuSyntax term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimUserCmd term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCmdSep term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimIsCommand term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0 term=bold cterm=bold ctermbg=148 ctermfg=22 gui=bold guibg=#afdf00 guifg=#005f00", + "hi LightLineLeft_normal_0_1 term=NONE cterm=NONE ctermbg=240 ctermfg=148 gui=NONE guibg=#585858 guifg=#afdf00", + "hi LightLineLeft_insert_0 term=bold cterm=bold ctermbg=231 ctermfg=23 gui=bold guibg=#ffffff guifg=#005f5f", + "hi LightLineLeft_insert_0_1 term=NONE cterm=NONE ctermbg=31 ctermfg=231 gui=NONE guibg=#0087af guifg=#ffffff", + "hi LightLineLeft_insert_0_tabsel term=bold cterm=bold ctermbg=235 ctermfg=231 gui=bold guibg=#262626 guifg=#ffffff", + "hi LightLineLeft_insert_tabsel_0 term=bold cterm=bold ctermbg=231 ctermfg=235 gui=bold guibg=#ffffff guifg=#262626", + "hi LightLineLeft_insert_1 term=NONE cterm=NONE ctermbg=31 ctermfg=231 gui=NONE guibg=#0087af guifg=#ffffff", + "hi LightLineLeft_insert_1_2 term=NONE cterm=NONE ctermbg=24 ctermfg=31 gui=NONE guibg=#005f87 guifg=#0087af", + "hi LightLineLeft_insert_1_tabsel term=NONE cterm=NONE ctermbg=235 ctermfg=31 gui=NONE guibg=#262626 guifg=#0087af", + "hi LightLineLeft_insert_tabsel_1 term=NONE cterm=NONE ctermbg=31 ctermfg=235 gui=NONE guibg=#0087af guifg=#262626", + "hi LightLineMiddle_insert term=NONE cterm=NONE ctermbg=24 ctermfg=117 gui=NONE guibg=#005f87 guifg=#87dfff", + "hi LightLineRight_insert_0_1 term=NONE cterm=NONE ctermbg=31 ctermfg=117 gui=NONE guibg=#0087af guifg=#87dfff", + "hi vimNormCmds term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Folded term=NONE cterm=NONE ctermbg=16 ctermfg=59 gui=NONE guibg=#000000 guifg=#465457", + "hi FoldColumn term=NONE cterm=NONE ctermbg=16 ctermfg=59 gui=NONE guibg=#000000 guifg=#465457", + "hi DiffAdd term=bold cterm=NONE ctermbg=23 ctermfg=fg gui=NONE guibg=#13354A guifg=fg", + "hi DiffChange term=bold cterm=NONE ctermbg=59 ctermfg=102 gui=NONE guibg=#4C4745 guifg=#89807D", + "hi DiffDelete term=bold cterm=bold ctermbg=16 ctermfg=89 gui=bold guibg=#1E0010 guifg=#960050", + "hi DiffText term=reverse cterm=NONE ctermbg=59 ctermfg=fg gui=NONE guibg=#4C4745 guifg=fg", + "hi SignColumn term=NONE cterm=NONE ctermbg=235 ctermfg=186 gui=NONE guibg=#232526 guifg=#DAD085", + "hi Conceal term=NONE cterm=NONE ctermbg=248 ctermfg=252 gui=NONE guibg=DarkGrey guifg=LightGrey", + "hi SpellBad term=reverse cterm=undercurl ctermbg=bg ctermfg=196 gui=undercurl guibg=bg guifg=fg guisp=#FF0000", + "hi SpellCap term=reverse cterm=undercurl ctermbg=bg ctermfg=63 gui=undercurl guibg=bg guifg=fg guisp=#7070F0", + }; + + +static list /*vim style coloriser specification*/ +atom_88 = { + "set background=dark", + "hi Normal term=NONE cterm=NONE ctermbg=80 ctermfg=79 gui=NONE guibg=#1D1F21 guifg=#F8F8F2", + "hi vimFiletype term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimExecute term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFunction term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0_tabsel term=bold cterm=bold ctermbg=80 ctermfg=56 gui=bold guibg=#262626 guifg=#afdf00", + "hi LightLineLeft_normal_tabsel_0 term=bold cterm=bold ctermbg=56 ctermfg=80 gui=bold guibg=#afdf00 guifg=#262626", + "hi LightLineLeft_normal_1 term=NONE cterm=NONE ctermbg=81 ctermfg=79 gui=NONE guibg=#585858 guifg=#ffffff", + "hi LightLineLeft_normal_1_2 term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineLeft_normal_1_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_normal_tabsel_1 term=NONE cterm=NONE ctermbg=81 ctermfg=80 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineMiddle_normal term=NONE cterm=NONE ctermbg=80 ctermfg=83 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_normal_0_1 term=NONE cterm=NONE ctermbg=81 ctermfg=86 gui=NONE guibg=#585858 guifg=#d0d0d0", + "hi LightLineRight_normal_0 term=NONE cterm=NONE ctermbg=86 ctermfg=81 gui=NONE guibg=#d0d0d0 guifg=#606060", + "hi LightLineRight_normal_0_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=86 gui=NONE guibg=#262626 guifg=#d0d0d0", + "hi SpecialKey term=bold cterm=NONE ctermbg=bg ctermfg=81 gui=NONE guibg=bg guifg=#465457", + "hi NonText term=bold cterm=bold ctermbg=bg ctermfg=81 gui=bold guibg=bg guifg=#465457", + "hi Directory term=bold cterm=NONE ctermbg=bg ctermfg=84 gui=NONE guibg=bg guifg=#AAAAAA", + "hi ErrorMsg term=NONE cterm=NONE ctermbg=80 ctermfg=43 gui=NONE guibg=#232526 guifg=#92C5F7", + "hi IncSearch term=reverse cterm=reverse ctermbg=57 ctermfg=16 gui=reverse guibg=#000000 guifg=#C4BE89", + "hi Search term=reverse cterm=NONE ctermbg=61 ctermfg=16 gui=NONE guibg=#B4EC85 guifg=#000000", + "hi MoreMsg term=bold cterm=bold ctermbg=bg ctermfg=45 gui=bold guibg=bg guifg=#A8FF60", + "hi ModeMsg term=bold cterm=bold ctermbg=bg ctermfg=45 gui=bold guibg=bg guifg=#A8FF60", + "hi LineNr term=underline cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#232526 guifg=#465457", + "hi LightLineRight_insert_0 term=NONE cterm=NONE ctermbg=43 ctermfg=21 gui=NONE guibg=#87dfff guifg=#005f5f", + "hi LightLineRight_insert_0_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=43 gui=NONE guibg=#262626 guifg=#87dfff", + "hi LightLineRight_insert_tabsel_0 term=NONE cterm=NONE ctermbg=43 ctermfg=80 gui=NONE guibg=#87dfff guifg=#262626", + "hi LightLineRight_insert_1_2 term=NONE cterm=NONE ctermbg=21 ctermfg=22 gui=NONE guibg=#005f87 guifg=#0087af", + "hi LightLineRight_insert_1 term=NONE cterm=NONE ctermbg=22 ctermfg=43 gui=NONE guibg=#0087af guifg=#87dfff", + "hi LightLineRight_insert_1_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=22 gui=NONE guibg=#262626 guifg=#0087af", + "hi LightLineRight_insert_tabsel_1 term=NONE cterm=NONE ctermbg=22 ctermfg=80 gui=NONE guibg=#0087af guifg=#262626", + "hi LightLineRight_insert_2_3 term=NONE cterm=NONE ctermbg=21 ctermfg=21 gui=NONE guibg=#005f87 guifg=#005f87", + "hi LightLineRight_insert_2 term=NONE cterm=NONE ctermbg=21 ctermfg=43 gui=NONE guibg=#005f87 guifg=#87dfff", + "hi LightLineRight_insert_2_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=21 gui=NONE guibg=#262626 guifg=#005f87", + "hi vimClusterName term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi SpellRare term=reverse cterm=undercurl ctermbg=bg ctermfg=79 gui=undercurl guibg=bg guifg=fg guisp=#FFFFFF", + "hi SpellLocal term=underline cterm=undercurl ctermbg=bg ctermfg=47 gui=undercurl guibg=bg guifg=fg guisp=#70F0F0", + "hi Pmenu term=NONE cterm=NONE ctermbg=16 ctermfg=43 gui=NONE guibg=#000000 guifg=#66D9EF", + "hi PmenuSel term=NONE cterm=NONE ctermbg=83 ctermfg=fg gui=NONE guibg=#808080 guifg=fg", + "hi vimSynKeyRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi PmenuThumb term=NONE cterm=NONE ctermbg=16 ctermfg=43 gui=NONE guibg=Black guifg=#66D9EF", + "hi TabLine term=underline cterm=NONE ctermbg=80 ctermfg=83 gui=NONE guibg=#1D1F21 guifg=#808080", + "hi TabLineSel term=bold cterm=bold ctermbg=bg ctermfg=fg gui=bold guibg=bg guifg=fg", + "hi TabLineFill term=reverse cterm=reverse ctermbg=80 ctermfg=80 gui=reverse guibg=#1D1F21 guifg=#1D1F21", + "hi CursorColumn term=reverse cterm=NONE ctermbg=80 ctermfg=fg gui=NONE guibg=#293739 guifg=fg", + "hi Identifier term=underline cterm=NONE ctermbg=bg ctermfg=59 gui=NONE guibg=bg guifg=#B6B7EB", + "hi NERDTreeLink term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimOperParen term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynLine term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel_0 term=NONE cterm=NONE ctermbg=86 ctermfg=80 gui=NONE guibg=#d0d0d0 guifg=#262626", + "hi LightLineRight_normal_1_2 term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineRight_normal_1 term=NONE cterm=NONE ctermbg=81 ctermfg=85 gui=NONE guibg=#585858 guifg=#bcbcbc", + "hi LightLineRight_normal_1_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_normal_tabsel_1 term=NONE cterm=NONE ctermbg=81 ctermfg=80 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineRight_normal_2_3 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#303030", + "hi LightLineRight_normal_2 term=NONE cterm=NONE ctermbg=80 ctermfg=84 gui=NONE guibg=#303030 guifg=#9e9e9e", + "hi LightLineRight_normal_2_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_normal_tabsel_2 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_normal_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=85 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_insert_tabsel_2 term=NONE cterm=NONE ctermbg=21 ctermfg=80 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineLeft_insert_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=85 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_insert_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=85 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_insert_tabsel_2 term=NONE cterm=NONE ctermbg=21 ctermfg=80 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineLeft_insert_2_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=21 gui=NONE guibg=#262626 guifg=#005f87", + "hi LightLineRight_insert_tabsel_3 term=NONE cterm=NONE ctermbg=21 ctermfg=80 gui=NONE guibg=#005f87 guifg=#262626", + "hi LightLineRight_insert_3_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=21 gui=NONE guibg=#262626 guifg=#005f87", + "hi LightLineLeft_insert_tabsel_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_insert_tabsel_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_insert_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMatchRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMtchCchar term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynMtchGroup term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi ColorColumn term=reverse cterm=NONE ctermbg=86 ctermfg=fg gui=NONE guibg=lightgray guifg=fg", + "hi MatchParen term=reverse cterm=NONE ctermbg=80 ctermfg=85 gui=NONE guibg=#444444 guifg=#B7B9B8", + "hi Comment term=bold cterm=NONE ctermbg=bg ctermfg=82 gui=NONE guibg=bg guifg=#7C7C7C", + "hi Constant term=underline cterm=NONE ctermbg=bg ctermfg=41 gui=NONE guibg=bg guifg=#99CC99", + "hi Special term=bold cterm=NONE ctermbg=80 ctermfg=43 gui=NONE guibg=bg guifg=#66D9EF", + "hi vimSynRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Statement term=bold cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#92C5F7", + "hi PreProc term=underline cterm=NONE ctermbg=bg ctermfg=57 gui=NONE guibg=bg guifg=#DAD085", + "hi Type term=underline cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#66D9EF", + "hi LightLineLeft_inactive_0 term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_inactive_0_1 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi vimMenuRhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroup term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroupError term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=85 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_normal_tabsel_2 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_normal_2_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_normal_tabsel_3 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_normal_3_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_normal_tabsel_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_normal_tabsel_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi Repeat term=NONE cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#92C5F7", + "hi LightLineLeft_insert_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiBang term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSynPatMod term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncLines term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Underlined term=underline cterm=underline ctermbg=bg ctermfg=83 gui=underline guibg=bg guifg=#808080", + "hi Ignore term=NONE cterm=NONE ctermbg=80 ctermfg=83 gui=NONE guibg=bg guifg=#808080", + "hi Error term=reverse cterm=NONE ctermbg=16 ctermfg=45 gui=NONE guibg=#1E0010 guifg=#A8FF60", + "hi vimSyncLinecont term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi String term=NONE cterm=NONE ctermbg=bg ctermfg=45 gui=NONE guibg=bg guifg=#A8FF60", + "hi Character term=NONE cterm=NONE ctermbg=bg ctermfg=45 gui=NONE guibg=bg guifg=#A8FF60", + "hi Number term=NONE cterm=NONE ctermbg=bg ctermfg=41 gui=NONE guibg=bg guifg=#99CC99", + "hi Boolean term=NONE cterm=NONE ctermbg=bg ctermfg=41 gui=NONE guibg=bg guifg=#99CC99", + "hi Float term=NONE cterm=NONE ctermbg=bg ctermfg=41 gui=NONE guibg=bg guifg=#99CC99", + "hi Function term=NONE cterm=NONE ctermbg=bg ctermfg=57 gui=NONE guibg=bg guifg=#DAD085", + "hi vimMenuMap term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_inactive_0_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_inactive_tabsel_0 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineMiddle_inactive term=NONE cterm=NONE ctermbg=80 ctermfg=83 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_inactive_0_1 term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#262626 guifg=#606060", + "hi LightLineRight_inactive_0 term=NONE cterm=NONE ctermbg=81 ctermfg=80 gui=NONE guibg=#606060 guifg=#262626", + "hi LightLineRight_inactive_0_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#262626 guifg=#606060", + "hi LightLineRight_inactive_tabsel_0 term=NONE cterm=NONE ctermbg=81 ctermfg=80 gui=NONE guibg=#606060 guifg=#262626", + "hi LightLineRight_inactive_1_2 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_inactive_1 term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_inactive_1_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi vimEcho term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimIf term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_insert_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiLink term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Conditional term=NONE cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#92C5F7", + "hi vimHiKeyList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Label term=NONE cterm=NONE ctermbg=bg ctermfg=45 gui=NONE guibg=bg guifg=#A8FF60", + "hi Operator term=NONE cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#92C5F7", + "hi Keyword term=NONE cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#92C5F7", + "hi Exception term=NONE cterm=NONE ctermbg=bg ctermfg=57 gui=NONE guibg=bg guifg=#DAD085", + "hi Define term=NONE cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#66D9EF", + "hi Macro term=NONE cterm=NONE ctermbg=bg ctermfg=57 gui=NONE guibg=bg guifg=#C4BE89", + "hi PreCondit term=NONE cterm=NONE ctermbg=bg ctermfg=57 gui=NONE guibg=bg guifg=#DAD085", + "hi LightLineRight_inactive_tabsel_1 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_inactive_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=85 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_inactive_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=85 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_inactive_tabsel_1 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_inactive_1_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_inactive_tabsel_2 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_inactive_2_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_inactive_tabsel_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_inactive_tabsel_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_command_0 term=bold cterm=bold ctermbg=56 ctermfg=20 gui=bold guibg=#afdf00 guifg=#005f00", + "hi vimFuncBody term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFuncBlank term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimEscapeBrace term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSetEqual term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRep term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRange term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiTermcap term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi CursorLine term=underline cterm=NONE ctermbg=80 ctermfg=fg gui=NONE guibg=#293739 guifg=fg", + "hi LightLineRight_insert_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiCtermColor term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiFontname term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimHiGuiFontname term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Structure term=NONE cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#66D9EF", + "hi Typedef term=NONE cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#66D9EF", + "hi Tag term=NONE cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#92C5F7", + "hi SpecialChar term=NONE cterm=NONE ctermbg=bg ctermfg=43 gui=NONE guibg=bg guifg=#92C5F7", + "hi Delimiter term=NONE cterm=NONE ctermbg=bg ctermfg=83 gui=NONE guibg=bg guifg=#8F8F8F", + "hi SpecialComment term=NONE cterm=NONE ctermbg=bg ctermfg=82 gui=NONE guibg=bg guifg=#7C7C7C", + "hi Debug term=NONE cterm=NONE ctermbg=bg ctermfg=53 gui=NONE guibg=bg guifg=#BCA3A3", + "hi Cursor term=NONE cterm=NONE ctermbg=82 ctermfg=87 gui=NONE guibg=#777777 guifg=#F1F1F1", + "hi iCursor term=NONE cterm=NONE ctermbg=82 ctermfg=87 gui=NONE guibg=#777777 guifg=#F1F1F1", + "hi PmenuSbar term=NONE cterm=NONE ctermbg=16 ctermfg=fg gui=NONE guibg=#080808 guifg=fg", + "hi LightLineLeft_command_0_1 term=NONE cterm=NONE ctermbg=81 ctermfg=56 gui=NONE guibg=#585858 guifg=#afdf00", + "hi LightLineLeft_command_0_tabsel term=bold cterm=bold ctermbg=80 ctermfg=56 gui=bold guibg=#262626 guifg=#afdf00", + "hi LightLineLeft_command_tabsel_0 term=bold cterm=bold ctermbg=56 ctermfg=80 gui=bold guibg=#afdf00 guifg=#262626", + "hi LightLineLeft_command_1 term=NONE cterm=NONE ctermbg=81 ctermfg=79 gui=NONE guibg=#585858 guifg=#ffffff", + "hi LightLineLeft_command_1_2 term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineLeft_command_1_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineLeft_command_tabsel_1 term=NONE cterm=NONE ctermbg=81 ctermfg=80 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineMiddle_command term=NONE cterm=NONE ctermbg=80 ctermfg=83 gui=NONE guibg=#303030 guifg=#8a8a8a", + "hi LightLineRight_command_0_1 term=NONE cterm=NONE ctermbg=81 ctermfg=86 gui=NONE guibg=#585858 guifg=#d0d0d0", + "hi LightLineRight_command_0 term=NONE cterm=NONE ctermbg=86 ctermfg=81 gui=NONE guibg=#d0d0d0 guifg=#606060", + "hi LightLineRight_normal_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_insert_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCommentTitleLeader term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimGlobal term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_0_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=86 gui=NONE guibg=#262626 guifg=#d0d0d0", + "hi LightLineRight_command_tabsel_0 term=NONE cterm=NONE ctermbg=86 ctermfg=80 gui=NONE guibg=#d0d0d0 guifg=#262626", + "hi LightLineRight_command_1_2 term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#303030 guifg=#585858", + "hi LightLineRight_command_1 term=NONE cterm=NONE ctermbg=81 ctermfg=85 gui=NONE guibg=#585858 guifg=#bcbcbc", + "hi LightLineRight_command_1_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=81 gui=NONE guibg=#262626 guifg=#585858", + "hi LightLineRight_command_tabsel_1 term=NONE cterm=NONE ctermbg=81 ctermfg=80 gui=NONE guibg=#585858 guifg=#262626", + "hi LightLineRight_command_2_3 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#303030", + "hi LightLineRight_command_2 term=NONE cterm=NONE ctermbg=80 ctermfg=84 gui=NONE guibg=#303030 guifg=#9e9e9e", + "hi LightLineRight_command_2_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_command_tabsel_2 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_command_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimPatRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCollection term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstPat term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSubstRep4 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncMatch term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSyncLinebreak term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Todo term=NONE cterm=NONE ctermbg=80 ctermfg=79 gui=NONE guibg=bg guifg=#FFFFFF", + "hi vimSyncRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimExtCmd term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimFilter term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimSet term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=85 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineRight_command_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=85 gui=NONE guibg=#262626 guifg=#bcbcbc", + "hi LightLineLeft_command_tabsel_2 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineLeft_command_2_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineRight_command_tabsel_3 term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#303030 guifg=#262626", + "hi LightLineRight_command_3_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#303030", + "hi LightLineLeft_command_tabsel_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineRight_command_tabsel_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=80 gui=NONE guibg=#262626 guifg=#262626", + "hi LightLineLeft_command_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCollClass term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_1_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_0_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_0 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi pythonSpaceError term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_1 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi pythonSync term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapLhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoCmdSpace term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoEventList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAutoCmdSfxList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapRhs term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMapRhsExtend term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi StorageClass term=NONE cterm=NONE ctermbg=bg ctermfg=59 gui=NONE guibg=bg guifg=#B6B7EB", + "hi LightLineLeft_normal_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimPythonRegion term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAugroupSyncA term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_tabsel_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_tabsel term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_2 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_command_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_command_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimGroupList term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMenuBang term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimMenuPriority term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi CursorLineNr term=bold cterm=NONE ctermbg=bg ctermfg=59 gui=NONE guibg=bg guifg=#B6B7EB", + "hi Question term=NONE cterm=bold ctermbg=bg ctermfg=43 gui=bold guibg=bg guifg=#66D9EF", + "hi StatusLine term=bold,reverse cterm=NONE ctermbg=79 ctermfg=21 gui=NONE guibg=fg guifg=#455354", + "hi StatusLineNC term=reverse cterm=reverse ctermbg=83 ctermfg=16 gui=reverse guibg=#080808 guifg=#808080", + "hi VertSplit term=reverse cterm=reverse ctermbg=83 ctermfg=16 gui=reverse guibg=#080808 guifg=#808080", + "hi Title term=bold cterm=NONE ctermbg=bg ctermfg=59 gui=NONE guibg=bg guifg=#B6B7EB", + "hi Visual term=reverse cterm=NONE ctermbg=80 ctermfg=fg gui=NONE guibg=#403D3D guifg=fg", + "hi VisualNOS term=NONE cterm=NONE ctermbg=80 ctermfg=fg gui=NONE guibg=#403D3D guifg=fg", + "hi WarningMsg term=NONE cterm=NONE ctermbg=80 ctermfg=79 gui=NONE guibg=#333333 guifg=#FFFFFF", + "hi WildMenu term=NONE cterm=NONE ctermbg=16 ctermfg=43 gui=NONE guibg=#000000 guifg=#66D9EF", + "hi LightLineLeft_normal_2_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_3 term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_3_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimAuSyntax term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineRight_normal_raw_raw term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimUserCmd term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimCmdSep term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi vimIsCommand term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi LightLineLeft_normal_0 term=bold cterm=bold ctermbg=56 ctermfg=20 gui=bold guibg=#afdf00 guifg=#005f00", + "hi LightLineLeft_normal_0_1 term=NONE cterm=NONE ctermbg=81 ctermfg=56 gui=NONE guibg=#585858 guifg=#afdf00", + "hi LightLineLeft_insert_0 term=bold cterm=bold ctermbg=79 ctermfg=21 gui=bold guibg=#ffffff guifg=#005f5f", + "hi LightLineLeft_insert_0_1 term=NONE cterm=NONE ctermbg=22 ctermfg=79 gui=NONE guibg=#0087af guifg=#ffffff", + "hi LightLineLeft_insert_0_tabsel term=bold cterm=bold ctermbg=80 ctermfg=79 gui=bold guibg=#262626 guifg=#ffffff", + "hi LightLineLeft_insert_tabsel_0 term=bold cterm=bold ctermbg=79 ctermfg=80 gui=bold guibg=#ffffff guifg=#262626", + "hi LightLineLeft_insert_1 term=NONE cterm=NONE ctermbg=22 ctermfg=79 gui=NONE guibg=#0087af guifg=#ffffff", + "hi LightLineLeft_insert_1_2 term=NONE cterm=NONE ctermbg=21 ctermfg=22 gui=NONE guibg=#005f87 guifg=#0087af", + "hi LightLineLeft_insert_1_tabsel term=NONE cterm=NONE ctermbg=80 ctermfg=22 gui=NONE guibg=#262626 guifg=#0087af", + "hi LightLineLeft_insert_tabsel_1 term=NONE cterm=NONE ctermbg=22 ctermfg=80 gui=NONE guibg=#0087af guifg=#262626", + "hi LightLineMiddle_insert term=NONE cterm=NONE ctermbg=21 ctermfg=43 gui=NONE guibg=#005f87 guifg=#87dfff", + "hi LightLineRight_insert_0_1 term=NONE cterm=NONE ctermbg=22 ctermfg=43 gui=NONE guibg=#0087af guifg=#87dfff", + "hi vimNormCmds term=NONE cterm=NONE ctermbg=bg ctermfg=fg gui=NONE guibg=bg guifg=fg", + "hi Folded term=NONE cterm=NONE ctermbg=16 ctermfg=81 gui=NONE guibg=#000000 guifg=#465457", + "hi FoldColumn term=NONE cterm=NONE ctermbg=16 ctermfg=81 gui=NONE guibg=#000000 guifg=#465457", + "hi DiffAdd term=bold cterm=NONE ctermbg=17 ctermfg=fg gui=NONE guibg=#13354A guifg=fg", + "hi DiffChange term=bold cterm=NONE ctermbg=36 ctermfg=37 gui=NONE guibg=#4C4745 guifg=#89807D", + "hi DiffDelete term=bold cterm=bold ctermbg=16 ctermfg=33 gui=bold guibg=#1E0010 guifg=#960050", + "hi DiffText term=reverse cterm=NONE ctermbg=36 ctermfg=fg gui=NONE guibg=#4C4745 guifg=fg", + "hi SignColumn term=NONE cterm=NONE ctermbg=80 ctermfg=57 gui=NONE guibg=#232526 guifg=#DAD085", + "hi Conceal term=NONE cterm=NONE ctermbg=84 ctermfg=86 gui=NONE guibg=DarkGrey guifg=LightGrey", + "hi SpellBad term=reverse cterm=undercurl ctermbg=bg ctermfg=64 gui=undercurl guibg=bg guifg=fg guisp=#FF0000", + "hi SpellCap term=reverse cterm=undercurl ctermbg=bg ctermfg=39 gui=undercurl guibg=bg guifg=fg guisp=#7070F0" + }; + + +void +colorscheme_atom_dark(void) +{ + string termname; + int colordepth; + + get_term_feature(TF_NAME, termname); + get_term_feature(TF_COLORDEPTH, colordepth); + + if (colordepth >= 256 && strstr(termname, "kconsole") /*TODO*/) { + vim_colorscheme("atom_konsole", 256, NULL, atom_kconsole, TRUE); + + } else if (colordepth >= 256 && strstr(termname, "eterm") /*TODO*/) { + vim_colorscheme("atom_eterm", 256, NULL, atom_eterm, TRUE); + + } else if (colordepth >= 256) { + vim_colorscheme("atom_256", 256, NULL, atom_256, TRUE); + + } else if (colordepth >= 88) { + vim_colorscheme("atom_88", 88, NULL, atom_88, TRUE); + } +} + +/*end*/ diff --git a/macsrc/debug.h b/macsrc/debug.h index ade5363b..1c25004d 100644 --- a/macsrc/debug.h +++ b/macsrc/debug.h @@ -22,7 +22,6 @@ #define DBG_INQ_OPCODES 8 /* OPCODE descriptions */ - /* * Debug flags */ diff --git a/macsrc/demos/regress.cr b/macsrc/demos/regress.cr index d4e15b43..5faa430f 100644 --- a/macsrc/demos/regress.cr +++ b/macsrc/demos/regress.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: regress.cr,v 1.35 2020/04/22 19:45:43 cvsuser Exp $ +/* $Id: regress.cr,v 1.38 2021/08/14 17:08:33 cvsuser Exp $ * * This set of macros are used when debugging and fixing CRISP to aid in regression testing and * catching bugs introduced inadvertently. These tests dont attempt an exhaustive test, yet @@ -244,6 +244,7 @@ regress(~string test) int h, m, s, dy, yr; string mn, infobuf; + set_buffer_type(NULL, BFTYP_UTF8); date(yr, NULL, dy, mn); time(h, m, s); version(maj, min, edit); @@ -629,83 +630,91 @@ test_arith(void) TEST(79, 12 % 10 == 2); // MOD - TEST(80, 1 << 10 == 1024); // LSH - TEST(81, 8 >> 3 == 1); // RSH - TEST(82, (10 ^ 2) == 8); // XOR - TEST(83, (0xff54 & 0xff) == 0x54); // AND - TEST(84, (0xff54 | 0xff) == 0xffff); // OR + TEST(80, 1 << 10 == 1024); // LSH + TEST(81, 8 >> 3 == 1); // RSH - TEST(85, (~0 & 0xffff) == 0xffff); // COM - TEST(86, !0 == 1); // NOT +#pragma warning(push) +#pragma warning(off) + TEST(82, 1 << 0 == 1); // LSH + TEST(83, 8 >> 0 == 8); // RSH +#pragma warning(pop) + + TEST(84, (10 ^ 2) == 8); // XOR + + TEST(85, (0xff54 & 0xff) == 0x54); // AND + TEST(86, (0xff54 | 0xff) == 0xffff); // OR - TEST(87, -(+1) == -1); // NEG - TEST(88, +(-1) == -1); // PLUS - TEST(89, ((-(-2)) == +2)); - TEST(90, (3 - (-2) == 5)); + TEST(87, (~0 & 0xffff) == 0xffff); // COM + TEST(88, !0 == 1); // NOT + + TEST(89, -(+1) == -1); // NEG + TEST(90, +(-1) == -1); // PLUS + TEST(91, ((-(-2)) == +2)); + TEST(92, (3 - (-2) == 5)); /* * operators * non-contant expressions */ - i = 1; TEST(91, i + 2 == 3); - f = 1.5; TEST(92, f + 2 == 3.5); + i = 1; TEST(93, i + 2 == 3); + f = 1.5; TEST(94, f + 2 == 3.5); - i = 2; TEST(93, i - 1 == 1); - f = 2.5; TEST(94, f - 1 == 1.5); + i = 2; TEST(95, i - 1 == 1); + f = 2.5; TEST(96, f - 1 == 1.5); - i = 8; TEST(95, i / 2 == 4); - f = 9; TEST(96, f / 2 == 4.5); + i = 8; TEST(97, i / 2 == 4); + f = 9; TEST(98, f / 2 == 4.5); - i = 5; TEST(97, i * 5 == 25); - f = 5; TEST(98, f * 5.1 == 25.5); + i = 5; TEST(99, i * 5 == 25); + f = 5; TEST(100, f * 5.1 == 25.5); - i = 12; TEST(99, i % 10 == 2); - i = 0; TEST(100, (~i & 0xffff) == 0xffff); - i = 0; TEST(101, (! i) == 1); + i = 12; TEST(101, i % 10 == 2); + i = 0; TEST(102, (~i & 0xffff) == 0xffff); + i = 0; TEST(103, (! i) == 1); - i = 1; TEST(102, i << 10 == 1024); - i = 8; TEST(103, i >> 3 == 1); - i = 10; TEST(104, (i ^ 2) == 8); - i = 0xff54; TEST(105, (i & 0xff) == 0x54); - i = 0xff54; TEST(106, (i | 0xff) == 0xffff); + i = 1; TEST(104, i << 10 == 1024); + i = 8; TEST(105, i >> 3 == 1); + i = 10; TEST(106, (i ^ 2) == 8); + i = 0xff54; TEST(107, (i & 0xff) == 0x54); + i = 0xff54; TEST(108, (i | 0xff) == 0xffff); /* * operators * non-contant assignment expressions */ - i = 1; TEST(107, i + 2 == 3); - i = 2; TEST(108, i - 1 == 1); - i = 8; TEST(109, i / 2 == 4); - i = 5; TEST(110, i * 5 == 25); - i = 12; TEST(111, i % 10 == 2); - - i = 1; TEST(112, i << 10 == 1024); - i = 8; TEST(113, i >> 3 == 1); - i = 10; TEST(114, (i ^ 2) == 8); - i = 0xff54; TEST(115, (i & 0xff) == 0x54); - i = 0xff54; TEST(116, (i | 0xff) == 0xffff); - - i = 69; TEST(117, (i += 10) == 79 && i == 79); - i = 42; TEST(118, (i -= 40) == 2 && i == 2); - i = 99; TEST(119, (i /= 3) == 33 && i == 33); - i = 41; TEST(120, (i *= 3) == 123 && i == 123); - i = 102; TEST(121, (i %= 10) == 2 && i == 2); - - i = 42; TEST(122, (i <<= 3) == 336 && i == 336); - i = 8; TEST(123, (i >>= 3) == 1 && i == 1); - i = 10; TEST(124, (i ^= 2) == 8 && i == 8); - i = 0xf7; TEST(125, (i &= 0xf) == 0x7 && i == 0x7); - i = 0xf7; TEST(126, (i |= 0xf) == 0xff && i == 0xff); + i = 1; TEST(109, i + 2 == 3); + i = 2; TEST(110, i - 1 == 1); + i = 8; TEST(111, i / 2 == 4); + i = 5; TEST(112, i * 5 == 25); + i = 12; TEST(113, i % 10 == 2); + + i = 1; TEST(114, i << 10 == 1024); + i = 8; TEST(115, i >> 3 == 1); + i = 10; TEST(116, (i ^ 2) == 8); + i = 0xff54; TEST(117, (i & 0xff) == 0x54); + i = 0xff54; TEST(118, (i | 0xff) == 0xffff); + + i = 69; TEST(119, (i += 10) == 79 && i == 79); + i = 42; TEST(120, (i -= 40) == 2 && i == 2); + i = 99; TEST(121, (i /= 3) == 33 && i == 33); + i = 41; TEST(122, (i *= 3) == 123 && i == 123); + i = 102; TEST(123, (i %= 10) == 2 && i == 2); + + i = 42; TEST(124, (i <<= 3) == 336 && i == 336); + i = 8; TEST(125, (i >>= 3) == 1 && i == 1); + i = 10; TEST(126, (i ^= 2) == 8 && i == 8); + i = 0xf7; TEST(127, (i &= 0xf) == 0x7 && i == 0x7); + i = 0xf7; TEST(128, (i |= 0xf) == 0xff && i == 0xff); /* * type conversion */ f = 2.34; i = f; - TEST(127, i == 2); - TEST(128, is_integer(i)); + TEST(129, i == 2); + TEST(130, is_integer(i)); } @@ -719,27 +728,27 @@ test_typeof(void) declare d1; d1 = "hello"; - TEST(129, typeof(d1) == "string"); + TEST(131, typeof(d1) == "string"); d1 = 1; - TEST(130, typeof(d1) == "integer"); + TEST(132, typeof(d1) == "integer"); d1 = 1.2334; - TEST(131, typeof(d1) == "float"); + TEST(133, typeof(d1) == "float"); d1 = NULL; - TEST(132, typeof(d1) == "NULL"); + TEST(134, typeof(d1) == "NULL"); d1 = quote_list("one", "two"); - TEST(133, typeof(d1) == "list"); + TEST(135, typeof(d1) == "list"); /* * FIXME/XXX - unsure. review bug or feature * assigning NULL to list zeros the list yet the type is still "list". */ d1 = NULL; - TEST(134, typeof(d1) == "list"); - TEST(135, is_null(d1)); + TEST(136, typeof(d1) == "list"); + TEST(137, is_null(d1)); } @@ -753,19 +762,19 @@ test_for(void) int x, y; for (x = 0; x < 2; ++x) { } - TEST(136, 2 == x); + TEST(138, 2 == x); for (x = 0, y = 1234; x < 2; ++x) { break; y = 0; } - TEST(137, 1234 == y); - TEST(138, 0 == x); + TEST(139, 1234 == y); + TEST(140, 0 == x); for (x = 0; x < 2; ++x) { if (0 == x) continue; - TEST(139, 1 == x); + TEST(141, 1 == x); } - TEST(140, 2 == x); + TEST(142, 2 == x); } @@ -780,14 +789,14 @@ test_while(void) x = 0; while (x < 2) { ++x; } - TEST(141, 2 == x); + TEST(143, 2 == x); x = 0; y = 1234; while (x < 2) { break; y = 0; ++x; } - TEST(142, 1234 == y); - TEST(143, 0 == x); + TEST(144, 1234 == y); + TEST(145, 0 == x); x = 0; while (x < 2) { @@ -795,10 +804,10 @@ test_while(void) x++; continue; } - TEST(144, 1 == x); + TEST(146, 1 == x); ++x; } - TEST(145, 2 == x); + TEST(147, 2 == x); } @@ -813,14 +822,14 @@ test_do(void) x = 0; do { ++x; } while (x < 2); - TEST(146, 2 == x); + TEST(148, 2 == x); x = 0; y = 1234; do { break; y = 0; ++x; } while (x < 2); - TEST(147, 1234 == y); - TEST(148, 0 == x); + TEST(149, 1234 == y); + TEST(150, 0 == x); x = 0; do { @@ -828,10 +837,10 @@ test_do(void) x++; continue; } - TEST(149, 1 == x); + TEST(151, 1 == x); ++x; } while (x < 2); - TEST(150, 2 == x); + TEST(152, 2 == x); } @@ -849,16 +858,16 @@ test_switch(void) for (i = 1; i <= 8; i *= 2) { switch (i) { case 1: - TEST(151, 1 == i); + TEST(153, 1 == i); break; case 2: case 3: - TEST(152, 2 == i); + TEST(154, 2 == i); case 5: case 4: - TEST(153, 4 == i); + TEST(155, 4 == i); default: - TEST(154, 8 == i); + TEST(156, 8 == i); break; } } @@ -869,14 +878,14 @@ test_switch(void) case 2: i = 102; break; case 3: i = 103; break; } - TEST(155, i == 103); + TEST(157, i == 103); switch("hello") { case "hello, everybod": s1 = "first"; break; case "hello": s1 = "second"; break; default: s1 = "default"; } - TEST(156, s1 == "second"); + TEST(158, s1 == "second"); s1 = "hello, everybod"; s2 = "hello"; @@ -887,17 +896,17 @@ test_switch(void) default: s1 = "default"; break; } #pragma warning on - TEST(157, s1 == "second"); + TEST(159, s1 == "second"); - TEST(158, "none" == switchi(0)); - TEST(159, "one" == switchi(1)); - TEST(160, "two" == switchi(2)); - TEST(161, "three" == switchi(3)); + TEST(160, "none" == switchi(0)); + TEST(161, "one" == switchi(1)); + TEST(162, "two" == switchi(2)); + TEST(163, "three" == switchi(3)); - TEST(162, 0 == switchs("")); - TEST(163, 1 == switchs("1")); - TEST(164, 2 == switchs("22")); - TEST(165, 3 == switchs("333")); + TEST(164, 0 == switchs("")); + TEST(165, 1 == switchs("1")); + TEST(166, 2 == switchs("22")); + TEST(167, 3 == switchs("333")); } @@ -954,7 +963,7 @@ test_cexpr(void) do ""; while (++i <= 6); - TEST(166, 7 == i); + TEST(168, 7 == i); } @@ -972,36 +981,36 @@ test_math(void) float modintegral, modfractional; - TEST(167, abs(1) == 1); - TEST(168, abs(-2) == 2); + TEST(169, abs(1) == 1); + TEST(170, abs(-2) == 2); - TEST(169, 0 == isclose(1.233, 1.4566)); - TEST(170, 1 == isclose(1.233, 1.233)); - TEST(171, 1 == isclose(1.233, 1.233000001)); + TEST(171, 0 == isclose(1.233, 1.4566)); + TEST(172, 1 == isclose(1.233, 1.233)); + TEST(173, 1 == isclose(1.233, 1.233000001)); - TEST(172, acos(0.55) == 0.9884320889261531); - TEST(173, acos(-0.55) == 2.15316056466364); + TEST(174, acos(0.55) == 0.9884320889261531); + TEST(175, acos(-0.55) == 2.15316056466364); - TEST(174, asin(0.55) == 0.5823642378687435); - TEST(175, asin(-0.55) == -0.5823642378687435); + TEST(176, asin(0.55) == 0.5823642378687435); + TEST(177, asin(-0.55) == -0.5823642378687435); - TEST(176, atan(67.0) == 1.5558720618048116); - TEST(177, atan(-21.0) == -1.5232132235179132); + TEST(178, atan(67.0) == 1.5558720618048116); + TEST(179, atan(-21.0) == -1.5232132235179132); - TEST(178, atan2(8.0, 5.0) == 1.0121970114513341); - TEST(179, atan2(20.0, 10.0) == 1.1071487177940904); + TEST(180, atan2(8.0, 5.0) == 1.0121970114513341); + TEST(181, atan2(20.0, 10.0) == 1.1071487177940904); - TEST(180, ceil(9.2) == 10.0); - TEST(181, ceil(-9.2) == -9.0); + TEST(182, ceil(9.2) == 10.0); + TEST(183, ceil(-9.2) == -9.0); // TODO: comb() [ Python ] // TODO: copysign() [ Python ] - TEST(182, cos(0.0) == 1.0); - TEST(183, cos(3.14159265359) == -1.0); + TEST(184, cos(0.0) == 1.0); + TEST(185, cos(3.14159265359) == -1.0); - TEST(184, cosh(1.0) == 1.5430806348152437); - TEST(185, cosh(0.0) == 1.0); + TEST(186, cosh(1.0) == 1.5430806348152437); + TEST(187, cosh(0.0) == 1.0); // TODO: degrees() [ Python ] // TODO: dist() [ Python ] @@ -1009,85 +1018,85 @@ test_math(void) // TODO: erfc() [ Python ] // TODO: div() - TEST(186, isclose(exp(23.0), 9744803446.248903)); - TEST(187, exp(-1.234) == 0.2911257425960852); + TEST(188, isclose(exp(23.0), 9744803446.248903)); + TEST(189, exp(-1.234) == 0.2911257425960852); - TEST(188, fabs(2.0) == 2.0); - TEST(189, fabs(-4.0) == 4.0); + TEST(190, fabs(2.0) == 2.0); + TEST(191, fabs(-4.0) == 4.0); // TODO: fdiv() // TODO: factorial() [ Python ] - TEST(190, floor(9.2) == 9.0); - TEST(191, floor(-9.2) == -10.0); + TEST(192, floor(9.2) == 9.0); + TEST(193, floor(-9.2) == -10.0); - TEST(192, fmod(67.0, 7.0) == 4.0); - TEST(193, fmod(17.0, 4.0) == 1.0); + TEST(194, fmod(67.0, 7.0) == 4.0); + TEST(195, fmod(17.0, 4.0) == 1.0); expmantissa = frexp(4.0, expret); - TEST(194, expmantissa == 0.5 && expret == 3); + TEST(196, expmantissa == 0.5 && expret == 3); expmantissa = frexp(7.9, expret); - TEST(195, expmantissa == 0.9875 && expret == 3); + TEST(197, expmantissa == 0.9875 && expret == 3); // TODO: fsum [ Python ] // TODO: gamma [ Python ] - TEST(196, isfinite(-45.34)); - TEST(197, isfinite(+45.34)); + TEST(198, isfinite(-45.34)); + TEST(199, isfinite(+45.34)); // FIXME: +45.34 grunch should handle leading '+' - TEST(198, ! isfinite(NAN)); - TEST(199, ! isfinite(INFINITY)); - TEST(200, ! isfinite(-INFINITY)); + TEST(200, ! isfinite(NAN)); + TEST(201, ! isfinite(INFINITY)); + TEST(202, ! isfinite(-INFINITY)); - TEST(201, isinf(INFINITY)); - TEST(202, isinf(-INFINITY)); - TEST(203, ! isinf(56.00)); - TEST(204, ! isinf(NAN)); + TEST(203, isinf(INFINITY)); + TEST(204, isinf(-INFINITY)); + TEST(205, ! isinf(56.00)); + TEST(206, ! isinf(NAN)); - TEST(205, isnan(NAN)); - TEST(206, ! isnan(56.00)); - TEST(207, ! isnan(INFINITY)); - TEST(208, ! isnan(-INFINITY)); + TEST(207, isnan(NAN)); + TEST(208, ! isnan(56.00)); + TEST(209, ! isnan(INFINITY)); + TEST(210, ! isnan(-INFINITY)); // TODO: isqrt [ Python ] // TODO: ldexp // TODO: lgamma [ Python ] - TEST(209, fabs(log(2.0) - 0.693147) < 0.000001); - TEST(210, isclose(log(2.0), 0.693147, 1e-5)); - TEST(211, fabs(log(4.0) - 1.386294) < 0.000001); - TEST(212, isclose(log(4.0), 1.386294, 1e-5)); + TEST(211, fabs(log(2.0) - 0.693147) < 0.000001); + TEST(212, isclose(log(2.0), 0.693147, 1e-5)); + TEST(213, fabs(log(4.0) - 1.386294) < 0.000001); + TEST(214, isclose(log(4.0), 1.386294, 1e-5)); - TEST(213, log10(10.0) == 1.0); - TEST(214, log10(100.0) == 2.0); + TEST(215, log10(10.0) == 1.0); + TEST(216, log10(100.0) == 2.0); modfractional = modf(52.42, modintegral); - TEST(215, modintegral == 52 && isclose(modfractional, 0.42)); + TEST(217, modintegral == 52 && isclose(modfractional, 0.42)); modfractional = modf(NAN, modintegral); - TEST(216, isnan(modfractional)); + TEST(218, isnan(modfractional)); - TEST(217, pow(9.0, 3.0) == 729.0); + TEST(219, pow(9.0, 3.0) == 729.0); - TEST(218, sin(0.0) == 0.0); - TEST(219, sin(10.0) == -0.5440211108893698); - TEST(220, sin(PI / 2) == 1.0); + TEST(220, sin(0.0) == 0.0); + TEST(221, sin(10.0) == -0.5440211108893698); + TEST(222, sin(PI / 2) == 1.0); - TEST(221, sinh(0.0) == 0.0); - TEST(222, isclose(sinh(-23.45), -7641446994.979367)); - TEST(223, isclose(sinh(23.0), 4872401723.124452)); - TEST(224, isclose(sinh(PI), 11.548739357257748)); + TEST(223, sinh(0.0) == 0.0); + TEST(224, isclose(sinh(-23.45), -7641446994.979367)); + TEST(225, isclose(sinh(23.0), 4872401723.124452)); + TEST(226, isclose(sinh(PI), 11.548739357257748)); - TEST(225, sqrt(4.0) == 2.0); - TEST(226, isclose(sqrt(10.0), 3.162278, 0.000001)); + TEST(227, sqrt(4.0) == 2.0); + TEST(228, isclose(sqrt(10.0), 3.162278, 0.000001)); - TEST(227, tan(90.0) == -1.995200412208242); - TEST(228, tan(-90.0) == 1.995200412208242); - TEST(229, tan(45.0) == 1.6197751905438615); - TEST(230, tan(60.0) == 0.320040389379563); + TEST(229, tan(90.0) == -1.995200412208242); + TEST(230, tan(-90.0) == 1.995200412208242); + TEST(231, tan(45.0) == 1.6197751905438615); + TEST(232, tan(60.0) == 0.320040389379563); - TEST(231, isclose(tanh(8.0), 0.9999997749296758, 1e14)); - TEST(232, isclose(tanh(1.0), 0.7615941559557649, 1e14)); - TEST(233, tanh(-6.2) == -0.9999917628565104); + TEST(233, isclose(tanh(8.0), 0.9999997749296758, 1e14)); + TEST(234, isclose(tanh(1.0), 0.7615941559557649, 1e14)); + TEST(235, tanh(-6.2) == -0.9999917628565104); // TODO: trunc } @@ -1102,11 +1111,11 @@ test_cast(void) { declare x; - TEST(234, (int)1.1 == 1); - x = ((int)1.1); TEST(235, is_integer(x)); + TEST(236, (int)1.1 == 1); + x = ((int)1.1); TEST(237, is_integer(x)); - TEST(236, (float)3 == 3.0); - x = ((float)1); TEST(237, is_float(x)); + TEST(238, (float)3 == 3.0); + x = ((float)1); TEST(239, is_float(x)); } @@ -1117,14 +1126,14 @@ test_cast(void) static void test_escapes(void) { - TEST(238, '\cA' == 0x00 && '\0' == 0x00 && '\000' == 0x00); + TEST(240, '\cA' == 0x00 && '\0' == 0x00 && '\000' == 0x00); // NUL - TEST(239, '\c[' == 0x1b && '\e' == 0x1b); // ESC + TEST(241, '\c[' == 0x1b && '\e' == 0x1b); // ESC #pragma warning(push, off) - TEST(240, L'\u2b3c' == 0x2b3c); // Unicode - TEST(241, L'\U00012b3c' == 0x12b3c); // Unicode (76604 dec) - TEST(242, L'\x{1a2b}' == 0x1a2b); // Extended hexidecimal contants. - TEST(243, L'\o{1234}' == 01234); // Extended octal contants. + TEST(242, L'\u2b3c' == 0x2b3c); // Unicode + TEST(243, L'\U00012b3c' == 0x12b3c); // Unicode (76604 dec) + TEST(244, L'\x{1a2b}' == 0x1a2b); // Extended hexidecimal contants. + TEST(245, L'\o{1234}' == 01234); // Extended octal contants. #pragma warning(pop) } @@ -1141,47 +1150,47 @@ test_string(void) int i; // operations on string scalars - TEST(244, !empty); // undocumented feature, scalar reference. - TEST(245, nonempty); // only function as 'single' expression NOT within compound + TEST(246, !empty); // undocumented feature, scalar reference. + TEST(247, nonempty); // only function as 'single' expression NOT within compound // string addition s1 = "xyz"; s1 += "abc"; - TEST(246, s1 == "xyzabc"); + TEST(248, s1 == "xyzabc"); s1 = "xyz"; s2 = "abc"; s1 += s2; - TEST(247, s1 == "xyzabc"); + TEST(249, s1 == "xyzabc"); s1 = "xyz"; s2 = s1; s1 += s2; - TEST(248, s1 == "xyzxyz"); + TEST(250, s1 == "xyzxyz"); s1 = "xyz"; - TEST(249, (s1 += "abc") == "xyzabc"); + TEST(251, (s1 += "abc") == "xyzabc"); s1 = "xyz"; - TEST(250, (s1 += s1) == "xyzxyz"); + TEST(252, (s1 += s1) == "xyzxyz"); s1 = "xyz"; - TEST(251, (s1 = s1) == "xyz"); + TEST(253, (s1 = s1) == "xyz"); // numeric conversion i = 99; s1 = "abc"; s1 = s1 + i; - TEST(252, s1 == "abc99"); + TEST(254, s1 == "abc99"); i = 99; s1 = "abc"; s1 = i + s1; - TEST(253, s1 == "99abc"); + TEST(255, s1 == "99abc"); s1 = "abc"; s1 += 0; - TEST(254, s1 == "abc0"); + TEST(256, s1 == "abc0"); f = 1.234; s1 = "abc"; s1 = f + s1; - TEST(255, s1 == "1.234abc"); + TEST(257, s1 == "1.234abc"); // string multipler // trailing or leading @@ -1189,90 +1198,96 @@ test_string(void) // i = 0; s1 = "xyz" * i; - TEST(256, s1 == ""); + TEST(258, s1 == ""); s1 = i * "xyz"; - TEST(257, s1 == ""); + TEST(259, s1 == ""); i = 1; s1 = "xyz" * i; - TEST(258, s1 == "xyz"); + TEST(260, s1 == "xyz"); s1 = i * "xyz"; - TEST(259, s1 == "xyz"); + TEST(261, s1 == "xyz"); i = 2; s1 = "xyz" * i; - TEST(260, s1 == "xyzxyz"); + TEST(262, s1 == "xyzxyz"); s1 = i * "xyz"; - TEST(261, s1 == "xyzxyz"); + TEST(263, s1 == "xyzxyz"); f = 1.1; s1 = "xyz" * f; f = 2.2; s1 = "xyz" * f; - TEST(262, s1 == "xyzxyz"); + TEST(264, s1 == "xyzxyz"); // string accumulator tests - TEST(263, "abc" + "def" == "abcdef"); - TEST(264, 1 + "def" == "1def"); - TEST(265, "abc" + 1 == "abc1"); - TEST(266, 1.2 + "def" == "1.2def"); - TEST(267, "abc" + 1.2 == "abc1.2"); + TEST(265, "abc" + "def" == "abcdef"); + TEST(266, 1 + "def" == "1def"); + TEST(267, "abc" + 1 == "abc1"); + TEST(268, 1.2 + "def" == "1.2def"); + TEST(269, "abc" + 1.2 == "abc1.2"); // string primitives - TEST(268, trim(" harry ") == "harry"); - TEST(269, rtrim("harry ") == "harry"); - TEST(270, ltrim(" harry") == "harry"); + TEST(270, trim(" harry ") == "harry"); + TEST(271, rtrim("harry ") == "harry"); + TEST(272, ltrim(" harry") == "harry"); s1 = " harry "; - TEST(271, rtrim(s1) == " harry"); - TEST(272, ltrim(s1) == "harry "); + TEST(273, rtrim(s1) == " harry"); + TEST(274, ltrim(s1) == "harry "); - TEST(273, atoi("98") == 98); - TEST(274, strlen("abcd") == 4); + TEST(275, atoi("98") == 98); + TEST(276, strlen("abcd") == 4); s1 = "abcd" + " "; - TEST(275, strlen(s1) == 5); + TEST(277, strlen(s1) == 5); - TEST(276, strlen("nothing") == 7); + TEST(278, strlen("nothing") == 7); s1 = "1234554321"; - TEST(277, index(s1, "4") == 4); - TEST(278, index(s1, "") == 11); - TEST(279, rindex(s1, "5") == 6); + TEST(279, index(s1, "4") == 4); + TEST(280, index(s1, "") == 11); + TEST(281, rindex(s1, "5") == 6); s1 = ""; s1 = substr(s1, index(s1, ";") + 1); - TEST(280, s1 == ""); + TEST(282, s1 == ""); gs1 = ""; get_parm(2, gs1); gs1 = substr(gs1, index(gs1, ";") + 1); - TEST(281, gs1 == ""); + TEST(283, gs1 == ""); - TEST(282, upper("aBc") == "ABC"); - TEST(283, lower("AbC") == "abc"); - TEST(284, 5 == string_count("axba bax", "abz")); + TEST(284, upper("aBc") == "ABC"); + TEST(285, lower("AbC") == "abc"); + TEST(286, 5 == string_count("axba bax", "abz")); - TEST(285, 0 == strcasecmp("AaA", "aAa")); - TEST(286, strerror(0) == "Success"); + TEST(287, 0 == strcasecmp("AaA", "aAa")); + TEST(288, strerror(0) == "Success"); s1 = "abAB"; - TEST(287, "a" == strpop(s1)); - TEST(288, "b" == strpop(s1)); - TEST(289, "AB" == strpop(s1, 2)); - TEST(290, "" == strpop(s1)); + TEST(289, "a" == strpop(s1)); + TEST(290, "b" == strpop(s1)); + TEST(291, "AB" == strpop(s1, 2)); + TEST(292, "" == strpop(s1)); s1 = "abcdefg"; - TEST(291, 3 == strpbrk(s1, "dc")); + TEST(293, 3 == strpbrk(s1, "dc")); // strstr, strrstr and strcasestr s1 = "abcmandefg"; - TEST(292, 4 == strstr(s1, "man")); - TEST(293, 4 == strrstr(s1, "man")); - TEST(294, 4 == strcasestr(s1, "MAN")); + TEST(294, 4 == strstr(s1, "man")); + TEST(295, 4 == strrstr(s1, "man")); + TEST(296, 4 == strcasestr(s1, "MAN")); s1 = "abcmanmandefg"; - TEST(295, 4 == strstr(s1, "man")); - TEST(296, 7 == strrstr(s1, "man")); + TEST(297, 4 == strstr(s1, "man")); + TEST(298, 7 == strrstr(s1, "man")); + + TEST(299, 0 == strstr(s1, "ban")); + TEST(300, 0 == strrstr(s1, "ban")); + + TEST(301, 1 == strstr(s1, "")); + TEST(302, 0 == strrstr(s1, "")); } @@ -1292,66 +1307,66 @@ test_regexp(void) // test offset and length returns. // i = -1; - TEST(297, 6 == search_string(" [worl]+", s1, i, -2 /*MAXIMUM*/, FALSE)); - TEST(298, 5 == i); + TEST(303, 6 == search_string(" [worl]+", s1, i, -2 /*MAXIMUM*/, FALSE)); + TEST(304, 5 == i); i = -1; /* FIXME/XXX - Brief minimal logic needs reviewing */ - TEST(299, 6 == re_search(SF_BRIEF|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); - TEST(300, 2 == i); + TEST(305, 6 == re_search(SF_BRIEF|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); + TEST(306, 2 == i); i = -1; - TEST(301, 6 == re_search(SF_BRIEF|SF_MAXIMAL|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); - TEST(302, 5 == i); + TEST(307, 6 == re_search(SF_BRIEF|SF_MAXIMAL|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); + TEST(308, 5 == i); i = -1; - TEST(303, 6 == re_search(SF_UNIX|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); - TEST(304, 5 == i); + TEST(309, 6 == re_search(SF_UNIX|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); + TEST(310, 5 == i); i = -1; - TEST(305, 6 == re_search(SF_EXTENDED|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); - TEST(306, 5 == i); + TEST(311, 6 == re_search(SF_EXTENDED|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); + TEST(312, 5 == i); i = -1; - TEST(307, 6 == re_search(SF_PERL|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); - TEST(308, 5 == i); + TEST(313, 6 == re_search(SF_PERL|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); + TEST(314, 5 == i); i = -1; - TEST(309, 6 == re_search(SF_TRE|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); - TEST(310, 5 == i); + TEST(315, 6 == re_search(SF_TRE|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); + TEST(316, 5 == i); - TEST(311, 6 == re_search(SF_PERL|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); - TEST(312, 5 == i); + TEST(317, 6 == re_search(SF_PERL|SF_IGNORE_CASE, " [worl]+", s1, NULL, i)); + TEST(318, 5 == i); s1 = "Hello World"; - TEST(313, 6 == re_search(SF_PERL|SF_IGNORE_CASE, " ([worl]+)", s1, NULL, i)); - TEST(314, 5 == i); + TEST(319, 6 == re_search(SF_PERL|SF_IGNORE_CASE, " ([worl]+)", s1, NULL, i)); + TEST(320, 5 == i); // captures // s1 = "y aabbccddee z"; s2 = "y XaabbccddeeX z"; - TEST(315, re_search(SF_BRIEF, " {[abcde]+} ", s1, NULL, i) == 2); + TEST(321, re_search(SF_BRIEF, " {[abcde]+} ", s1, NULL, i) == 2); - TEST(316, re_search(SF_UNIX, " \\([abcde]+\\) ", s1, NULL, i) == 2); + TEST(322, re_search(SF_UNIX, " \\([abcde]+\\) ", s1, NULL, i) == 2); - TEST(317, re_search(SF_EXTENDED, " ([abcde]+) ", s1, NULL, i) == 2); + TEST(323, re_search(SF_EXTENDED, " ([abcde]+) ", s1, NULL, i) == 2); - TEST(318, re_search(SF_PERL, " ([abcde]+) ", s1, NULL, i) == 2); + TEST(324, re_search(SF_PERL, " ([abcde]+) ", s1, NULL, i) == 2); - TEST(319, re_translate(SF_BRIEF|SF_MAXIMAL, "{[abcde]+}", "X\\0X", s1) == s2); + TEST(325, re_translate(SF_BRIEF|SF_MAXIMAL, "{[abcde]+}", "X\\0X", s1) == s2); - TEST(320, re_translate(SF_UNIX, "\\([abcde]+\\)", "X\\0X", s1) == s2); + TEST(326, re_translate(SF_UNIX, "\\([abcde]+\\)", "X\\0X", s1) == s2); - TEST(321, re_translate(SF_EXTENDED, "([abcde]+)", "X\\0X", s1) == s2); + TEST(327, re_translate(SF_EXTENDED, "([abcde]+)", "X\\0X", s1) == s2); - TEST(322, re_translate(SF_PERL, "([abcde]+)", "X$1X", s1) == s2); + TEST(328, re_translate(SF_PERL, "([abcde]+)", "X$1X", s1) == s2); - TEST(323, re_translate(SF_PERL, "([abcde]+)", "$`", s1) == "y y z"); + TEST(329, re_translate(SF_PERL, "([abcde]+)", "$`", s1) == "y y z"); - TEST(324, re_translate(SF_PERL, "([abcde]+)", "$'", s1) == "y z z"); + TEST(330, re_translate(SF_PERL, "([abcde]+)", "$'", s1) == "y z z"); - TEST(325, re_translate(SF_TRE, "([abcde]+)", "X$1X", s1) == s2); + TEST(331, re_translate(SF_TRE, "([abcde]+)", "X$1X", s1) == s2); } @@ -1362,20 +1377,20 @@ test_regexp(void) static void test_sub(void) { - TEST(326, gsub("ana", "anda", "banana") == "bandana"); - TEST(327, gsub("a", "-&-", "banana") == "b-a-n-a-n-a-"); - TEST(328, gsub("a+", "-&-", "banana") == "b-a-n-a-n-a-"); - TEST(329, gsub("a+", "-a-", "baaaanaaaaanaaaa") == "b-a-n-a-n-a-"); - TEST(330, sub("ana", "anda", "banana") == "bandana"); - TEST(331, sub("a", "-&-", "banana") == "b-a-nana"); - TEST(332, sub("a+", "-&-", "banana") == "b-a-nana"); - TEST(333, sub("a+", "-a-", "baaaanaaaaanaaaa") == "b-a-naaaaanaaaa"); - TEST(334, sub("na$", "na.", "banana") == "banana."); - TEST(335, gsub("^a", "A", "anana") == "Anana"); - TEST(336, gsub("n.n", "[&]", "banana") == "ba[nan]a"); - TEST(337, gsub("a|n", "z", "anna") == "zzzz"); + TEST(332, gsub("ana", "anda", "banana") == "bandana"); + TEST(333, gsub("a", "-&-", "banana") == "b-a-n-a-n-a-"); + TEST(334, gsub("a+", "-&-", "banana") == "b-a-n-a-n-a-"); + TEST(335, gsub("a+", "-a-", "baaaanaaaaanaaaa") == "b-a-n-a-n-a-"); + TEST(336, sub("ana", "anda", "banana") == "bandana"); + TEST(337, sub("a", "-&-", "banana") == "b-a-nana"); + TEST(338, sub("a+", "-&-", "banana") == "b-a-nana"); + TEST(339, sub("a+", "-a-", "baaaanaaaaanaaaa") == "b-a-naaaaanaaaa"); + TEST(340, sub("na$", "na.", "banana") == "banana."); + TEST(341, gsub("^a", "A", "anana") == "Anana"); + TEST(342, gsub("n.n", "[&]", "banana") == "ba[nan]a"); + TEST(343, gsub("a|n", "z", "anna") == "zzzz"); - TEST(338, sub("f\\(.*\\)t", "F\\1T", "first:second") == "FirsT:second"); + TEST(344, sub("f\\(.*\\)t", "F\\1T", "first:second") == "FirsT:second"); } @@ -1390,37 +1405,37 @@ test_substr(void) string s1; s1 = substr("ABC", 0, 3); - TEST(339, s1 == "ABC"); + TEST(345, s1 == "ABC"); s1 = substr("ABC", -1000, 1000); - TEST(340, s1 == "ABC"); + TEST(346, s1 == "ABC"); s1 = substr("ABC", 1000, 1000); - TEST(341, s1 == ""); + TEST(347, s1 == ""); s1 = substr("ABC", 1, 0); - TEST(342, s1 == ""); + TEST(348, s1 == ""); s1 = substr("ABC", 1, 1); - TEST(343, s1 == "A"); + TEST(349, s1 == "A"); s1 = substr("ABC", 1, 2); - TEST(344, s1 == "AB"); + TEST(350, s1 == "AB"); s1 = substr("ABC", 1, 3); - TEST(345, s1 == "ABC"); + TEST(351, s1 == "ABC"); s1 = substr("ABC", 1, 100); - TEST(346, s1 == "ABC"); + TEST(352, s1 == "ABC"); s1 = substr("ABC", 3, 0); - TEST(347, s1 == ""); + TEST(353, s1 == ""); s1 = substr("ABC", 3, 1); - TEST(348, s1 == "C"); + TEST(354, s1 == "C"); s1 = substr("ABC", 3, 100); - TEST(349, s1 == "C"); + TEST(355, s1 == "C"); } @@ -1432,15 +1447,15 @@ static void test_compress(void) { // basic - TEST(350, compress(" harry ", 0) == " harry "); - TEST(351, compress(" harry ", 1) == "harry"); - TEST(352, compress(" h a r r y ", 0) == " h a r r y "); - TEST(353, compress(" h a r r y ", 0) == " h a r r y "); - TEST(354, compress(" h a r r y ", 1) == "h a r r y"); + TEST(356, compress(" harry ", 0) == " harry "); + TEST(357, compress(" harry ", 1) == "harry"); + TEST(358, compress(" h a r r y ", 0) == " h a r r y "); + TEST(359, compress(" h a r r y ", 0) == " h a r r y "); + TEST(360, compress(" h a r r y ", 1) == "h a r r y"); // extended features - TEST(355, compress(" harry ", 0, " r") == " ha y "); - TEST(356, compress(" harry ", 0, " r", 'x') == "xhaxyx"); + TEST(361, compress(" harry ", 0, " r") == " ha y "); + TEST(362, compress(" harry ", 0, " r", 'x') == "xhaxyx"); } @@ -1458,198 +1473,198 @@ test_list(void) // 1. l1 = quote_list(123, 1.23, "xyz", hello()); /* int, float, string and symbol */ - TEST(357, length_of_list(l1) == 4); + TEST(363, length_of_list(l1) == 4); l2 = l1; - TEST(358, length_of_list(l2) == 4); - TEST(359, l1[0] == l2[0]); - TEST(360, l1[1] == l2[1]); - TEST(361, l1[2] == l2[2]); + TEST(364, length_of_list(l2) == 4); + TEST(365, l1[0] == l2[0]); + TEST(366, l1[1] == l2[1]); + TEST(367, l1[2] == l2[2]); d1 = l1[0]; - TEST(362, is_integer(d1)); /* 123 */ - TEST(363, is_type(d1, "integer")); + TEST(368, is_integer(d1)); /* 123 */ + TEST(369, is_type(d1, "integer")); d1 = l1[1]; - TEST(364, is_float(d1)); /* 1.23 */ - TEST(365, is_type(d1, "float")); + TEST(370, is_float(d1)); /* 1.23 */ + TEST(371, is_type(d1, "float")); d1 = l1[2]; - TEST(366, is_string(d1)); /* "xyz" */ - TEST(367, is_type(d1, "string")); + TEST(372, is_string(d1)); /* "xyz" */ + TEST(373, is_type(d1, "string")); d1 = l1[3]; - TEST(368, is_list(d1)); /* hello() */ - TEST(369, is_type(d1, "list")); + TEST(374, is_list(d1)); /* hello() */ + TEST(375, is_type(d1, "list")); pause_on_error(0, FALSE); d1 = l1[4]; /* range error */ pause_on_error(1, FALSE); - TEST(370, is_null(d1)); - TEST(371, is_type(d1, "null")); + TEST(376, is_null(d1)); + TEST(377, is_type(d1, "null")); // 2. l1 = quote_list(1); l1[0] = 2; - TEST(372, l1[0] == 2); + TEST(378, l1[0] == 2); l1 = quote_list(1, "abc"); l1[0] = 2; - TEST(373, l1[0] == 2); + TEST(379, l1[0] == 2); l1 = quote_list("abc"); l1[0] = 2; - TEST(374, l1[0] == 2); + TEST(380, l1[0] == 2); l1 = quote_list("abc", 1); l1[1] = 2; - TEST(375, l1[1] == 2); + TEST(381, l1[1] == 2); l1 = quote_list(1, "abc", 3); l1[1] = 2; - TEST(376, l1[1] == 2); + TEST(382, l1[1] == 2); l1 = quote_list(1, 2, 3); l1[1] = "abc"; - TEST(377, l1[1] == "abc"); + TEST(383, l1[1] == "abc"); l1 = quote_list(1, 2, 3); l2 = l1; l1[1] = l2; - TEST(378, length_of_list(l1) == 5); + TEST(384, length_of_list(l1) == 5); l1 = quote_list(1, 2, 3); l1[1] = quote_list(1, 2, 3); - TEST(379, length_of_list(l1) == 5); + TEST(385, length_of_list(l1) == 5); - TEST(380, 1. == 1); + TEST(386, 1. == 1); l1 = quote_list(1, 2, 3); l1[1] = make_list(quote_list(1, 2, 3)); l1[3] = "end"; - TEST(381, l1[3] == "end"); - TEST(382, length_of_list(l1) == 4); + TEST(387, l1[3] == "end"); + TEST(388, length_of_list(l1) == 4); l3[0] = 0; l3[1] = 1; l3[2] = 2; - TEST(383, l3[0] == 0); - TEST(384, l3[1] == 1); - TEST(385, l3[2] == 2); + TEST(389, l3[0] == 0); + TEST(390, l3[1] == 1); + TEST(391, l3[2] == 2); l1 = NULL; - TEST(386, length_of_list(l1) == 0); + TEST(392, length_of_list(l1) == 0); l1[0] = "hello"; - TEST(387, l1[0] == "hello"); + TEST(393, l1[0] == "hello"); s1 = "abc"; l1[0] = s1; - TEST(388, l1[0] == "abc"); + TEST(394, l1[0] == "abc"); s1 = "abc"; l1[0] = s1; s1 = "123456789"; - TEST(389, l1[0] == "abc"); + TEST(395, l1[0] == "abc"); b57 = "hello"; a57 = b57; - TEST(390, a57 == "hello"); + TEST(396, a57 == "hello"); - TEST(391, test_6() == 99); + TEST(397, test_6() == 99); l1 = quote_list("one", "", "three"); s1 = "TWO"; l1[1] = s1; l1[1] = s1; - TEST(392, l1[1] == "TWO"); + TEST(398, l1[1] == "TWO"); l1 = quote_list(1, 2, 3); l2 = make_list(l1); l1[1] = l2; - TEST(393, length_of_list(l1) == 3); + TEST(399, length_of_list(l1) == 3); l1 = quote_list("hello", "list", 1, NULL, 2.3); l2 = make_list(l1); l1[1] = l2; - TEST(394, length_of_list(l1) == 5); + TEST(400, length_of_list(l1) == 5); l1 = quote_list(1, 2, 3); l1[1] = make_list(quote_list(1, 2, 3)); - TEST(395, length_of_list(l1) == 3); + TEST(401, length_of_list(l1) == 3); l1 = quote_list(1, 2, 3); l1[2] = make_list(quote_list(1, 2, 3)); - TEST(396, length_of_list(l1) == 3); + TEST(402, length_of_list(l1) == 3); l1 = quote_list(1, 2, 3); l1[0] = make_list(quote_list(1, 2, 3)); - TEST(397, length_of_list(l1) == 3); + TEST(403, length_of_list(l1) == 3); l1 = make_list(quote_list(1, 2, 3)); l1 += "abc"; l1 += "def"; l1[1] = 1; - TEST(398, length_of_list(l1) == 3); + TEST(404, length_of_list(l1) == 3); l1 = make_list(quote_list(1, 2, 3), quote_list(1, 2, 3)); - TEST(399, car(car(l1)) == 1); - TEST(400, length_of_list(l1) == 2); + TEST(405, car(car(l1)) == 1); + TEST(406, length_of_list(l1) == 2); l1 = NULL; - TEST(401, length_of_list(l1) == 0); + TEST(407, length_of_list(l1) == 0); pause_on_error(0, FALSE); nth(l1, 99); /* subscript out of range */ pause_on_error(1, FALSE); // list functions l1 = command_list(); - TEST(402, is_list(l1)); + TEST(408, is_list(l1)); l1 = macro_list(); - TEST(403, is_list(l1)); + TEST(409, is_list(l1)); l1 = get_term_keyboard(); - TEST(404, is_list(l1)); + TEST(410, is_list(l1)); l1 = key_list(); - TEST(405, is_list(l1)); + TEST(411, is_list(l1)); l1 = bookmark_list(); - TEST(406, is_list(l1)); + TEST(412, is_list(l1)); l1 = macro_list(); - TEST(407, strlen(l1) != 0); - TEST(408, length_of_list(cdr(macro_list())) > 0); - TEST(409, search_list(NULL, "def", quote_list("abc", "def", "ghi")) == 1); + TEST(413, strlen(l1) != 0); + TEST(414, length_of_list(cdr(macro_list())) > 0); + TEST(415, search_list(NULL, "def", quote_list("abc", "def", "ghi")) == 1); l1 = quote_list("abc"); l1 += "def"; l1 += "ghi"; - TEST(410, search_list(NULL, "def", l1) == 1); + TEST(416, search_list(NULL, "def", l1) == 1); // features l1 = inq_feature(); - TEST(411, is_list(l1)); + TEST(417, is_list(l1)); // list concat l1 = quote_list(1, "2", 3.0); l1 = l1 + l1; - TEST(412, length_of_list(l1) == 6); + TEST(418, length_of_list(l1) == 6); l2 = l1; // element insert l1[3] = quote_list("a", "b", "c"); - TEST(413, length_of_list(l1) == 8); + TEST(419, length_of_list(l1) == 8); // element replace l1[0] = 99; - TEST(414, l1[0] != l2[0]); + TEST(420, l1[0] != l2[0]); // re_search l1 = quote_list("abc"); l1 += "def"; l1 += "ghi"; - TEST(415, re_search(NULL, "def", l1) == 1); + TEST(421, re_search(NULL, "def", l1) == 1); } @@ -1662,27 +1677,27 @@ test_list2(void) { list l1 = {"one", "two", "three", "four"}; - TEST(416, shift(l1) == "one"); - TEST(417, 3 == length_of_list(l1)); // two, three, four + TEST(422, shift(l1) == "one"); + TEST(423, 3 == length_of_list(l1)); // two, three, four - TEST(418, 5 == unshift(l1, "first", "second")); - TEST(419, 5 == length_of_list(l1)); // first, second, two, three, four + TEST(424, 5 == unshift(l1, "first", "second")); + TEST(425, 5 == length_of_list(l1)); // first, second, two, three, four - TEST(420, pop(l1) == "four"); // first, second, two, three - TEST(421, 4 == length_of_list(l1)); + TEST(426, pop(l1) == "four"); // first, second, two, three + TEST(427, 4 == length_of_list(l1)); - TEST(422, shift(l1) == "first" && shift(l1) == "second"); - TEST(423, 2 == length_of_list(l1)); // two, three + TEST(428, shift(l1) == "first" && shift(l1) == "second"); + TEST(429, 2 == length_of_list(l1)); // two, three - TEST(424, pop(l1) == "three"); // two - TEST(425, 1 == length_of_list(l1)); + TEST(430, pop(l1) == "three"); // two + TEST(431, 1 == length_of_list(l1)); - TEST(426, shift(l1) == "two"); // null - TEST(427, 0 == length_of_list(l1)); - TEST(428, is_null(l1)); + TEST(432, shift(l1) == "two"); // null + TEST(433, 0 == length_of_list(l1)); + TEST(434, is_null(l1)); push(l1, "five", "six"); - TEST(429, 2 == length_of_list(l1)); + TEST(435, 2 == length_of_list(l1)); } @@ -1700,27 +1715,27 @@ test_list3(void) while ((idx = list_each(l1, value)) >= 0) { switch(idx) { case 0: - TEST(430, 1 == value); + TEST(436, 1 == value); break; case 1: - TEST(431, "2" == value); + TEST(437, "2" == value); break; case 2: - TEST(432, 3.3 == value); + TEST(438, 3.3 == value); break; case 3: - TEST(433, 4 == value); + TEST(439, 4 == value); break; case 4: - TEST(434, "5" == value); + TEST(440, "5" == value); break; case 5: - TEST(435, 6.6 == value); + TEST(441, 6.6 == value); break; } ++count; } - TEST(436, length_of_list(l1) == count); + TEST(442, length_of_list(l1) == count); } @@ -1734,16 +1749,16 @@ test_nth(void) declare d1; gl1[1] = "TWO"; - TEST(437, gl1[1] == "TWO"); - TEST(438, gl1[3][0] == "x"); - TEST(439, gl1[3][1] == "y"); - TEST(440, gl1[2][1][1] == "2.1.1"); - TEST(441, gl1[gl2[0]][gl2[1]][gl2[2]] == "2.1.1"); - TEST(442, gl1[test_10(2)][test_10(1)][test_10(1)] == "2.1.1"); + TEST(443, gl1[1] == "TWO"); + TEST(444, gl1[3][0] == "x"); + TEST(445, gl1[3][1] == "y"); + TEST(446, gl1[2][1][1] == "2.1.1"); + TEST(447, gl1[gl2[0]][gl2[1]][gl2[2]] == "2.1.1"); + TEST(448, gl1[test_10(2)][test_10(1)][test_10(1)] == "2.1.1"); pause_on_error(0, FALSE); d1 = gl1[2][1][4]; /* range error */ pause_on_error(1, FALSE); - TEST(443, is_null(d1)); + TEST(449, is_null(d1)); } @@ -1769,23 +1784,23 @@ splice_1(void) /* [a, b, a, b] */ l += l; - TEST(444, length_of_list(l) == 4 && l[0] == "a" && l[1] == "b" && l[2] == "a" && l[3] == "b"); + TEST(450, length_of_list(l) == 4 && l[0] == "a" && l[1] == "b" && l[2] == "a" && l[3] == "b"); /* [x, x, b, a, b] */ l[0] = x; - TEST(445, length_of_list(l) == 5 && l[0] == "x" && l[1] == "x"); + TEST(451, length_of_list(l) == 5 && l[0] == "x" && l[1] == "x"); /* [x, x, b, a, b, Nul, Nul, Nul, Nul, x, x] */ l[9] = x; - TEST(446, length_of_list(l) == 11 && l[9] == "x"); + TEST(452, length_of_list(l) == 11 && l[9] == "x"); /* Join */ l = splice_l1 + splice_l1; - TEST(447, length_of_list(l) == 6); + TEST(453, length_of_list(l) == 6); /* Append */ l += splice_l1; - TEST(448, length_of_list(l) == 9); + TEST(454, length_of_list(l) == 9); } @@ -1807,22 +1822,22 @@ splice_2(void) list l = quote_list("red", "green", "blue"); splice(l, -1); - TEST(449, length_of_list(l) == 3 && l[2] == "blue"); + TEST(455, length_of_list(l) == 3 && l[2] == "blue"); splice(l, 999); - TEST(450, length_of_list(l) == 3 && l[2] == "blue"); + TEST(456, length_of_list(l) == 3 && l[2] == "blue"); splice(l, 3); - TEST(451, length_of_list(l) == 3 && l[2] == "blue"); + TEST(457, length_of_list(l) == 3 && l[2] == "blue"); splice(l, 2); - TEST(452, length_of_list(l) == 2 && l[1] == "green"); + TEST(458, length_of_list(l) == 2 && l[1] == "green"); splice(l, 0); - TEST(453, length_of_list(l) == 0); + TEST(459, length_of_list(l) == 0); splice(l, 0); - TEST(454, length_of_list(l) == 0); + TEST(460, length_of_list(l) == 0); } @@ -1833,13 +1848,13 @@ splice_3(void) list l2 = quote_list("red", "green", "blue"); splice(l1, 1, 2, "yellow", "orange", "pink"); - TEST(455, length_of_list(l1) == 4 && l1[0] == "red" && l1[1] == "yellow" && l1[2] == "orange" && l1[3] == "pink"); + TEST(461, length_of_list(l1) == 4 && l1[0] == "red" && l1[1] == "yellow" && l1[2] == "orange" && l1[3] == "pink"); splice(l2, 1, 2, "yellow"); - TEST(456, length_of_list(l2) == 2 && l2[0] == "red" && l2[1] == "yellow"); + TEST(462, length_of_list(l2) == 2 && l2[0] == "red" && l2[1] == "yellow"); splice(l2, -1, 0, "orange"); - TEST(457, length_of_list(l2) == 3 && l2[0] == "red" && l2[1] == "yellow" && l2[2] == "orange"); + TEST(463, length_of_list(l2) == 3 && l2[0] == "red" && l2[1] == "yellow" && l2[2] == "orange"); } @@ -1853,13 +1868,13 @@ splice_4(void) list l0 = quote_list(l1, l2, l3); splice(l0, 0, 3, l1, l2, l3, l4); - TEST(458, length_of_list(l0) == 4); + TEST(464, length_of_list(l0) == 4); splice(l0, 0, 0, l1, l2, l3, l4, l1, l2, l3, l4, l1, l2, l3, l4, l1, l2, l3, l4); - TEST(459, length_of_list(l0) == 20); + TEST(465, length_of_list(l0) == 20); splice(l0, -1, 0, l0); /* self reference */ - TEST(460, length_of_list(l0) == 21); + TEST(466, length_of_list(l0) == 21); } @@ -1892,49 +1907,49 @@ test_sort_list(void) list r; r = sort_list(NULL); // error - TEST(461, is_null(r)); + TEST(467, is_null(r)); r = sort_list(list_0); - TEST(462, is_null(r)); + TEST(468, is_null(r)); r = sort_list(list_1); - TEST(463, length_of_list(r) == 1 && r[0] == "a"); + TEST(469, length_of_list(r) == 1 && r[0] == "a"); r = sort_list(list_2); - TEST(464, length_of_list(r) == 2 && r[0] == "a"); + TEST(470, length_of_list(r) == 2 && r[0] == "a"); r = sort_list(list_3); - TEST(465, length_of_list(r) == 3 && r[0] == "a"); + TEST(471, length_of_list(r) == 3 && r[0] == "a"); r = sort_list(list_7); - TEST(466, length_of_list(r) == 7 && r[0] == "a"); + TEST(472, length_of_list(r) == 7 && r[0] == "a"); r = sort_list(list_2, 0); // forward - TEST(467, length_of_list(r) == 2 && r[0] == "a"); + TEST(473, length_of_list(r) == 2 && r[0] == "a"); r = sort_list(list_7, 0); - TEST(468, length_of_list(r) == 7 && r[0] == "a"); + TEST(474, length_of_list(r) == 7 && r[0] == "a"); r = sort_list(list_2, 1); // backwards - TEST(469, length_of_list(r) == 2 && r[0] == "b"); + TEST(475, length_of_list(r) == 2 && r[0] == "b"); r = sort_list(list_7, 1); - TEST(470, length_of_list(r) == 7 && r[0] == "z"); + TEST(476, length_of_list(r) == 7 && r[0] == "z"); r = sort_list(list_2, "::sort_forward"); - TEST(471, length_of_list(r) == 2 && r[0] == "a"); + TEST(477, length_of_list(r) == 2 && r[0] == "a"); r = sort_list(list_7, "::sort_forward"); - TEST(472, length_of_list(r) == 7 && r[0] == "a"); + TEST(478, length_of_list(r) == 7 && r[0] == "a"); r = sort_list(list_2, "::sort_backward"); - TEST(473, length_of_list(r) == 2 && r[0] == "b"); + TEST(479, length_of_list(r) == 2 && r[0] == "b"); r = sort_list(list_7, "::sort_backward"); - TEST(474, length_of_list(r) == 7 && r[0] == "z"); + TEST(480, length_of_list(r) == 7 && r[0] == "z"); // qsort r = sort_list(list_7, NULL, 1); - TEST(475, length_of_list(r) == 7 && r[0] == "a"); + TEST(481, length_of_list(r) == 7 && r[0] == "a"); // mergesort r = sort_list(list_7, NULL, 2); - TEST(476, length_of_list(r) == 7 && r[0] == "a"); + TEST(482, length_of_list(r) == 7 && r[0] == "a"); // heapsort r = sort_list(list_7, NULL, 3); - TEST(477, length_of_list(r) == 7 && r[0] == "a"); + TEST(483, length_of_list(r) == 7 && r[0] == "a"); } @@ -1949,42 +1964,42 @@ test_sprintf(void) int i; // enhanced features - TEST(478, sprintf(s1, "Hello world") == 11); - TEST(479, sprintf(s1, "%*s", 20, "") == 20); - TEST(480, sprintf(s1, "%b", 0xf3) == 8 && s1 == "11110011"); - TEST(481, sprintf(s1, "val=%B", 3, "\10\2BITTWO\1BITONE") == 20 && + TEST(484, sprintf(s1, "Hello world") == 11); + TEST(485, sprintf(s1, "%*s", 20, "") == 20); + TEST(486, sprintf(s1, "%b", 0xf3) == 8 && s1 == "11110011"); + TEST(487, sprintf(s1, "val=%B", 3, "\10\2BITTWO\1BITONE") == 20 && s1 == "val=3"); - TEST(482, sprintf(s1, "12345%n6", "i") == 6 && i == 5); + TEST(488, sprintf(s1, "12345%n6", "i") == 6 && i == 5); // error cases - TEST(483, sprintf(s1, "%s", NULL) && s1 == ""); - TEST(484, sprintf(s1, "%s") && s1 == ""); - TEST(485, sprintf(s1, "%d", NULL) && s1 == "0"); - TEST(486, sprintf(s1, "%c", NULL) && s1 == " "); - TEST(487, sprintf(s1, "%.2f", NULL) && s1 == "0.00"); - TEST(488, sprintf(s1, "%y") && s1 == "y"); + TEST(489, sprintf(s1, "%s", NULL) && s1 == ""); + TEST(490, sprintf(s1, "%s") && s1 == ""); + TEST(491, sprintf(s1, "%d", NULL) && s1 == "0"); + TEST(492, sprintf(s1, "%c", NULL) && s1 == " "); + TEST(493, sprintf(s1, "%.2f", NULL) && s1 == "0.00"); + TEST(494, sprintf(s1, "%y") && s1 == "y"); // format - TEST(489, format("Hello World") == "Hello World"); - TEST(490, format("%b", 0xf3) == "11110011"); + TEST(495, format("Hello World") == "Hello World"); + TEST(496, format("%b", 0xf3) == "11110011"); // large argument list - TEST(491, format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + TEST(497, format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.") == "1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16."); - TEST(492, format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + TEST(498, format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.") == "1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16."); - TEST(493, format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + TEST(499, format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.") == "1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16."); - TEST(494, format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + TEST(500, format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.", "1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10.", "11.", "12.", "13.", "14.", "15.", "16.", @@ -2012,35 +2027,35 @@ __regress_replacement(int x, // return original 2th parameter // ret = __regress_replacement(2, a, b, c, d); - TEST(495, ret == a); + TEST(501, ret == a); break; case 2: // return original 2th parameter // ret = __regress_replacement(2, NULL, b, c, d); - TEST(496, ret == a); + TEST(502, ret == a); break; case 3: // return override 2th parameter // ret = __regress_replacement(2, 999, b, c, d); - TEST(497, ret == 999); + TEST(503, ret == 999); break; case 4: // return original 6th parameter // ret = __regress_replacement(6, a, b, c, d); - TEST(498, ret == e); + TEST(504, ret == e); break; case 5: // return original 6th parameter // ret = __regress_replacement(6, a, b, c, d, NULL); - TEST(499, ret == e); + TEST(505, ret == e); } return 42; } @@ -2058,7 +2073,7 @@ test_replacement(void) ret = __regress_replacement(3, 1, "2", l3, 4, 5, "6", l7, 8); ret = __regress_replacement(4, 1, "2", l3, 4, 5, "6", l7, 8); ret = __regress_replacement(5, 1, "2", l3, 4, 5, "6", l7, 8); - TEST(500, ret == 42); + TEST(506, ret == 42); } @@ -2069,21 +2084,21 @@ test_replacement(void) static void test_isa(void) { - TEST(501, isalpha('A')); - TEST(502, isascii('A')); - TEST(503, iscntrl(0x01)); - TEST(504, iscsym('_')); - TEST(505, isgraph('A')); - TEST(506, isprint('A')); - TEST(507, ispunct('!')); + TEST(507, isalpha('A')); + TEST(508, isascii('A')); + TEST(509, iscntrl(0x01)); + TEST(510, iscsym('_')); + TEST(511, isgraph('A')); + TEST(512, isprint('A')); + TEST(513, ispunct('!')); - TEST(508, isdigit('1') && isdigit(0x30) && isdigit("a1a", 2)); - TEST(509, isdigit("1a1") && isdigit("a1a", 2) && !isdigit("a1a", -1) && !isdigit("", 1)); - TEST(510, islower('a') && !islower('A')); - TEST(511, isupper('A') && !isupper('a')); - TEST(512, isalnum('Z') && !isalnum('*')); - TEST(513, isxdigit('f') && isxdigit('F') && isxdigit('1')); - TEST(514, isspace(' ') && isspace('\t') && isspace('\n') && !isspace('a')); + TEST(514, isdigit('1') && isdigit(0x30) && isdigit("a1a", 2)); + TEST(515, isdigit("1a1") && isdigit("a1a", 2) && !isdigit("a1a", -1) && !isdigit("", 1)); + TEST(516, islower('a') && !islower('A')); + TEST(517, isupper('A') && !isupper('a')); + TEST(518, isalnum('Z') && !isalnum('*')); + TEST(519, isxdigit('f') && isxdigit('F') && isxdigit('1')); + TEST(520, isspace(' ') && isspace('\t') && isspace('\n') && !isspace('a')); } @@ -2094,23 +2109,23 @@ test_isa(void) static void test_basedir(void) { - TEST(515, basename("dir/file") == "file"); - TEST(516, basename("dir/file.c", ".c") == "file"); - TEST(517, basename("", "") == ""); - TEST(518, basename("//", "") == "/"); - TEST(519, basename("dir/file/") == "file"); - TEST(520, basename("dir\\file/") == "file"); - TEST(521, basename("/x/") == "x"); - TEST(522, basename("x/") == "x"); - TEST(523, basename("/x") == "x"); + TEST(521, basename("dir/file") == "file"); + TEST(522, basename("dir/file.c", ".c") == "file"); + TEST(523, basename("", "") == ""); + TEST(524, basename("//", "") == "/"); + TEST(525, basename("dir/file/") == "file"); + TEST(526, basename("dir\\file/") == "file"); + TEST(527, basename("/x/") == "x"); + TEST(528, basename("x/") == "x"); + TEST(529, basename("/x") == "x"); - TEST(524, dirname(".") == "."); - TEST(525, dirname("/") == "/"); - TEST(526, dirname("//") == "/"); - TEST(527, dirname("/xx") == "/"); - TEST(528, dirname("//xx") == "/"); - TEST(529, dirname("aaa/bbb") == "aaa"); - TEST(530, dirname("aaaa//bbb/cccc///") == "aaaa//bbb" ); + TEST(530, dirname(".") == "."); + TEST(531, dirname("/") == "/"); + TEST(532, dirname("//") == "/"); + TEST(533, dirname("/xx") == "/"); + TEST(534, dirname("//xx") == "/"); + TEST(535, dirname("aaa/bbb") == "aaa"); + TEST(536, dirname("aaaa//bbb/cccc///") == "aaaa//bbb" ); } @@ -2122,21 +2137,21 @@ static void test_env(void) { putenv("GRREGRESS", "home"); - TEST(531, getenv("GRREGRESS") == "home"); - TEST(532, expandpath("$$/filename", 0x3) == "$/filename"); - TEST(533, expandpath("$GRREGRESS", 0x3) == "home"); - TEST(534, expandpath("$GRREGRESS/", 0x3) == "home/"); - TEST(535, expandpath("${GRREGRESS}xxx/", 0x3) == "homexxx/"); - TEST(536, expandpath("$(GRREGRESS)xxx/", 0x3) == "homexxx/"); + TEST(537, getenv("GRREGRESS") == "home"); + TEST(538, expandpath("$$/filename", 0x3) == "$/filename"); + TEST(539, expandpath("$GRREGRESS", 0x3) == "home"); + TEST(540, expandpath("$GRREGRESS/", 0x3) == "home/"); + TEST(541, expandpath("${GRREGRESS}xxx/", 0x3) == "homexxx/"); + TEST(542, expandpath("$(GRREGRESS)xxx/", 0x3) == "homexxx/"); /*invalid*/ - TEST(537, expandpath("${GRREGRESSxxx/", 0x3) == "${GRREGRESSxxx/"); - TEST(538, expandpath("$(GRREGRESSxxx/", 0x3) == "$(GRREGRESSxxx/"); - TEST(539, expandpath("${GRREGRESSxxx", 0x3) == "${GRREGRESSxxx"); - TEST(540, expandpath("$(GRREGRESSxxx", 0x3) == "$(GRREGRESSxxx"); - TEST(541, expandpath("$UNKNOWN/", 0x3) == "/"); - TEST(542, expandpath("$(UNKNOWN)xxx/", 0x3) == "xxx/"); - TEST(543, expandpath("${UNKNOWN}xxx/", 0x3) == "xxx/"); + TEST(543, expandpath("${GRREGRESSxxx/", 0x3) == "${GRREGRESSxxx/"); + TEST(544, expandpath("$(GRREGRESSxxx/", 0x3) == "$(GRREGRESSxxx/"); + TEST(545, expandpath("${GRREGRESSxxx", 0x3) == "${GRREGRESSxxx"); + TEST(546, expandpath("$(GRREGRESSxxx", 0x3) == "$(GRREGRESSxxx"); + TEST(547, expandpath("$UNKNOWN/", 0x3) == "/"); + TEST(548, expandpath("$(UNKNOWN)xxx/", 0x3) == "xxx/"); + TEST(549, expandpath("${UNKNOWN}xxx/", 0x3) == "xxx/"); } @@ -2151,22 +2166,22 @@ test_register(void) register_macro(REG_REGRESS, "__regress_event"); call_registered_macro(REG_REGRESS); - TEST(544, 1 == event); + TEST(550, 1 == event); event = 0; register_macro(REG_REGRESS, "__regress_event"); reregister_macro(REG_REGRESS, "__regress_event"); call_registered_macro(REG_REGRESS); - TEST(545, 2 == event); + TEST(551, 2 == event); event = 0; unregister_macro(REG_REGRESS, "__regress_event"); call_registered_macro(REG_REGRESS); - TEST(546, 1 == event); + TEST(552, 1 == event); event = 0; unregister_macro(REG_REGRESS, "__regress_event"); - TEST(547, 0 == event); + TEST(553, 0 == event); } @@ -2189,28 +2204,62 @@ test_buffer(void) if ((buf = create_buffer("-regress-buffer-", NULL, TRUE)) == -1) { return; } - TEST(548, curbuf == inq_buffer()); - TEST(549, curbuf == set_buffer(buf)); - TEST(550, buf == inq_buffer()); - TEST(551, 0 != inq_system()); - TEST(552, (inq_buffer_flags(buf) & BF_SYSBUF) == BF_SYSBUF); - TEST(553, 0 != inq_buffer_flags(NULL, "sysbuf")); - TEST(554, 0 == inq_modified()); + TEST(554, curbuf == inq_buffer()); + TEST(555, curbuf == set_buffer(buf)); + TEST(556, buf == inq_buffer()); + TEST(557, 0 != inq_system()); + TEST(558, (inq_buffer_flags(buf) & BF_SYSBUF) == BF_SYSBUF); + TEST(559, 0 != inq_buffer_flags(NULL, "sysbuf")); + TEST(560, 0 == inq_modified()); //TODO // set_attribute() // inq_attribute() - // inq_line_length - // insert() - // insertf() // insert_buffer() - // read() - // set_buffer() // inq_next_buffer() // inq_prev_buffer() // + { const string sval = "1234567890abcdefghijklmnopqrstuvwxyz"+ + "1234567890abcdefghijklmnopqrstuvwxyz\n"; + const int slen = strlen(sval); + int status, count; + string line; + + top_of_buffer(); + count = insert(sval); + TEST(561, slen == count); + TEST(562, slen == inq_line_length()); + + top_of_buffer(); + line = read(NULL, status); + TEST(563, status == 1); /* EOF */ + TEST(564, line == sval); + + line = read(slen, status); + TEST(565, status == 1); /* EOF */ + TEST(566, line == sval); + + line = read(1, status); + TEST(567, status == 0); /* partial */ + TEST(568, line == "1"); + + line = read(9, status); + TEST(569, status == 0); /* partial */ + TEST(570, line == "123456789"); + + top_of_buffer(); + count = insertf("%s\n", "abcdefg1234567890"); + TEST(571, 18 == count); + TEST(572, slen == inq_line_length()); + + top_of_buffer(); + line = read(NULL, status); + TEST(573, status == 1); /* EOF */ + TEST(574, line == "abcdefg1234567890\n"); + } + restore_position(2); - TEST(555, curbuf == inq_buffer()); - TEST(556, curwin == inq_window()); + TEST(575, curbuf == inq_buffer()); + TEST(576, curwin == inq_window()); delete_buffer(buf); } @@ -2218,7 +2267,7 @@ test_buffer(void) static void test_key(void) { - TEST(557, int_to_key(key_to_int("")) == ""); + TEST(577, int_to_key(key_to_int("")) == ""); } @@ -2228,11 +2277,11 @@ test_debug(void) list l1; l1 = debug_support(DBG_INQ_VARS, 0); - TEST(558, is_list(l1)); + TEST(578, is_list(l1)); l1 = debug_support(DBG_STACK_TRACE, NULL, ""); - TEST(559, is_list(l1)); + TEST(579, is_list(l1)); l1 = debug_support(DBG_INQ_VAR_INFO, 0, "l1"); - TEST(560, is_list(l1)); + TEST(580, is_list(l1)); } @@ -2242,27 +2291,27 @@ test_strtol(void) int ret, endp; ret = strtol("xxx"); /* basic */ - TEST(561, ret == 0); + TEST(581, ret == 0); ret = strtol("1"); /* dec */ - TEST(562, ret == 1); + TEST(582, ret == 1); ret = strtol("01"); /* oct */ - TEST(563, ret == 1); + TEST(583, ret == 1); ret = strtol("0x1"); /* hex */ - TEST(564, ret == 1); + TEST(584, ret == 1); ret = strtol("g", NULL, 36); /* base 36 (0123456789abc...) */ - TEST(565, ret == 16); + TEST(585, ret == 16); ret = strtol("xxx", endp); /* invalid */ - TEST(566, ret == 0); - TEST(567, endp == 0); + TEST(586, ret == 0); + TEST(587, endp == 0); ret = strtol("12", endp); - TEST(568, ret == 12); - TEST(569, endp == 3); + TEST(588, ret == 12); + TEST(589, endp == 3); } @@ -2273,24 +2322,24 @@ test_strtof(void) int endp; ret = strtof("0.0"); /* dec */ - TEST(570, ret == 0.0); + TEST(590, ret == 0.0); ret = strtof("1.0"); /* dec */ - TEST(571, ret == 1.0); + TEST(591, ret == 1.0); ret = strtof("xxx", endp); /* invalid */ - TEST(572, ret == 0); - TEST(573, endp == 0); + TEST(592, ret == 0); + TEST(593, endp == 0); ret = strtof("0.0"); /* dec */ - TEST(574, ret == 0.0); + TEST(594, ret == 0.0); ret = strtof("1.0"); /* dec */ - TEST(575, ret == 1.0); + TEST(595, ret == 1.0); ret = strtof("xxx", endp); /* invalid */ - TEST(576, ret == 0); - TEST(577, endp == 0); + TEST(596, ret == 0); + TEST(597, endp == 0); } @@ -2301,45 +2350,45 @@ test_strtod(void) int endp; ret = strtod("0.0"); /* dec */ - TEST(578, ret == 0.0); + TEST(598, ret == 0.0); ret = strtod("1.0"); /* dec */ - TEST(579, ret == 1.0); + TEST(599, ret == 1.0); ret = strtod("xxx", endp); /* invalid */ - TEST(580, ret == 0); - TEST(581, endp == 0); + TEST(600, ret == 0); + TEST(601, endp == 0); ret = strtod("0.0"); /* dec */ - TEST(582, ret == 0.0); + TEST(602, ret == 0.0); ret = strtod("1.0"); /* dec */ - TEST(583, ret == 1.0); + TEST(603, ret == 1.0); ret = strtod("xxx", endp); /* invalid */ - TEST(584, ret == 0); - TEST(585, endp == 0); + TEST(604, ret == 0); + TEST(605, endp == 0); } static void test_defaults1(int value = 666) { - TEST(586, value == 666); + TEST(606, value == 666); } static void test_defaults2(string value = "666") { - TEST(587, value == "666"); + TEST(607, value == "666"); } static void test_defaults3(string value = 1.1) { - TEST(588, value == 1.1); + TEST(608, value == 1.1); } @@ -2381,11 +2430,11 @@ test_reference(void) float fvalue = 1; test_reference1(ivalue); - TEST(589, ivalue == 2); + TEST(609, ivalue == 2); test_reference2(svalue); - TEST(590, svalue == "two"); + TEST(610, svalue == "two"); test_reference3(fvalue); - TEST(591, fvalue == 2); + TEST(611, fvalue == 2); } @@ -2405,7 +2454,7 @@ test_pushpop(void) sprintf(msg, "work%04d", i); push(l, msg); } - TEST(592, length_of_list(l) == 1000); + TEST(612, length_of_list(l) == 1000); for (i = i-1; i >= 0; --i) { sprintf(msg, "work%04d", i); @@ -2414,13 +2463,13 @@ test_pushpop(void) break; } } - TEST(593, success); + TEST(613, success); - TEST(594, length_of_list(l) == 0); + TEST(614, length_of_list(l) == 0); pause_on_error(0, FALSE); r = pop(l); pause_on_error(1, FALSE); - TEST(595, is_null(r)); /* FIXME/XXX - is_null(pop(l)) broken/limitation of LVAL's */ + TEST(615, is_null(r)); /* FIXME/XXX - is_null(pop(l)) broken/limitation of LVAL's */ } @@ -2429,12 +2478,12 @@ test_globals(void) { int line, col; - TEST(596, inq_window() == current_window); - TEST(597, inq_buffer() == current_buffer); + TEST(616, inq_window() == current_window); + TEST(617, inq_buffer() == current_buffer); inq_position(line, col); - TEST(598, line == current_line); + TEST(618, line == current_line); inq_position(line, col); - TEST(599, col == current_col); + TEST(619, col == current_col); } @@ -2445,7 +2494,7 @@ test_globals(void) static void test_search(void) { - TEST(600, quote_regexp("<>") == "\\<\\>"); + TEST(620, quote_regexp("<>") == "\\<\\>"); // search string // search buffer } @@ -2463,17 +2512,17 @@ test_search(void) static void test_called(void) { - TEST(601, "test_called" == caller()); + TEST(621, "test_called" == caller()); set_calling_name(""); - TEST(602, "" == caller()); + TEST(622, "" == caller()); set_calling_name("test_called"); - TEST(603, "test_called" == caller()); + TEST(623, "test_called" == caller()); set_calling_name("hello_world"); - TEST(604, "hello_world" == caller()); + TEST(624, "hello_world" == caller()); set_calling_name(inq_called()); - TEST(605, "regress" == caller()); + TEST(625, "regress" == caller()); set_calling_name(NULL); /* extension, reset/clear */ - TEST(606, "test_called" == caller()); + TEST(626, "test_called" == caller()); } @@ -2494,16 +2543,16 @@ test_macro(void) int ret; ret = inq_macro("regress"); /* defined */ - TEST(607, ret == 1); + TEST(627, ret == 1); ret = inq_macro("list_of_dictionaries"); /* builtin */ - TEST(608, ret == 0); + TEST(628, ret == 0); ret = inq_macro("cut"); /* replacement */ - TEST(609, ret == 2); + TEST(629, ret == 2); ret = inq_macro("this_should_not_be_undefined"); - TEST(610, ret == -1); /* undefined */ + TEST(630, ret == -1); /* undefined */ } @@ -2519,12 +2568,12 @@ test_undef(void) // // control how 'undefines' are handled?? // try { if (1) { - TEST(611, inq_symbol("undefined_ival") == 0); - TEST(612, inq_symbol("undefined_fval") == 0); - TEST(613, inq_symbol("undefined_sval") == 0); - TEST(614, undefined_ival == 0); /* wont be executed! */ - TEST(615, undefined_fval == 0); /* wont be executed! */ - TEST(616, undefined_sval == ""); /* wont be executed! */ + TEST(631, inq_symbol("undefined_ival") == 0); + TEST(632, inq_symbol("undefined_fval") == 0); + TEST(633, inq_symbol("undefined_sval") == 0); + TEST(634, undefined_ival == 0); /* wont be executed! */ + TEST(635, undefined_fval == 0); /* wont be executed! */ + TEST(636, undefined_sval == ""); /* wont be executed! */ } // } catch { // } finally { @@ -2543,12 +2592,12 @@ test_history(void) const string top = inq_macro_history(0); /* or from features */ - TEST(617, top == "execute_macro" || top == "sel_list"); - TEST(618, inq_command() == inq_macro_history()); + TEST(637, top == "execute_macro" || top == "sel_list"); + TEST(638, inq_command() == inq_macro_history()); set_macro_history(0, "function1"); set_macro_history(1, "function2"); - TEST(619, "function1" == inq_macro_history()); - TEST(620, "function2" == inq_macro_history(1)); + TEST(639, "function1" == inq_macro_history()); + TEST(640, "function2" == inq_macro_history(1)); } @@ -2560,24 +2609,24 @@ static void test_scope(void) { if (first_time()) { /* can only be run once */ - TEST(621, 1 == scope_1()); - TEST(622, 2 == scope_1()); - TEST(623, 3 == scope_1()); + TEST(641, 1 == scope_1()); + TEST(642, 2 == scope_1()); + TEST(643, 3 == scope_1()); - TEST(624, 1 == scope_2()); - TEST(625, 2 == scope_2()); - TEST(626, 3 == scope_2()); + TEST(644, 1 == scope_2()); + TEST(645, 2 == scope_2()); + TEST(646, 3 == scope_2()); - TEST(627, 1 == scope_3()); - TEST(628, 2 == scope_3()); - TEST(629, 3 == scope_3()); + TEST(647, 1 == scope_3()); + TEST(648, 2 == scope_3()); + TEST(649, 3 == scope_3()); } else { /* emulate */ extern int num_passed; num_passed += 9; } - TESTASYNC(630, 0 == inq_symbol("x_extern_dontexist")); - TEST(631, 0 != inq_symbol("x_static")); + TESTASYNC(650, 0 == inq_symbol("x_extern_dontexist")); + TEST(651, 0 != inq_symbol("x_static")); } @@ -2633,38 +2682,38 @@ test_dict(void) /* create dictionaries */ dict = create_dictionary(); - TEST(632, dict); + TEST(652, dict); dict2 = create_dictionary("namedict"); - TEST(633, dict2); + TEST(653, dict2); /* basic set/get primitives */ set_property(dict, "property", 1234); var = get_property(dict, "property"); - TEST(634, 1234 == var); + TEST(654, 1234 == var); set_property(dict, "property", "hello world"); var = get_property(dict, "property"); - TEST(635, "hello world" == var); + TEST(655, "hello world" == var); /* indirection operators */ dict.value = "value1"; /* FIXME/XXX - compiler issues yet resolved */ - TEST(636, "value1" == dict.value); + TEST(656, "value1" == dict.value); dict2.value = "value2"; dict.indirect = dict2; /* FIXME/XXX - reference count issues */ - TEST(637, "value2" == dict.indirect.value); + TEST(657, "value2" == dict.indirect.value); ret = dict_exists(dict, "property"); - TEST(638, ret); + TEST(658, ret); l1 = dict_list(dict); - TEST(639, is_list(l1)); - TEST(640, 3 == length_of_list(l1)); + TEST(659, is_list(l1)); + TEST(660, 3 == length_of_list(l1)); set_property(dict, "property2", 1234); set_property(dict, "property3", 5678); l1 = dict_list(dict); - TEST(641, 5 == length_of_list(l1)); + TEST(661, 5 == length_of_list(l1)); // FIXME/XXX -- // compiler bug, allows declare when string expected. @@ -2677,36 +2726,36 @@ test_dict(void) while ((idx = dict_each(dict, key, value)) >= 0) { switch(key) { case "property": - TESTASYNC(642, "hello world" == value); + TESTASYNC(662, "hello world" == value); ++count; break; case "property2": - TESTASYNC(643, 1234 == value); + TESTASYNC(663, 1234 == value); ++count; break; case "property3": - TESTASYNC(644, 5678 == value); + TESTASYNC(664, 5678 == value); ++count; break; } } - TESTASYNC(645, 3 == count); + TESTASYNC(665, 3 == count); ret = dict_delete(dict, "property"); - TEST(646, 0 == ret); + TEST(666, 0 == ret); l1 = dict_list(dict); - TEST(647, is_list(l1)); - TEST(648, 4 == length_of_list(l1)); + TEST(667, is_list(l1)); + TEST(668, 4 == length_of_list(l1)); l1 = list_of_dictionaries(); - TEST(649, is_list(l1)); - TEST(650, length_of_list(l1) >= 2); /* all dictionaries */ + TEST(669, is_list(l1)); + TEST(670, length_of_list(l1) >= 2); /* all dictionaries */ ret = delete_dictionary(dict); - TEST(651, 0 == ret); + TEST(671, 0 == ret); ret = delete_dictionary(dict2); - TEST(652, 0 == ret); + TEST(672, 0 == ret); } @@ -2718,7 +2767,7 @@ test_dict(void) static int test_leaks(void) { - TEST(653, leak_1(1000) == 1000); /* list are limited 2^16 atoms */ + TEST(673, leak_1(1000) == 1000); /* list are limited 2^16 atoms */ } @@ -2823,8 +2872,8 @@ regress_renumber(void) while (re_search(0, "TES[A-Z]+([0-9]+,") > 0) { /* * examples: - * TEST(654, - * TESTASYNC(655, + * TEST(674, + * TESTASYNC(675, */ line = read(18); delete_char(index(line, ",")); diff --git a/macsrc/demos/regress2.cr b/macsrc/demos/regress2.cr index e40e1df5..aa410611 100644 --- a/macsrc/demos/regress2.cr +++ b/macsrc/demos/regress2.cr @@ -1,5 +1,6 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: regress2.cr,v 1.20 2020/04/23 12:37:00 cvsuser Exp $ +/* charset=utf8 + * $Id: regress2.cr,v 1.24 2021/07/05 15:01:29 cvsuser Exp $ * Regression tests ... part2. * * @@ -55,7 +56,25 @@ static void test_datetime(void); static void test_sysinfo(void); static void test_ini(void); static void test_register_int(void); -#endif + +static void test_unicode_version(void); +static void test_wcwidth(void); +static void test_wstrlen(void); +static void test_wstrnlen(void); +static void test_wcharacterat(void); +static void test_wstrstr(void); +static void test_wstrrstr(void); +static void test_wsubstr(void); +static void test_wfirstof(void); +static void test_wstrpbrk(void); +static void test_wlastof(void); +static void test_wstrcmp(void); +static void test_wstrcasecmp(void); +static void test_wlower(void); +static void test_wupper(void); +static void test_wread(void); +static void test_wsprintf(void); +#endif //__PROTOTYPES__ void @@ -131,6 +150,25 @@ regress2(void) test_sysinfo(); test_ini(); test_register_int(); + + // 06/2020 + test_unicode_version(); + test_wcwidth(); + test_wstrlen(); + test_wstrnlen(); + test_wcharacterat(); + test_wstrstr(); + test_wstrrstr(); + test_wsubstr(); + test_wfirstof(); + test_wstrpbrk(); + test_wlastof(); + test_wstrcmp(); + test_wstrcasecmp(); + test_wlower(); + test_wupper(); + test_wread(); + test_wsprintf(); } @@ -1287,12 +1325,231 @@ test_register_int(void) #pragma warning(pop) #endif -/*end*/ +static void +test_unicode_version(void) +{ + string uv = inq_unicode_version(); + TEST(1241, set_unicode_version("11.0.0") == 110000); //match + TEST(1242, set_unicode_version("13.0.0") == 130000); //match + TEST(1243, set_unicode_version("19.0.0") == 130000); //closet + set_unicode_version(uv); +} + + +static void +test_wcwidth(void) +{ + TEST(1244, wcwidth("") == 0); + TEST(1245, wcwidth("a") == 1); + TEST(1246, wcwidth("The quick brown fox jumps over the lazy dog") == 43); + TEST(1247, wcwidth("ξεσκεπάζω την ψυχοφθόÏα βδελυγμία") == 33); +} + + +static void +test_wstrlen(void) +{ + TEST(1248, wstrlen("") == 0); + TEST(1249, wstrlen("a") == 1); + TEST(1250, wstrlen("The quick brown fox jumps over the lazy dog") == 43); + TEST(1251, wstrlen("ξεσκεπάζω την ψυχοφθόÏα βδελυγμία") == 33); +} + + +static void +test_wstrnlen(void) +{ + TEST(1252, wstrnlen("", 0) == 0); + TEST(1253, wstrnlen("a", 1) == 1); + TEST(1254, wstrnlen("The quick brown fox jumps over the lazy dog", 30) == 30); + TEST(1255, wstrnlen("ξεσκεπάζω την ψυχοφθόÏα βδελυγμία", 34) == 33); +} + + +static void +test_wcharacterat(void) +{ + TEST(1256, wcharacterat("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", 1) == L'Ð') + TEST(1257, wcharacterat("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", 7) == L'Ж') + TEST(1258, wcharacterat("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", 33) == -1) +} + + +static void +test_wstrstr(void) +{ + TEST(1259, 4 == wstrstr("abcmandefg", "man")); + TEST(1260, 4 == wstrstr("abcmanmandefg", "man")); + TEST(1261, 0 == wstrstr("abcmanmandefg", "ban")); + TEST(1262, 1 == wstrstr("abcmanmandefg", "")); + + TEST(1263, wstrstr("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "БВ") == 2) + TEST(1264, wstrstr("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "A") == 0) + TEST(1265, wstrstr("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "") == 1) +} + + +static void +test_wstrrstr(void) +{ + TEST(1266, 4 == wstrrstr("abcmandefg", "man")); + TEST(1267, 7 == wstrrstr("abcmanmandefg", "man")); + TEST(1268, 0 == wstrrstr("abcmanmandefg", "ban")); + TEST(1269, 0 == wstrrstr("abcmanmandefg", "")); + + TEST(1270, wstrrstr("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "БВ") == 34) + TEST(1271, wstrrstr("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "A") == 0) + TEST(1272, wstrrstr("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "") == 0) +} + + +static void +test_wsubstr(void) +{ + TEST(1273, wsubstr("ABC", 0, 3) == "ABC"); + TEST(1274, wsubstr("ABC", -1000, 1000) == "ABC"); + TEST(1275, wsubstr("ABC", 1000, 1000) == ""); + TEST(1276, wsubstr("ABC", 1, 0) == ""); + TEST(1277, wsubstr("ABC", 1, 1) == "A"); + TEST(1278, wsubstr("ABC", 1, 2) == "AB"); + TEST(1279, wsubstr("ABC", 1, 3) == "ABC"); + TEST(1280, wsubstr("ABC", 1, 100) == "ABC"); + TEST(1281, wsubstr("ABC", 3, 0) == ""); + TEST(1282, wsubstr("ABC", 3, 1) == "C"); + TEST(1283, wsubstr("ABC", 3, 100) == "C"); + + TEST(1284, wsubstr("ξεσκεπάζω την ψυχοφθόÏα βδελυγμία", 33, 0) == ""); + TEST(1285, wsubstr("ξεσκεπάζω την ψυχοφθόÏα βδελυγμία", 1, 9) == "ξεσκεπάζω"); + TEST(1286, wsubstr("ξεσκεπάζω την ψυχοφθόÏα βδελυγμία", 11, 3) == "την"); +} + +static void +test_wfirstof(void) +{ + int wch; + TEST(1287, wfirstof("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "БВ", wch) == 2 && wch == L'Б') + TEST(1288, wfirstof("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "CФВ", wch) == 3 && wch == L'Ð’') + TEST(1289, wfirstof("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "XBC", wch) == 0 && wch == 0) +} + + +static void +test_wstrpbrk(void) +{ + TEST(1290, 3 == wstrpbrk("abcdefg", "dc")); + TEST(1291, wfirstof("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "БВ") == 2) + TEST(1292, wfirstof("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "CФВ") == 3) + TEST(1293, wfirstof("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "XBC") == 0) +} + + +static void +test_wlastof(void) +{ + int wch; + TEST(1294, wlastof("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "БВ", wch) == 35 && wch == L'Ð’') + TEST(1295, wlastof("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "CФВ", wch) == 53 && wch == L'Ф') + TEST(1296, wlastof("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "XBC", wch) == 0 && wch == 0) +} +static void +test_wstrcmp(void) +{ + TEST(1297, 0 == wstrcmp("aaa", "aaa")); + TEST(1298, 0 == wstrcmp("aaa", "aaa")); + TEST(1299, 0 == wstrcmp("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ", "ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ")); + TEST(1300, 0 == wstrcmp("ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯYYYY", "ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯXXXX", 32)); +} +static void +test_wstrcasecmp(void) +{ + TEST(1301, 0 == wstrcasecmp("AaA", "aAa")); + TEST(1302, 0 == wstrcasecmp("AaAXXX", "aAaYYY", 3)); +} +static void +test_wlower(void) +{ + TEST(1303, wlower("AbC") == "abc"); + TEST(1304, wlower("ÓÓ") == "óó"); + TEST(1305, wlower(L'Ó') == L'ó'); +} + + +static void +test_wupper(void) +{ + TEST(1306, wupper("aBc") == "ABC"); + TEST(1307, wupper("óó") == "ÓÓ"); + TEST(1308, wupper(L'ó') == L'Ó'); +} + + +static void +test_wread(void) +{ + const string sval = "1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz\n"; + const string wval = "ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ\n"; + const int wlen = wstrlen(wval); + int buf, status; + string line; + + save_position(); + if ((buf = create_buffer("-regress-wbuffer-", NULL, TRUE, 0, "utf8")) == -1) { + return; + } + set_buffer(buf); + + top_of_buffer(); + insert(sval); + top_of_buffer(); + line = read(NULL, status); + TEST(1309, status == 1); /* EOF */ + TEST(1310, line == sval); + + top_of_buffer(); + insert(wval); + top_of_buffer(); + line = read(NULL, status); + TEST(1311, status == 1); /* EOF */ + TEST(1312, line == wval); + + line = read(wlen, status); + TEST(1313, status == 1); /* EOF */ + TEST(1314, line == wval); + + line = read(10, status); + TEST(1315, status == 0); /* partial */ + TEST(1316, line == wsubstr(line, 1, 10)); + + restore_position(2); + delete_buffer(buf); +} + + +static void +test_wsprintf(void) +{ + const string sval = "1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz"; + const string wval = "ÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ"; + const string dval = "他們所有的設備和儀器彷彿都是有生命的"; + string buffer; + int wc; + + wc = sprintf(buffer, "%s", sval); // string, by length. + TEST(1317, wc == strlen(sval)); + + wc = sprintf(buffer, "%S", wval); // wide-string, by length. + TEST(1318, wc == wstrlen(wval)); + + wc = sprintf(buffer, "%W", dval); // by width + TEST(1319, wc == wcwidth(dval)); +} + +/*end*/ diff --git a/macsrc/demos/tetris.cr b/macsrc/demos/tetris.cr index 29c24f17..066b1e25 100644 --- a/macsrc/demos/tetris.cr +++ b/macsrc/demos/tetris.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; tabs: 4; -*- */ -/* $Id: tetris.cr,v 1.13 2014/10/27 23:28:32 ayoung Exp $ +/* $Id: tetris.cr,v 1.14 2021/06/19 16:26:25 cvsuser Exp $ * Tetris game. * * This implementation is based on the X11 version by Rob Mayoff @@ -220,6 +220,7 @@ tetris() #define LEFT_X 20 win = create_window(LEFT_X, HEIGHT + 1, LEFT_X + PWIDTH * WIDTH + 20, 1); set_buffer(buf); + set_buffer_type(NULL, BFTYP_UNIX); if (tetris_cmap < 0) { create_syntax(TETRISMODE); syntax_token(SYNT_OPERATOR, BLOCK); diff --git a/macsrc/ff.cr b/macsrc/ff.cr index ec0d68e7..11498e4d 100644 --- a/macsrc/ff.cr +++ b/macsrc/ff.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: ff.cr,v 1.39 2020/05/04 20:11:58 cvsuser Exp $ +/* $Id: ff.cr,v 1.40 2021/07/05 15:01:28 cvsuser Exp $ * Find find and other assorted directory/file searches. * * ff File find. @@ -26,6 +26,7 @@ #define BACKWARD_SLASH '\\' #define WILD "?*" #define CURRENTDIR "." +#define DELIMIT ";" #define FF_MINWIDTH 68 @@ -50,6 +51,7 @@ #define F_PIPE 0x0400 #define F_DIR 0x0800 #define F_CURRBUFFER 0x1000 +#define F_TOPLINE 0x2000 /* Globals */ static string ffslashc; @@ -116,6 +118,7 @@ ff(~string, ~string, ~int) return ""; } set_buffer(ff_buf); + set_buffer_type(NULL, BFTYP_UTF8); tabs(7, 13); if (alldirs == "<") { @@ -271,10 +274,11 @@ dir(~string, ~string) string tree(~string) { - string directory, tmpstr; - int old_buf = inq_buffer(), - msg_level = inq_msg_level(); - int tree_buf, picked_no; + string directory, curdir, result, tmp; + int old_buf = inq_buffer(), + msg_level = inq_msg_level(); + int tree_buf, picked_no; + int ilen; /* Retrieve base directory */ if (! get_parm(0, directory, "Directory: ", NULL, CURRENTDIR)) { @@ -290,19 +294,20 @@ tree(~string) return ""; } - tmpstr = directory; - if (rindex(tmpstr, sysslash()) != strlen(tmpstr)) { - tmpstr += sysslash(); + tmp = directory; + if (rindex(tmp, sysslash()) != strlen(tmp)) { + tmp += sysslash(); } if ((tree_buf = - create_buffer("Directory Tree", tmpstr + TREE_FILE, FALSE)) < 0) { + create_buffer("Directory Tree", tmp + TREE_FILE, FALSE)) < 0) { message("tree: Unable to access directory buffer."); return ""; } set_buffer(tree_buf); set_buffer_flags(tree_buf, BF_SYSBUF|BF_NO_UNDO, ~BF_BACKUP); + set_buffer_type(NULL, BFTYP_UTF8); if (inq_lines() <= 1) ffrescan = 1; /* new buffer; scan */ @@ -315,18 +320,20 @@ tree(~string) end_of_buffer(); delete_block(); write_buffer(); - /* Insert BASE directory */ - getwd("", tmpstr); + /* Base directory */ + getwd("", curdir); cd(directory); getwd("", directory); - insert(directory); - move_abs(0, TREE_WIDTH); - insert(";" + directory); - - /* Create the TREE from the base directory */ - /* recursive, tree */ - _ff(directory, "", "", F_RECURSIVE|F_SPECIALS|F_DIRTREE); - cd(tmpstr); + + if ((ilen = wcwidth(directory)) > TREE_WIDTH) { + ilen = TREE_WIDTH; + } + insertf("%S%*s%S", directory, + TREE_WIDTH - ilen, DELIMIT, directory); + + /* Recursive, tree */ + _ff(directory, "", "", F_RECURSIVE|F_SPECIALS|F_DIRTREE|F_TOPLINE); + cd(curdir); write_buffer(); /* flush result */ message(""); ffrescan = 0; @@ -348,7 +355,7 @@ tree(~string) /* Left,bottom,right,top */ _dialog_menu(col, (sline / 3) * 2, col+width, 3, "DirTree", ", , Re-Scan, Search", - NULL, tree_buf, "_tree_act", TRUE, picked_no, tmpstr); + NULL, tree_buf, "_tree_act", TRUE, picked_no, result); set_buffer(tree_buf); } @@ -359,9 +366,9 @@ tree(~string) directory = ""; } else { top_of_buffer(); - move_abs(0, TREE_WIDTH + 1); - directory = trim(read()); - directory += substr(tmpstr, index(tmpstr, ";")+1); + tmp = rtrim(read()); + directory = substr(tmp, rindex(tmp, DELIMIT) + 1); + directory += substr(result, rindex(result, DELIMIT) + 1); } break; } @@ -573,6 +580,7 @@ tsmain(int flags, string pattern, string file, string caller) set_buffer(tsbuf); set_buffer_flags(NULL, BF_NO_UNDO, ~BF_BACKUP); + set_buffer_type(NULL, BFTYP_UTF8); /* search */ if (flags & F_PIPE) { /* piping search results */ @@ -1018,11 +1026,12 @@ _ff(string rootdir, string fmask, string pattern, int flags) setwidth(pattern); /* set display width */ - _ff_lines = 0; + _ff_lines = 0; + if (flags & F_TOPLINE) _ff_lines = 1; _ff_rootdir = rootdir; - _ff_fmask = fmask; + _ff_fmask = fmask; _ff_pattern = pattern; - _ff_flags = flags; + _ff_flags = flags; return _ff2((flags & F_DIRTREE ? 1 : 0), 0); } @@ -1035,8 +1044,8 @@ _ff2(int dirtree, int dirmask) extern int _ff_lines, _ff_flags; string curdir, subdir, buffer, name; int dircnt, diridx; + int mode, ilen, i; list dirlst; - int mode, i; /* Process files within the directory */ getwd("", curdir); @@ -1065,24 +1074,26 @@ _ff2(int dirtree, int dirmask) date(cyear, NULL, NULL); file_pattern(_ff_fmask); while (find_file(name, size, mtime, NULL, mode)) { - /* append to directory list */ + + /* Append to directory list */ if (mode & S_IFDIR) { - if (_ff_fmask == WILD) - if (substr(name, 1, 1) != ".") + if (_ff_fmask == WILD) { + if (wsubstr(name, 1, 1) != ".") {/* Save the need the scan directory twice */ dirlst += name; - dircnt++; + ++dircnt; } + } continue; - } - + } + /* Filter specials */ if (0 == (mode & S_IFDIR) && 0 == (_ff_flags & F_SPECIALS)) { if (name == GRRESTORE_FILE || name == GRSTATE_FILE) { continue; /* grief internal */ } - if (substr(name, 1, 1) == ".") { + if (wsubstr(name, 1, 1) == ".") { continue; /* special name */ } } @@ -1096,39 +1107,37 @@ _ff2(int dirtree, int dirmask) } /* Default action, build directory list */ - buffer = curdir+name; - if ((i = strlen(buffer)) > flen) { - buffer = substr(buffer, i-flen); - if ((i = index(buffer, sysslash()))) { - buffer = substr(buffer, i); + buffer = curdir + name; + if ((i = wstrlen(buffer)) > flen) { + buffer = wsubstr(buffer, i - flen); + if ((i = windex(buffer, sysslash())) > 0) { + buffer = wsubstr(buffer, i); } buffer = "..." + buffer; } - if (mode & S_IFDIR) { - sprintf(buffer, " %-" + flen + "s ", - buffer+sysslash()); + if (_ff_lines) insert("\n"); + if (mode & S_IFDIR) { /* file/dir name/size */ + insertf(" %-*S ", flen, buffer + sysslash()); } else { - sprintf(buffer, " %-" + flen + "s %7d", buffer, size); + insertf(" %-*S %7d", flen, buffer, size); } - insert(buffer); /* file/dir name/size */ if (smode) { /* mode */ insert(" " + mode_string(mode)); } - /* modification date/time */ + /* Modification date/time */ localtime(mtime, year, NULL, day, mon, NULL, hour, min, NULL); if (cyear == year) { - sprintf(buffer, " %s %2d %02d:%02d ;", substr(mon,1,3), day, hour, min); + insertf(" %s %2d %02d:%02d ", substr(mon,1,3), day, hour, min); } else { - sprintf(buffer, " %s %2d %04d ;", substr(mon,1,3), day, year); + insertf(" %s %2d %04d ", substr(mon,1,3), day, year); } - insert(buffer); - insert(curdir + name + "\n"); /* full path */ - - if (++_ff_lines % 100 == 0) { + /* Full path */ + insert(DELIMIT + curdir + name); + if ((++_ff_lines % 50) == 0) { if (aborted_pressed()) { return "."; /* user abort ? */ } @@ -1147,13 +1156,12 @@ _ff2(int dirtree, int dirmask) while (find_file(name, NULL, NULL, NULL, mode)) if ((mode & S_IFDIR) && substr(name, 1, 1) != ".") { #if defined(S_IFLNK) - if (0 == lstat(name, NULL, NULL, NULL, NULL, mode) && - (mode & S_IFLNK)) { + if (0 == lstat(name, NULL, NULL, NULL, NULL, mode) && (mode & S_IFLNK)) { continue; /* dont follow links */ } #endif dirlst += name; /* append to directory list */ - dircnt++; + ++dircnt; } } @@ -1166,9 +1174,9 @@ _ff2(int dirtree, int dirmask) } /* Recurse list */ - diridx = 0; /* directory list, into list */ + diridx = 0; // directory list, into list while (diridx < dircnt) { - name = dirlst[ diridx ]; /* Next directory name */ + name = dirlst[ diridx ]; // next directory name subdir = curdir + name + sysslash(); /* Draw tree structure: @@ -1177,42 +1185,30 @@ _ff2(int dirtree, int dirmask) * a given level. */ if (dirtree) { - buffer = "\n"; + buffer = ""; -#if defined(MSDOS) && (0) // MCHAR??? - for (i=2; i= dircnt) { // level - dirmask |= (1 << dirtree); - buffer += "\xC0"; - } else { - buffer += "\xC3"; - } - buffer += "\xC4\xC4\xC4\xC4\xC4" + upper(name); -#else - for (i=2; i= dircnt) { // level + + if ((diridx + 1) >= dircnt) { // level dirmask |= (1 << dirtree); } - buffer += "+----" + upper(name); -#endif - insert(buffer); - move_abs(0, TREE_WIDTH); // save the whole directory path - insert(";"); - insert(lower(substr(subdir, strlen(_ff_rootdir)+1)) ); - if (++_ff_lines % 200 == 0) { + buffer += "+---- "; + buffer += name; + + if ((ilen = wcwidth(buffer)) > TREE_WIDTH) { + ilen = TREE_WIDTH; + } + insertf("\n%S%*s%S", buffer, TREE_WIDTH - ilen, DELIMIT, + lower(substr(subdir, strlen(_ff_rootdir) + 1))); + + if ((++_ff_lines % 100) == 0) { if (aborted_pressed()) { return "."; } @@ -1228,8 +1224,7 @@ _ff2(int dirtree, int dirmask) } cd(curdir); // restore directory - /* Increment list reference */ - diridx++; + ++diridx; // list reference } return ""; } @@ -1261,16 +1256,14 @@ shortname( string name, int add ) { int len, maxlen, i; - if (add == 0) { - add = 10; - } - len = strlen(name); + if (add == 0) add = 10; + len = wstrlen(name); maxlen = ffwidth - (31 + add); // 31=std status line length if (len < maxlen || maxlen < 0) { return name; } - i = maxlen/2; - return substr(name, 1, i) + "~" + substr(name, len - (maxlen - (i + 2))); + i = maxlen / 2; + return wsubstr(name, 1, i) + "~" + wsubstr(name, len - (maxlen - (i + 2))); } @@ -1294,8 +1287,8 @@ validdir(string newdir, int restore) if (cd(newdir) == FALSE) { int ctm; - error("%s : (%s)", shortname(newdir, strlen(strerror())+4), strerror()); - ctm = time()+5; + error("%s : (%s)", shortname(newdir, strlen(strerror()) + 4), strerror()); + ctm = time() + 5; while (read_char(1) == -1 && ctm > time()) { refresh(); } @@ -1399,7 +1392,7 @@ searchbuffer(int dest) int hlen = strlen(home); if (hlen && (home == substr(file, 1, hlen))) { - file = "~"+substr(file, hlen + 1); /* strip home dir */ + file = "~"+substr(file, hlen + 1); // strip home dir } set_buffer(dest); insert(" File: " + file + " Pattern: " + _ff_pattern + "\n"); @@ -1447,8 +1440,7 @@ readline(string file) text_line = rtrim(read(flen)); beginning_of_line(); down(); - sprintf( text_line, " %5d,%3d %-" + flen + "s;%s\n", - line, col, text_line, file); + sprintf(text_line, " %5d,%3d %-" + flen + "S;%S\n", line, col, text_line, file); return(text_line); } diff --git a/macsrc/grief.h b/macsrc/grief.h index 717fd119..46b297df 100644 --- a/macsrc/grief.h +++ b/macsrc/grief.h @@ -97,8 +97,7 @@ #define TF_ENCODING 100 /* terminal character encoding */ #define TF_ENCODING_GUESS 101 /* text encoding guess specification */ -#define TF_UNICODE_VERSION 102 /* UNICODE version, 300 = 3.00 */ -#define TF_UNICODE_WIDTH 103 /* width table version */ +#define TF_UNICODE_VERSION 102 /* UNICODE version; eg. "6.0.0" */ /* * Terminal characters flags. diff --git a/macsrc/key.cr b/macsrc/key.cr index d7457f95..3f944293 100644 --- a/macsrc/key.cr +++ b/macsrc/key.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: key.cr,v 1.22 2014/10/27 23:28:23 ayoung Exp $ +/* $Id: key.cr,v 1.24 2021/07/11 10:59:08 cvsuser Exp $ * Key definition tools. * * @@ -146,22 +146,25 @@ key(void) void keyx() { - int seq = 6; + string description; + int seq = 7; while (--seq > 0) { - message("keyx (%d):", seq); + message("keyx (%d): %s", seq, description); int key = read_char(1000, -1); /* next event */ if (key >= 0) { if (IsMouse(key)) { int x, y; - get_mouse_pos(x, y); - message("keyx=%s (%d,%d)", int_to_key(key), x, y); + sprintf(description, "keyx=%s (%d,%d)", int_to_key(key), x, y); + } else { - message("keyx=" + int_to_key(key)); + sprintf(description, "keyx=" + int_to_key(key)); } - sleep(2); - seq = 4; + seq = 7; + + } else { + description = ""; } } message(""); @@ -421,7 +424,7 @@ static void _key_learn_print(list def, string prefix, int quote) { int defs = length_of_list(def); - int d, c; + int d, w; if (defs > 1) { /* list? */ insert(" ", 12 - strlen(prefix)); @@ -429,11 +432,11 @@ _key_learn_print(list def, string prefix, int quote) } if (def[0] == "") { /* arg1 */ - c = insert("NULL"); + w = insert("NULL"); } else if (quote) { - c = insertf("\"%s\"", def[0]); + w = insertf("\"%s\"", def[0]); } else { - c = insert(def[0]); + w = insert(def[0]); } for (d = 1; d < defs; d++) { /* arg2 ... x */ @@ -442,16 +445,16 @@ _key_learn_print(list def, string prefix, int quote) insert(" ", 12 - strlen(prefix)); insert(prefix ); } else { - c += insert(", "); - insert(" ", 16 - c); + w += insert(", "); + insert(" ", 16 - w); } if (def[d] == "") { - c = insert("NULL"); + w = insert("NULL"); } else if (quote) { - c = insertf("\"%s\"", def[d]); + w = insertf("\"%s\"", def[d]); } else { - c = insert(def[d]); + w = insert(def[d]); } } } diff --git a/macsrc/modes/cr.cr b/macsrc/modes/cr.cr index 17d22a45..7e1c3e75 100644 --- a/macsrc/modes/cr.cr +++ b/macsrc/modes/cr.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: cr.cr,v 1.14 2014/10/22 02:34:33 ayoung Exp $ +/* $Id: cr.cr,v 1.15 2021/07/05 15:01:29 cvsuser Exp $ * GRIEF/Crisp syntax definition mode. * * @@ -111,17 +111,17 @@ main(void) syntax_rule("%" + "\\[[^\\]]\\]", // regular expressions, character-set. "group=string:operator"); - // format specifications (includes c99). - syntax_rule("%" + "[-+ #0']?[0-9]*\\.[0-9]*[hlL]*[bdiuoxXDOUfeEgGcCsSpn]", + // format specifications (includes c99 and 'W' extensions). + syntax_rule("%" + "[-+ #0']?[0-9]*\\.[0-9]*[hlL]*[bdiuoxXDOUfeEgGcCsSWpn]", "group=string,quick:operator"); - syntax_rule("%" + "[-+ #0']?[0-9]*[hlL]*[bdiuoxXDOUfeEgGcCsSpn]", + syntax_rule("%" + "[-+ #0']?[0-9]*[hlL]*[bdiuoxXDOUfeEgGcCsSWpn]", "group=string,quick:operator"); - syntax_rule("%" + "[-+ #0']?[*]?\\.[*]?[hlL]*[bdiuoxXDOUfeEgGcCsSpn]", + syntax_rule("%" + "[-+ #0']?[*]?\\.[*]?[hlL]*[bdiuoxXDOUfeEgGcCsSWpn]", "group=string,quick:operator"); - syntax_rule("%" + "[-+ #0']?[*]?[hlL]*[bdiuoxXDOUfeEgGcCsSpn]", + syntax_rule("%" + "[-+ #0']?[*]?[hlL]*[bdiuoxXDOUfeEgGcCsSWpn]", "group=string,quick:operator"); syntax_rule("%" + "[^ \"]+", // non-standard character escapes. diff --git a/macsrc/nc.cr b/macsrc/nc.cr index f598bf99..b9a0da26 100644 --- a/macsrc/nc.cr +++ b/macsrc/nc.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: nc.cr,v 1.31 2018/10/01 21:05:01 cvsuser Exp $ +/* $Id: nc.cr,v 1.35 2021/07/11 08:26:12 cvsuser Exp $ * Norton Commander (NC) style directory services * * @@ -9,7 +9,7 @@ #include "dialog.h" /* dialog manager */ #if defined(DEBUG) -#define Debug(x) debug x; /* local debug diag's */ +#define Debug(x) debug x; /* local debug diag's */ #else #define Debug(x) #endif @@ -20,12 +20,12 @@ #define FORWARD_SLASH '/' #define BACKWARD_SLASH '\\' #define WILD "?*" -#define SMINCOLUMNS 62 /* screen width */ +#define SMINCOLUMNS 62 /* screen width */ #define SMAXCOLUMNS 90 #define SFILECOLUMNS (nc_fwidth) #define SINFOCOLUMNS 38 -#define TYPEPOS (ncwidth + 1) -#define NAMEPOS (ncwidth + 2) +#define TYPEPOS(__base) (__base + 1) +#define NAMEPOS(__base) (__base + 2) #if defined(MSDOS) #define MARKER "\xfe" @@ -128,14 +128,14 @@ main() syntax_rule("^[ =]\\*[^ ]+", "lsexecute"); syntax_rule("^[ =]\\@[^ ]+", "lssymlink"); syntax_rule("^[ =]\\|[^ ]+", "lspipe"); - syntax_rule("^[ =]\\![^ ]+", "lserror"); // broken link + syntax_rule("^[ =]\\![^ ]+", "lserror"); /* broken link */ syntax_rule("^[ =][-=S+][^ ]+", "lsspecial"); syntax_rule("^[ =][^-/~@|!*=$+][^ ]+", "lsnormal"); syntax_build(__COMPILETIME__); /* build keyboard definition */ keyboard_push(); - keyboard_typeables(); // keys 0...127 + keyboard_typeables(); /* keys 0...127 */ assign_to_key("", "::NcEnter"); assign_to_key("", "::NcSelBack"); @@ -226,6 +226,7 @@ nc(void) string cwd; /* saved directory */ int old_buffer, old_window; int dir_buffer; + int base; /* Initialise directory */ old_buffer = inq_buffer(); @@ -239,6 +240,7 @@ nc(void) getwd(NULL, cwd); /* current working dir */ set_buffer(dir_buffer); attach_syntax(SYNTAX); + set_buffer_type(NULL, BFTYP_UTF8); NcDirectory(cwd); create_window(nccols, ncrows + 4, nccols + ncwidth, 3, @@ -262,7 +264,8 @@ nc(void) top_of_buffer(); while (search_fwd("<\\c" + MARKER)) { nclinebuf = read(); - ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS)); + base = index(nclinebuf, '\t'); /* delimiter */ + ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS(base))); down(); message("Loading \"%s\" for editing...", ncfilebuf); @@ -589,7 +592,7 @@ static void NcDelete(void) { string answer; - int line; + int line, base; inq_position(line); raise_anchor(); @@ -616,9 +619,11 @@ NcDelete(void) beginning_of_line(); down(); - if (substr(nclinebuf, TYPEPOS, 1) == "D") { + base = index(nclinebuf, '\t'); /* delimiter */ + + if (substr(nclinebuf, TYPEPOS(base), 1) == "D") { /* directory */ - ncfilebuf = trim(substr(nclinebuf, NAMEPOS)); + ncfilebuf = trim(substr(nclinebuf, NAMEPOS(base))); if (ncfilebuf != "..") { error("%s", nclinebuf); message("Deleting Directory \"%s\"...", ncfilebuf); @@ -628,9 +633,9 @@ NcDelete(void) } } - } else if (substr(nclinebuf, TYPEPOS, 1) == "F") { + } else if (substr(nclinebuf, TYPEPOS(base), 1) == "F") { /* file */ - ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS)); + ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS(base))); message("Deleting \"%s\"...", ncfilebuf); if (remove(ncfilebuf) == -1) { error("Unable to delete \"%s\" : %d (%s) - Press any key", @@ -668,9 +673,11 @@ NcDelete(void) } if (upper(answer) == "Y") { - if (substr(nclinebuf, TYPEPOS, 1) == "D") { + base = index(nclinebuf, '\t'); /* delimiter */ + + if (substr(nclinebuf, TYPEPOS(base), 1) == "D") { /* directory */ - ncfilebuf = trim(substr(nclinebuf, NAMEPOS)); + ncfilebuf = trim(substr(nclinebuf, NAMEPOS(base))); if (ncfilebuf != "..") { message("Deleting Directory \"%s\"...", ncfilebuf); if (-1 == rmdir(ncfilebuf)) { @@ -679,9 +686,9 @@ NcDelete(void) } } - } else if (substr(nclinebuf, TYPEPOS, 1) == "F") { + } else if (substr(nclinebuf, TYPEPOS(base), 1) == "F") { /* file */ - ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS)); + ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS(base))); message("Deleting \"%s\"...", ncfilebuf); if (remove(ncfilebuf) == -1) { error("Unable to delete \"%s\" : %d (%s) - Press any key", @@ -708,7 +715,7 @@ NcDelete(void) static void NcEdit(void) { - int line; + int line, base; inq_position(line); nclinebuf = read(); @@ -719,8 +726,10 @@ NcEdit(void) ncfilebuf = MARKER; } else { + base = index(nclinebuf, '\t'); /* delimiter */ + /* directory */ - if (substr(nclinebuf, TYPEPOS, 1) == "D") { + if (substr(nclinebuf, TYPEPOS(base), 1) == "D") { error("Cannot edit directory, press any key..."); beep(); while(!inq_kbd_char()) @@ -730,8 +739,8 @@ NcEdit(void) return; /* file */ - } else if (substr(nclinebuf, TYPEPOS, 1) == "F") { - ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS)); + } else if (substr(nclinebuf, TYPEPOS(base), 1) == "F") { + ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS(base))); } } exit(); /* exit 'nc' */ @@ -918,8 +927,11 @@ NcMarkInv(void) static int NcMark(void) { + int base; + nclinebuf = read(); - if (substr(nclinebuf, TYPEPOS, 1) != "F") { + base = index(nclinebuf, '\t'); /* delimiter */ + if (substr(nclinebuf, TYPEPOS(base), 1) != "F") { return (-1); } delete_char(); @@ -942,6 +954,7 @@ static void NcMarkMultiple( int mark_typ ) { list result; + int base; result[0] =""; result = field_list((mark_typ == MARK_SELECT ? "Select" : @@ -963,11 +976,11 @@ NcMarkMultiple( int mark_typ ) while (line_no) { move_abs(line_no, 1); nclinebuf = read(); - ncfilebuf = trim(substr(nclinebuf, NAMEPOS)); + base = index(nclinebuf, '\t'); /* delimiter */ - if (substr(nclinebuf, TYPEPOS, 1) == "F" && + if (substr(nclinebuf, TYPEPOS(base), 1) == "F" && re_search(NULL, pat, ncfilebuf) > 0) { - message(".. %s", ncfilebuf); + message(".. %s", trim(substr(nclinebuf, NAMEPOS(base)))); delete_char(); switch (mark_typ) { @@ -1002,9 +1015,13 @@ NcMarkMultiple( int mark_typ ) static void NcEnter(void) { + int base; + nclinebuf = read(); - if (substr(nclinebuf, TYPEPOS, 1) == "D") { /* Directory selection */ - ncfilebuf = trim(substr(nclinebuf, NAMEPOS)); + base = index(nclinebuf, '\t'); /* delimiter */ + + if (substr(nclinebuf, TYPEPOS(base), 1) == "D") { /* Directory selection */ + ncfilebuf = trim(substr(nclinebuf, NAMEPOS(base))); if (ncfilebuf == "..") { NcCd(DIR_UP); @@ -1012,8 +1029,8 @@ NcEnter(void) NcCd(DIR_DOWN + ncfilebuf); } /* File selection */ - } else if (substr(nclinebuf, TYPEPOS, 1) == "F") { - ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS)); + } else if (substr(nclinebuf, TYPEPOS(base), 1) == "F") { + ncfilebuf = "./" + trim(substr(nclinebuf, NAMEPOS(base))); exit(); } } @@ -1105,13 +1122,14 @@ NcDirectory(string cwd) while (find_file(name, bytes, mtime, NULL, mode)) { if (S_IFDIR & mode) { /* - * Directories + * Directories */ if ((ncsortorder != "Unsorted" && 2 == pass) || name == "." ) { /* skip on 2nd sort pass */ continue; /* or if '.' directory */ } - sprintf(buffer, " /%-*.*s| |", ncfwidth, ncfwidth, name); + + sprintf(buffer, " /%-*.*W| |", ncfwidth, ncfwidth, name); } else { /* @@ -1131,7 +1149,7 @@ NcDirectory(string cwd) sprintf(size, "%dG", bytes/1024); } - sprintf(buffer, " %s%-*.*s|%7s|", + sprintf(buffer, " %s%-*.*W|%7s|", substr(mode_string(mode, cwd+"/"+name, TRUE), 1, 1), ncfwidth, ncfwidth, name, size); } @@ -1145,11 +1163,10 @@ NcDirectory(string cwd) } insert(buffer); - move_abs(0, TYPEPOS); /* encode type details */ - if (mode & S_IFDIR) { - insert("D" + name + "\n"); + if (mode & S_IFDIR) { /* */ + insert(" \tD" + name + "\n"); } else { - insert("F" + name + "\n"); + insert(" \tF" + name + "\n"); } ++nclineno; } diff --git a/macsrc/nlang.cr b/macsrc/nlang.cr index 09bdba6d..c11e6714 100644 --- a/macsrc/nlang.cr +++ b/macsrc/nlang.cr @@ -1,7 +1,6 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: nlang.cr,v 1.4 2014/10/22 02:34:21 ayoung Exp $ +/* $Id: nlang.cr,v 1.5 2021/07/11 08:26:12 cvsuser Exp $ * Macro to allow insertion of national language chars - * XXX - needs work * * */ @@ -10,44 +9,44 @@ static list greek = { - "\xe0", /* alpha - a */ - "\xe1" /* beta - b */ + 0xe0, /* alpha - a */ + 0xe1 /* beta - b */ }; static list graves = { - "\x85", /* A */ - "\x85", /* a */ - "\x8a", /* e */ - "\x95", /* o */ - "\x97" /* u */ + 0x85, /* A */ + 0x85, /* a */ + 0x8a, /* e */ + 0x95, /* o */ + 0x97 /* u */ }; static list acutes = { - "\xa0", /* A */ - "\xa0", /* a */ - "\x82", /* e */ - "\xa2", /* o */ - "\xa3" /* u */ + 0xa0, /* A */ + 0xa0, /* a */ + 0x82, /* e */ + 0xa2, /* o */ + 0xa3 /* u */ }; static list circs = { - "\x83", /* A */ - "\x83", /* a */ - "\x88", /* e */ - "\x93", /* o */ - "\x96" /* u */ + 0x83, /* A */ + 0x83, /* a */ + 0x88, /* e */ + 0x93, /* o */ + 0x96 /* u */ }; static list umlauts = { - "\x8e", /* A */ - "\x84", /* a */ - "\x88", /* e */ - "\x94", /* o */ - "\x81" /* u */ + 0x8e, /* A */ + 0x84, /* a */ + 0x88, /* e */ + 0x94, /* o */ + 0x81 /* u */ }; @@ -58,24 +57,68 @@ static list umlauts = void nlang() /*MCHAR???*/ { - string letters = "Aaeou"; + string letters = "Aaeou", ch; int accent, letter, i; - string ch; - message("Type '[%s] [acgu]' or 'g[letter]' (Greek).", letters); + message("Type '[%s] [acgu]', 'g[letter]' (Greek) or x[hexchar].", letters); - /* Read in two characters and allow to abort selection. */ + /* Read mode selection charcater */ while ((letter = read_char()) == -1) ; + if (letter == key_to_int("")) { + message("esc"); + return; + } + + if (letter == 'x') { + int hexval = 0, value; + int done = 0; + + while (1) { + message("hexval=0x%x", hexval); + while ((letter = read_char()) == -1) + ; + if (letter == key_to_int("")) { + message("esc"); + return; + } + + if (letter == key_to_int("")) { + done = 1; + break; + } + + sprintf(ch, "%c", letter); + if (!isxdigit(letter) || + 1 != sscanf(ch, "%x", value)) { + break; + } + + hexval <<= 4; + hexval += value; + if (hexval > 0x10ffff) { + done = 1; + break; + } + } - if (letter == key_to_int("")) + if (done) { + message("hexval=0x%x, done", hexval); + insert(hexval); + return; + } + + error("nlang - invalid hexval"); return; + } + /* Accent selection */ while ((accent = read_char()) == -1) ; - - if (accent == key_to_int("")) + if (accent == key_to_int("")) { + message("esc"); return; + } /* Handle Greek alphabet. */ if (letter == 'g') { @@ -92,32 +135,33 @@ nlang() /*MCHAR???*/ /* o" and c" are open and close double angle brackets (<< and >>) */ if (letter == 'o' && accent == '"') { - insert("\xae"); + insert(0xae); message(""); return; } else if (letter == 'c' && accent == '"') { - insert("\xaf"); + insert(0xaf); message(""); return; } else if (letter == 'c' && accent == 'c') { /* Handle C-cedilla. */ - insert("\x87"); + insert(0x87); message(""); return; } else if (letter == 'n' && accent == 'n') { /* Handle Spanish n with a twiddle on top. */ - insert("\xa4"); + insert(0xa4); message(""); return; } sprintf(ch, "%c", letter); - i = index(letters, ch) - 1; - if (i < 0) + if ((i = index(letters, ch) - 1) < 0) { + error("nlang - unknown character sequence."); return; + } switch (accent) { case key_to_int("a"): @@ -132,12 +176,12 @@ nlang() /*MCHAR???*/ case key_to_int("u"): insert(umlauts[i]); break; - default: { - error("Unknown character sequence."); - return; - } + default: + error("nlang - unknown character sequence."); + return; } message(""); } /*end*/ + diff --git a/macsrc/select.cr b/macsrc/select.cr index 9f935a31..3a7dbb6e 100644 --- a/macsrc/select.cr +++ b/macsrc/select.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: select.cr,v 1.41 2014/10/27 23:28:27 ayoung Exp $ +/* $Id: select.cr,v 1.44 2021/07/05 15:01:29 cvsuser Exp $ * Selection macros implementing buffer based popup user interface. * * @@ -135,7 +135,7 @@ buffer_list(~ int shortmode, ~ int sysbuffers) listbuf = create_buffer("Buffer List", NULL, 1); homedir = inq_home(); - homelen = strlen(homedir); + homelen = wstrlen(homedir); /* dynamic sizing */ #define MINWIN 74 /* below this, window is truncated */ @@ -165,7 +165,7 @@ buffer_list(~ int shortmode, ~ int sysbuffers) int t_len; inq_names(NULL, NULL, buf_name); - if ((t_len = strlen(buf_name)) > len) { + if ((t_len = wcwidth(buf_name)) > len) { len = t_len; } } @@ -199,7 +199,7 @@ buffer_list(~ int shortmode, ~ int sysbuffers) inq_names(file_name, NULL, buf_name); /* buffer name */ - if ((len = strlen(buf_name)) > buflen) { + if ((len = wcwidth(buf_name)) > buflen) { /* .. shorten name */ buf_name = buf_shortname(buf_name, len, buflen); @@ -212,17 +212,17 @@ buffer_list(~ int shortmode, ~ int sysbuffers) /* format file name */ if (homelen && /* .. strip home */ - (homedir == substr(file_name, 1, homelen))) { - t_file_name = "~" + substr(file_name, homelen + 1); + (homedir == wsubstr(file_name, 1, homelen))) { + t_file_name = "~" + wsubstr(file_name, homelen + 1); } else { t_file_name = file_name; } - if ((len = strlen(t_file_name)) > pathlen) { + if ((len = wcwidth(t_file_name)) > pathlen) { /* - * truncate image - */ + * truncate image + */ int plen, flen; /* .. determine path length */ if (0 == (plen = rindex(t_file_name, "/"))) { @@ -235,12 +235,12 @@ buffer_list(~ int shortmode, ~ int sysbuffers) } t_file_name = /* .. shorten name to 'flen' */ - substr(t_file_name, 1, plen) + - buf_shortname(substr(t_file_name, plen+1), len-plen, flen); + wsubstr(t_file_name, 1, plen) + + buf_shortname(wsubstr(t_file_name, plen + 1), len - plen, flen); - if ((len = strlen(t_file_name)) > pathlen) { + if ((len = wcwidth(t_file_name)) > pathlen) { t_file_name = /* .. shorten path */ - ".." + substr(t_file_name, len - (pathlen-3)); + ".." + wsubstr(t_file_name, len - (pathlen - 3)); } } @@ -249,7 +249,8 @@ buffer_list(~ int shortmode, ~ int sysbuffers) * within the global 'flaglen' parameter. */ if (shortmode) { - sprintf(line, "%s %s%s", buf_name, t_file_name, inq_modified() ? "*" : ""); + if (inq_modified()) t_file_name += "*"; + sprintf(line, "%s %-*S", buf_name, pathlen + 10, t_file_name); } else { inq_position(position); @@ -288,12 +289,12 @@ buffer_list(~ int shortmode, ~ int sysbuffers) } if (sysbuffers) { /* sys mode, include buffer identifier */ - sprintf(line, "%s (%3d) %s %5d %s %s %s", - buf_name, inq_buffer(), lines, position, modes, encoding, t_file_name); + sprintf(line, "%S (%3d) %s %5d %s %s %-*S", + buf_name, inq_buffer(), lines, position, modes, encoding, pathlen + 10, t_file_name); } else { /* normal mode */ - sprintf(line, "%s %s %5d %s %s %s", - buf_name, lines, position, modes, encoding, t_file_name); + sprintf(line, "%S %s %5d %s %s %-*S", + buf_name, lines, position, modes, encoding, pathlen + 10, t_file_name); } } @@ -303,9 +304,8 @@ buffer_list(~ int shortmode, ~ int sysbuffers) insert(nl); nl = "\n"; insert(line); - /* insert fullname for Alt-D */ - move_abs(0, buflen + flaglen + pathlen + 10); - insert(DELIMIT); + + insert(DELIMIT); /* insert fullname for Alt-D */ insert(file_name); ++buf_no; @@ -333,6 +333,7 @@ buffer_list(~ int shortmode, ~ int sysbuffers) set_ctrl_state(WCTRLO_VERT_SCROLL, WCTRLS_SHOW, win); set_buffer(listbuf); + set_buffer_type(NULL, BFTYP_UTF8); sort_buffer(); set_buffer(curbuf); retval = select_buffer(listbuf, win, SEL_NORMAL, "buf_keys", NULL, "Buffer List"); @@ -372,7 +373,7 @@ buf_shortname(string name, int len, int maxlen) if (len < maxlen) { return name; } - return substr(name, 1, i) + "~" + substr(name, len - (maxlen - (i+2))); + return wsubstr(name, 1, i) + "~" + wsubstr(name, len - (maxlen - (i+2))); } @@ -562,9 +563,12 @@ selfile_list(string path, string wild_card, string title, int dirs, int multi) int ret; curbuf = inq_buffer(); - min_width = strlen(path) + 6; + if ((min_width = strlen(path) + 6) < 28) { + min_width = 28; + } buf = create_buffer(title != "" ? title : path, NULL, 1); set_buffer(buf); + set_buffer_type(NULL, BFTYP_UTF8); if (wild_card == "" || wild_card == "*" || substr(wild_card, strlen(wild_card) - 1, 1) == "/") { @@ -586,9 +590,9 @@ selfile_list(string path, string wild_card, string title, int dirs, int multi) continue; // ignore, only directories } if (multi) { - sprintf(tmpbuf, " %s%s", name, (mode & S_IFDIR) ? "/" : ""); + sprintf(tmpbuf, " %S%s", name, (mode & S_IFDIR) ? "/" : ""); } else { - sprintf(tmpbuf, "%s%s", name, (mode & S_IFDIR) ? "/" : ""); + sprintf(tmpbuf, "%S%s", name, (mode & S_IFDIR) ? "/" : ""); } if (0 == (S_IFDIR & mode)) { // inserts files etc insert(tmpbuf + "\n"); @@ -826,6 +830,7 @@ select_list(string title, string message_string, int step, old_buffer = inq_buffer(); buffer = create_buffer(title, NULL, 1); set_buffer(buffer); + set_buffer_type(NULL, BFTYP_UTF8); width = strlen(title) + 4; len = length_of_list(items); diff --git a/macsrc/tty/xterm.cr b/macsrc/tty/xterm.cr index e8e9b59d..38019ab7 100644 --- a/macsrc/tty/xterm.cr +++ b/macsrc/tty/xterm.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; tabs: 8; -*- - * $Id: xterm.cr,v 1.20 2014/10/22 02:34:43 ayoung Exp $ + * $Id: xterm.cr,v 1.22 2021/07/11 08:26:12 cvsuser Exp $ * terminal description file for the xterm window under X11, an VT-100 like emulator. * * @@ -265,7 +265,7 @@ main() if (-2 == datype) { if (daversion > 0 && daversion < 166) { - set_term_feature(TF_UNICODE_WIDTH, 300); + set_term_feature(TF_UNICODE_VERSION, "3.0.0"); } xterm_locale(); } @@ -401,7 +401,7 @@ main() BACK_TAB, "\x1b[Z", /* rxvt and others */ BACK_TAB, "\x1b\t", /* alt-form, older VT100.Trans */ - BACKSPACE, "\x7f", + KEY_BACKSPACE, "\x7f", /* VT100.Trans */ ALT_MINUS, "\xad", diff --git a/macsrc/tty/xterm_linux.cr b/macsrc/tty/xterm_linux.cr index 69e0223d..438bc86b 100644 --- a/macsrc/tty/xterm_linux.cr +++ b/macsrc/tty/xterm_linux.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: xterm_linux.cr,v 1.22 2014/10/22 02:34:43 ayoung Exp $ +/* $Id: xterm_linux.cr,v 1.23 2021/07/11 08:26:12 cvsuser Exp $ * terminal description file for the xterm window under X11/Linux. * * @@ -130,7 +130,7 @@ main() KEYPAD_STAR, "\x1bOj", /* Keypad-* */ KEYPAD_MINUS, "\x1bOm", /* Keypad-- */ KEYPAD_PLUS, "\x1bOk", /* Keypad-+ */ - ENTER, "\x1bOM", /* Keypad-enter */ + KEYPAD_ENTER, "\x1bOM", /* Keypad-enter */ SHIFT_KEYPAD_2, "\x1bO2B", /* down */ SHIFT_KEYPAD_4, "\x1bO2D", /* left */ diff --git a/macsrc/tty/xterm_mintty.cr b/macsrc/tty/xterm_mintty.cr index ae43bdd0..71116776 100644 --- a/macsrc/tty/xterm_mintty.cr +++ b/macsrc/tty/xterm_mintty.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: xterm_mintty.cr,v 1.4 2014/10/22 02:34:43 ayoung Exp $ +/* $Id: xterm_mintty.cr,v 1.5 2021/07/11 08:26:12 cvsuser Exp $ * Mintty terminal profile. * * @@ -112,7 +112,7 @@ main() // Miscellous keys // BACK_TAB, "\x1b[Z", - BACKSPACE, "\x7f" + KEY_BACKSPACE, "\x7f" ); } diff --git a/macsrc/tty/xterm_mrxvt.cr b/macsrc/tty/xterm_mrxvt.cr index e0669792..0d43c7de 100644 --- a/macsrc/tty/xterm_mrxvt.cr +++ b/macsrc/tty/xterm_mrxvt.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: xterm_mrxvt.cr,v 1.3 2014/10/22 02:34:43 ayoung Exp $ +/* $Id: xterm_mrxvt.cr,v 1.4 2021/07/11 08:26:12 cvsuser Exp $ * mrxvt terminal * * The mrxvt program is a terminal emulator for X Window System. It provides DEC VT102 @@ -170,7 +170,7 @@ main() BACK_TAB, "\x1b[Z", /* Shift-Tab, may require Xdefault resource about */ BACK_TAB, "\x1b\t", /* Alt-Tab */ - BACKSPACE, "\x7f" + KEY_BACKSPACE, "\x7f" ); xterm_altmeta_keys(); diff --git a/macsrc/tty/xterm_rxvt.cr b/macsrc/tty/xterm_rxvt.cr index 31f5f9c0..4c9eec0d 100644 --- a/macsrc/tty/xterm_rxvt.cr +++ b/macsrc/tty/xterm_rxvt.cr @@ -1,5 +1,5 @@ /* -*- mode: cr; indent-width: 4; -*- */ -/* $Id: xterm_rxvt.cr,v 1.9 2014/10/22 02:34:43 ayoung Exp $ +/* $Id: xterm_rxvt.cr,v 1.10 2021/07/11 08:26:12 cvsuser Exp $ * rxvt is a very popular xterm replacement. @@ -245,7 +245,7 @@ main() BACK_TAB, "\x1b[Z", /* Shift-Tab */ BACK_TAB, "\x1b\t", /* Alt-Tab */ - BACKSPACE, "\x7f" + KEY_BACKSPACE, "\x7f" ); xterm_altmeta_keys(); diff --git a/makeconfig.pm b/makeconfig.pm index 877929c4..644b7a6c 100644 --- a/makeconfig.pm +++ b/makeconfig.pm @@ -1,4 +1,4 @@ -# $Id: makeconfig.pm,v 1.2 2020/06/20 22:38:28 cvsuser Exp $ +# $Id: makeconfig.pm,v 1.3 2022/03/22 08:02:55 cvsuser Exp $ # Makefile generation under Win32. # -*- perl; tabs: 8; indent-width: 4; -*- # Automake emulation for non-unix environments. @@ -7,14 +7,21 @@ # Copyright (c) 2020, Adam Young. # All rights reserved. # -# This file is part of the Midnight Commander. +# This file is part of GRIEF # -# The Midnight Commander is free software: you can redistribute it +# The applications are free software: you can redistribute it # and/or modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation, either version 3 of the License, -# or (at your option) any later version. +# published by the Free Software Foundation, version 3. # -# The Midnight Commander is distributed in the hope that it will be useful, +# Redistributions of source code must retain the above copyright +# notice, and must be distributed with the license document above. +# +# Redistributions in binary form must reproduce the above copyright +# notice, and must include the license document above in +# the documentation and/or other materials provided with the +# distribution. +# +# The applications are distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. @@ -35,7 +42,13 @@ my $x_tokens = undef; my $o_verbose = undef; our $PACKAGE = undef; -our $PACKAGE_NAME = undef; +our $PACKAGE_NAME = ''; +our $PACKAGE_VERSION = ''; + +our $PACKAGE_BUGREPORT = ''; +our $PACKAGE_TARNAME = ''; +our $PACKAGE_URL = ''; + our $PACKAGE_PATH = undef; our $PACKAGE_H = undef; # defunct, use PACKAGE_FILE our $PACKAGE_FILE = 'package.h'; @@ -275,8 +288,8 @@ sub __ExportConfigurations { } } - $self->{PACKAGE} = $PACKAGE; - $self->{PACKAGE_NAME} = $PACKAGE_NAME if ($PACKAGE_NAME); + $self->{PACKAGE} = $PACKAGE if (defined $PACKAGE); + $self->{PACKAGE_NAME} = $PACKAGE_NAME; $self->{PACKAGE_PATH} = $PACKAGE_PATH if ($PACKAGE_PATH); $self->{PACKAGE_H} = $PACKAGE_H if ($PACKAGE_H); $self->{PACKAGE_FILE} = $PACKAGE_FILE if ($PACKAGE_FILE); @@ -289,6 +302,12 @@ sub __ExportConfigurations { $self->{LIBRARIES2} = \@LIBRARIES2; $self->{OPTLIBRARIES} = \@OPTLIBRARIES; + $$x_tokens{PACKAGE_VERSION} = $PACKAGE_VERSION; + $$x_tokens{PACKAGE_STRING} = $PACKAGE_NAME . ' ' . $PACKAGE_VERSION; + $$x_tokens{PACKAGE_URL} = $ PACKAGE_URL; + $$x_tokens{PACKAGE_BUGREPORT} = $PACKAGE_BUGREPORT; + $$x_tokens{PACKAGE_TARNAME} = $PACKAGE_TARNAME; + $$x_tokens{CC} = $CC; $$x_tokens{CXX} = $CXX; $$x_tokens{RTLIBRARY} = $RTLIBRARY; diff --git a/makelib.in b/makelib.in index 9fc8ded8..21f87691 100644 --- a/makelib.in +++ b/makelib.in @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $Id: makelib.in,v 1.6 2020/06/18 20:35:15 cvsuser Exp $ +# $Id: makelib.in,v 1.8 2021/07/05 17:18:41 cvsuser Exp $ # -*- mode: perl; tabs: 8; indent-width: 4; -*- # makelib configuration # @@ -36,6 +36,7 @@ $PACKAGE_FILE = 'edpackage.h'; 'vfs', 'charudet', 'chartable', + 'widechar', 'teken', 'duktape', # duktape embeddable JavaScript engine. 'duktape_static', @@ -97,6 +98,7 @@ $PACKAGE_FILE = 'edpackage.h'; 'libduktape', 'libvfs', 'libchartable', + 'libwidechar', 'libcharudet', 'libteken', 'libonigrx', diff --git a/makelib.pl b/makelib.pl index 2bf60f3c..4c7a14da 100644 --- a/makelib.pl +++ b/makelib.pl @@ -1,17 +1,18 @@ #!/usr/bin/perl -# $Id: makelib.pl,v 1.113 2021/04/10 09:51:56 cvsuser Exp $ +# $Id: makelib.pl,v 1.123 2022/03/22 08:07:31 cvsuser Exp $ # Makefile generation under WIN32 (MSVC/WATCOMC/MINGW) and DJGPP. -# -*- tabs: 8; indent-width: 4; -*- +# -*- perl; tabs: 8; indent-width: 4; -*- # Automake emulation for non-unix environments. # # -# Copyright (c) 1998 - 2021, Adam Young. +# Copyright (c) 1998 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. # -# The GRIEF Editor is free software: you can redistribute it -# and/or modify it under the terms of the GRIEF Editor License. +# The applications are free software: you can redistribute it +# and/or modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, version 3. # # Redistributions of source code must retain the above copyright # notice, and must be distributed with the license document above. @@ -21,10 +22,10 @@ # the documentation and/or other materials provided with the # distribution. # -# The GRIEF Editor is distributed in the hope that it will be useful, +# The applications are distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# License for more details. +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. # ==end== # @@ -53,6 +54,7 @@ BEGIN my $CWD = getcwd(); my $BINPATH = ''; my $PERLPATH = ''; +my $MFCDIR = undef; my $BUSYBOX = undef; my $WGET = undef; my $INNO = undef; @@ -151,8 +153,8 @@ BEGIN LDMAPFILE => '-MAP:$(MAPFILE)', MFCDIR => '', - MFCCFLAGS => '-nologo -RTC1 @RTLIBRARY@', - MFCCXXFLAGS => '-nologo -RTC1 @RTLIBRARY@ -EHsc', + MFCCFLAGS => '-nologo @RTLIBRARY@', + MFCCXXFLAGS => '-nologo @RTLIBRARY@ -EHsc', MFCCOPT => '-Zc:wchar_t- -Zc:forScope -Gm', MFCCXXOPT => '-Zc:wchar_t- -Zc:forScope -Gm', MFCCINCLUDE => '', @@ -211,9 +213,11 @@ BEGIN # -Fm: if positioned before /link # -MAP: if positioned afer /link + # 7600.16385.1: Windows Driver Kit Version 7.1.0 + # ==> http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=11800 MFCDIR => '/tools/WinDDK/7600.16385.1', - MFCCFLAGS => '-nologo -RTC1 @RTLIBRARY@', - MFCCXXFLAGS => '-nologo -RTC1 @RTLIBRARY@ -EHsc', + MFCCFLAGS => '-nologo @RTLIBRARY@', + MFCCXXFLAGS => '-nologo @RTLIBRARY@ -EHsc', MFCCOPT => '-Zc:wchar_t- -Zc:forScope -Gm', MFCCXXOPT => '-Zc:wchar_t- -Zc:forScope -Gm', MFCCINCLUDE => '-I$(MFCDIR)/inc/atl71 -I$(MFCDIR)/inc/mfc42', @@ -245,6 +249,16 @@ BEGIN LDMAPFILE => '-MAP:$(MAPFILE)', # -Fm: if positioned before /link # -MAP: if positioned afer /link + + # 7600.16385.1: Windows Driver Kit Version 7.1.0 + # ==> http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=11800 + MFCDIR => '/tools/WinDDK/7600.16385.1', + MFCCFLAGS => '-nologo @RTLIBRARY@', + MFCCXXFLAGS => '-nologo @RTLIBRARY@ -EHsc', + MFCCOPT => '-Zc:wchar_t- -Zc:forScope -Gm', + MFCCXXOPT => '-Zc:wchar_t- -Zc:forScope -Gm', + MFCCINCLUDE => '-I$(MFCDIR)/inc/atl71 -I$(MFCDIR)/inc/mfc42', + MFCLIBS => '/LIBPATH:$(MFCDIR)\lib\atl\i386 /LIBPATH:$(MFCDIR)\lib\mfc\i386' }, 'vc1900' => { # 2015, Visual Studio 19 @@ -273,6 +287,16 @@ BEGIN LDMAPFILE => '-MAP:$(MAPFILE)', # -Fm: if positioned before /link # -MAP: if positioned afer /link + + # 7600.16385.1: Windows Driver Kit Version 7.1.0 + # ==> http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=11800 + MFCDIR => '/tools/WinDDK/7600.16385.1', + MFCCFLAGS => '-nologo @RTLIBRARY@', + MFCCXXFLAGS => '-nologo @RTLIBRARY@ -EHsc', + MFCCOPT => '-Zc:wchar_t- -Zc:forScope -Gm', + MFCCXXOPT => '-Zc:wchar_t- -Zc:forScope -Gm', + MFCCINCLUDE => '-I$(MFCDIR)/inc/atl71 -I$(MFCDIR)/inc/mfc42', + MFCLIBS => '/LIBPATH:$(MFCDIR)\lib\atl\i386 /LIBPATH:$(MFCDIR)\lib\mfc\i386' }, # See: VsDevCmd.bat @@ -313,13 +337,15 @@ BEGIN # -Fm: if positioned before /link # -MAP: if positioned afer /link - # MFCDIR => '/tools/WinDDK/7600.16385.1', - # MFCCFLAGS => '-nologo -RTC1 @RTLIBRARY@', - # MFCCXXFLAGS => '-nologo -RTC1 @RTLIBRARY@ -EHsc', - # MFCCOPT => '-Zc:wchar_t- -Zc:forScope -Gm', - # MFCCXXOPT => '-Zc:wchar_t- -Zc:forScope -Gm', - # MFCCINCLUDE => '-I$(MFCDIR)/inc/atl71 -I$(MFCDIR)/inc/mfc42', - # MFCLIBS => '/LIBPATH:$(MFCDIR)\lib\atl\i386 /LIBPATH:$(MFCDIR)\lib\mfc\i386' + MFCDIR => '', + MFCCFLAGS => '-nologo @RTLIBRARY@', + MFCCXXFLAGS => '-nologo @RTLIBRARY@ -EHsc', + MFCCOPT => '-Zc:wchar_t- -Zc:forScope', + MFCCXXOPT => '-Zc:wchar_t- -Zc:forScope', + # MFCCINCLUDE => '-I$(MFCDIR)/inc/atl71 -I$(MFCDIR)/inc/mfc42', + # MFCLIBS => '/LIBPATH:$(MFCDIR)\lib\atl\i386 /LIBPATH:$(MFCDIR)\lib\mfc\i386' + MFCCINCLUDE => '', + MFCLIBS => '' }, 'vc1920' => { # 2019, Visual Studio 19.2x @@ -348,6 +374,54 @@ BEGIN LDMAPFILE => '-MAP:$(MAPFILE)', # -Fm: if positioned before /link # -MAP: if positioned afer /link + + MFCDIR => '', + MFCCFLAGS => '-nologo @RTLIBRARY@', + MFCCXXFLAGS => '-nologo @RTLIBRARY@ -EHsc', + MFCCOPT => '-Zc:wchar_t- -Zc:forScope', + MFCCXXOPT => '-Zc:wchar_t- -Zc:forScope', + # MFCCINCLUDE => '-I$(MFCDIR)/inc/atl71 -I$(MFCDIR)/inc/mfc42', + # MFCLIBS => '/LIBPATH:$(MFCDIR)\lib\atl\i386 /LIBPATH:$(MFCDIR)\lib\mfc\i386' + MFCCINCLUDE => '', + MFCLIBS => '' + }, + + 'vc1930' => { # 2022, Visual Studio 19.3x + TOOLCHAIN => 'vs170', + TOOLCHAINEXT => '.vs170', + CC => 'cl', + COMPILERPATHS => '%VS170COMNTOOLS%/../../VC/bin|%VCToolsInstallDir%/bin/Hostx86/x86', + COMPILERPATH => '', + VSWITCH => '', + VPATTERN => undef, + OSWITCH => '-Fo', + LSWITCH => '', + XSWITCH => '-Fe', + AR => 'lib', + CINCLUDE => '', + RTLIBRARY => '-MDd', + CFLAGS => '-nologo @RTLIBRARY@ -fp:precise', + CXXFLAGS => '-nologo @RTLIBRARY@ -EHsc -fp:precise', + CDEBUG => '-Zi -RTC1 -Od', + CRELEASE => '-O2 -GL -Gy -DNDEBUG', + CWARN => '-W3', + CXXWARN => '-W3', + LDFLAGS => '-nologo @RTLIBRARY@', + LDDEBUG => '-Zi -RTC1', + LDRELEASE => '-GL', + LDMAPFILE => '-MAP:$(MAPFILE)', + # -Fm: if positioned before /link + # -MAP: if positioned afer /link + + MFCDIR => '', + MFCCFLAGS => '-nologo @RTLIBRARY@', + MFCCXXFLAGS => '-nologo @RTLIBRARY@ -EHsc', + MFCCOPT => '-Zc:wchar_t- -Zc:forScope', + MFCCXXOPT => '-Zc:wchar_t- -Zc:forScope', + # MFCCINCLUDE => '-I$(MFCDIR)/inc/atl71 -I$(MFCDIR)/inc/mfc42', + # MFCLIBS => '/LIBPATH:$(MFCDIR)\lib\atl\i386 /LIBPATH:$(MFCDIR)\lib\mfc\i386' + MFCCINCLUDE => '', + MFCLIBS => '' }, 'wc1300' => { # Watcom 11 @@ -439,9 +513,13 @@ BEGIN LDRELEASE => '', LDMAPFILE => '-fm=$(MAPFILE)', + # 7600.16385.1: Windows Driver Kit Version 7.1.0 + # ==> http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=11800 MFCDIR => '/tools/WinDDK/7600.16385.1', - MFCCOPT => '-q -j -ei -6r -d2 -hw -db -ofr -zlf -bt=nt -bm -br -aa', - MFCCXXOPT => '-q -j -ei -6r -d2i -db -ofr -zlf -bt=nt -bm -br -xs -xr -cc++', + MFCCFLAGS => '-q -j -ei -6r -d2 -hw -db -ofr -zlf -bt=nt -bm -br -aa', + MFCCXXFLAGS => '-q -j -ei -6r -d2i -db -ofr -zlf -bt=nt -bm -br -xs -xr -cc++', + MFCCOPT => '', + MFCCXXOPT => '', MFCCINCLUDE => '-I$(MFCDIR)/inc/atl71 -I$(MFCDIR)/inc/mfc42', MFCLIBS => '/LIBPATH:$(MFCDIR)\lib\atl\i386 /LIBPATH:$(MFCDIR)\lib\mfc\i386' }, @@ -777,6 +855,7 @@ BEGIN 'stdarg.h', 'stdlib.h', 'stdio.h', + 'stddef.h', 'limits.h', 'inttypes.h', # c99 'stdint.h', # c99 @@ -787,6 +866,7 @@ BEGIN 'pthread.h', # MINGW 'string.h', 'strings.h', 'errno.h', + 'locale.h', # setlocale() 'wchar.h', 'wctype.h', 'time.h', # TIME_WITH_SYS_TIME 'alloca.h', # alloca() @@ -800,7 +880,6 @@ BEGIN 'memory.h', 'process.h', 'libgen.h', # basename(), dirname() - 'limits.h', 'share.h', 'signal.h', 'utime.h', @@ -858,6 +937,8 @@ BEGIN 'uintmax_t', 'intptr_t', 'uintptr_t', + 'ptrdiff_t', + 'long double', 'long long int', 'unsigned long long int', 'int8_t', @@ -931,7 +1012,10 @@ BEGIN 'snprintf', '_snprintf', 'vsnprintf', '_vsnprintf', 'strrchr', 'strdup', 'asnprintf', 'vasnprintf', + 'setlocale', 'mbrtowc', 'wcrtomb', 'wcscmp', 'wcscpy', 'wcslen', 'wctomb', 'wmemcmp', 'wmemmove', 'wmemcpy', + 'wcwidth', + '_tzset', # msvc 'fgetpos', 'fsetpos', 'fseeko', 'fgetln', # bsd/linux extensions 'truncate', 'ftruncate', @@ -968,7 +1052,7 @@ BEGIN HAVE_EIGHTBIT => '1' ); -my %CONFIG_H = ( # predefined config.h values +our %CONFIG_H = ( # predefined config.h values IS_LITTLE_ENDIAN => '1', # TODO STDC_HEADERS => '1', HAVE_EIGHTBIT => '1', @@ -990,7 +1074,8 @@ BEGIN my @EXTRALIBS = (); my @DLLS = (); -my $x_tmpdir = '.makelib'; +my $x_workdir = '.makelib'; +my $x_tmpdir = undef; my $x_compiler = ''; my $x_version = ''; my @x_include = (); @@ -999,8 +1084,8 @@ BEGIN my $o_makelib = './makelib.in'; my $o_keep = 0; -my $o_version = undef; my $o_verbose = 0; +my $o_version = undef; my $o_gnuwin32 = 'auto'; my $o_contrib = 1; my $o_gnulibs = 0; @@ -1019,6 +1104,7 @@ BEGIN sub ExeRealpath($); sub LoadContrib($$$$$); sub CheckCompiler($$); +sub CheckHeader($$); sub CheckDecl($$); sub CheckType($$); sub CheckSize($$); @@ -1050,6 +1136,7 @@ BEGIN 'bison=s' => \$BISON, 'flex=s' => \$FLEX, 'busybox=s' => \$BUSYBOX, + 'mfcdir=s' => \$MFCDIR, 'wget=s' => \$WGET, 'inno=s' => \$INNO, 'version=i' => \$o_version, @@ -1078,20 +1165,16 @@ BEGIN (-f $o_makelib) or Usage("missing makelib.in"); - # see: https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B + # See: https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B # # MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008 version 9.0) # MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010 version 10.0) # MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012 version 11.0) # MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013 version 12.0) # MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015 version 14.0) - # MSVC++ 14.1 _MSC_VER == 1910 (Visual Studio 2017 version 15.0) - # MSVC++ 14.11 _MSC_VER == 1911 (Visual Studio 2017 version 15.3) - # MSVC++ 14.12 _MSC_VER == 1912 (Visual Studio 2017 version 15.5) - # MSVC++ 14.13 _MSC_VER == 1913 (Visual Studio 2017 version 15.6) - # MSVC++ 14.14 _MSC_VER == 1914 (Visual Studio 2017 version 15.7) - # MSVC++ 14.16 _MSC_VER == 1916 (Visual Studio 2017 version 15.9) - # MSVC++ 14.20 _MSC_VER == 1920 (Visual Studio 2019 version 15.7) + # MSVC++ 14.1x _MSC_VER == 1910 (Visual Studio 2017 version 15.x) + # MSVC++ 14.2x _MSC_VER == 192x (Visual Studio 2019 version 16.x) + # MSVC++ 14.3x _MSC_VER == 193x (Visual Studio 2022 version 17.x) # if ('vc12' eq $cmd) { $o_version = 1200, $cmd = 'vc' } elsif ('vc14' eq $cmd) { $o_version = 1400; $cmd = 'vc' } elsif ('vc2005' eq $cmd) { $o_version = 1400; $cmd = 'vc' } @@ -1101,6 +1184,7 @@ BEGIN elsif ('vc19' eq $cmd) { $o_version = 1900; $cmd = 'vc' } elsif ('vc2015' eq $cmd) { $o_version = 1900; $cmd = 'vc' } elsif ('vc1910' eq $cmd) { $o_version = 1910; $cmd = 'vc' } elsif ('vc2017' eq $cmd) { $o_version = 1910; $cmd = 'vc' } elsif ('vc1920' eq $cmd) { $o_version = 1920; $cmd = 'vc' } elsif ('vc2019' eq $cmd) { $o_version = 1920; $cmd = 'vc' } + elsif ('vc1930' eq $cmd) { $o_version = 1930; $cmd = 'vc' } elsif ('vc2022' eq $cmd) { $o_version = 1930; $cmd = 'vc' } elsif ('owc19' eq $cmd) { $o_version = 1900; $cmd = 'owc' } elsif ('owc20' eq $cmd) { $o_version = 2000; $cmd = 'owc' } @@ -1115,7 +1199,7 @@ BEGIN $cmd eq 'owc' || $cmd eq 'wc' || $cmd eq 'dj' || $cmd eq 'mingw') { - my $cache = "${x_tmpdir}/${cmd}${o_version}.cache"; + my $cache = "${x_workdir}/${cmd}${o_version}.cache"; if (! $o_clean && -f $cache) { eval { @@ -1139,9 +1223,9 @@ BEGIN $Data::Dumper::Purity = 1; $Data::Dumper::Sortkeys = 1; print CACHE Data::Dumper->Dump([\%x_tokens], [qw(*XXTOKENS)]); - print CACHE Data::Dumper->Dump([\%CONFIG_H], [qw(*XXCONFIG_H)]); print CACHE Data::Dumper->Dump([\@HEADERS], [qw(*XXHEADERS)]); print CACHE Data::Dumper->Dump([\@EXTHEADERS], [qw(*XXEXTHEADERS)]); + print CACHE Data::Dumper->Dump([\%CONFIG_H], [qw(*CONFIG_H)]); print CACHE Data::Dumper->Dump([\%DECLS], [qw(*DECLS)]); print CACHE Data::Dumper->Dump([\%TYPES], [qw(*TYPES)]); print CACHE Data::Dumper->Dump([\%SIZES], [qw(*SIZES)]); @@ -1341,10 +1425,19 @@ BEGIN foreach my $entry (keys %$env) { # target profile $x_tokens{$entry} = $$env{$entry}; } + if ($MFCDIR) { #override + print "MFCDIR: ${MFCDIR}\n"; + $x_tokens{MFCDIR} = $MFCDIR; + } MakelibConfigure($type, $env); # toolchain dynamic configuration + (-d $x_workdir || mkdir($x_workdir)) or + die "makelib: unable to access/create workdir <$x_workdir> : $!\n"; + + $x_tmpdir = "${x_workdir}/${type}${version}"; + (-d $x_tmpdir || mkdir($x_tmpdir)) or die "makelib: unable to access/create tmpdir <$x_tmpdir> : $!\n"; @@ -1391,35 +1484,54 @@ BEGIN print "Scanning: @INCLUDE\n" if ($o_verbose); + + my $headerdefines = ""; my $idx = -1; foreach my $header (@x_headers, @x_headers2) { my $headers2 = (++$idx >= scalar @x_headers); - my $fullpath = undef; + my $fullpath = ""; + my $include = ""; + my $check = -1; + + my $name = $header; + $name =~ s/[\/.]/_/g; + $name = "HAVE_".uc($name); # HAVE_XXXX_H - print "header: ${header} ..."; - print " " x (28 - length($header)); - foreach my $include (@INCLUDE) { + my $cached = (exists $CONFIG_H{$name}); + + # present check + print "header: ${header} present ..."; + print " " x (28 - (length($header)+8)); + foreach $include (@INCLUDE) { $fullpath = "${include}/${header}"; $fullpath =~ s/\\/\//g; - if (-f $fullpath) { - print "[${fullpath}]"; + last if (-f $fullpath); + $fullpath = ""; + } + print "[".($fullpath ? "yes" : "no")."] <$fullpath>\n"; - if ($headers2) { # headers2 - push @EXTHEADERS, $header; - } else { - push @HEADERS, $header; - push @EXTHEADERS, $header - if ($include ne $x_libw32); - } - $header =~ s/[\/.]/_/g; - $header = uc($header); - $CONFIG_H{"HAVE_${header}"} = '1'; - last; + # usability check + print "header: ${header} usability ... "; + print " " x (28 - (length($header)+11)); + if ($headers2) { + $check = ($fullpath ? 0 : -1); # found? + } else { + $check = ($cached ? 0 : CheckHeader($header, $headerdefines)); # build check + } + print "[".(0 == $check ? "yes" : "no").($cached?", cached":"")."]\n"; + + if (0 == $check) { + if ($headers2) { # headers2 + push @EXTHEADERS, $header; + } else { + push @HEADERS, $header; + push @EXTHEADERS, $header + if ($include ne $x_libw32); } - $fullpath = undef; + + $CONFIG_H{$name} = '1'; + $headerdefines .= "#define ${name} 1\n"; } - print "[not found]" if (! defined $fullpath); - print "\n"; } # decls @@ -2017,7 +2129,7 @@ BEGIN die "cannot create ${x_tmpdir}/$SOURCE : $!\n"; print TMP<${x_tmpdir}/$SOURCE") or + die "cannot create ${x_tmpdir}/$SOURCE : $!\n"; + print TMP< +int main(int argc, char **argv) { + return 0; +} +EOT + close TMP; + + return CheckExec($BASE, $cmd, 1); +} + + # Function: CheckType # Determine whether the stated 'type' exists. # @@ -2536,9 +2686,8 @@ BEGIN my $ret = System($cmd); if (! -f "${base}.exe") { my $out = "${base}.out"; - - printf " ::<%s>\n", $out; if ($o_verbose && -f $out) { + printf " ::<%s>\n", $out; open(OUT, "<${out}") or die "cannot open ${out}"; while (defined (my $line = )) { @@ -2887,8 +3036,12 @@ BEGIN die "cannot create $dir/$file"; if ($file eq 'Makefile') { print MAKEFILE "# Generated by makelib.pl, $asctime\n"; - } elsif ($file =~ /.h$/) { - print MAKEFILE "/* Generated by makelib.pl, $asctime */\n"; + } else { + if (! ($file =~ s/\@configure_input\@/Generated by makelib.pl, $asctime/)) { + if ($file =~ /.h$/) { + print MAKEFILE "/* Generated by makelib.pl, $asctime */\n"; + } + } } if ($file eq 'Makefile') { # compact whitespace diff --git a/support/owc20config.bat b/support/owc20config.bat new file mode 100644 index 00000000..ebe9fae0 --- /dev/null +++ b/support/owc20config.bat @@ -0,0 +1,12 @@ +@echo off +rem +rem Open Watcom C/C++ 1.9 +rem +if not defined GNUWIN32 ( + set GNUWIN32=\devl\gnuwin32 +) +if not defined PERL ( + set PERL=perl +) +%PERL% makelib.pl --gnuwin32=%GNUWIN32% %1 %2 %3 %4 owc20 + diff --git a/support/vc2015config.bat b/support/vc2015config.bat index a69d8787..c2604a1b 100644 --- a/support/vc2015config.bat +++ b/support/vc2015config.bat @@ -1,6 +1,6 @@ @echo off rem -rem Microsoft Visual Studio C/C++ 2013+ +rem Microsoft Visual Studio C/C++ 2015+ rem if not defined GNUWIN32 ( set GNUWIN32=\devl\gnuwin32 diff --git a/support/vc2019config.bat b/support/vc2019config.bat index 27892b40..3b6796e4 100644 --- a/support/vc2019config.bat +++ b/support/vc2019config.bat @@ -1,6 +1,6 @@ @echo off rem -rem Microsoft Visual Studio C/C++ 2013+ +rem Microsoft Visual Studio C/C++ 2019+ rem if not defined GNUWIN32 ( set GNUWIN32=\devl\gnuwin32 diff --git a/support/vc2022config.bat b/support/vc2022config.bat new file mode 100644 index 00000000..317d132b --- /dev/null +++ b/support/vc2022config.bat @@ -0,0 +1,12 @@ +@echo off +rem +rem Microsoft Visual Studio C/C++ 2022+ +rem +if not defined GNUWIN32 ( + set GNUWIN32=\devl\gnuwin32 +) +if not defined PERL ( + set PERL=perl +) +%PERL% makelib.pl --gnuwin32=%GNUWIN32% --icu=auto vc2022 %1 %2 %3 %4 + diff --git a/support/wdgr.bat b/support/wdgr.bat index de373f8a..24506578 100644 --- a/support/wdgr.bat +++ b/support/wdgr.bat @@ -1,2 +1,2 @@ @echo off -wd bin\gr.exe --nosigtrap %1 %2 %3 %4 %5 %6 %7 %8 %9 +wd ..\bin.owc19\debug\gr.exe -DGRPATH=..\macros -DGRHELP=..help --nosigtrap %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/util/.cvsignore b/util/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/util/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/util/Makefile.in b/util/Makefile.in index c41290ee..08358f89 100644 --- a/util/Makefile.in +++ b/util/Makefile.in @@ -1,9 +1,9 @@ # -*- mode: mak; -*- -# $Id: Makefile.in,v 1.10 2020/06/20 02:13:52 cvsuser Exp $ +# $Id: Makefile.in,v 1.12 2022/03/22 08:25:35 cvsuser Exp $ # GRIEF utilities makefile. # # -# Copyright (c) 1998 - 2020, Adam Young. +# Copyright (c) 1998 - 2022, Adam Young. # All rights reserved. # # This file is part of the GRIEF Editor. @@ -110,12 +110,16 @@ GRWCOBJS= $(D_OBJ)/grwc$(O) \ $(D_OBJ)/fmt_scaled$(O) \ $(D_OBJ)/err$(O) +GRKEYTEST= $(D_BIN)/grkeytest$(E) +GRKEYTESTOBJS= $(D_OBJ)/grkeytest$(O) + TARGETS= $(GRTAGS) \ - $(GRWC) + $(GRWC) \ + $(GRKEYTEST) OBJS= $(GRTAGSOBJS) \ - $(GRWCOBJS) - + $(GRWCOBJS) \ + $(GRKEYTESTOBJS) ######################################################################################### # Rules @@ -128,14 +132,18 @@ release: debug: $(MAKE) BUILD_TYPE=debug $(filter-out debug, $(MAKECMDGOALS)) -$(GRTAGS): LINKLIBS=-lmisc +$(GRTAGS): LINKLIBS=-lmisc -lllist $(GRTAGS): $(D_OBJ)/.created $(GRTAGSOBJS) $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(GRTAGSOBJS) $(LDLIBS) -$(GRWC): LINKLIBS=-lmisc +$(GRWC): LINKLIBS=-lmisc -lllist $(GRWC): $(D_OBJ)/.created $(GRWCOBJS) $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(GRWCOBJS) $(LDLIBS) +$(GRKEYTEST): LINKLIBS=-lmisc -lllist +$(GRKEYTEST): $(D_OBJ)/.created $(GRKEYTESTOBJS) + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(GRKEYTESTOBJS) $(LDLIBS) + $(D_OBJ)/.created: -@mkdir $(D_OBJ) @echo "do not delete" > $@ diff --git a/util/grkeytest.c b/util/grkeytest.c new file mode 100644 index 00000000..ffe72cb9 --- /dev/null +++ b/util/grkeytest.c @@ -0,0 +1,22 @@ +/* + * console key-test + */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#if defined(_WIN32) +#include "w32keytest.c" + +#else +#include + +int +main(void) +{ + printf("not implemented\n"); + return 3; +} + +#endif diff --git a/util/w32keytest.c b/util/w32keytest.c new file mode 100644 index 00000000..22cc8c4a --- /dev/null +++ b/util/w32keytest.c @@ -0,0 +1,741 @@ +/* + * win32 console key-test + */ + +#define _WIN32_WINNT 0x0601 +#include +#include +#include + +#define ALT_PRESSED (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED) +#define CTRL_PRESSED (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED) +#define APP_PRESSED 0x0200 /* APPS enabled, extension */ + +#if defined(__WATCOMC__) +#if !defined(_countof) +#define _countof(array) (sizeof(array) / sizeof(array[0])) +#endif +#endif + +#define CTRLSTATUSMASK (LEFT_ALT_PRESSED|LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED|RIGHT_CTRL_PRESSED|SHIFT_PRESSED|APP_PRESSED) + +static const struct w32key { + WORD wVirtualKeyCode; /* windows virtual key code */ + +#define VKMOD_ANY (0x10000000) +#define VKMOD_META (0x20000000) +#define VKMOD_CTRL (0x30000000) +#define VKMOD_SHIFT (0x40000000) +#define VKMOD_NONSHIFT (0x50000000) +#define VKMOD_ENHANCED (0x60000000) +#define VKMOD_NOTENHANCED (0x70000000) + + DWORD modifiers; /* modifiers */ + const wchar_t * desc; /* description */ + +} w32Keys[] = { + // Only reportsd as an up event, down redirected to event handler. +// { VK_CANCEL, MOD_CTRL, L"Ctrl-Break" }, + + { VK_BACK, 0, L"Back" }, + { VK_TAB, 0, L"Tab" }, + { VK_BACK, VKMOD_SHIFT, L"Back" }, + { VK_TAB, VKMOD_SHIFT, L"Tab" }, + { VK_BACK, VKMOD_CTRL, L"Back" }, + { VK_TAB, VKMOD_CTRL, L"Tab" }, + { VK_BACK, VKMOD_META, L"Back" }, + { VK_TAB, VKMOD_META, L"Tab" }, + { VK_ESCAPE, VKMOD_ANY, L"Esc" }, + { VK_RETURN, VKMOD_ANY, L"Return" }, + { VK_RETURN, VKMOD_ENHANCED, L"Keypad-Return" }, + { VK_PAUSE, VKMOD_ANY, L"Keypad-Pause" }, + { VK_PRIOR, VKMOD_ANY, L"PgUp" }, + { VK_NEXT, VKMOD_ANY, L"PgDn" }, + { VK_END, VKMOD_ANY, L"End" }, + { VK_HOME, VKMOD_ANY, L"Home" }, + { VK_LEFT, VKMOD_ANY, L"Left" }, + { VK_UP, VKMOD_ANY, L"Up" }, + { VK_RIGHT, VKMOD_ANY, L"Right" }, + { VK_DOWN, VKMOD_ANY, L"Down" }, + { VK_INSERT, VKMOD_ANY, L"Ins" }, + { VK_DELETE, VKMOD_ANY, L"Delete" }, + + { VK_HELP, VKMOD_ANY, L"Help" }, + { VK_ICO_HELP, VKMOD_ANY, L"Help" }, + + { VK_PRIOR, VKMOD_NOTENHANCED, L"Keypad-PgUp" }, + { VK_NEXT, VKMOD_NOTENHANCED, L"Keypad-PgDn" }, + { VK_END, VKMOD_NOTENHANCED, L"Keypad-End" }, + { VK_HOME, VKMOD_NOTENHANCED, L"Keypad-Home" }, + { VK_LEFT, VKMOD_NOTENHANCED, L"Keypad-Left" }, + { VK_CLEAR, VKMOD_NOTENHANCED, L"Keypad-5" }, + { VK_UP, VKMOD_NOTENHANCED, L"Keypad-Up" }, + { VK_RIGHT, VKMOD_NOTENHANCED, L"Keypad-Right" }, + { VK_DOWN, VKMOD_NOTENHANCED, L"Keypad-Down" }, + { VK_INSERT, VKMOD_NOTENHANCED, L"Keypad-Ins" }, + { VK_DELETE, VKMOD_NOTENHANCED, L"Keypad-Delete" }, + { VK_HELP, VKMOD_NOTENHANCED, L"Keypad-Help" }, + { VK_SUBTRACT, VKMOD_ANY, L"Keypad-Minus" }, + { VK_MULTIPLY, VKMOD_ANY, L"Keypad-Star" }, + { VK_ADD, VKMOD_ANY, L"Keypad-Plus" }, + { VK_DIVIDE, VKMOD_ANY, L"Keypad-Divide" }, + + /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ + /* VK_A - VK_Z are the same as ASCII 'A'- 'Z' (0x41 - 0x5A) */ + + { 0x30, VKMOD_CTRL, L"0" }, + { 0x31, VKMOD_CTRL, L"1" }, + { 0x32, VKMOD_CTRL, L"2" }, + { 0x33, VKMOD_CTRL, L"3" }, + { 0x34, VKMOD_CTRL, L"4" }, + { 0x35, VKMOD_CTRL, L"5" }, + { 0x36, VKMOD_CTRL, L"6" }, + { 0x37, VKMOD_CTRL, L"7" }, + { 0x38, VKMOD_CTRL, L"8" }, + { 0x39, VKMOD_CTRL, L"9" }, + + { VK_F1, VKMOD_ANY, L"F1" }, + { VK_F2, VKMOD_ANY, L"F2" }, + { VK_F3, VKMOD_ANY, L"F3" }, + { VK_F4, VKMOD_ANY, L"F4" }, + { VK_F5, VKMOD_ANY, L"F5" }, + { VK_F6, VKMOD_ANY, L"F6" }, + { VK_F7, VKMOD_ANY, L"F7" }, + { VK_F8, VKMOD_ANY, L"F8" }, + { VK_F9, VKMOD_ANY, L"F9" }, + { VK_F10, VKMOD_ANY, L"F10" }, + { VK_F11, VKMOD_ANY, L"F11" }, + { VK_F12, VKMOD_ANY, L"F12" }, + { VK_F13, VKMOD_ANY, L"F13" }, + { VK_F14, VKMOD_ANY, L"F14" }, + { VK_F15, VKMOD_ANY, L"F15" }, + { VK_F16, VKMOD_ANY, L"F16" }, + { VK_F17, VKMOD_ANY, L"F17" }, + { VK_F18, VKMOD_ANY, L"F18" }, + { VK_F19, VKMOD_ANY, L"F19" }, + { VK_F20, VKMOD_ANY, L"F20" }, + + { VK_NUMLOCK, VKMOD_ANY, L"Keypad-Numlock" }, + { VK_SCROLL, VKMOD_ANY, L"Keypad-Scroll" }, + + { VK_OEM_PLUS, VKMOD_NONSHIFT, L"+" }, + { VK_OEM_COMMA, VKMOD_NONSHIFT, L"," }, + { VK_OEM_MINUS, VKMOD_NONSHIFT, L"-" }, + { VK_OEM_PERIOD, VKMOD_NONSHIFT, L"." }, + { VK_OEM_3, VKMOD_NONSHIFT, L"~" }, + }; + +#define ISHEX(_uc) \ + ((_uc >= '0' && _uc <= '9') || (_uc >= 'a' && _uc <= 'f') || (_uc >= 'A' && _uc <= 'F') ? 1 : 0) + +static void Usage(const struct argparms *args); +static void Process(HANDLE in); +static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType); +static int AltPlusEvent(const KEY_EVENT_RECORD *ke, int offset); +static int AltPlusEnabled(void); +static const wchar_t *key_description(const KEY_EVENT_RECORD *ker); +static const wchar_t *control_state(DWORD dwControlKeyState); +static const wchar_t *virtual_description(WORD wVirtualKeyCode); + +static int xf_altcode = -1; /* 1=enable,0=disable,-1=auto */ +static int xf_mouse = 1; + + +int +main(void) +{ + HANDLE in = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode = 0; + + GetConsoleMode(in, &mode); + if (xf_mouse) { /* mouse enabled */ + if (! SetConsoleMode(in, ENABLE_EXTENDED_FLAGS|\ + ENABLE_WINDOW_INPUT|ENABLE_MOUSE_INPUT/*|ENABLE_PROCESSED_INPUT*/)) { + // Note: Stating ENABLE_EXTENDED_FLAGS disables ENABLE_INSERT_MODE and/or ENABLE_QUICK_EDIT_MODE. + // required for correct mouse operation; restored within sys_shutdown(). + SetConsoleMode(in, ENABLE_WINDOW_INPUT|ENABLE_MOUSE_INPUT/*|ENABLE_PROCESSED_INPUT*/); + // No extended support/XP. + } + } else { + SetConsoleMode(in, ENABLE_WINDOW_INPUT/*|ENABLE_PROCESSED_INPUT*/); + } + + // The ENABLE_LINE_INPUT and ENABLE_ECHO_INPUT modes only affect processes that use ReadFile or ReadConsole + // to read from the console's input buffer. Similarly, the ENABLE_PROCESSED_INPUT mode primarily affects + // ReadFile and ReadConsole users, except that it also determines whether CTRL+C input is reported in the + // input buffer (to be read by the ReadConsoleInput function) or is passed to a function defined by + // the application. + SetConsoleCtrlHandler(CtrlHandler, TRUE); + + Process(in); + SetConsoleMode(in, mode); + + return 0; +} + + +static void +Process(HANDLE in) +{ + int alt_state = 0, esc_state = 0, event_count = 0; + DWORD apps_control = 0; + int offset = 0; + +#define COLUMN1 100 + + printf("\nConsole input test, ESC+ESC to quit."); + if (xf_altcode < 0) { + if (0 == xf_altcode || + (xf_altcode < 0 && ! AltPlusEnabled())) { + wprintf(L"\nAlt-Plus-KeyCode not enabled"); + xf_altcode = 0; + } else { + wprintf(L"\nAlt-Plus-KeyCode enabled"); + xf_altcode = 1; + } + } + + printf("\n\n# UC Chr Dir Rpt VK SC State\n"); + fflush(stdout); + // nnnn U+uuuu c 1111 111 111111111111 1111 1111 xxxxxxxxxxxxxxx + + for (;;) { + INPUT_RECORD ir[1] = {0}; + DWORD i, cEventsRead = 0; + + if (! ReadConsoleInputW(in, ir, 1, &cEventsRead)) { + puts("ReadConsoleInput failed!"); + return; + } + + for (i = 0; i < cEventsRead; ++i, ++event_count) { + if (ir[i].EventType & KEY_EVENT) { + const KEY_EVENT_RECORD *ker = &ir[i].Event.KeyEvent; + + // Special filters + + alt_state = AltPlusEvent(ker, offset); + if (ker->bKeyDown) { + if (VK_APPS == ker->wVirtualKeyCode) { + apps_control = APP_PRESSED; + } + } else { + if (VK_APPS == ker->wVirtualKeyCode) { + apps_control = 0; + } + } + + // Key details + + wprintf(L"\n"); + offset = wprintf(L"%4d: U+%04x %c %s %03u %04x %-12s %04x %08x %s = %d", + event_count, (WORD) ker->uChar.UnicodeChar, + (ker->uChar.UnicodeChar > 32 ? ker->uChar.UnicodeChar : ' '), + (ker->bKeyDown ? L"down" : L" up "), ker->wRepeatCount, + ker->wVirtualKeyCode, virtual_description(ker->wVirtualKeyCode), ker->wVirtualScanCode, + ker->dwControlKeyState, control_state(ker->dwControlKeyState|apps_control), + alt_state); + + if (ker->bKeyDown) { + if (alt_state <= 0) { // "Alt +" inactive + KEY_EVENT_RECORD t_ker = *ker; + const wchar_t *kd; + + t_ker.dwControlKeyState |= apps_control; + if (NULL != (kd = key_description(&t_ker))) { + wprintf(L"%*s<%s>", COLUMN1 - offset, L"", kd); + offset = COLUMN1; + } + } + + if (0 == (CTRLSTATUSMASK & ker->dwControlKeyState) && + 0x1b == ker->uChar.UnicodeChar) { + if (++esc_state >= 2) { // Escape + puts("\nbye..."); + return; + } + } else { + esc_state = 0; + } + } + } + } + } +} + + +static BOOL WINAPI +CtrlHandler(DWORD fdwCtrlType) +{ + switch (fdwCtrlType) { + case CTRL_C_EVENT: // Ctrl-C signal. + printf("\nCtrl-C event\n"); + return TRUE; + case CTRL_BREAK_EVENT: // Ctrl-Break signal. + printf("\nCtrl-Break event\n"); + return TRUE; + case CTRL_CLOSE_EVENT: // Ctrl-Close: confirm that the user wants to exit. + printf("\nCtrl-Close event\n"); + Beep(600, 200); + return TRUE; + case CTRL_LOGOFF_EVENT: + printf("\nCtrl-Logoff event\n"); + Beep(1000, 200); + return FALSE; + case CTRL_SHUTDOWN_EVENT: + printf("\nCtrl-Shutdown event\n"); + Beep(750, 500); + return FALSE; + default: + return FALSE; + } +} + + +// Alt+ event handler +// +// Alt+KeyCode works and behaves well when character only input is required, by simply +// reporting any down or up key events which populate the 'UnicodeChar' value. Whereas +// when extended keystroke handling is required, for example arrow and numpad keys, +// additional effort is needed. +// +// Alt+Keycodes are only reported within the 'UnicodeChar' value of up event on a "ALT" key +// post the valid entry of one-or-more hex characters. During KeyCode entry the API unfortunately +// does not publiciy indicate this state plus continues to return the associated virtual keys, +// including the leading 'keypad-plus' and any associated key-code elements, wherefore we need +// to filter. Furthermore, if during the key-code entry an invalid non-hex key combination is +// given, the key-code is invalidated and UnicodeChar=0 is returned on the ALT release. +// +// Notes: +// o Requires the registry REG_SZ value "EnableHexNumpad" under +// "HKEY_Current_User/Control Panel/Input Method" to be "1". +// +// o Hex-value overflow goes unreported, limiting input to a 16-bit result. +// +static int +AltPlusEvent(const KEY_EVENT_RECORD *ke, int offset) +{ +#define ISXDIGIT(_uc) \ + ((_uc >= '0' && _uc <= '9') || (_uc >= 'a' && _uc <= 'f') || (_uc >= 'A' && _uc <= 'F') ? 1 : 0) + + static int alt_code = 0; + static DWORD alt_control = 0; + wchar_t completion[64]; + + if (! xf_altcode) return -1; // enabled? + + completion[0] = 0; + if (ke->bKeyDown) { // down event + const unsigned controlKeyState = (CTRLSTATUSMASK & ke->dwControlKeyState); + + if (VK_ADD == ke->wVirtualKeyCode && + (LEFT_ALT_PRESSED == controlKeyState || RIGHT_ALT_PRESSED == controlKeyState)) { + // "Alt + ..." event + alt_control = controlKeyState; + if (alt_code == 0) { + alt_code = 1; + } + return 1; // consume + + } else if (alt_code) { + if (alt_control != controlKeyState || + (ke->uChar.UnicodeChar && 0 == ISXDIGIT(ke->uChar.UnicodeChar))) { + // new control status or non-hex, emit "Alt-Plus" and reset state + swprintf(completion, _countof(completion), L"Alt-Plus"); + alt_code = 0; + + } else { + ++alt_code; // associated key count + return alt_code; // consume + } + } + + } else if (alt_code) { // up event + if (VK_MENU == ke->wVirtualKeyCode && + (0 == (ke->dwControlKeyState & ALT_PRESSED))) { + // Alt completion + const int oalt_code = alt_code; + + alt_code = 0; + if (1 == oalt_code && 0 == ke->uChar.UnicodeChar) { + // "Alt-Plus" only, emit + swprintf(completion, _countof(completion), L"Alt-Plus"); + + } else if (ke->uChar.UnicodeChar) { + // "Alt-Plus keycode", return keycode. + swprintf(completion, _countof(completion), L"Alt-Plus-#%d", ke->uChar.UnicodeChar); + } + } + } + + if (completion[0]) { // completion + wprintf(L"%*s<%s>", COLUMN1 - offset, L"", completion); + return 0; + } + + return -1; // unhandled +} + + +static int +AltPlusEnabled(void) +{ + HKEY hKey = 0; + int enabled = 0; + + if (RegOpenKeyExA(HKEY_CURRENT_USER, + "Control Panel\\Input Method", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + char szEnableHexNumpad[100] = { 0 }; + DWORD dwSize = _countof(szEnableHexNumpad); + if (RegQueryValueExA(hKey, "EnableHexNumpad", NULL, NULL, (LPBYTE) szEnableHexNumpad, &dwSize) == ERROR_SUCCESS) { + if (szEnableHexNumpad[0] == '1') { + enabled = 1; + } + } + RegCloseKey(hKey); + } + return enabled; +} + + +static const wchar_t * +key_description(const KEY_EVENT_RECORD *ker) +{ + static wchar_t t_buffer[200]; + wchar_t *cursor = t_buffer, *end = cursor + _countof(t_buffer); + + const DWORD dwControlKeyState = ker->dwControlKeyState; + const WORD wVirtualKeyCode = ker->wVirtualKeyCode; + const struct w32key *key = w32Keys + _countof(w32Keys); + + // Virtual key mapping + while (--key >= w32Keys) { + if (key->wVirtualKeyCode == wVirtualKeyCode) { + const DWORD modifiers = key->modifiers; + if (VKMOD_ANY == modifiers) { + break; + } else if (VKMOD_SHIFT == modifiers) { + if (0 != (dwControlKeyState & SHIFT_PRESSED)) { + break; + } + } else if (VKMOD_NONSHIFT == modifiers) { + if (0 == (dwControlKeyState & SHIFT_PRESSED)) { + break; + } + } else if (VKMOD_ENHANCED == modifiers) { + if (0 != (dwControlKeyState & ENHANCED_KEY)) { + break; + } + } else if (VKMOD_NOTENHANCED == modifiers) { + if (0 == (dwControlKeyState & ENHANCED_KEY)) { + break; + } + } else if (0 == modifiers || (dwControlKeyState & modifiers)) { + break; + } + } + } + if (key < w32Keys) { + if (0 == ker->uChar.UnicodeChar) { + return NULL; + } + key = NULL; + } + + // Control states + if (dwControlKeyState & ALT_PRESSED) + cursor += swprintf(cursor, end - cursor, L"Alt-"); + + if (dwControlKeyState & APP_PRESSED) + cursor += swprintf(cursor, end - cursor, L"App-"); + + if (dwControlKeyState & CTRL_PRESSED) + cursor += swprintf(cursor, end - cursor, L"Ctrl-"); + + if (dwControlKeyState & SHIFT_PRESSED) + cursor += swprintf(cursor, end - cursor, L"Shift-"); + + // Key code + if (key) { + cursor += swprintf(cursor, end - cursor, L"%s", key->desc); + + } else if (ker->uChar.UnicodeChar) { + const WORD uc = ker->uChar.UnicodeChar; + const wchar_t *desc = NULL; + + switch (uc) { + case '\b': desc = L"Backspace"; break; + case '\r': desc = L"Enter"; break; + case '\t': desc = L"Tab"; break; + case 0x1b: desc = L"Esc"; break; + case ' ': + if (dwControlKeyState & CTRLSTATUSMASK) { + desc = L"Space"; + } + break; + } + + if (desc) { + cursor += swprintf(cursor, end - cursor, desc); + } else { + if (uc > ' ' && uc < 0xff) { // ASCII + if ((dwControlKeyState & CTRLSTATUSMASK) && uc >= 'a' && uc <= 'z') { + *cursor++ = uc - 'a' + 'A'; // upper-case meta controls. + } else { + *cursor++ = uc; + } + *cursor++ = 0; + + } else if (uc < ' ' && (dwControlKeyState & CTRL_PRESSED)) { + *cursor++ = ('A' - 1) + uc; // controls + *cursor++ = 0; + + } else { // Unicode + cursor += swprintf(cursor, end - cursor, L"#%u", uc); + } + } + } + + return (cursor > t_buffer ? t_buffer : NULL); +} + + +static const wchar_t * +control_state(DWORD dwControlKeyState) +{ + static wchar_t t_buffer[200]; + wchar_t *cursor = t_buffer; + + t_buffer[0] = 0; + if (dwControlKeyState & CAPSLOCK_ON) wcscpy(cursor, L"CapLk,"), cursor += wcslen(cursor); + if (dwControlKeyState & ENHANCED_KEY) wcscpy(cursor, L"Enhanced,"), cursor += wcslen(cursor); + if (dwControlKeyState & LEFT_ALT_PRESSED) wcscpy(cursor, L"LeftAlt,"), cursor += wcslen(cursor); + if (dwControlKeyState & LEFT_CTRL_PRESSED) wcscpy(cursor, L"LeftCtl,"), cursor += wcslen(cursor); + if (dwControlKeyState & NUMLOCK_ON) wcscpy(cursor, L"NumLck,"), cursor += wcslen(cursor); + if (dwControlKeyState & RIGHT_ALT_PRESSED) wcscpy(cursor, L"RightAlt,"), cursor += wcslen(cursor); + if (dwControlKeyState & RIGHT_CTRL_PRESSED) wcscpy(cursor, L"RightCtl,"), cursor += wcslen(cursor); + if (dwControlKeyState & SCROLLLOCK_ON) wcscpy(cursor, L"ScrLk,"), cursor += wcslen(cursor); + if (dwControlKeyState & SHIFT_PRESSED) wcscpy(cursor, L"Shift,"), cursor += wcslen(cursor); + if (dwControlKeyState & APP_PRESSED) wcscpy(cursor, L"App,"), cursor += wcslen(cursor); + + if (cursor > t_buffer) cursor[-1] = 0; + return t_buffer; +} + + +static const wchar_t * +virtual_description(WORD wVirtualKeyCode) +{ + switch(wVirtualKeyCode) { + case VK_LBUTTON : /*0x01*/ return L"LBUTTON"; + case VK_RBUTTON : /*0x02*/ return L"RBUTTON"; + case VK_CANCEL : /*0x03*/ return L"CANCEL"; + case VK_MBUTTON : /*0x04*/ return L"MBUTTON"; + + case VK_XBUTTON1 : /*0x05*/ return L"XBUTTON1"; + case VK_XBUTTON2 : /*0x06*/ return L"XBUTTON2"; + + case VK_BACK : /*0x08*/ return L"BACK"; + case VK_TAB : /*0x09*/ return L"TAB"; + + case VK_CLEAR : /*0x0C*/ return L"CLEAR"; + case VK_RETURN : /*0x0D*/ return L"RETURN"; + + case VK_SHIFT : /*0x10*/ return L"SHIFT"; + case VK_CONTROL : /*0x11*/ return L"CONTROL"; + case VK_MENU : /*0x12*/ return L"MENU"; + case VK_PAUSE : /*0x13*/ return L"PAUSE"; + case VK_CAPITAL : /*0x14*/ return L"CAPITAL"; + + case VK_KANA : /*0x15*/ return L"KANA"; +// case VK_HANGEUL : /*0x15*/ return L"HANGEUL"; +// case VK_HANGUL : /*0x15*/ return L"HANGUL"; + case VK_JUNJA : /*0x17*/ return L"JUNJA"; + case VK_FINAL : /*0x18*/ return L"FINAL"; + case VK_HANJA : /*0x19*/ return L"HANJA"; +// case VK_KANJI : /*0x19*/ return L"KANJI"; + + case VK_ESCAPE : /*0x1B*/ return L"ESCAPE"; + + case VK_CONVERT : /*0x1C*/ return L"CONVERT"; + case VK_NONCONVERT : /*0x1D*/ return L"NONCONVERT"; + case VK_ACCEPT : /*0x1E*/ return L"ACCEPT"; + case VK_MODECHANGE : /*0x1F*/ return L"MODECHANGE"; + + case VK_SPACE : /*0x20*/ return L"SPACE"; + case VK_PRIOR : /*0x21*/ return L"PRIOR"; + case VK_NEXT : /*0x22*/ return L"NEXT"; + case VK_END : /*0x23*/ return L"END"; + case VK_HOME : /*0x24*/ return L"HOME"; + case VK_LEFT : /*0x25*/ return L"LEFT"; + case VK_UP : /*0x26*/ return L"UP"; + case VK_RIGHT : /*0x27*/ return L"RIGHT"; + case VK_DOWN : /*0x28*/ return L"DOWN"; + case VK_SELECT : /*0x29*/ return L"SELECT"; + case VK_PRINT : /*0x2A*/ return L"PRINT"; + case VK_EXECUTE : /*0x2B*/ return L"EXECUTE"; + case VK_SNAPSHOT : /*0x2C*/ return L"SNAPSHOT"; + case VK_INSERT : /*0x2D*/ return L"INSERT"; + case VK_DELETE : /*0x2E*/ return L"DELETE"; + case VK_HELP : /*0x2F*/ return L"HELP"; + + case VK_LWIN : /*0x5B*/ return L"LWIN"; + case VK_RWIN : /*0x5C*/ return L"RWIN"; + case VK_APPS : /*0x5D*/ return L"APPS"; + + case VK_SLEEP : /*0x5F*/ return L"SLEEP"; + + case VK_NUMPAD0 : /*0x60*/ return L"NUMPAD0"; + case VK_NUMPAD1 : /*0x61*/ return L"NUMPAD1"; + case VK_NUMPAD2 : /*0x62*/ return L"NUMPAD2"; + case VK_NUMPAD3 : /*0x63*/ return L"NUMPAD3"; + case VK_NUMPAD4 : /*0x64*/ return L"NUMPAD4"; + case VK_NUMPAD5 : /*0x65*/ return L"NUMPAD5"; + case VK_NUMPAD6 : /*0x66*/ return L"NUMPAD6"; + case VK_NUMPAD7 : /*0x67*/ return L"NUMPAD7"; + case VK_NUMPAD8 : /*0x68*/ return L"NUMPAD8"; + case VK_NUMPAD9 : /*0x69*/ return L"NUMPAD9"; + case VK_MULTIPLY : /*0x6A*/ return L"MULTIPLY"; + case VK_ADD : /*0x6B*/ return L"ADD"; + case VK_SEPARATOR : /*0x6C*/ return L"SEPARATOR"; + case VK_SUBTRACT : /*0x6D*/ return L"SUBTRACT"; + case VK_DECIMAL : /*0x6E*/ return L"DECIMAL"; + case VK_DIVIDE : /*0x6F*/ return L"DIVIDE"; + case VK_F1 : /*0x70*/ return L"F1"; + case VK_F2 : /*0x71*/ return L"F2"; + case VK_F3 : /*0x72*/ return L"F3"; + case VK_F4 : /*0x73*/ return L"F4"; + case VK_F5 : /*0x74*/ return L"F5"; + case VK_F6 : /*0x75*/ return L"F6"; + case VK_F7 : /*0x76*/ return L"F7"; + case VK_F8 : /*0x77*/ return L"F8"; + case VK_F9 : /*0x78*/ return L"F9"; + case VK_F10 : /*0x79*/ return L"F10"; + case VK_F11 : /*0x7A*/ return L"F11"; + case VK_F12 : /*0x7B*/ return L"F12"; + case VK_F13 : /*0x7C*/ return L"F13"; + case VK_F14 : /*0x7D*/ return L"F14"; + case VK_F15 : /*0x7E*/ return L"F15"; + case VK_F16 : /*0x7F*/ return L"F16"; + case VK_F17 : /*0x80*/ return L"F17"; + case VK_F18 : /*0x81*/ return L"F18"; + case VK_F19 : /*0x82*/ return L"F19"; + case VK_F20 : /*0x83*/ return L"F20"; + case VK_F21 : /*0x84*/ return L"F21"; + case VK_F22 : /*0x85*/ return L"F22"; + case VK_F23 : /*0x86*/ return L"F23"; + case VK_F24 : /*0x87*/ return L"F24"; + + case VK_NUMLOCK : /*0x90*/ return L"NUMLOCK"; + case VK_SCROLL : /*0x91*/ return L"SCROLL"; + + case VK_OEM_NEC_EQUAL : /*0x92*/ return L"OEM_NEC_EQUAL"; + +// case VK_OEM_FJ_JISHO : /*0x92*/ return L"OEM_FJ_JISHO"; + case VK_OEM_FJ_MASSHOU : /*0x93*/ return L"OEM_FJ_MASSHOU"; + case VK_OEM_FJ_TOUROKU : /*0x94*/ return L"OEM_FJ_TOUROKU"; + case VK_OEM_FJ_LOYA : /*0x95*/ return L"OEM_FJ_LOYA"; + case VK_OEM_FJ_ROYA : /*0x96*/ return L"OEM_FJ_ROYA"; + + case VK_LSHIFT : /*0xA0*/ return L"LSHIFT"; + case VK_RSHIFT : /*0xA1*/ return L"RSHIFT"; + case VK_LCONTROL : /*0xA2*/ return L"LCONTROL"; + case VK_RCONTROL : /*0xA3*/ return L"RCONTROL"; + case VK_LMENU : /*0xA4*/ return L"LMENU"; + case VK_RMENU : /*0xA5*/ return L"RMENU"; + + case VK_BROWSER_BACK : /*0xA6*/ return L"BROWSER_BACK"; + case VK_BROWSER_FORWARD : /*0xA7*/ return L"BROWSER_FORWARD"; + case VK_BROWSER_REFRESH : /*0xA8*/ return L"BROWSER_REFRESH"; + case VK_BROWSER_STOP : /*0xA9*/ return L"BROWSER_STOP"; + case VK_BROWSER_SEARCH : /*0xAA*/ return L"BROWSER_SEARCH"; + case VK_BROWSER_FAVORITES : /*0xAB*/ return L"BROWSER_FAVORITES"; + case VK_BROWSER_HOME : /*0xAC*/ return L"BROWSER_HOME"; + + case VK_VOLUME_MUTE : /*0xAD*/ return L"VOLUME_MUTE"; + case VK_VOLUME_DOWN : /*0xAE*/ return L"VOLUME_DOWN"; + case VK_VOLUME_UP : /*0xAF*/ return L"VOLUME_UP"; + case VK_MEDIA_NEXT_TRACK : /*0xB0*/ return L"MEDIA_NEXT_TRACK"; + case VK_MEDIA_PREV_TRACK : /*0xB1*/ return L"MEDIA_PREV_TRACK"; + case VK_MEDIA_STOP : /*0xB2*/ return L"MEDIA_STOP"; + case VK_MEDIA_PLAY_PAUSE : /*0xB3*/ return L"MEDIA_PLAY_PAUSE"; + case VK_LAUNCH_MAIL : /*0xB4*/ return L"LAUNCH_MAIL"; + case VK_LAUNCH_MEDIA_SELECT : /*0xB5*/ return L"LAUNCH_MEDIA_SELECT"; + case VK_LAUNCH_APP1 : /*0xB6*/ return L"LAUNCH_APP1"; + case VK_LAUNCH_APP2 : /*0xB7*/ return L"LAUNCH_APP2"; + + case VK_OEM_1 : /*0xBA*/ return L"OEM_1"; + case VK_OEM_PLUS : /*0xBB*/ return L"OEM_PLUS"; + case VK_OEM_COMMA : /*0xBC*/ return L"OEM_COMMA"; + case VK_OEM_MINUS : /*0xBD*/ return L"OEM_MINUS"; + case VK_OEM_PERIOD : /*0xBE*/ return L"OEM_PERIOD"; + case VK_OEM_2 : /*0xBF*/ return L"OEM_2"; + case VK_OEM_3 : /*0xC0*/ return L"OEM_3"; + + case VK_OEM_4 : /*0xDB*/ return L"OEM_4"; + case VK_OEM_5 : /*0xDC*/ return L"OEM_5"; + case VK_OEM_6 : /*0xDD*/ return L"OEM_6"; + case VK_OEM_7 : /*0xDE*/ return L"OEM_7"; + case VK_OEM_8 : /*0xDF*/ return L"OEM_8"; + + case VK_OEM_AX : /*0xE1*/ return L"OEM_AX"; + case VK_OEM_102 : /*0xE2*/ return L"OEM_102"; + case VK_ICO_HELP : /*0xE3*/ return L"ICO_HELP"; + case VK_ICO_00 : /*0xE4*/ return L"ICO_00"; + + case VK_PROCESSKEY : /*0xE5*/ return L"PROCESSKEY"; + + case VK_ICO_CLEAR : /*0xE6*/ return L"ICO_CLEAR"; + + case VK_PACKET : /*0xE7*/ return L"PACKET"; + + case VK_OEM_RESET : /*0xE9*/ return L"OEM_RESET"; + case VK_OEM_JUMP : /*0xEA*/ return L"OEM_JUMP"; + case VK_OEM_PA1 : /*0xEB*/ return L"OEM_PA1"; + case VK_OEM_PA2 : /*0xEC*/ return L"OEM_PA2"; + case VK_OEM_PA3 : /*0xED*/ return L"OEM_PA3"; + case VK_OEM_WSCTRL : /*0xEE*/ return L"OEM_WSCTRL"; + case VK_OEM_CUSEL : /*0xEF*/ return L"OEM_CUSEL"; + case VK_OEM_ATTN : /*0xF0*/ return L"OEM_ATTN"; + case VK_OEM_FINISH : /*0xF1*/ return L"OEM_FINISH"; + case VK_OEM_COPY : /*0xF2*/ return L"OEM_COPY"; + case VK_OEM_AUTO : /*0xF3*/ return L"OEM_AUTO"; + case VK_OEM_ENLW : /*0xF4*/ return L"OEM_ENLW"; + case VK_OEM_BACKTAB : /*0xF5*/ return L"OEM_BACKTAB"; + + case VK_ATTN : /*0xF6*/ return L"ATTN"; + case VK_CRSEL : /*0xF7*/ return L"CRSEL"; + case VK_EXSEL : /*0xF8*/ return L"EXSEL"; + case VK_EREOF : /*0xF9*/ return L"EREOF"; + case VK_PLAY : /*0xFA*/ return L"PLAY"; + case VK_ZOOM : /*0xFB*/ return L"ZOOM"; + case VK_NONAME : /*0xFC*/ return L"NONAME"; + case VK_PA1 : /*0xFD*/ return L"PA1"; + case VK_OEM_CLEAR : /*0xFE*/ return L"OEM_CLEAR"; + + default: + return L""; + } +} + + +#if (0) +#pragma comment(lib, "Imm32.lib") +static int +ImmTest(void) +{ + HWND hWnd = GetConsoleWindow(); + HWND hIME = ImmGetDefaultIMEWnd(hWnd); + LRESULT status = SendMessage(hIME, WM_IME_CONTROL, IMC_GETOPENSTATUS, 0); + HIMC imc = ImmCreateContext(), + oldimc = ImmAssociateContext(hWnd, imc), + retimc = ImmGetContext(hWnd); + ImmSetOpenStatus(imc, TRUE); + BOOL isopen = ImmGetOpenStatus(imc); + Sleep(2 * 2000); + ImmAssociateContext(hWnd, oldimc); + ImmReleaseContext(hWnd, imc); + Sleep(100); +} +#endif + diff --git a/win32/.cvsignore b/win32/.cvsignore new file mode 100644 index 00000000..6daffeef --- /dev/null +++ b/win32/.cvsignore @@ -0,0 +1,4 @@ +Makefile +*.err +*.exe + diff --git a/win32/.gitignore b/win32/.gitignore new file mode 100644 index 00000000..4fa37469 --- /dev/null +++ b/win32/.gitignore @@ -0,0 +1,2 @@ +grief.manifest + diff --git a/win32/AutoUpdater/.cvsignore b/win32/AutoUpdater/.cvsignore new file mode 100644 index 00000000..8c40b219 --- /dev/null +++ b/win32/AutoUpdater/.cvsignore @@ -0,0 +1,2 @@ +Makefile +*.err diff --git a/win32/AutoUpdater/Makefile.in b/win32/AutoUpdater/Makefile.in new file mode 100644 index 00000000..b7a6aaab --- /dev/null +++ b/win32/AutoUpdater/Makefile.in @@ -0,0 +1,218 @@ +# -*- mode: mak; indent-tabs-mode: t; tab-width: 8 -*- +# $Id: Makefile.in,v 1.16 2021/10/19 15:50:56 cvsuser Exp $ +# libautoupdater and utils makefile +# +# +# + +@SET_MAKE@ +ROOT= @abs_top_builddir@ +top_builddir= @top_builddir@ + +# File extensions + +E= +O= .o +A= .a +LP= lib + +CLEAN= *.bak *~ *.BAK *.swp *.tmp core *.core a.out +XCLEAN= + +# Compilers, programs + +CC= @CC@ +CXX= @CXX@ +AR= @AR@ +RANLIB= @RANLIB@ +RM= @RM@ +PERL= @PERL@ +LIBTOOL= @LIBTOOL@ +RC= @RC@ + +# Configuration + +ifeq ("$(BUILD_TYPE)","") #default +BUILD_TYPE= debug +MAKEFLAGS+= BUILD_TYPE=debug +endif +ifneq ("$(BUILD_TYPE)","release") +RTSUFFIX=d +endif + +# Directories + +D_INC= $(ROOT)/include +D_BIN= $(ROOT)/bin@TOOLCHAINEXT@/$(BUILD_TYPE) +D_OBJ= $(ROOT)/objects@TOOLCHAINEXT@/$(BUILD_TYPE)/libautoupdater +D_LIB= $(ROOT)/lib@TOOLCHAINEXT@/$(BUILD_TYPE) + +# Common flags + +XFLAGS= +CFLAGS= @CFLAGS@ +CWARN= @CWARN@ $(CWALL) +CDEBUG= @CDEBUG@ +CRELEASE= @CRELEASE@ +CXXFLAGS= @CXXFLAGS@ +CXXDEBUG= @CXXDEBUG@ +ifeq ("$(CXXDEBUG)","") +CXXDEBUG= $(CDEBUG) +endif +CXXRELEASE= @CXXRELEASE@ +ifeq ("$(CXXRELEASE)","") +CXXRELEASE= $(CRELEASE) +endif +LDDEBUG= @LDDEBUG@ +LDRELEASE= @LDRELEASE@ + +CINCLUDE= -I$(D_INC) @CINCLUDE@ +CEXTRA= @DEFS@ @LIBCURL_CPPFLAGS@ -DLIBTRE_DLL +ifdef PURIFY +CEXTRA+= -DUSING_PURIFY +endif +ifeq ("win32","@build_os@") +CEXTRA+= -DWIN32 +endif +CDEPFLAGS= $(CEXTRA) $(CINCLUDE) + +ifeq ("$(BUILD_TYPE)","release") +CFLAGS+= $(CRELEASE) $(CWARN) $(CINCLUDE) $(CEXTRA) $(XFLAGS) +CXXFLAGS+= $(CXXRELEASE) $(CWARN) $(CINCLUDE) @CXXINCLUDE@ $(CEXTRA) $(XFLAGS) +LDFLAGS= $(LDRELEASE) @LDFLAGS@ +else +CFLAGS+= $(CDEBUG) $(CWARN) $(CINCLUDE) $(CEXTRA) $(XFLAGS) +CXXFLAGS+= $(CXXDEBUG) $(CWARN) $(CINCLUDE) @CXXINCLUDE@ $(CEXTRA) $(XFLAGS) +LDFLAGS= $(LDDEBUG) @LDFLAGS@ +endif +LDLIBS= -L$(D_LIB) @LIBS@ @EXTRALIBS@ + +YFLAGS= -d +ARFLAGS= rcv +RMFLAGS= -f +RMDFLAGS= -rf + + +######################################################################################### +# Targets + +UPDATERDLL= $(D_LIB)/$(LP)autoupdater.la +UPDATERTSK= $(D_BIN)/grupdater$(E) +SIGNATURETSK= $(D_BIN)/grsignature$(E) + +UPDATERSRC= ../libappupdater +#ifeq ("wcl386","@CC@") +#EXPATSRC= ../libappupdater/compat +#else +EXPATSRC= ../libappupdater/expat +#endif +SIGNSRC= ../libappupdater/sign + +VPATH= $(UPDATERSRC) $(UPDATERSRC)/src $(UPDATERSRC)/localisation $(UPDATERSRC)/localisation/test $(EXPATSRC) $(SIGNSRC) ./sign + +DLLOBJS=\ + $(D_OBJ)/libautoupdater.lo \ + $(D_OBJ)/AutoConfig.lo \ + $(D_OBJ)/AutoConsole.lo \ + $(D_OBJ)/AutoDialog.lo \ + $(D_OBJ)/AutoDownload.lo \ + $(D_OBJ)/AutoError.lo \ + $(D_OBJ)/AutoLogger.lo \ + $(D_OBJ)/AutoManifest.lo \ + $(D_OBJ)/AutoUpdater.lo \ + $(D_OBJ)/AutoUpdater.res \ + $(D_OBJ)/AutoVersion.lo \ + \ + $(D_OBJ)/CProgressDialog.lo \ + $(D_OBJ)/CSimpleBrowser.lo \ + $(D_OBJ)/CUpdateInstallDlg.lo \ + $(D_OBJ)/CUpdatePromptDlg.lo \ + $(D_OBJ)/CUptodateDlg.lo \ + $(D_OBJ)/TProgressBar.lo \ + \ + $(D_OBJ)/NSLocalizedCollection.lo \ + $(D_OBJ)/NSLocalizedCollectionImpl.lo \ + $(D_OBJ)/NSLocalizedDefault.lo \ + $(D_OBJ)/NSLocalizedString.lo \ + $(D_OBJ)/NSFormat.lo \ + $(D_OBJ)/NSFormatTests.lo \ + \ + $(D_OBJ)/xmlparse.lo \ + $(D_OBJ)/xmlrole.lo \ + $(D_OBJ)/xmltok.lo + +UPDATEROBJS=\ + $(D_OBJ)/grupdater$(O) \ + $(D_OBJ)/grupdater.res \ + $(D_OBJ)/upgetopt$(O) + +SIGNATUREOBJS=\ + $(D_OBJ)/grsignature$(O) \ + $(D_OBJ)/signature$(O) \ + $(D_OBJ)/upgetopt$(O) + +OBJS= $(DLLOBJS) $(UPDATEROBJS) $(SIGNATUREOBJS) +LIBS= $(UPDATERDLL) +TSKS= $(UPDATERTSK) $(SIGNATURETSK) + + +######################################################################################### +# Rules + +.PHONY: build release debug +build: $(LIBS) $(TSKS) + +release: + $(MAKE) BUILD_TYPE=release $(filter-out release, $(MAKECMDGOALS)) +debug: + $(MAKE) BUILD_TYPE=debug $(filter-out debug, $(MAKECMDGOALS)) + +$(UPDATERDLL): CEXTRA += -I$(UPDATERSRC) -I$(UPDATERSRC)/src -I$(EXPATSRC) +$(UPDATERDLL): CEXTRA += -DXML_STATIC -DCOMPILED_FROM_DSP -D_CRT_SECURE_NO_DEPRECATE +$(UPDATERDLL): CEXTRA += -DUNICODE -D_UNICODE +$(UPDATERDLL): CEXTRA += -D_WIN32 +ifdef USE_DEBUG +$(UPDATERDLL): CEXTRA += -D_DEBUG +endif +$(UPDATERDLL): CEXTRA += -DBUILDING_LIBAUTOUPDATER +$(UPDATERDLL): $(D_OBJ)/.created $(DLLOBJS) + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(DLLOBJS) -version-number 1.0.1 \ + -rpath $(D_LIB) -bindir $(D_BIN) $(LDLIBS) version.lib wininet.lib advapi32.lib user32.lib + +$(UPDATERTSK): CEXTRA += -I$(UPDATERSRC) +$(UPDATERTSK): $(UPDATEROBJS) + $(LIBTOOL) --mode=link $(CXX) $(LDFLAGS) -o $@ $(UPDATEROBJS) $(D_LIB)/libautoupdater$(A) $(LDLIBS) @LDMAPFILE@ + +$(SIGNATURETSK): CEXTRA += -I$(UPDATERSRC) -I$(SIGNSRC) +$(SIGNATURETSK): $(SIGNATUREOBJS) + $(LIBTOOL) --mode=link $(CXX) $(LDFLAGS) -o $@ $(SIGNATUREOBJS) $(D_LIB)/libautoupdater$(A) $(LDLIBS) @LDMAPFILE@ + +installinc: include/.created + @echo publishing headers ... + -cp $(UPDATERSRC)/magic.h include + @echo publishing magicdb ... + -cp magic.mgc $(D_BIN) + +%/.created: + -@mkdir $(@D) + @echo "do not delete, managed directory" > $@ + +clean: + -@$(RM) $(RMFLAGS) $(BAK) $(TSKS) $(LIBS) $(OBJS) $(CLEAN) $(XCLEAN) >/dev/null 2>&1 + +$(D_OBJ)/%$(O): %.cpp + $(CC) $(CXXFLAGS) -o $@ -c $< + +$(D_OBJ)/%$(O): %.c + $(CC) $(CFLAGS) -o $@ -c $< + +$(D_OBJ)/%.lo: %.cpp + $(LIBTOOL) --mode=compile $(CC) $(CXXFLAGS) -o $@ -c $< + +$(D_OBJ)/%.lo: %.c + $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) -o $@ -c $< + +$(D_OBJ)/%.res: %.rc + $(RC) -Fo$@ -I../libappupdater/src $(RCDEFS) $< + +#end diff --git a/win32/AutoUpdater/grlibrun.bat b/win32/AutoUpdater/grlibrun.bat new file mode 100644 index 00000000..4ae0d0c1 --- /dev/null +++ b/win32/AutoUpdater/grlibrun.bat @@ -0,0 +1,2 @@ +rundll32 ../../lib/libautoupdater.1.0.dll,ShellExecute "interactive" + diff --git a/win32/AutoUpdater/grupdater.cpp b/win32/AutoUpdater/grupdater.cpp new file mode 100644 index 00000000..0b02fbf9 --- /dev/null +++ b/win32/AutoUpdater/grupdater.cpp @@ -0,0 +1,171 @@ +// $Id: grupdater.cpp,v 1.9 2021/08/17 06:02:21 cvsuser Exp $ +// +// GRIEF AutoUpdater command line. +// + +#include +#include +#include + +#include + +#include "libautoupdater.h" +#include "sign/upgetopt.h" + +static void Usage(); +static const char * Basename(const char *name); + +static const char * x_progname; + + +// Function: Main +// Application entry. +// +// Returns: +// 0 - No check performed. +// 1 - Up-to-date. +// 2 - Installed. +// 3 - Update available. +// 99 - Usage +// +int +main(int argc, char *argv[]) +{ + const char *version = GR_VERSION "." GR_BUILD_NUMBER, + *hosturl = "https://sourceforge.net/projects/grief/files/grief.manifest/download"; + int mode = 2, interactive = 0; + int ch; + + x_progname = Basename(argv[0]); + while (-1 != (ch = Updater::Getopt(argc, argv, "V:H:L:icvh"))) { + switch (ch) { + case 'V': /* application version */ + version= Updater::optarg; + break; + case 'H': /* host URL */ + hosturl = Updater::optarg; + break; + case 'L': /* logpath */ + autoupdate_logger_path(Updater::optarg); + break; + case 'i': /* interactive */ + ++interactive; + break; + case 'c': /* console */ + autoupdate_set_console_mode(1); + break; + case 'v': /* verbose */ + autoupdate_logger_stdout(1); + break; + case 'h': + default: + Usage(); + break; + } + } + + argv += Updater::optind; + if ((argc -= Updater::optind) < 1) { + std::cerr << "\n" << + x_progname << ": expected arguments " << std::endl; + Usage(); + } else if (argc > 1) { + std::cerr << "\n" << + x_progname << ": unexpected arguments '" << argv[1] << "' ..." << std::endl; + Usage(); + } + + const char *arg = argv[0]; + + if (0 == _stricmp("disable", arg)) { + mode = 0; + } else if (0 == _stricmp("enable", arg)) { + mode = 1; + } else if (0 == _stricmp("auto", arg)) { + mode = 2; + } else if (0 == _stricmp("prompt", arg)) { + mode = 3; + } else if (0 == _stricmp("force", arg)) { + mode = 4; + } else if (0 == _stricmp("reinstall", arg)) { + mode = 5; + } else if (0 == _stricmp("reset", arg)) { + mode = -1; + } else if (0 == _stricmp("dump", arg)) { + mode = -2; + } else if (0 == _stricmp("config", arg)) { + std::cout + << GR_PACKAGE_NAME << "\n" + << "Built: " << GR_BUILD_DATE << "\n" + << "Version: " << version << "\n" + << "Host: " << hosturl << "\n"; + return 0; + } else { + std::cerr << "\n" << + x_progname << ": unknown mode '" << arg << "'" << std::endl; + Usage(); + } + + if (mode >= 1) { + autoupdate_appversion_set(version); + autoupdate_hosturl_set(hosturl); + } + + return autoupdate_execute(mode, interactive); +} + + +// Function: Usage +// Echo the command line usage and exit. +// +// Parameters: +// none +// +// Returns: +// n/a +// +static void +Usage() +{ + std::cerr << + "\n"\ + "GRIEF updater version 1.01\n"\ + "\n"\ + " grupdater [options] mode\n"\ + "\n"\ + "Modes:\n"\ + " auto - Periodically check for updates.\n"\ + " prompt - Re-prompt user when periodic updates are disabled.\n"\ + " force - Prompt ignoring skip status.\n"\ + " reinstall - Prompt unconditionally, even if up-to-date/skipped.\n"\ + "\n"\ + " enable - Enable periodic checks.\n"\ + " disable - Disable automatic periodic checks.\n"\ + " reset - Reset the updater status.\n"\ + "\n"\ + " config - Configuration.\n"\ + "\n"\ + "\n"\ + "Options:\n"\ + " -V Version label.\n"\ + " -H Host URL.\n"\ + " -L Diagnostics log path.\n"\ + " -i Interactive ('auto' only).\n"\ + " -v Verbose diagnostice.\n"\ + "\n" << std::endl; + std::exit(99); +} + + +// Function: Basename +// Retrieve the file basename from the specified file path. +// +static const char * +Basename(const char *filename) +{ + const char *name; + return (NULL != (name = std::strrchr(filename, '/'))) + || (NULL != (name = std::strrchr(filename, '\\'))) ? name + 1 : filename; +} + +/*end*/ diff --git a/win32/AutoUpdater/grupdater.rc b/win32/AutoUpdater/grupdater.rc new file mode 100644 index 00000000..43106e03 --- /dev/null +++ b/win32/AutoUpdater/grupdater.rc @@ -0,0 +1,99 @@ +/* + * windows resource file; this file is part of the GRIEF. + */ + +#ifndef WINDRES +#include "windows.h" +#include "winver.h" +#endif + +/* + * English (U.S.) resources + */ + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) + +#ifdef _WIN32 +#ifndef WINDRES +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#endif +#pragma code_page(1252) +#endif /* _WIN32 */ + +/* + * Manifest + */ +#ifndef RT_MANIFEST +#define RT_MANIFEST 24 +#endif +#ifndef CREATEPROCESS_MANIFEST_RESOURCE_ID +#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1 +#endif +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "../libappupdater/manifest.xml" + +/* + * Updater Meta Data + * nameID typeID { raw data } + */ + +UPDATER HostURL { "\0" } +UPDATER Channel { "release\0" } + + +/* + * Version Information + */ + +VS_VERSION_INFO VERSIONINFO +#if defined(RC_FILEVERSION) + FILEVERSION RC_FILEVERSION + PRODUCTVERSION RC_PRODUCTVERSION +#endif + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS (VS_FF_SPECIALBUILD|VS_FF_DEBUG) +#else + FILEFLAGS (VS_FF_SPECIALBUILD) +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE VFT2_UNKNOWN + BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "" + VALUE "FileDescription", "GRIEF Editor, Auto Updater" +#if defined(VERSION) && defined(BUILD_DATE) + VALUE "FileVersion", VERSION ", Build:" BUILD_DATE "-" BUILD_NUMBER +#endif + VALUE "InternalName", "GRIEF" + VALUE "Copyright", + "Copyright (C) 2012 - 2021, Adam Young. All rights reserved. " + "Licensed under the Grief License. " + "This is free software; see the source for copying conditions. " + "There is NO warranty; not even for MERCHANTABILITY " + "or FITNESS FOR A PARTICULAR PURPOSE. " + VALUE "Maintainers", "griefedit@gmail.com" + VALUE "LegalTrademarks", "see GRIEF License" + VALUE "OriginalFilename", "grupdater.exe" + VALUE "ProductName", "GRIEF" + END + END + + /* The following line should only be modified for localized versions. */ + /* It consists of any number of WORD,WORD pairs, with each pair */ + /* describing a language,codepage combination supported by the file. */ + /* */ + /* For example, a file might have values "0x409,1252" indicating that it */ + /* supports English language (0x409) in the Windows ANSI codepage (1252). */ + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END + END + +#endif /* English (U.S.) resources */ + diff --git a/win32/AutoUpdater/sign/grsignature.bat b/win32/AutoUpdater/sign/grsignature.bat new file mode 100644 index 00000000..3b553aeb --- /dev/null +++ b/win32/AutoUpdater/sign/grsignature.bat @@ -0,0 +1 @@ +..\..\bin\signature ..\grwin32-build8-setup.exe diff --git a/win32/AutoUpdater/sign/grsignature.cpp b/win32/AutoUpdater/sign/grsignature.cpp new file mode 100644 index 00000000..e010cbfa --- /dev/null +++ b/win32/AutoUpdater/sign/grsignature.cpp @@ -0,0 +1,129 @@ +// $Id: grsignature.cpp,v 1.6 2021/08/13 16:58:27 cvsuser Exp $ +// +// AutoUpdater: Manifest generation tool. +// + +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include + +#include + +#include +#include "upgetopt.h" + + +static void Usage(); +static const char * Basename(const char *name); + +static const char * x_progname; + + +// Function: Main +// Application entry. +// +int +main(int argc, char *argv[]) +{ + const char *version = GR_VERSION "." GR_BUILD_NUMBER, + *hosturl = "https://master.dl.sourceforge.net/project/grief/%%?viasf=1"; + int ch; + + x_progname = Basename(argv[0]); + while (-1 != (ch = Updater::Getopt(argc, argv, "V:H:h"))) { + switch (ch) { + case 'V': /* application version */ + version = Updater::optarg; + break; + case 'H': /* host URL template */ + hosturl = Updater::optarg; + break; + case 'h': + default: + Usage(); + break; + } + } + + argv += Updater::optind; + if ((argc -= Updater::optind) < 1) { + std::cerr << "\n" << + x_progname << ": expected arguments []" << std::endl; + Usage(); + + } else if (argc > 2) { + std::cerr << "\n" << + x_progname << ": unexpected arguments '" << argv[2] << "' ..." << std::endl; + Usage(); + } + + const char *inputname = argv[0], + *outputname = argv[1]; + size_t inputlen; + + if ((inputlen = strlen(inputname)) < 5 || _stricmp(inputname + (inputlen-4), ".exe")) { + std::cerr << "\n" << + x_progname << ": should reference an installer exe image\n"; + Usage(); + } + + if (outputname && 0 == strcmp(inputname, outputname)) { + std::cerr << "\n" << + x_progname << ": and names must be different\n"; + Usage(); + } + + sign_manifest(inputname, version, hosturl); + return 0; +} + + +// Function: Usage +// Echo the command line usage and exit. +// +// Parameters: +// none +// +// Returns: +// n/a +// +static void +Usage() +{ + std::cerr << + "\n"\ + "Autoupdater manifest signature generator version 1.01\n"\ + "\n"\ + " grsignature [options] []\n"\ + "\n"\ + "Options:\n"\ + " -H HostURL template.\n"\ + " -V Version label.\n"\ + "\n"\ + "Arguments:\n"\ + " input Name of the input file.\n"\ + " output Optional name of the results output file.\n"\ + "\n" << std::endl; + exit(3); +} + + +// Function: Basename +// Retrieve the file basename from the specified file path. +// +// +static const char * +Basename(const char *filename) +{ + const char *name; + return (NULL != (name = strrchr(filename, '/'))) + || (NULL != (name = strrchr(filename, '\\'))) ? name + 1 : filename; +} + +/*end*/ + diff --git a/win32/AutoUpdater/sign/upgetopt.cpp b/win32/AutoUpdater/sign/upgetopt.cpp new file mode 100644 index 00000000..a2eb91c3 --- /dev/null +++ b/win32/AutoUpdater/sign/upgetopt.cpp @@ -0,0 +1,70 @@ +// $Id: upgetopt.cpp,v 1.2 2021/08/12 14:48:38 cvsuser Exp $ +// +// getopt() implementation +// + +#include +#include +#include + +#include "upgetopt.h" + +namespace Updater { + +int optind = 1, /* index into parent argv vector */ + optopt; /* character checked for validity */ +const char *optarg; /* argument associated with option */ + +int +Getopt(int nargc, char **nargv, const char *ostr) +{ +#define OPTBADCH (int)'?' +#define OPTEMSG "" +#define OPTERR(s) \ + fputs(*nargv,stderr);fputs(s,stderr); \ + fputc(optopt,stderr);fputc('\n',stderr); \ + return(OPTBADCH); + + static const char *place = OPTEMSG; /* option letter processing */ + const char *oli; /* option letter list index */ + + if (!*place) { /* update scanning pointer */ + if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) { + return(EOF); + } + + if (*place == '-') { /* found "--" */ + ++optind; + return EOF; + } + } + /* option letter okay? */ + if ((optopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr,optopt))) { + if (!*place) ++optind; + OPTERR(": illegal option -- "); + } + + if (*++oli != ':') { /* don't need argument */ + optarg = NULL; + if (!*place) ++optind; + + } else { /* need an argument */ + if (*place) optarg = place; /* no white space */ + else if (nargc <= ++optind) { /* no arg */ + place = OPTEMSG; + OPTERR(": option requires an argument -- "); + + } else optarg = nargv[optind]; /* white space */ + place = OPTEMSG; + ++optind; + } + +#undef OPTBADCH +#undef OPTEMSG +#undef OPTERR + + return(optopt); /* dump back option letter */ +} + +} // namespace Updater diff --git a/win32/AutoUpdater/sign/upgetopt.h b/win32/AutoUpdater/sign/upgetopt.h new file mode 100644 index 00000000..23bfa217 --- /dev/null +++ b/win32/AutoUpdater/sign/upgetopt.h @@ -0,0 +1,18 @@ +#ifndef UPGETOPT_H_INCLUDED +#define UPGETOPT_H_INCLUDED +// $Id: upgetopt.h,v 1.2 2015/01/05 23:44:26 ayoung Exp $ +// +// getopt() implementation +// + +namespace Updater { + +extern int optind, /* index into parent argv vector */ + optopt; /* character checked for validity */ +extern const char *optarg; /* argument associated with option */ + +extern int Getopt(int nargc, char **nargv, const char *ostr); + +} //namespace Updater + +#endif /*UPGETOPT_H_INCLUDED*/ diff --git a/win32/gr-inno-setup.iss b/win32/gr-inno-setup.iss index ce3893e8..349ac6a1 100644 --- a/win32/gr-inno-setup.iss +++ b/win32/gr-inno-setup.iss @@ -1,7 +1,30 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! ; +; GRIEF - Inno Setup Script. +; +; This file is part of the GRIEF Editor. +; +; The GRIEF Editor is free software: you can redistribute it +; and/or modify it under the terms of the GRIEF Editor License. +; +; Redistributions of source code must retain the above copyright +; notice, and must be distributed with the license document above. +; +; Redistributions in binary form must reproduce the above copyright +; notice, and must include the license document above in +; the documentation and/or other materials provided with the +; distribution. +; +; The GRIEF Editor is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; License for more details. +; + +#if defined(BUILD_INFO) #include "../include/edbuildinfo.h" +#else +#include "../include/edpackageinfo.h" +#endif #if defined(BUILD_TOOLCHAIN) #if defined(BUILD_TYPE) @@ -21,10 +44,10 @@ AppId={{1BDBED1A-1B0E-4D87-BD04-31E9E3DA5ADC}} AppName=GRIEF AppVersion={#GR_VERSION} (build: {#GR_BUILD_DATE}-{#GR_BUILD_NUMBER}) -AppCopyright=Copyright (C) 1998-2020. +AppCopyright=Copyright (C) 1998-2022. AppPublisherURL=http://sourceforge.net/projects/grief/ -AppSupportURL=http://sourceforge.net/projects/grief/ -AppUpdatesURL=http://sourceforge.net/projects/grief/ +AppSupportURL=https://github.com/adamyg/grief +AppUpdatesURL=https://github.com/adamyg/grief ;TODO, skins ; http://isskin.codejock.com/ @@ -50,8 +73,17 @@ Name: modifypath; Description: Add application directory to your environmental p Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 +[Registry] +Root: HKLM; Subkey: "Software\GRIEF-Edit"; ValueType: string; ValueName: ""; ValueData: {app}; Flags: uninsdeletevalue uninsdeletekeyifempty +Root: HKLM; Subkey: "Software\GRIEF-Edit"; ValueType: string; ValueName: "Path"; ValueData: "{app}"; Flags: uninsdeletevalue +Root: HKLM; Subkey: "Software\GRIEF-Edit"; ValueType: string; ValueName: "UninstallString"; ValueData: {uninstallexe}; Flags: uninsdeletevalue + +Root: HKLM; Subkey: "Software\GRIEF-Edit"; ValueType: dword; ValueName: "MajorVersion"; ValueData: "{#GR_VERSION_1}"; Flags: uninsdeletevalue +Root: HKLM; Subkey: "Software\GRIEF-Edit"; ValueType: dword; ValueName: "MinorVersion"; ValueData: "{#GR_VERSION_2}"; Flags: uninsdeletevalue +Root: HKLM; Subkey: "Software\GRIEF-Edit"; ValueType: dword; ValueName: "PatchVersion"; ValueData: "{#GR_VERSION_3}"; Flags: uninsdeletevalue +Root: HKLM; Subkey: "Software\GRIEF-Edit"; ValueType: dword; ValueName: "BuildVersion"; ValueData: "{#GR_VERSION_4}"; Flags: uninsdeletevalue + [Files] -; NOTE: Don't use "Flags: ignoreversion" on any shared system files Source: "..\{#BinDir}\gr.exe"; DestDir: "{app}\bin"; Flags: ignoreversion Source: "..\{#BinDir}\gm.exe"; DestDir: "{app}\bin"; Flags: ignoreversion Source: "..\{#BinDir}\grcpp.exe"; DestDir: "{app}\bin"; Flags: ignoreversion @@ -65,6 +97,7 @@ Source: "..\macros\*"; DestDir: "{app}\macros"; Flags: ignorevers Source: "..\help\*"; DestDir: "{app}\help"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "..\COPYING"; DestDir: "{app}"; Flags: ignoreversion Source: "..\Changes"; DestDir: "{app}"; Flags: ignoreversion +; NOTE: Dont use "Flags: ignoreversion" on any shared system files [Icons] Name: "{group}\Grief"; Filename: "{app}\bin\gr.exe" @@ -75,12 +108,62 @@ Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\Grief"; Filename: Filename: "{app}\bin\gr.exe"; Description: "{cm:LaunchProgram,Grief}"; Flags: nowait postinstall skipifsilent [Code] -const - ModPathName = 'modifypath'; - ModPathType = 'user'; +function GRIEFInstalled(var version, uninstallcmd:string):boolean; +var major,minor,patch,build:Cardinal; +begin + Result := RegQueryDWordValue(HKLM, 'Software\GRIEF-Edit', 'MajorVersion', major) + and RegQueryDWordValue(HKLM, 'Software\GRIEF-Edit', 'MinorVersion', minor) + and RegQueryDWordValue(HKLM, 'Software\GRIEF-Edit', 'PatchVersion', patch) + and RegQueryDWordValue(HKLM, 'Software\GRIEF-Edit', 'BuildVersion', build); + + if not RegQueryStringValue(HKLM, 'Software\GRIEF-Edit', 'UninstallString', uninstallcmd) + then if not RegQueryStringValue(HKLM, 'Software\GRIEF-Edit', 'Uninstall', uninstallcmd) + then RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\GRIEF-Edit', 'UninstallString', uninstallcmd); + version := IntToStr(major)+'.'+IntToStr(minor)+'.'+IntToStr(patch)+'-'+IntToStr(build); +end; + +function InitializeSetup(): Boolean; + var version, uninst :string; + msgres, execres :integer; +begin + Result:=true; + if GRIEFInstalled(version,uninst) + then + begin + msgres:= MsgBox('GRIEF Edit-'+version+' is currently installed.'+#13#13 +'Do you want to uninstall it first?.', mbError, MB_YESNOCANCEL); + case msgres of + IdYes: begin + Exec(uninst, '', '', SW_SHOWNORMAL, true, execres); + Result:=InitializeSetup(); + end; + IdCancel: + Result:=false; + IdNo: ; + end; + end; +end; + +[Code] +const ModPathName = 'modifypath'; + ModPathType = 'user'; + function ModPathDir(): TArrayOfString; begin - setArrayLength(Result, 1) - Result[0] := ExpandConstant('{app}\bin'); + setArrayLength(Result, 1) + Result[0] := ExpandConstant('{app}\bin'); end; + +procedure DosToUnix(); +var + path : String; + data : String; + ANSIdata : AnsiString; +begin + path := ExpandConstant(CurrentFileName); + LoadStringFromFile(path, ANSIdata); + data := String(ANSIData); + StringChangeEx(data, #13#10, #10, True); + SaveStringToFile(path, AnsiString(data), False); +end; + #include "modpath.iss" diff --git a/win32/grief.rc b/win32/grief.rc index f9e4a2b1..64aec792 100644 --- a/win32/grief.rc +++ b/win32/grief.rc @@ -51,7 +51,7 @@ VS_VERSION_INFO VERSIONINFO VALUE "FileVersion", GR_VERSION ", Build:" GR_BUILD_DATE "-" GR_BUILD_NUMBER VALUE "InternalName", "GRIEF" VALUE "Copyright", - "Copyright (C) 2014-2020, Adam Young. All rights reserved. " + "Copyright (C) 2014-2022, Adam Young. All rights reserved. " "Licensed under the GRIEF License. " "This is free software; see the source for copying conditions. " "There is NO warranty; not even for MERCHANTABILITY " diff --git a/win32/libappupdater b/win32/libappupdater new file mode 160000 index 00000000..a9dd5314 --- /dev/null +++ b/win32/libappupdater @@ -0,0 +1 @@ +Subproject commit a9dd531499cc87046347d9710574b459e5d541f3 diff --git a/win32/libtool_win32.pl b/win32/libtool_win32.pl index 7f93598f..237aef5b 100644 --- a/win32/libtool_win32.pl +++ b/win32/libtool_win32.pl @@ -1,11 +1,11 @@ #!/usr/bin/perl -w # -*- mode: perl; -*- -# $Id: libtool_win32.pl,v 1.35 2020/06/20 02:06:56 cvsuser Exp $ +# $Id: libtool_win32.pl,v 1.36 2022/03/21 14:31:25 cvsuser Exp $ # libtool emulation for WIN32 builds. # # **Warning** # -# Functionality is limited to the current GRIEF/MC build requirements. +# Functionality is limited to the current GRIEF/MC/WINRSH build requirements. # # Example usage: # @@ -18,10 +18,12 @@ # $(D_LIB)/%.lo: %.cpp # $(LIBTOOL) --mode=compile $(CXX) $(CXXFLAGS) -o $(D_OBJ)/$@ -c $< # -# Copyright Adam Young 2012-2020 +# Copyright Adam Young 2012-2022 +# All rights reserved. # # This file is part of the GRIEF Editor. # + use strict; use warnings 'all'; @@ -325,7 +327,7 @@ Link() { my $cc = shift @ARGV; - my ($output, $rpath, $bindir, $module, $mapfile); + my ($output, $dlbase, $rpath, $bindir, $module, $mapfile); my $version_number = ''; my $wc_fastcall = -1; # fastcall (Watcom) convention. my $wc_debugger = ''; @@ -422,6 +424,12 @@ if (! -d $val); $bindir = $val; + } elsif (/^-dlbase[=]?(.*)/) { # -dlbase[=] (extension) + my $val = ($1 ? $1 : shift @ARGV); + Error("link: multiple dll base names specified <$dlbase> and <$val>") + if ($dlbase); + $dlbase = $val; # dll base name, version is appended. + } elsif (/^-dlopen(.*)$/) { Error("link: $_ not supported\n"); @@ -655,24 +663,28 @@ if ($version_number) { if ($version_number =~ /^\s*(\d+)\s*$/) { # - ($dll_major, $dll_minor) = ($1, 0); + $dll_version = "$1.0"; # major.0 + $version_number = ".$1"; - $dll_version = "$1"; # major - $version_number = "$1"; + } elsif ($version_number =~ /^\s*(\d+):(\d+)$/) { + # : + $dll_version = "$1.$2"; # major.minor + $version_number = ".$1.$2"; # .[:[:]] - ($dll_major, $dll_minor) = ($1, $2); + } elsif ($version_number =~ /^\s*(\d+):(\d+):(\d+)$/) { + # :: + $dll_version = "$1.$2"; # major.minor + $version_number = ".$1.$2.$3"; # ..dll + } elsif ($version_number =~ /^\s*(\d+)\s*\.\s*(\d+)$/) { + # . $dll_version = "$1.$2"; # major.minor $version_number = ".$1.$2"; # ..dll - } elsif ($version_number =~ /^\s*(\d+)\s*\.\s*(\d+)/) { - # [.[.]] - ($dll_major, $dll_minor) = ($1, $2); - + } elsif ($version_number =~ /^\s*(\d+)\s*\.\s*(\d+)\.\s*(\d+)$/) { + # .. $dll_version = "$1.$2"; # major.minor - $version_number = ".$1.$2"; # ..dll + $version_number = ".$1.$2.$3"; # ..dll } else { Error("link: invalid -version_number <$version_number>\n"); @@ -683,11 +695,15 @@ my $basedir = unix2dos(dirname($output)); my $basename = unix2dos(basename($output, '.la')); my $basepath = $basedir.'\\'.$basename; - my $dllname = "${basename}${version_number}.dll"; - my $dllpath = "${basepath}${version_number}.dll"; - my $pdbpath = "${basepath}${version_number}.pdb"; - my $mappath = ($mapfile ? $mapfile : "${basepath}${version_number}.map"); - my $manifestpath = "${basepath}${version_number}.dll.manifest"; + my $dllbasename = $dlbase ? unix2dos($dlbase) : $basename; + my $dllbasepath = $basedir.'\\'.$dllbasename; + + my $dllname = "${dllbasename}${version_number}.dll"; + my $dllpath = "${dllbasepath}${version_number}.dll"; + my $pdbpath = "${dllbasepath}${version_number}.pdb"; + my $mappath = ($mapfile ? $mapfile : + ($linktype eq 'dll' ? "${dllbasepath}${version_number}.map" : "${basepath}.map")); + my $manifestpath = "${dllbasepath}${version_number}.dll.manifest"; my $libpath = "${basepath}.lib"; # import library my $exppath = "${basepath}.exp"; # export library # Notes: @@ -796,7 +812,6 @@ open(CMD, ">${cmdfile}") or die "cannot create <${$cmdfile}>: $!\n"; - if ($linktype eq 'dll') { print CMD "system nt_dll initinstance terminstance\n"; # @@ -838,7 +853,7 @@ if ($o_quiet || $o_silent); if (! $wc_debugger) { # options are exclusive; plus before objects. - $sympath = "${basepath}${version_number}.sym"; + $sympath = "${dllbasepath}${version_number}.sym"; print CMD "option symfile=${sympath}\n"; #XXX: consider default when -d1, allowing use within a production environment } elsif ($wc_debugger eq 'w') { @@ -928,6 +943,8 @@ "# can be result of an incorrect version of cvtres.exe due to dual VC10/VC2012 installations,\n". "# rename 'C:/Program Files (x86)/Microsoft Visual Studio 10/VC/Bin/cvtres.exe' => cvtres_org.exe\n". "#\n"; +# $o_verbose = 0; +# System("which cvtres"); } exit ($ret); }