diff options
90 files changed, 15676 insertions, 1157 deletions
diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.am b/Build/source/texk/texlive/linked_scripts/Makefile.am index 1d6db0fa415..09c2f3b6896 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.am +++ b/Build/source/texk/texlive/linked_scripts/Makefile.am @@ -79,7 +79,9 @@ texmf_shell_scripts = \ pdfxup/pdfxup \ pst-pdf/ps4pdf \ simpdftex/simpdftex \ - texosquery/texosquery \ + texosquery/texosquery.sh \ + texosquery/texosquery-jre5.sh \ + texosquery/texosquery-jre8.sh \ typeoutfileinfo/typeoutfileinfo.sh texmf_other_scripts = \ a2ping/a2ping.pl \ diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.in b/Build/source/texk/texlive/linked_scripts/Makefile.in index 214737306b2..50e0d82452f 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.in +++ b/Build/source/texk/texlive/linked_scripts/Makefile.in @@ -293,7 +293,9 @@ texmf_shell_scripts = \ pdfxup/pdfxup \ pst-pdf/ps4pdf \ simpdftex/simpdftex \ - texosquery/texosquery \ + texosquery/texosquery.sh \ + texosquery/texosquery-jre5.sh \ + texosquery/texosquery-jre8.sh \ typeoutfileinfo/typeoutfileinfo.sh texmf_other_scripts = \ diff --git a/Build/source/texk/texlive/linked_scripts/scripts.lst b/Build/source/texk/texlive/linked_scripts/scripts.lst index c5ce779362c..dd52f5545e1 100644 --- a/Build/source/texk/texlive/linked_scripts/scripts.lst +++ b/Build/source/texk/texlive/linked_scripts/scripts.lst @@ -25,7 +25,9 @@ pdfjam/pdfpun pdfxup/pdfxup pst-pdf/ps4pdf simpdftex/simpdftex -texosquery/texosquery +texosquery/texosquery.sh +texosquery/texosquery-jre5.sh +texosquery/texosquery-jre8.sh typeoutfileinfo/typeoutfileinfo.sh a2ping/a2ping.pl accfonts/mkt1font diff --git a/Build/source/texk/texlive/linked_scripts/texosquery/texosquery-jre5.sh b/Build/source/texk/texlive/linked_scripts/texosquery/texosquery-jre5.sh new file mode 100755 index 00000000000..67a402279b5 --- /dev/null +++ b/Build/source/texk/texlive/linked_scripts/texosquery/texosquery-jre5.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +jarpath=`kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre5.jar` +java -jar "$jarpath" "$@" diff --git a/Build/source/texk/texlive/linked_scripts/texosquery/texosquery-jre8.sh b/Build/source/texk/texlive/linked_scripts/texosquery/texosquery-jre8.sh new file mode 100755 index 00000000000..472c531453a --- /dev/null +++ b/Build/source/texk/texlive/linked_scripts/texosquery/texosquery-jre8.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +jarpath=`kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre8.jar` +java -Djava.locale.providers=CLDR,JRE -jar "$jarpath" "$@" diff --git a/Master/texmf-dist/scripts/texosquery/texosquery b/Build/source/texk/texlive/linked_scripts/texosquery/texosquery.sh index 2f97a43db65..2f97a43db65 100755 --- a/Master/texmf-dist/scripts/texosquery/texosquery +++ b/Build/source/texk/texlive/linked_scripts/texosquery/texosquery.sh diff --git a/Master/bin/amd64-freebsd/texosquery b/Master/bin/amd64-freebsd/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/amd64-freebsd/texosquery +++ b/Master/bin/amd64-freebsd/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/amd64-freebsd/texosquery-jre5 b/Master/bin/amd64-freebsd/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/amd64-freebsd/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/amd64-freebsd/texosquery-jre8 b/Master/bin/amd64-freebsd/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/amd64-freebsd/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/amd64-netbsd/texosquery b/Master/bin/amd64-netbsd/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/amd64-netbsd/texosquery +++ b/Master/bin/amd64-netbsd/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/amd64-netbsd/texosquery-jre5 b/Master/bin/amd64-netbsd/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/amd64-netbsd/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/amd64-netbsd/texosquery-jre8 b/Master/bin/amd64-netbsd/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/amd64-netbsd/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/armel-linux/texosquery b/Master/bin/armel-linux/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/armel-linux/texosquery +++ b/Master/bin/armel-linux/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/armel-linux/texosquery-jre5 b/Master/bin/armel-linux/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/armel-linux/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/armel-linux/texosquery-jre8 b/Master/bin/armel-linux/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/armel-linux/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/armhf-linux/texosquery b/Master/bin/armhf-linux/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/armhf-linux/texosquery +++ b/Master/bin/armhf-linux/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/armhf-linux/texosquery-jre5 b/Master/bin/armhf-linux/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/armhf-linux/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/armhf-linux/texosquery-jre8 b/Master/bin/armhf-linux/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/armhf-linux/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/i386-cygwin/texosquery b/Master/bin/i386-cygwin/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/i386-cygwin/texosquery +++ b/Master/bin/i386-cygwin/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/i386-cygwin/texosquery-jre5 b/Master/bin/i386-cygwin/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/i386-cygwin/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/i386-cygwin/texosquery-jre8 b/Master/bin/i386-cygwin/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/i386-cygwin/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/i386-freebsd/texosquery b/Master/bin/i386-freebsd/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/i386-freebsd/texosquery +++ b/Master/bin/i386-freebsd/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/i386-freebsd/texosquery-jre5 b/Master/bin/i386-freebsd/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/i386-freebsd/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/i386-freebsd/texosquery-jre8 b/Master/bin/i386-freebsd/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/i386-freebsd/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/i386-linux/texosquery b/Master/bin/i386-linux/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/i386-linux/texosquery +++ b/Master/bin/i386-linux/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/i386-linux/texosquery-jre5 b/Master/bin/i386-linux/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/i386-linux/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/i386-linux/texosquery-jre8 b/Master/bin/i386-linux/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/i386-linux/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/i386-netbsd/texosquery b/Master/bin/i386-netbsd/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/i386-netbsd/texosquery +++ b/Master/bin/i386-netbsd/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/i386-netbsd/texosquery-jre5 b/Master/bin/i386-netbsd/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/i386-netbsd/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/i386-netbsd/texosquery-jre8 b/Master/bin/i386-netbsd/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/i386-netbsd/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/i386-solaris/texosquery b/Master/bin/i386-solaris/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/i386-solaris/texosquery +++ b/Master/bin/i386-solaris/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/i386-solaris/texosquery-jre5 b/Master/bin/i386-solaris/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/i386-solaris/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/i386-solaris/texosquery-jre8 b/Master/bin/i386-solaris/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/i386-solaris/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/powerpc-linux/texosquery b/Master/bin/powerpc-linux/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/powerpc-linux/texosquery +++ b/Master/bin/powerpc-linux/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/powerpc-linux/texosquery-jre5 b/Master/bin/powerpc-linux/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/powerpc-linux/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/powerpc-linux/texosquery-jre8 b/Master/bin/powerpc-linux/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/powerpc-linux/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/sparc-solaris/texosquery b/Master/bin/sparc-solaris/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/sparc-solaris/texosquery +++ b/Master/bin/sparc-solaris/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/sparc-solaris/texosquery-jre5 b/Master/bin/sparc-solaris/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/sparc-solaris/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/sparc-solaris/texosquery-jre8 b/Master/bin/sparc-solaris/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/sparc-solaris/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/universal-darwin/texosquery b/Master/bin/universal-darwin/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/universal-darwin/texosquery +++ b/Master/bin/universal-darwin/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/universal-darwin/texosquery-jre5 b/Master/bin/universal-darwin/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/universal-darwin/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/universal-darwin/texosquery-jre8 b/Master/bin/universal-darwin/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/universal-darwin/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/win32/texosquery.exe b/Master/bin/win32/texosquery.exe Binary files differdeleted file mode 100755 index 5777d90a17a..00000000000 --- a/Master/bin/win32/texosquery.exe +++ /dev/null diff --git a/Master/bin/x86_64-cygwin/texosquery b/Master/bin/x86_64-cygwin/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/x86_64-cygwin/texosquery +++ b/Master/bin/x86_64-cygwin/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-cygwin/texosquery-jre5 b/Master/bin/x86_64-cygwin/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/x86_64-cygwin/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-cygwin/texosquery-jre8 b/Master/bin/x86_64-cygwin/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/x86_64-cygwin/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-darwin/texosquery b/Master/bin/x86_64-darwin/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/x86_64-darwin/texosquery +++ b/Master/bin/x86_64-darwin/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-darwin/texosquery-jre5 b/Master/bin/x86_64-darwin/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/x86_64-darwin/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-darwin/texosquery-jre8 b/Master/bin/x86_64-darwin/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/x86_64-darwin/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-linux/texosquery b/Master/bin/x86_64-linux/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/x86_64-linux/texosquery +++ b/Master/bin/x86_64-linux/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-linux/texosquery-jre5 b/Master/bin/x86_64-linux/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/x86_64-linux/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-linux/texosquery-jre8 b/Master/bin/x86_64-linux/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/x86_64-linux/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-solaris/texosquery b/Master/bin/x86_64-solaris/texosquery index 507d22edfe4..2946bce9d51 120000 --- a/Master/bin/x86_64-solaris/texosquery +++ b/Master/bin/x86_64-solaris/texosquery @@ -1 +1 @@ -../../texmf-dist/scripts/texosquery/texosquery
\ No newline at end of file +../../texmf-dist/scripts/texosquery/texosquery.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-solaris/texosquery-jre5 b/Master/bin/x86_64-solaris/texosquery-jre5 new file mode 120000 index 00000000000..5bc0a41e3a3 --- /dev/null +++ b/Master/bin/x86_64-solaris/texosquery-jre5 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre5.sh
\ No newline at end of file diff --git a/Master/bin/x86_64-solaris/texosquery-jre8 b/Master/bin/x86_64-solaris/texosquery-jre8 new file mode 120000 index 00000000000..96251bb6b92 --- /dev/null +++ b/Master/bin/x86_64-solaris/texosquery-jre8 @@ -0,0 +1 @@ +../../texmf-dist/scripts/texosquery/texosquery-jre8.sh
\ No newline at end of file diff --git a/Master/texmf-dist/doc/support/texosquery/CHANGES b/Master/texmf-dist/doc/support/texosquery/CHANGES index 86ae40b460c..ba18c85d3d5 100644 --- a/Master/texmf-dist/doc/support/texosquery/CHANGES +++ b/Master/texmf-dist/doc/support/texosquery/CHANGES @@ -1,3 +1,109 @@ +1.2 (2017/03/23): + + * Now has three .jar files depending on the Java installation: + + - texosquery-jre8.jar + + Full application. May be used with the CLDR locale provider + (Unicode Consortium's Common Locale Data Repository). + Requires at least Java 8 (use with + java -Djava.locale.providers=CLDR,JRE or + add "java.locale.providers=CLDR,JRE" to the + JAVA_TOOLS_OPTIONS environment variable to access the CLDR) + + - texosquery.jar + + The default version of the application. Can't be used with + CLDR. Less locale support. Requires at least Java 7. + + - texosquery-jre5.jar + + Cut-down version of the application with significantly less + locale support. Provided for old systems that can't upgrade, + but not recommended. (Use of Java 5 or 6 is deprecated.) + Requires at least Java 5. + + * Corresponding scripts that run the appropriate .jar file + are bundled in texosquery.dtx and extracted using: + + tex texosquery.ins + + - Unix-like (run `chmod +x texosquery*.sh`): + + texosquery-jre8.sh : runs texosquery-jre8.jar with + -Djava.locale.providers=CLDR,JRE + + texosquery.sh : runs texosquery.jar + + texosquery-jre5.sh : runs texosquery-jre5.jar + + (I recommend the removal of the '.sh' extension + for more convenient invocation.) + + - Windows (rename texosquery*.batch to texosquery*.bat): + + texosquery-jre8.bat : runs texosquery-jre8.jar with + -Djava.locale.providers=CLDR,JRE + + texosquery.bat : runs texosquery.jar + + texosquery-jre5.bat : runs texosquery-jre5.jar + + You can edit these files if additional Java settings + are required (e.g. -Dfile.encoding=UTF-8). Alternatively + set the JAVA_TOOLS_OPTIONS environment variable. + + * New texosquery.cfg configuration file. Edit the definition + of \TeXOSInvokerName to indicate which application you + need to use. For example, if Java 8 is installed: + + \def\TeXOSInvokerName{texosquery-jre8} + + See the installation section of the manual. + + * New command line switches: + + Actions: + + --bcp47 / -b + --codeset-lcs / -C + --locale-data / -D + --numeric / -N + --date-time / -M + --time-zones / -Z + --list-dir / -ld + --list-regular / -lr + --filterlist-dir / -fd + --filterlist-regular / -fr + --walk / -w + + Options: + + --debug [⟨n⟩] + --nodebug + --compatible ⟨n⟩ / -compat ⟨n⟩ + + * Actions --list (-i) and --filterlist (-f) now have an + optional argument to indicate the sort order. + + * When accessing file information, the TEXMF openin_any + setting is first checked to determine if read access is + permitted. + + * Returned values now include some shorthand markup that's + internally converted when read in by \TeXOSQuery. For + example "texosquery -n" now returns + + \pdfd \fcln 20161113161156\fpls 00\fcsq 00\fcsq + + instead of + + D:20161113161156+00'00' + + To restore the original behaviour use --compatible 1 + + See the manual for further details. + 1.1 (2016-07-14): * texosquery.jar: diff --git a/Master/texmf-dist/doc/support/texosquery/Manifest.txt b/Master/texmf-dist/doc/support/texosquery/Manifest.txt deleted file mode 100644 index 92d656204b2..00000000000 --- a/Master/texmf-dist/doc/support/texosquery/Manifest.txt +++ /dev/null @@ -1,2 +0,0 @@ -Main-Class: com/dickimawbooks/texosquery/TeXOSQuery -Class-Path: . diff --git a/Master/texmf-dist/doc/support/texosquery/README.md b/Master/texmf-dist/doc/support/texosquery/README.md index 49b390d55a3..bad3733503a 100644 --- a/Master/texmf-dist/doc/support/texosquery/README.md +++ b/Master/texmf-dist/doc/support/texosquery/README.md @@ -4,7 +4,8 @@ TeX's shell escape mechanism. The application can query the following: - - locale and codeset + - locale information + - default file encoding - current working directory - user home directory - temporary directory @@ -24,42 +25,162 @@ The application can query the following: All paths use a forward slash as directory divider so results can be used, for example, in commands like `\includegraphics`. -There are files provided for easy access in TeX documents: +There are files provided for easy access in (La)TeX documents: - `texosquery.tex` : generic TeX code - `texosquery.sty` : LaTeX package -This provides commands to run `texosquery` using TeX's shell -escape mechanism and capture the result in a control sequence. -The category code of most of TeX's default special characters -(and some other potentially problematic characters) is temporarily -changed to 12 while reading the result. +This provides the command `\TeXOSQuery` to run `texosquery` using +TeX's shell escape mechanism and capture the result in a control +sequence. The category code of most of TeX's default special +characters (and some other potentially problematic characters) is +temporarily changed to 12 while reading the result. Some of the +`texosquery` output contains short markup commands (such as `\wrp`) +which are internally converted within `\TeXOSQuery`. ## Installation -The actual Java application is in `texosquery.jar`. -The `.tex` and `.sty` files can be extracted from `texosquery.dtx` -using `tex texosquery.ins`. In the following, replace TEXMF with the -path to your TEXMF directory. - - - Move `texosquery.tex` to `TEXMF/tex/generic/texosquery/` - - Move `texosquery.sty` to `TEXMF/tex/latex/texosquery/` - - Move `texosquery.pdf` to `TEXMF/doc/generic/texosquery/` - - Move `texosquery.jar` to `TEXMF/scripts/texosquery/` - -Unix-like users: move the bash script `texosquery` to somewhere on -your path. - -Windows users: TeX Live's generic wrapper should be able to locate -the `texosquery.jar` file, but if not or you're not using TL, -then (untested) create a file called `texosquery.bat` that contains: -```dos -@ECHO OFF -FOR /F %%I IN ('kpsewhich --progname=texosquery --format=texmfscripts texosquery.jar') DO SET JARPATH=%%I -START javaw -jar "%JARPATH%\texosquery.jar" %* +Installation is best done using your TeX package manager. +Manual installation instructions are described below. +For more detail, see the documentation. + +### Compiling the Documentation + +To compile the documentation: +```bash +pdflatex texosquery.dtx +makeglossaries texosquery +makeindex -s gglo.ist -t texosquery.glg -o texosquery.gls texosquery.glo +pdflatex texosquery.dtx +makeindex -s gind.ist texosquery.idx +pdflatex texosquery.dtx +pdflatex texosquery.dtx ``` -(or skip the `FOR` line and replace `%JARPATH%` with the full path name to -`texosquery.jar`.) Put this file on your system's path. + +### Extracting the Files + +Except for the `.jar` files, the `texosquery` files are all +bundled inside `texosquery.dtx` with the extraction commands +provided in `texosquery.ins`. To extract all the files do: +```bash +tex texosquery.ins +``` + +The `.sh` files are bash scripts for Unix-like users. These will +need to be set to executable using `chmod`. I recommend +that you also remove the `.sh` extension. Windows users can +deleted these files. + +The `.batch` files are batch scripts for Windows users. Unix-like +users can delete these files. These files are given the extension +`.batch` as TeX on Windows doesn't allow the creation of `.bat` +files. The extension will need to be changed to `.bat` after the +files have been extracted. + +### Installing the Application + +In the following, replace _TEXMF_ with the path to your TEXMF directory. +You can find your home TEXMF directory using +```bash +kpsewhich -var-value=TEXMFHOME +``` + +There are now three Java applications provided by this package: + + - `texosquery.jar` (requires at least Java 7) + - `texosquery-jre8.jar` (requires at least Java 8) + - `texosquery-jre5.jar` (requires at least Java 5) + +There are corresponding bash scripts for Unix-like users (the `.sh` +extension added by `texosquery.ins` should be removed and the files +made executable): + + - `texosquery` + - `texosquery-jre8` + - `texosquery-jre5` + +There are also corresponding batch scripts for Windows users (the `.batch` +extension created by the `.ins` file should be changed to `.bat`): + + - `texosquery.bat` + - `texosquery-jre8.bat` + - `texosquery-jre5.bat` + +Each script uses `kpsewhich` to find the corresponding `.jar` file +and runs it. + +Put the `.jar` files in _TEXMF_`/scripts/texosquery/` and the +bash or `.bat` files somewhere on your path. You may or may not need +to refresh the TeX database. + +To test the installation, run +```bash +texosquery -v +``` +in the command prompt or terminal. (Also try with `texosquery-jre8` +and `texosquery-jre5`.) + +If successful, it should show the version number. + +### Installing the TeX Code + +The `.tex`, `.cfg` and `.sty` files should all be extracted from `texosquery.dtx` +with `tex texosquery.ins` as described above. + + - Move `texosquery.tex` to _TEXMF_`/tex/generic/texosquery/` + - Move `texosquery.cfg` to _TEXMF_`/tex/generic/texosquery/` + - Move `texosquery.sty` to _TEXMF_`/tex/latex/texosquery/` + - Move `texosquery.pdf` to _TEXMF_`/doc/generic/texosquery/` + +The `texosquery.cfg` file allows you to specify which application you +want to use. First check which version of the Java Runtime +Environment (JRE) you have installed: +```bash +java -version +``` +This should display the version information. (For example, `"1.8.0_92"`) + +If the version number starts with `1.8` (“Java 8”), then you can use `texosquery-jre8.jar`. +This is the full application. You can use `texosquery` or +`texosquery-jre5` as well, but there's less locale support with them. +The `texosquery-jre8` bash script and `texosquery-jre8.bat` batch script invokes Java with +`-Djava.locale.providers=CLDR,JRE`. + +If Windows users have simply been supplied with an executable versions +of the `texosquery-jre8.jar` file (`texosquery-jre8.exe`) then you'll have to set the +`JAVA_TOOL_OPTIONS` environment variable instead. + +This `java.locale.providers` setting allows Java to access locale +information from the [Unicode Common Locale Data Repository +(CLDR)](http://cldr.unicode.org/) installed on their system. The +pending Java 9 should include this by default, so this will only be +relevant to Java 8. Earlier versions of Java (7 or below) don't have +this option, which limits the locale support to that which is +natively provided by the JRE. + +If the version information starts with `1.7` (“Java 7”), then you can use +`texosquery.jar`. This is the default application and provides most +of the functions of the full application, but there's less locale support. +You can also use the even more limited `texosquery-jre5`, but you can't use +`texosquery-jre8`, so you can't take advantage of the CLDR. + +If the version information starts with `1.5` (“Java 5”) or `1.6` +(“Java 6”), then you can _only_ use `texosquery-jre5`. The locale +support is significantly reduced in this case and there's no support +for language scripts. Note that these versions of Java are +deprecated. + +Once you have determined which application you want to use, edit the +`texosquery.cfg` so that `\TeXOSInvokerName` is defined to the appropriate invocation. For example, with Java 8: +```tex +\def\TeXOSInvokerName{texosquery-jre8} +``` +or with Java 5 or 6: +```tex +\def\TeXOSInvokerName{texosquery-jre5} +``` +(bash users will have to add the `.sh` extension if it hasn't +been removed, as per the above instructions.) ## Examples: @@ -69,8 +190,11 @@ Plain TeX: % arara: pdftex: {shell: on} \input texosquery +\TeXOSQuery{\result}{-b} +IEFT BCP 47 language tag: \result. + \TeXOSQueryLocale{\result} -locale: \result. +POSIX locale: \result. \TeXOSQueryCwd{\result} cwd: {\tt \result}. @@ -98,8 +222,11 @@ LaTeX: \begin{document} +\TeXOSQuery{\result}{-b} +IEFT BCP 47 language tag: \result. + \TeXOSQueryLocale{\result} -locale: \result. +POSIX locale: \result. \TeXOSQueryCwd{\result} cwd: \texttt{\result}. @@ -125,39 +252,39 @@ All jpg and png files in current directory: For a full list of available commands, see the documentation (`texosquery.pdf`). -You can omit `texosquery.tex` and directly use `texosquery` -in TeX's shell escape, but take care of special characters -occurring in the result or if double-quotes occur in -`\jobname`. - ## Source code -The `.tex` and `.sty` files and documentation are contained in -`texosquery.dtx`. To compile the documentation: -```bash -pdflatex texosquery.dtx -makeindex -s gglo.ist -t texosquery.glg -o texosquery.gls texosquery.glo -makeindex -s gind.ist texosquery.idx -pdflatex texosquery.dtx -pdflatex texosquery.dtx -``` - -The Java source is in `TeXOSQuery.java` and the manifest for the -`.jar` file is `Manifest.txt`. Assuming the following directory -structure: +The Java source is in the `.java` files and the manifest for each +`.jar` file is `Manifest*.txt` (`Manifest-jre8.txt` for `texosquery-jre8` etc). +Assuming the following directory structure: ``` java/TeXOSQuery.java -java/Manifest.txt +java/TeXOSQueryJRE5.java +java/TeXOSQueryJRE7.java +java/TeXOSQueryJRE8.java +java/QueryAction.java +java/QueryActionType.java +java/FileSortType.java +java/FileSortComparator.java +java/FileListType.java +java/FileWalkVisitor.java +java/Manifest-jre5.txt +java/Manifest-jre7.txt +java/Manifest-jre8.txt classes/com/dickimawbooks/texosquery/ ``` -Then to create `texosquery.jar`, do: +Then to create `texosquery-jre8.jar`, do (for JDK version 1.8): ```bash cd java -javac -d ../classes TeXOSQuery.java +javac -d ../classes TeXOSQuery.java QueryAction.java QueryActionType.java TeXOSQueryJRE8.java FileSortType.java FileSortComparator.java FileListType.java FileWalkVisitor.java cd ../classes -jar cmf ../java/Manifest.txt ../texosquery.jar com/dickimawbooks/texosquery/*.class +jar cmf ../java/Manifest-jre8.txt ../texosquery-jre8.jar com/dickimawbooks/texosquery/*.class ``` +Similarly for the other `.jar` files, replacing `8` with `7` or `5`. +(The Java 7 version should really be `texosquery-jre7.jar`, but is +simply named `texosquery.jar` in the distribution for backward compatibility reasons. If you compile the code, the `.jar` name is your choice.) + --- Source on GitHub: https://github.com/nlct/texosquery diff --git a/Master/texmf-dist/doc/support/texosquery/texosquery.pdf b/Master/texmf-dist/doc/support/texosquery/texosquery.pdf Binary files differindex 7471094188a..a1b3862d24f 100644 --- a/Master/texmf-dist/doc/support/texosquery/texosquery.pdf +++ b/Master/texmf-dist/doc/support/texosquery/texosquery.pdf diff --git a/Master/texmf-dist/scripts/texosquery/texosquery-jre5.jar b/Master/texmf-dist/scripts/texosquery/texosquery-jre5.jar Binary files differnew file mode 100755 index 00000000000..63d0fc4f9b3 --- /dev/null +++ b/Master/texmf-dist/scripts/texosquery/texosquery-jre5.jar diff --git a/Master/texmf-dist/scripts/texosquery/texosquery-jre5.sh b/Master/texmf-dist/scripts/texosquery/texosquery-jre5.sh new file mode 100755 index 00000000000..67a402279b5 --- /dev/null +++ b/Master/texmf-dist/scripts/texosquery/texosquery-jre5.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +jarpath=`kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre5.jar` +java -jar "$jarpath" "$@" diff --git a/Master/texmf-dist/scripts/texosquery/texosquery-jre8.jar b/Master/texmf-dist/scripts/texosquery/texosquery-jre8.jar Binary files differnew file mode 100755 index 00000000000..06f3b342b51 --- /dev/null +++ b/Master/texmf-dist/scripts/texosquery/texosquery-jre8.jar diff --git a/Master/texmf-dist/scripts/texosquery/texosquery-jre8.sh b/Master/texmf-dist/scripts/texosquery/texosquery-jre8.sh new file mode 100755 index 00000000000..472c531453a --- /dev/null +++ b/Master/texmf-dist/scripts/texosquery/texosquery-jre8.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +jarpath=`kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre8.jar` +java -Djava.locale.providers=CLDR,JRE -jar "$jarpath" "$@" diff --git a/Master/texmf-dist/scripts/texosquery/texosquery.jar b/Master/texmf-dist/scripts/texosquery/texosquery.jar Binary files differindex 84f4c1140a2..feb800910ab 100755 --- a/Master/texmf-dist/scripts/texosquery/texosquery.jar +++ b/Master/texmf-dist/scripts/texosquery/texosquery.jar diff --git a/Master/texmf-dist/scripts/texosquery/texosquery.sh b/Master/texmf-dist/scripts/texosquery/texosquery.sh new file mode 100755 index 00000000000..2f97a43db65 --- /dev/null +++ b/Master/texmf-dist/scripts/texosquery/texosquery.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +jarpath=`kpsewhich --progname=texosquery --format=texmfscripts texosquery.jar` +java -jar "$jarpath" "$@" diff --git a/Master/texmf-dist/source/support/texosquery/TeXOSQuery.java b/Master/texmf-dist/source/support/texosquery/TeXOSQuery.java deleted file mode 100644 index dca8fa7c32d..00000000000 --- a/Master/texmf-dist/source/support/texosquery/TeXOSQuery.java +++ /dev/null @@ -1,767 +0,0 @@ -package com.dickimawbooks.texosquery; - -import java.io.BufferedReader; -import java.util.Locale; -import java.util.Calendar; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -/** - * Main class. - * @author Nicola Talbot - * @version 1.1 - * @since 1.0 - */ -public class TeXOSQuery { - - private static final String VERSION_NUMBER = "1.1"; - private static final String VERSION_DATE = "2016-07-14"; - private static final char BACKSLASH = '\\'; - private static final char FORWARDSLASH = '/'; - private static final long ZERO = 0L; - - /** - * Escapes hash from input string. - * @param string Input string. - * @return String with hash escaped. - */ - private static String escapeHash(String string) { - return string.replaceAll("#", "\\\\#"); - } - - /** - * Gets a string representation of the provided locale. - * @param locale The provided locale. - * @return String representation. - */ - private static String getLocale(Locale locale) { - return getLocale(locale, false); - } - - /** - * Gets a string representation of the provided locale, converting the code - * set if possible. - * @param locale The provided locale. - * @param convertCodeset Boolean value to convert the code set. - * @return String representation. - */ - private static String getLocale(Locale locale, boolean convertCodeset) { - - String identifier = ""; - - if (locale != null) { - - String language = locale.getLanguage(); - - if (language != null) { - identifier = language; - } - - String country = locale.getCountry(); - - if ((country != null) && - (!"".equals(country))) { - - if ("".equals(identifier)) { - identifier = country; - } else { - identifier = identifier.concat("-").concat(country); - } - - } - - String codeset = System.getProperty("file.encoding", "UTF-8"); - - if ((codeset != null) && - (!"".equals(codeset))) { - - if (convertCodeset) { - codeset = codeset.toLowerCase().replaceAll("-", ""); - } - - identifier = identifier.concat(".").concat(codeset); - } - - String script = locale.getScript(); - - if ((script != null) && - (!"".equals(script))) { - identifier = identifier.concat("@").concat(escapeHash(script)); - } - - } - - return identifier; - } - - /** - * Gets the OS name. - * @return The OS name as string. - */ - private static String getOSname() { - return getSystemProperty("os.name"); - } - - /** - * Gets the OS architecture. - * @return The OS architecture as string. - */ - private static String getOSarch() { - return getSystemProperty("os.arch"); - } - - /** - * Gets the OS version. - * @return The OS version as string. - */ - private static String getOSversion() { - return getSystemProperty("os.version"); - } - - /** - * Gets the user home. - * @return The user home as string. - */ - private static String getUserHome() { - return getSystemProperty("user.home"); - } - - /* - * - */ - /** - * Converts the filename string to TeX path. Since this is designed to work - * within TeX, backslashes in paths need to be replaced with forward - * slashes. - * @param filename The filename string. - * @return TeX path. - */ - private static String toTeXPath(String filename) { - - String path = ""; - - if (filename != null) { - if (File.separatorChar == BACKSLASH) { - filename = filename.replaceAll("\\\\", "/"); - } - path = escapeHash(filename); - } - - return path; - } - - /** - * Converts the TeX path back to the original representation. - * @param filename The filename string. - * @return The original representation. - */ - private static String fromTeXPath(String filename) { - - if (File.separatorChar != FORWARDSLASH) { - filename = filename.replaceAll("/", File.separator); - } - - return filename; - } - - /** - * Gets a file representation from a filename string. - * @param filename Filename string. - * @return File representation - */ - private static File fileFromTeXPath(String filename) { - - filename = fromTeXPath(filename); - File file = new File(filename); - - if (!file.exists() && file.getParent() == null) { - - try { - Process process = new ProcessBuilder( - "kpsewhich", - filename - ).start(); - - if (process.waitFor() == 0) { - - InputStream stream = process.getInputStream(); - - if (stream != null) { - - BufferedReader reader = new BufferedReader( - new InputStreamReader(stream) - ); - - String line = reader.readLine(); - reader.close(); - - if ((line != null) && (!"".equals(line))) { - file = new File(fromTeXPath(line)); - } - } - } - } catch (IOException exception1) { - // quack quack - } catch (InterruptedException exception2) { - // quack quack - } - } - - return file; - } - - /** - * Gets the current working directory. - * @return The current working directory. - */ - private static String getCwd() { - return getSystemProperty("user.dir"); - } - - /** - * Gets the temporary directory. - * @return Temporary directory. - */ - private static String getTmpDir() { - return getSystemProperty("java.io.tmpdir"); - } - - /** - * Gets the current date. - * @return The current date. - */ - private static String pdfnow() { - return pdfDate(Calendar.getInstance()); - } - - /** - * Gets the date in an specific format. - * @param calendar A calendar object. - * @return Date in an specific format. - */ - private static String pdfDate(Calendar calendar) { - String tz = String.format("%1$tz", calendar); - return String.format( - "D:%1$tY%1$tm%1td%1$tH%1$tM%1$tS%2$s'%3$s'", - calendar, - tz.substring(0, 3), - tz.substring(3) - ); - } - - /** - * Gets the date from a file. - * @param file File. - * @return The date in an specific format. - */ - private static String pdfDate(File file) { - - String date = ""; - - try { - long millisecs = file.lastModified(); - - if (millisecs > ZERO) { - - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(millisecs); - date = pdfDate(calendar); - - } - } catch (SecurityException exception) { - // quack quack - } - - return date; - } - - /** - * Gets the file length. - * @param file The file. - * @return The length as a string. - */ - private static String getFileLength(File file) { - - String output = ""; - - try { - long length = file.length(); - - if (length > ZERO) { - output = String.format("%d", length); - } - } catch (SecurityException exception) { - // quack quack - } - - return output; - } - - /** - * Gets the list of files from a directory. - * @param separator Separator. - * @param directory Directory. - * @return List as a string. - */ - private static String getFileList(String separator, File directory) { - - StringBuilder builder = new StringBuilder(); - - if (directory.isDirectory()) { - - try { - - String[] list = directory.list(); - if (list != null) { - - for (int i = 0; i < list.length; i++) { - - if (i > 0) { - builder.append(separator); - } - - builder.append(escapeHash(list[i])); - - } - } - - } catch (SecurityException exception) { - // quack quack - } - } - - return builder.toString(); - } - - /** - * Gets a filtered list of files from directory. - * @param separator Separator. - * @param regex Regular expression. - * @param directory Directory. - * @return Filtered list as string. - */ - private static String getFilterFileList(String separator, - final String regex, File directory) { - - StringBuilder builder = new StringBuilder(); - - if (directory.isDirectory()) { - - if ((regex == null) || ("".equals(regex))) { - builder.append(getFileList(separator, directory)); - } - else { - try { - String[] list = directory.list(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.matches(regex); - } - }); - - if (list != null) { - - for (int i = 0; i < list.length; i++) { - - if (i > 0) { - builder.append(separator); - } - - builder.append(escapeHash(list[i])); - } - - } - } catch (SecurityException exception) { - // quack quack - } - } - } - - return builder.toString(); - } - - /** - * Gets the file URI. - * @param file The file. - * @return The URI. - */ - private static String fileURI(File file) { - - String uri = ""; - - if (file.exists()) { - try { - uri = file.toURI().toString(); - } catch (SecurityException exception) { - // quack quack - } - } - - return uri; - } - - /** - * Gets the file path. - * @param file The file. - * @return The path. - */ - private static String filePath(File file) { - - String path = ""; - - if (file.exists()) { - try { - path = toTeXPath(file.getCanonicalPath()); - } catch (SecurityException exception1) { - // quack quack - } catch (IOException exception2) { - // quack quack - } - } - - return path; - } - - /** - * Gets the path for the file's parent. - * @param file The file. - * @return The path. - */ - private static String parentPath(File file) { - - String path = ""; - - if (file.exists()) { - try { - path = toTeXPath(file.getCanonicalFile().getParent()); - } catch (SecurityException exception1) { - // quack quack - } catch (IOException exception2) { - // quack quack - } - } - - return path; - } - - /** - * Prints the syntax usage. - */ - private static void syntax() { - System.out.println("Usage: texosquery <option>..."); - - System.out.println(); - System.out.println("Cross-platform OS query application"); - System.out.println("for use with TeX's shell escape."); - System.out.println(); - System.out.println("Each query displays the result in a single line."); - System.out.println("A blank line is printed if the requested"); - System.out.println("information is unavailable."); - - System.out.println(); - System.out.println("-h or --help\tDisplay this help message and exit"); - System.out.println("-v or --version\tDisplay version information and exit"); - System.out.println(); - System.out.println("General:"); - System.out.println(); - System.out.println("-L or --locale\t\tDisplay locale information"); - System.out.println("-l or --locale-lcs\tAs --locale but codeset "); - System.out.println("\t\t\tin lowercase with hyphens stripped"); - System.out.println("-c or --cwd\t\tDisplay current working directory"); - System.out.println("-m or --userhome\tDisplay user's home directory"); - System.out.println("-t or --tmpdir\t\tDisplay temporary directory"); - System.out.println("-o or --osname\t\tDisplay OS name"); - System.out.println("-r or --osversion\tDisplay OS version"); - System.out.println("-a or --osarch\t\tDisplay OS architecture"); - System.out.println("-n or --pdfnow\t\tDisplay current date-time in PDF format"); - - System.out.println(); - System.out.println("File Queries:"); - System.out.println(); - System.out.println("Paths should use / for the directory divider."); - System.out.println(); - System.out.println("-d <file> or --pdfdate <file>"); - System.out.println(" Display date stamp of <file> in PDF format"); - System.out.println(); - System.out.println("-s <file> or --filesize <file>"); - System.out.println(" Display size of <file> in bytes"); - System.out.println(); - System.out.println("-i <sep> <dir> or --list <sep> <dir>"); - System.out.println(" Display list of all files in <dir> separated by <sep>"); - System.out.println(); - System.out.println("-f <sep> <regex> <dir> or --filterlist <sep> <regex> <dir>"); - System.out.println(" Display list of files in <dir> that match <regex> separated by <sep>"); - System.out.println(); - System.out.println("-u <file> or --uri <file>"); - System.out.println(" Display the URI of <file>"); - System.out.println(); - System.out.println("-p <file> or --path <file>"); - System.out.println(" Display the canonical path of <file>"); - System.out.println(); - System.out.println("-e <file> or --dirname <file>"); - System.out.println(" Display the canonical path of the parent of <file>"); - } - - /** - * Prints the version. - */ - private static void version() { - System.out.println(String.format("texosquery %s %s", VERSION_NUMBER, - VERSION_DATE)); - System.out.println("Copyright 2016 Nicola Talbot"); - System.out.println("License LPPL 1.3+ (http://ctan.org/license/lppl1.3)"); - } - - /** - * Prints the information with optional grouping. - * @param group Determines whether to add grouping - * @param info Information to print - */ - private static void print(boolean group, String info) - { - if (group) - { - System.out.println(String.format("{%s}", info)); - } - else - { - System.out.println(info); - } - } - - /** - * Main method. - * @param args Command line arguments. - */ - public static void main(String[] args) { - if (args.length == 0) { - System.err.println("Missing argument. Try texosquery --help"); - System.exit(1); - } - - boolean group = false; - - for (int i = 0, n=args.length-1; i < args.length; i++) { - if (args[i].equals("-L") || args[i].equals("--locale")) { - if (i < n) group = true; - - print(group, getLocale(Locale.getDefault())); - } else if (args[i].equals("-l") || args[i].equals("--locale-lcs")) { - if (i < n) group = true; - - print(group, getLocale(Locale.getDefault(), true)); - } else if (args[i].equals("-c") || args[i].equals("--cwd")) { - if (i < n) group = true; - - print(group, getCwd()); - } else if (args[i].equals("-m") || args[i].equals("--userhome")) { - if (i < n) group = true; - - print(group, getUserHome()); - } else if (args[i].equals("-t") || args[i].equals("--tmpdir")) { - if (i < n) group = true; - - print(group, getTmpDir()); - } else if (args[i].equals("-r") || args[i].equals("--osversion")) { - if (i < n) group = true; - - print(group, getOSversion()); - } else if (args[i].equals("-a") || args[i].equals("--osarch")) { - if (i < n) group = true; - - print(group, getOSarch()); - } else if (args[i].equals("-o") || args[i].equals("--osname")) { - if (i < n) group = true; - - print(group, getOSname()); - } else if (args[i].equals("-n") || args[i].equals("--pdfnow")) { - if (i < n) group = true; - - print(group, pdfnow()); - } else if (args[i].equals("-d") || args[i].equals("--pdfdate")) { - i++; - - if (i >= args.length) { - System.err.println( - String.format("filename expected after %s", args[i - 1])); - System.exit(1); - } - - if (i < n) group = true; - - if ("".equals(args[i])) { - print(group, ""); - } else { - print(group, pdfDate(fileFromTeXPath(args[i]))); - } - } else if (args[i].equals("-s") || args[i].equals("--filesize")) { - i++; - - if (i >= args.length) { - System.err.println( - String.format("filename expected after %s", args[i - 1])); - System.exit(1); - } - - if (i < n) group = true; - - if ("".equals(args[i])) { - print(group, ""); - } else { - print(group, getFileLength(fileFromTeXPath(args[i]))); - } - } else if (args[i].equals("-i") || args[i].equals("--list")) { - i++; - - if (i >= args.length) { - System.err.println( - String.format("separator and directory name expected after %s", - args[i - 1])); - System.exit(1); - } - - i++; - - if (i >= args.length) { - System.err.println( - String.format("directory name expected after %s %s", - args[i - 2], args[i - 1])); - System.exit(1); - } - - if (i < n) group = true; - - if ("".equals(args[i])) { - print(group, ""); - } else { - print(group, getFileList(args[i - 1], - new File(fromTeXPath(args[i])))); - } - } else if (args[i].equals("-f") || args[i].equals("--filterlist")) { - i++; - - if (i >= args.length) { - System.err.println( - String.format( - "separator, regex and directory name expected after %s", - args[i - 1])); - System.exit(1); - } - - i++; - - if (i >= args.length) { - System.err.println( - String.format("regex and directory name expected after %s %s", - args[i - 2], args[i - 1])); - System.exit(1); - } - - i++; - - if (i >= args.length) { - System.err.println( - String.format("directory name expected after %s %s", - args[i - 3], args[i - 2], args[i - 1])); - System.exit(1); - } - - if (i < n) group = true; - - if ("".equals(args[i])) { - print(group, ""); - } else { - print(group, getFilterFileList( - args[i - 2], args[i - 1], new File(fromTeXPath(args[i])))); - } - } else if (args[i].equals("-u") || args[i].equals("--uri")) { - i++; - - if (i >= args.length) { - System.err.println( - String.format("filename expected after %s", args[i - 1])); - System.exit(1); - } - - if (i < n) group = true; - - if ("".equals(args[i])) { - print(group, ""); - } else { - print(group, fileURI(fileFromTeXPath(args[i]))); - } - } - else if (args[i].equals("-p") || args[i].equals("--path")) - { - i++; - - if (i >= args.length) { - System.err.println( - String.format("filename expected after %s", args[i - 1])); - System.exit(1); - } - - if (i < n) group = true; - - if ("".equals(args[i])) { - print(group, ""); - } else { - print(group, filePath(fileFromTeXPath(args[i]))); - } - } - else if (args[i].equals("-e") || args[i].equals("--dirname")) - { - i++; - - if (i >= args.length) { - System.err.println( - String.format("filename expected after %s", args[i - 1])); - System.exit(1); - } - - if (i < n) group = true; - - if ("".equals(args[i])) { - print(group, ""); - } else { - print(group, - parentPath(fileFromTeXPath(args[i]))); - } - } - else if (args[i].equals("-h") || args[i].equals("--help")) { - syntax(); - System.exit(0); - } else if (args[i].equals("-v") || args[i].equals("--version")) { - version(); - System.exit(0); - } else { - System.err.println(String.format("unknown option '%s'", args[i])); - System.exit(1); - } - } - } - - /** - * Gets the system property. - * @param key Key. - * @return Value; - */ - private static String getSystemProperty(String key) { - - String value = ""; - - try { - value = System.getProperty(key, ""); - } - catch (SecurityException exception) { - // quack quack - } - - return value; - - } - -} diff --git a/Master/texmf-dist/source/support/texosquery/java/FileListType.java b/Master/texmf-dist/source/support/texosquery/java/FileListType.java new file mode 100644 index 00000000000..46d4732fc4d --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/FileListType.java @@ -0,0 +1,24 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +/** + * Indicates the type of file to be included in listings. + * @since 1.2 + */ +public enum FileListType +{ + FILE_LIST_ANY, FILE_LIST_DIRECTORIES_ONLY, + FILE_LIST_REGULAR_FILES_ONLY +} + diff --git a/Master/texmf-dist/source/support/texosquery/java/FilePathSortComparator.java b/Master/texmf-dist/source/support/texosquery/java/FilePathSortComparator.java new file mode 100644 index 00000000000..436a23867b9 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/FilePathSortComparator.java @@ -0,0 +1,186 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +import java.util.Comparator; +import java.nio.file.Path; +import java.nio.file.Files; +import java.nio.file.attribute.FileTime; + +/** + * Used to compare two paths according to the given sort type. + * This uses the java.nio.file library, which was introduced in Java 7, + * so this isn't available for the JRE5 version. + * @since 1.2 + */ +public class FilePathSortComparator implements Comparator<Path> +{ + /** + * Creates a new comparator for ordering path listings. + * @param sortType the way in which the files should be ordered + */ + public FilePathSortComparator(FileSortType sortType) + { + this.sortType = sortType; + } + + /** + * Compares two paths according to this object's sort type. + * @param path1 the first path + * @param path2 the second path + * @return -1 if path1 is considered less than path2, 0 if both are the same + * or +1 if path2 is greater than path1, according to the sort + * criteria + */ + @Override + public int compare(Path path1, Path path2) + { + int idx=-1; + int result=0; + long date1=0L; + long date2=0L; + long size1=0L; + long size2=0L; + String ext1=""; + String ext2=""; + FileTime time1=null; + FileTime time2=null; + + String name1 = path1.toString(); + String name2 = path2.toString(); + + String basename1 = path1.getName(path1.getNameCount()-1).toString(); + String basename2 = path2.getName(path2.getNameCount()-1).toString(); + + switch (sortType) + { + case FILE_SORT_NAME_ASCENDING: + return name1.compareTo(name2); + case FILE_SORT_NAME_DESCENDING: + return name2.compareTo(name1); + case FILE_SORT_NAME_NOCASE_ASCENDING: + return name1.compareToIgnoreCase(name2); + case FILE_SORT_NAME_NOCASE_DESCENDING: + return name2.compareToIgnoreCase(name1); + case FILE_SORT_EXT_ASCENDING: + + idx = basename1.lastIndexOf("."); + + ext1 = idx > -1 ? basename1.substring(idx+1) : ""; + + idx = basename2.lastIndexOf("."); + + ext2 = idx > -1 ? basename2.substring(idx+1) : ""; + + result = ext1.compareTo(ext2); + + // If the extensions are the same, compare paths instead + + return result == 0 ? name1.compareTo(name2) : result; + + case FILE_SORT_EXT_DESCENDING: + + idx = basename1.lastIndexOf("."); + + ext1 = idx > -1 ? basename1.substring(idx+1) : ""; + + idx = basename2.lastIndexOf("."); + + ext2 = idx > -1 ? basename2.substring(idx+1) : ""; + + result = ext2.compareTo(ext1); + + return result == 0 ? name2.compareTo(name1) : result; + + case FILE_SORT_DATE_ASCENDING: + + try + { + time1 = Files.getLastModifiedTime(path1); + } + catch (Exception e) + { + // IO error or security manager has prohibited access + return 1; + } + + try + { + time2 = Files.getLastModifiedTime(path2); + } + catch (Exception e) + { + // IO error or security manager has prohibited access + return -1; + } + + return time1.compareTo(time2); + + case FILE_SORT_DATE_DESCENDING: + + try + { + time1 = Files.getLastModifiedTime(path1); + } + catch (Exception e) + { + // IO error or security manager has prohibited access + return -1; + } + + try + { + time2 = Files.getLastModifiedTime(path2); + } + catch (Exception e) + { + // IO error or security manager has prohibited access + return 1; + } + + return time2.compareTo(time1); + + case FILE_SORT_SIZE_ASCENDING: + + try + { + size1 = Files.size(path1); + size2 = Files.size(path2); + } + catch (Exception e) + {// file missing or no read access or for some other + // reason the file size can't be obtained. + } + + return size1 == size2 ? 0 : (size1 < size2 ? -1 : 0); + + case FILE_SORT_SIZE_DESCENDING: + + try + { + size1 = Files.size(path1); + size2 = Files.size(path2); + } + catch (Exception e) + {// file missing or no read access or for some other + // reason the file size can't be obtained. + } + + return size1 == size2 ? 0 : (size1 > size2 ? -1 : 0); + } + + return 0; + } + + private FileSortType sortType; +} diff --git a/Master/texmf-dist/source/support/texosquery/java/FileSortComparator.java b/Master/texmf-dist/source/support/texosquery/java/FileSortComparator.java new file mode 100644 index 00000000000..d382e07f305 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/FileSortComparator.java @@ -0,0 +1,170 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +import java.util.Comparator; +import java.io.File; + +/** + * Used to compare two file names according to the given sort type. + * @since 1.2 + */ +public class FileSortComparator implements Comparator<String> +{ + /** + * Creates a new comparator for ordering file listings. + * @param baseDir the directory containing the listed files + * @param sortType the way in which the files should be ordered + */ + public FileSortComparator(File baseDir, FileSortType sortType) + { + this.baseDir = baseDir; + this.sortType = sortType; + } + + /** + * Compares two files according to this object's sort type. + * @param name1 the name of the first file + * @param name2 the name of the second file + * @return -1 if name1 is considered less than name2, 0 if both are the same + * or +1 if name2 is greater than name1, according to the sort + * criteria + */ + @Override + public int compare(String name1, String name2) + { + int idx=-1; + int result=0; + long date1=0L; + long date2=0L; + long size1=0L; + long size2=0L; + String ext1=""; + String ext2=""; + File file1; + File file2; + + switch (sortType) + { + case FILE_SORT_NAME_ASCENDING: + return name1.compareTo(name2); + case FILE_SORT_NAME_DESCENDING: + return name2.compareTo(name1); + case FILE_SORT_NAME_NOCASE_ASCENDING: + return name1.compareToIgnoreCase(name2); + case FILE_SORT_NAME_NOCASE_DESCENDING: + return name2.compareToIgnoreCase(name1); + case FILE_SORT_EXT_ASCENDING: + + idx = name1.lastIndexOf("."); + + ext1 = idx > -1 ? name1.substring(idx+1) : ""; + + idx = name2.lastIndexOf("."); + + ext2 = idx > -1 ? name2.substring(idx+1) : ""; + + result = ext1.compareTo(ext2); + + return result == 0 ? name1.compareTo(name2) : result; + + case FILE_SORT_EXT_DESCENDING: + + idx = name1.lastIndexOf("."); + + ext1 = idx > -1 ? name1.substring(idx+1) : ""; + + idx = name2.lastIndexOf("."); + + ext2 = idx > -1 ? name2.substring(idx+1) : ""; + + result = ext2.compareTo(ext1); + + return result == 0 ? name2.compareTo(name1) : result; + + case FILE_SORT_DATE_ASCENDING: + + file1 = new File(baseDir, name1); + file2 = new File(baseDir, name2); + + try + { + date1 = file1.lastModified(); + date2 = file2.lastModified(); + } + catch (Exception e) + {// file missing or no read access or for some other + // reason the last modified date can't be obtained. + } + + return date1 == date2 ? 0 : (date1 < date2 ? -1 : 0); + + case FILE_SORT_DATE_DESCENDING: + + file1 = new File(baseDir, name1); + file2 = new File(baseDir, name2); + + try + { + date1 = file1.lastModified(); + date2 = file2.lastModified(); + } + catch (Exception e) + {// file missing or no read access or for some other + // reason the last modified date can't be obtained. + } + + return date1 == date2 ? 0 : (date1 > date2 ? -1 : 0); + + case FILE_SORT_SIZE_ASCENDING: + + file1 = new File(baseDir, name1); + file2 = new File(baseDir, name2); + + try + { + size1 = file1.length(); + size2 = file2.length(); + } + catch (Exception e) + {// file missing or no read access or for some other + // reason the file size can't be obtained. + } + + return size1 == size2 ? 0 : (size1 < size2 ? -1 : 0); + + case FILE_SORT_SIZE_DESCENDING: + + file1 = new File(baseDir, name1); + file2 = new File(baseDir, name2); + + try + { + size1 = file1.length(); + size2 = file2.length(); + } + catch (Exception e) + {// file missing or no read access or for some other + // reason the file size can't be obtained. + } + + return size1 == size2 ? 0 : (size1 > size2 ? -1 : 0); + } + + return 0; + } + + + private File baseDir; + private FileSortType sortType; +} diff --git a/Master/texmf-dist/source/support/texosquery/java/FileSortType.java b/Master/texmf-dist/source/support/texosquery/java/FileSortType.java new file mode 100644 index 00000000000..4b3e303ff22 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/FileSortType.java @@ -0,0 +1,131 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +/** + * Indicates the ordering of files in listings. + * @since 1.2 + */ +public enum FileSortType +{ + FILE_SORT_DEFAULT ("default"), + FILE_SORT_DATE_ASCENDING ("date-ascending", "date", "date-asc"), + FILE_SORT_DATE_DESCENDING ("date-descending", "date-des"), + FILE_SORT_SIZE_ASCENDING ("size-ascending", "size", "size-asc"), + FILE_SORT_SIZE_DESCENDING ("size-descending", "size-des"), + FILE_SORT_NAME_ASCENDING ("name-ascending", "name", "name-asc"), + FILE_SORT_NAME_DESCENDING ("name-descending", "name-des"), + FILE_SORT_NAME_NOCASE_ASCENDING ("iname-ascending", "iname", "iname-asc"), + FILE_SORT_NAME_NOCASE_DESCENDING ("iname-descending", "iname-des"), + FILE_SORT_EXT_ASCENDING ("ext-ascending", "ext", "ext-asc"), + FILE_SORT_EXT_DESCENDING ("ext-descending", "ext-des"); + + private final String name, altName1, altName2; + + FileSortType(String name) + { + this(name, null, null); + } + + FileSortType(String name, String altName) + { + this(name, altName, null); + } + + FileSortType(String name, String altName1, String altName2) + { + this.name = name; + this.altName1 = altName1; + this.altName2 = altName2; + } + + /** + * Returns available option names. + */ + private String options() + { + if (altName1 == null && altName2 == null) + { + return name; + } + + if (altName2 == null) + { + return String.format("%s (or %s)", name, altName1); + } + + return String.format("%s (or %s or %s)", name, altName1, altName2); + } + + /** + * Checks if the given type matches this option. + * @return true if type matches this option + */ + private boolean isOption(String type) + { + return type.equals(name) || type.equals(altName1) + || type.equals(altName2); + } + + /** + * Returns a list of available sort options used in the command + * line invocation. + * @return list of options for syntax information. + */ + public static String getFileSortOptions() + { + StringBuilder builder = new StringBuilder(); + + for (FileSortType t : FileSortType.values()) + { + if (builder.length() > 0) + { + builder.append(", "); + } + + builder.append(t.options()); + } + + return builder.toString(); + } + + /** + * Gets the sort type from the given string. + * @param type the sort type as provided by the command line + * invocation + * @return a FileSortType object that indicates the sort type + */ + public static FileSortType getFileSortType(String type) + { + if (type == null) + { + return FileSortType.FILE_SORT_DEFAULT; + } + + for (FileSortType t : FileSortType.values()) + { + if (t.isOption(type)) + { + return t; + } + } + + throw new IllegalArgumentException( "Invalid sort type: "+type); + } + + public String toString() + { + return name; + } +} + diff --git a/Master/texmf-dist/source/support/texosquery/java/FileWalkVisitor.java b/Master/texmf-dist/source/support/texosquery/java/FileWalkVisitor.java new file mode 100644 index 00000000000..89e4fe73815 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/FileWalkVisitor.java @@ -0,0 +1,221 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +import java.io.File; +import java.io.IOException; +import java.io.FileNotFoundException; +import java.nio.file.Path; +import java.nio.file.Files; +import java.nio.file.FileVisitResult; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Vector; +import java.util.Comparator; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * This class is used during a file walk to determine if a directory + * may be descended and to add allowed files to the list. + * This relies on the java.nio.file library, which was introduced to + * Java 7, so this isn't available for the JRE5 version. + * @since 1.2 + */ +public class FileWalkVisitor extends SimpleFileVisitor<Path> +{ + /** + * Creates a new visitor for a file walk. This will only allow + * regular, non-hidden, readable files, where the name matches + * the supplied regular expression. The found files are inserted + * into the results list according to the comparator. + */ + public FileWalkVisitor(TeXOSQuery invoker, String regex, + Comparator<Path> comparator) + { + this.invoker = invoker; + this.comparator = comparator; + pattern = Pattern.compile(regex); + result = new Vector<Path>(); + } + + /** + * Returns the list built during the file walk. + * @return file list + */ + public Vector<Path> getList() + { + return result; + } + + /** + * Invoked for a directory before entries in the directory are + * visited. + * + * Hidden directories are automatically skipped, even if + * openin_any is <tt>a</tt>. Symbolic links and directories without + * read access are also skipped. + * + * @param dir the directory about to be visited + * @param attrs the directory's basic attributes + * @return the visit result + */ + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) + throws IOException + { + if (Files.isHidden(dir) || !Files.isReadable(dir) + || Files.isSymbolicLink(dir)) + { + invoker.info(String.format( + "Walk skipping directory: %s", dir.toString())); + return FileVisitResult.SKIP_SUBTREE; + } + + // We don't need to check openin_any here as the starting + // directory of the walk should already have been checked to + // ensure it's on the CWD path. + + return FileVisitResult.CONTINUE; + } + + + /** + * Invoked for a file in a directory. + * + * Hidden files are automatically skipped, regardless of + * openin_any. Files that don't have read access are also skipped + * and so are symbolic files. + * + * @param file a reference to the file + * @param attrs the file's basic attributes + * @return the visit result + */ + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException + { + if (Files.isHidden(file) || !Files.isReadable(file) + || attrs.isSymbolicLink()) + { + invoker.info(String.format( + "Walk skipping file: %s", file.toString())); + return FileVisitResult.CONTINUE; + } + + // Does the file name match the supplied pattern? + + String name = file.getName(file.getNameCount()-1).toString(); + + Matcher m = pattern.matcher(name); + + if (m.matches()) + { + addPath(file); + } + + return FileVisitResult.CONTINUE; + } + + /** + * Inserts path into results list according to the comparator. + * @param path the path to be added to the list + */ + private void addPath(Path path) + { + int n = result.size(); + + if (n == 0) + { + result.add(path); + return; + } + + for (int i = 0; i < n; i++) + { + Path thisPath = result.get(i); + + if (comparator.compare(thisPath, path) > 0) + { + result.add(i, path); + return; + } + } + + result.add(path); + } + + /** + *Walks the path starting from the given directory, which must be the + *current working directory or a descendent. + */ + public static String walk(TeXOSQuery invoker, + String separator, + String regex, + File directory, + FileSortType sortType) + throws IOException + { + if (!directory.exists()) + { + throw new FileNotFoundException( + String.format("No such file: %s", directory.toString())); + } + + if (!directory.isDirectory()) + { + throw new IOException( + String.format("Not a directory: %s", directory.toString())); + } + + directory = directory.getCanonicalFile(); + + File cwd = new File(invoker.getSystemProperty("user.dir", ".")); + + if (!cwd.equals(directory) && !invoker.isFileInTree(directory, cwd)) + { + throw new IOException( + String.format("Walk must start in current working directory path: %s", + cwd.toString())); + } + + Path start = directory.toPath(); + + FileWalkVisitor visitor = new FileWalkVisitor(invoker, regex, + new FilePathSortComparator(sortType)); + + Files.walkFileTree(start, visitor); + + Vector<Path> result = visitor.getList(); + + StringBuilder builder = new StringBuilder(); + + for (Path path : result) + { + if (builder.length() > 0) + { + builder.append(separator); + } + + builder.append( + invoker.escapeFileName(start.relativize(path).toString())); + } + + return builder.toString(); + } + + private TeXOSQuery invoker; + private Pattern pattern; + private Vector<Path> result; + private Comparator<Path> comparator; +} diff --git a/Master/texmf-dist/source/support/texosquery/java/Manifest-jre5.txt b/Master/texmf-dist/source/support/texosquery/java/Manifest-jre5.txt new file mode 100644 index 00000000000..f34ae37301d --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/Manifest-jre5.txt @@ -0,0 +1,2 @@ +Main-Class: com/dickimawbooks/texosquery/TeXOSQueryJRE5 +Class-Path: . diff --git a/Master/texmf-dist/source/support/texosquery/java/Manifest-jre7.txt b/Master/texmf-dist/source/support/texosquery/java/Manifest-jre7.txt new file mode 100644 index 00000000000..b5669d1e008 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/Manifest-jre7.txt @@ -0,0 +1,2 @@ +Main-Class: com/dickimawbooks/texosquery/TeXOSQueryJRE7 +Class-Path: . diff --git a/Master/texmf-dist/source/support/texosquery/java/Manifest-jre8.txt b/Master/texmf-dist/source/support/texosquery/java/Manifest-jre8.txt new file mode 100644 index 00000000000..0e460823ef4 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/Manifest-jre8.txt @@ -0,0 +1,2 @@ +Main-Class: com/dickimawbooks/texosquery/TeXOSQueryJRE8 +Class-Path: . diff --git a/Master/texmf-dist/source/support/texosquery/java/QueryAction.java b/Master/texmf-dist/source/support/texosquery/java/QueryAction.java new file mode 100644 index 00000000000..b50e65cc3ad --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/QueryAction.java @@ -0,0 +1,448 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +import java.io.Serializable; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ByteArrayInputStream; + +/** + * Class representing an action to be performed by the application. + * @since 1.2 + */ +public abstract class QueryAction implements Serializable +{ + public QueryAction() + { + } + + public QueryAction(String longForm, QueryActionType type, + String description) + { + this(longForm, null, 0, 0, "", type, description); + } + + public QueryAction(String longForm, QueryActionType type, + String description, int minCompat) + { + this(longForm, null, 0, 0, "", type, description, minCompat); + } + + public QueryAction(String longForm, String shortForm, + QueryActionType type, String description) + { + this(longForm, shortForm, 0, 0, "", type, description); + } + + public QueryAction(String longForm, String shortForm, + QueryActionType type, String description, int minCompat) + { + this(longForm, shortForm, 0, 0, "", type, description, minCompat); + } + + public QueryAction(String longForm, String shortForm, String syntax, + QueryActionType type, String description) + { + this(longForm, shortForm, 0, 0, syntax, type, description); + } + + public QueryAction(String longForm, String shortForm, + int numOptional, int numRequired, String syntax, + QueryActionType type, String description) + { + this(longForm, shortForm, numOptional, numRequired, + syntax, type, description, 0); + } + + public QueryAction(String longForm, String shortForm, + int numOptional, int numRequired, String syntax, + QueryActionType type, String description, int minCompat) + { + if (longForm != null) + { + longName = "--"+longForm; + } + + if (shortForm != null) + { + shortName = "-"+shortForm; + } + + optional = numOptional; + required = numRequired; + + this.syntax = syntax; + this.type = type; + this.description = description; + this.minCompatibility = minCompat; + } + + public boolean isAction(String name) + { + return name.equals(shortName) || name.equals(longName) + || (longName != null && name.startsWith(longName+"=")); + } + + public int parseArgs(String[] args, int index) + throws IllegalArgumentException + { + if (required > 0) + { + requiredArgs = new String[required]; + } + + if (args[index].startsWith(longName+"=")) + { + int idx = args[index].indexOf("=")+1; + invokedName = longName; + + if (idx == args[index].length()) + { + if (required == 1) + { + requiredArgs[0] = ""; + } + else + { + throw new IllegalArgumentException(String.format( + "Invalid syntax for action '%s'.%nExpected: %s", + invokedName, getUsage(invokedName))); + } + + return index+1; + } + + String[] sp; + + if (required+optional > 1) + { + sp = args[index].substring(idx).split(" "); + } + else + { + sp = new String[]{args[index].substring(idx)}; + } + + idx = 0; + + for (int i = 0; i < required; i++) + { + if (i >= sp.length) + { + throw new IllegalArgumentException(String.format( + "Invalid syntax for action '%s'.%nExpected: %s", + invokedName, getUsage(invokedName))); + } + + requiredArgs[i] = sp[idx++]; + } + + optionalProvided = 0; + + if (optional > 0) + { + optionalArgs = new String[optional]; + } + + for (int i = 0; i < optional; i++) + { + if (idx >= sp.length) + { + // no optional arguments, skip + break; + } + + optionalArgs[optionalProvided++] = sp[idx++]; + } + + return index+1; + } + else + { + invokedName = args[index++]; + + for (int i = 0; i < required; i++) + { + if (index >= args.length) + { + throw new IllegalArgumentException(String.format( + "Invalid syntax for action '%s'.%nExpected: %s", + invokedName, getUsage(invokedName))); + } + + requiredArgs[i] = args[index++]; + } + + optionalProvided = 0; + + if (optional > 0) + { + optionalArgs = new String[optional]; + } + + for (int i = 0; i < optional; i++) + { + if (index >= args.length || args[index].startsWith("-")) + { + // no optional arguments, skip + break; + } + + optionalArgs[optionalProvided++] = args[index++]; + } + } + + return index; + } + + public int providedOptionCount() + { + return optionalProvided; + } + + public String getOptionalArgument(int index) + { + return index < optionalArgs.length ? optionalArgs[index] : null; + } + + public String getRequiredArgument(int index) + { + return requiredArgs[index]; + } + + public String getInvocation() + { + StringBuilder builder = new StringBuilder(getInvokedName()); + + if (requiredArgs != null) + { + for (String arg : requiredArgs) + { + if (arg.contains(" ")) + { + builder.append(String.format(" '%s'", + arg.replaceAll("'", "\\\\'"))); + } + else + { + builder.append(String.format(" %s", arg)); + } + } + } + + if (optionalArgs != null) + { + for (String arg : optionalArgs) + { + if (arg == null) continue; + + if (arg.contains(" ")) + { + builder.append(String.format(" '%s'", + arg.replaceAll("'", "\\\\'"))); + } + else + { + builder.append(String.format(" %s", arg)); + } + } + } + + return builder.toString(); + } + + public String getInvokedName() + { + return invokedName; + } + + public QueryActionType getType() + { + return type; + } + + public String getUsage(String name) + { + return String.format("%s%s", + name, syntax == null || "".equals(syntax) ? "" : " "+syntax); + } + + /** + * Formats the description to fit maximum of 80 character line + * width. + */ + private String formatDescription() + { + int n = description.length(); + int max = MAX_CHARS_PER_LINE-8; + + if (n < max) + { + return description; + } + + StringBuilder builder = new StringBuilder(); + StringBuilder line = new StringBuilder(); + StringBuilder word = new StringBuilder(); + + for (int i = 0, offset=1; i < n; i += offset) + { + int codepoint = description.codePointAt(i); + offset = Character.charCount(codepoint); + + if (codepoint == ' ') + { + if (line.length()+word.length()+1 >= max) + { + builder.append(line); + builder.append(String.format("%n")); + line = new StringBuilder(); + line.append('\t'); + } + + line.append(word); + line.append(' '); + word = new StringBuilder(); + } + else + { + word.appendCodePoint(codepoint); + } + } + + if (line.length()+word.length()+1 >= max) + { + builder.append(line); + builder.append(String.format("%n")); + line = new StringBuilder(); + line.append('\t'); + } + + line.append(word); + builder.append(line); + + return builder.toString(); + } + + public String help() + { + String usage; + + if (shortName == null) + { + usage = getUsage(longName); + } + else + { + usage = String.format("%s or %s", getUsage(shortName), + getUsage(longName)); + } + + int n = usage.length(); + + return String.format("%s%n\t%s.%n", usage, formatDescription()); + } + + public String doAction(int compatible) throws IllegalArgumentException + { + if (compatible < minCompatibility) + { + throw new IllegalArgumentException(String.format( + "'%s' option not available in compatibility mode %d", + invokedName, compatible)); + } + + return action(); + } + + protected abstract String action(); + + /** + * Make a copy of this object. + */ + public final QueryAction copy() + { + try + { + ByteArrayOutputStream byteStr = new ByteArrayOutputStream(); + + new ObjectOutputStream(byteStr).writeObject(this); + + QueryAction action = (QueryAction) new ObjectInputStream( + new ByteArrayInputStream(byteStr.toByteArray())).readObject(); + action.same(this); + + return action; + } + catch (Exception e) + { + throw new AssertionError(e); + } + } + + private void same(QueryAction action) + { + longName = action.longName; + shortName = action.shortName; + invokedName = action.invokedName; + syntax = action.syntax; + optional = action.optional; + optionalProvided = action.optionalProvided; + required = action.required; + type = action.type; + description = action.description; + minCompatibility = action.minCompatibility; + + if (action.optionalArgs != null) + { + optionalArgs = new String[action.optionalArgs.length]; + + for (int i = 0; i < action.optionalArgs.length; i++) + { + optionalArgs[i] = action.optionalArgs[i]; + } + } + + if (action.requiredArgs != null) + { + requiredArgs = new String[action.requiredArgs.length]; + + for (int i = 0; i < action.requiredArgs.length; i++) + { + requiredArgs[i] = action.requiredArgs[i]; + } + } + } + + public String getLongName() + { + return longName; + } + + private String longName=null; + private String shortName=null; + private String invokedName=null; + private String syntax=""; + private int optional=0; + private int optionalProvided=0; + private int required=0; + private String[] requiredArgs=null; + private String[] optionalArgs=null; + private QueryActionType type; + private String description; + private int minCompatibility=0; + + private static final int MAX_CHARS_PER_LINE=80; +} diff --git a/Master/texmf-dist/source/support/texosquery/java/QueryActionType.java b/Master/texmf-dist/source/support/texosquery/java/QueryActionType.java new file mode 100644 index 00000000000..0eb2382766d --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/QueryActionType.java @@ -0,0 +1,19 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +public enum QueryActionType +{ + FILE_ACTION, LOCALE_ACTION, GENERAL_ACTION +} + diff --git a/Master/texmf-dist/source/support/texosquery/java/TeXOSQuery.java b/Master/texmf-dist/source/support/texosquery/java/TeXOSQuery.java new file mode 100644 index 00000000000..882cd3afb44 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/TeXOSQuery.java @@ -0,0 +1,4459 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +import java.io.BufferedReader; +import java.util.Locale; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; +import java.util.Vector; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.text.DecimalFormatSymbols; +import java.text.Format; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.text.DateFormatSymbols; +import java.text.NumberFormat; +import java.text.DecimalFormat; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Serializable; + +/** + * Application functions. These methods need to be Java version 1.5 + * compatible. The 1.7 methods need to be in the TeXOSQueryJRE7 class + * (which provides the main part of texosquery.jar) and the 1.8 methods in + * TeXOSQueryJRE8 (which provides the main part of texosquery-jre8.jar). + * + * The texosquery-jre5.jar version should not be considered secure + * and is only provided for antiquated systems. + * Java 5 and 6 are both deprecated and are now considered security + * risks. + * + * Since this application is designed to be run from TeX, the output + * needs to be easy to parse using TeX commands. For this reason, + * most exceptions are caught and an empty string is returned. The + * TeX code can then check for an empty value to determine failure. + * There's a debug mode to print error messages to STDERR to + * investigate the reason for failure. + * @author Nicola Talbot + * @version 1.2 + * @since 1.0 + */ +public class TeXOSQuery implements Serializable +{ + /** + * Constructor. + * @param name The application name. + */ + public TeXOSQuery(String name) + { + this.name = name; + } + + /** + * Gets the application name. + * @return the application name + * @since 1.2 + */ + public String getName() + { + return name; + } + + /** + * Runs kpsewhich and returns the result. This is for single + * argument lookups through kpsewhich, such as a file location + * or variable value. + * @param arg The argument to pass to kpsewhich + * @return The result read from the first line of STDIN + * @since 1.2 + */ + protected String kpsewhich(String arg) + throws IOException,InterruptedException + { + // Create and start the process. + Process process = + new ProcessBuilder("kpsewhich", arg).start(); + + int exitCode = process.waitFor(); + + String line = null; + + if (exitCode == 0) + { + // kpsewhich completed with exit code 0. + // Read STDIN to find the result. + + InputStream stream = process.getInputStream(); + + if (stream == null) + { + throw new IOException(String.format( + "Unable to open input stream from process: kpsewhich '%s'", + arg)); + } + + BufferedReader reader = null; + + try + { + reader = new BufferedReader(new InputStreamReader(stream)); + + // only read a single line, nothing further is required + // for a variable or file location query. + line = reader.readLine(); + } + finally + { + if (reader != null) + { + reader.close(); + } + } + } + else + { + // kpsewhich failed. + + throw new IOException(String.format( + "\"kpsewhich '%s'\" failed with exit code: %d", arg, exitCode)); + } + + return line; + } + + /** + * Print message if in debug mode. Message is printed to STDERR + * if the debug level is greater than or equal to the given level. + * Debugging messages are all written to STDERR rather than + * STDOUT so they show up in the transcript rather than being + * captured by the shell escape. + * @param message Debugging message. + * @param level Debugging level. + * @since 1.2 + */ + public void debug(String message, int level) + { + if (debugLevel >= level) + { + System.err.println(String.format("%s: %s", name, message)); + } + } + + /** + * Print message if in debug mode. Message is printed to STDERR + * if the debug level is 1 or more. + * @param message Debugging message. + * @since 1.2 + */ + public void debug(String message) + { + debug(message, DEBUG_ERROR_LEVEL); + } + + /** + * Message if in debug mode. This is for information rather than + * errors. The message is printed to STDERR if the debug level + * is 3 or more. + * @param message Debugging message. + * @since 1.2 + */ + public void info(String message) + { + debug(message, DEBUG_INFO_LEVEL); + } + + /** + * Print message and exception if in debug mode. Message is printed to + * STDERR if the debug level is greater than or equal to the given level. + * The exception may be null. If not null, the exception message + * is printed. + * @param message Debugging message. + * @param excpt Exception. + * @param msgLevel Debugging level for message. + * @param traceLevel Debugging level for stack trace. + * @since 1.2 + */ + public void debug(String message, Throwable excpt, int msgLevel, + int traceLevel) + { + debug(message, msgLevel); + + if (excpt != null) + { + debug(excpt.getMessage(), msgLevel); + + if (debugLevel >= traceLevel) + { + excpt.printStackTrace(); + } + } + } + + /** + * Print message and exception if in debug mode. The message + * level is 1 and the trace level is 2. + * @param message Debugging message. + * @param excpt Exception. + * @since 1.2 + */ + public void debug(String message, Throwable excpt) + { + debug(message, excpt, DEBUG_ERROR_LEVEL, DEBUG_STACK_TRACE_LEVEL); + } + + /** + * Checks if file is in or below the given directory. This might + * be easier with java.nio.file.Path etc but that requires Java + * 1.7, so use the old-fashioned method. + * @param file The file being checked + * @param dir The directory being searched + * @return true if found + * @since 1.2 + */ + protected boolean isFileInTree(File file, File dir) + throws IOException + { + if (file == null || dir == null) return false; + + file = file.getCanonicalFile(); + dir = dir.getCanonicalFile(); + + File parent = file.getParentFile(); + + while (parent != null) + { + if (parent.equals(dir)) + { + return true; + } + + parent = parent.getParentFile(); + } + + return false; + } + + /** + * Determine if the given file is hidden. + * Java's File.isHidden() method seems to consider "." and ".." + * as hidden directories, so this method converts the file to a + * canonical path before testing. + * @param file The file to check + * @return True if the file is considered hidden. + * @since 1.2 + */ + public boolean isHidden(File file) + { + try + { + return file.getCanonicalFile().isHidden(); + } + catch (IOException e) + { + // file can't be converted to a canonical path, so + // consider it hidden + + debug(String.format( + "Unable to convert file to a canonical path: ", + file.toString()), e); + } + + return true; + } + + /** + * Queries if the given file may be read according to + * openin_any. Since the user may not require any of the file + * access functions, the openin variable is only set the first + * time this method is used to reduce unnecessary overhead. + * kpsewhich is used to lookup the value of openin_any, which + * may have one of the following values: a (any), r (restricted, + * no hidden files) or p (paranoid, as restricted and no parent + * directories and no absolute paths except under $TEXMFOUTPUT) + * @param file The file to be checked + * @return true if read-access allowed + * @since 1.2 + */ + public boolean isReadPermitted(File file) + { + // if file doesn't exist, it can't be read + if (file == null || !file.exists()) + { + return false; + } + + try + { + if (openin == OPENIN_UNSET) + { + //First time this method has been called. Use kpsewhich + //to determine the value. + + try + { + String result = kpsewhich("-var-value=openin_any"); + + if ("a".equals(result)) + { + openin=OPENIN_A; + } + else if ("r".equals(result)) + { + openin=OPENIN_R; + } + else if ("p".equals(result)) + { + openin=OPENIN_P; + } + else + { + // This shouldn't occur, but just in case... + debug(String.format("Invalid openin_any value: %s", + result)); + openin = OPENIN_P; + } + } + catch (Exception e) + { + // kpsewhich failed, assume paranoid + debug("Can't determine openin value, assuming 'p'", e); + openin = OPENIN_P; + } + + // Now find TEXMFOUTPUT if set (only need this with the + // paranoid setting) + + if (openin == OPENIN_P) + { + String path = null; + + try + { + path = System.getenv("TEXMFOUTPUT"); + } + catch (SecurityException e) + { + debug("Can't query TEXMFOUTPUT", e); + } + + if (path != null && !"".equals(path)) + { + texmfoutput = new File(fromTeXPath(path)); + + if (!texmfoutput.exists()) + { + debug(String.format( + "TEXMFOUTPUT doesn't exist, ignoring: %s", + texmfoutput.toString())); + texmfoutput = null; + } + else if (!texmfoutput.isDirectory()) + { + debug(String.format( + "TEXMFOUTPUT isn't a directory, ignoring: %s", + texmfoutput.toString())); + texmfoutput = null; + } + else if (!texmfoutput.canRead()) + { + debug(String.format( + "TEXMFOUTPUT doesn't have read permission, ignoring: %s", + texmfoutput.toString())); + texmfoutput = null; + } + } + } + } + + // Now check if the given file can be read according to the + // openin setting. + + switch (openin) + { + case OPENIN_A: + // any file can be read as long as the OS allows it + return file.canRead(); + case OPENIN_P: + // paranoid check + + if (isFileInTree(file, texmfoutput)) + { + // file under TEXMFOUTPUT, so it's okay as long + // as it has read permission + return file.canRead(); + } + + // does the file have an absolute path? + + if (file.isAbsolute()) + { + debug(String.format( + "Read access forbidden by openin_any=%c (has absolute path outside TEXMFOUTPUT): %s", + openin, file)); + return false; + } + + // is the file outside the cwd? + File cwd = new File(getSystemProperty("user.dir", ".")); + + if (file.getParentFile() != null && !isFileInTree(file, cwd)) + { + debug(String.format( + "Read access forbidden by openin_any=%c (outside cwd path): %s", + openin, file)); + return false; + } + + // no break, fall through to restricted check + case OPENIN_R: + + if (isHidden(file)) + { + // hidden file so not permitted + debug(String.format( + "Read access forbidden by openin_any=%c (hidden file): %s", + openin, file)); + return false; + } + + break; + default: + // this shouldn't happen, but just in case... + debug(String.format("Invalid openin value: %d", openin)); + // don't allow, something's gone badly wrong + return false; + } + + // return read access + return file.canRead(); + } + catch (Exception e) + { + // Catch all exceptions + debug(String.format("Read permission check failed: %s", file), e); + + // Can't permit read if something's gone wrong here. + return false; + } + } + + /** + * Gets the given system property or the default value. + * Returns the default value if the property isn't set or can't be accessed. + * @param propName The property name + * @param defValue The default value + * @return The property value or the default if unavailable + * @since 1.2 + */ + public String getSystemProperty(String propName, String defValue) + { + try + { + return System.getProperty(propName, defValue); + } + catch (SecurityException e) + { + // The security manager doesn't permit access to this property. + + debug(String.format("Unable to access property: %s", propName), e); + return defValue; + } + } + + /** + * Escapes potentially problematic characters from a string that will be + * expanded when input by TeX's shell escape. + * + * Some of the methods in this class return TeX code. Those + * returned values shouldn't be escaped as it would interfere + * with the code, so just use this method on information + * directly obtained from Java. This will typically be either + * file names (in which case the characters within the string + * must all be "letter" or "other") or regular text for use in + * the document (such as dates or times, in which case the + * characters may be active to allow them to be correctly + * typeset, such as UTF-8 characters with inputenc.sty). + * + * The date-time and numeric patterns (such as "YYYY-MM-DD" + * or "#,##0.0") are dealt with elsewhere as they need different treatment. + * + * \\TeXOSQuery locally defines commands for characters + * used in file names (catcode 12). These are all in the form + * \\fxxx (such as \\fhsh for a literal hash). Since the + * texosquery.tex code is designed to be generic we can't assume + * the eTeX \\detokenize primitive is available. This does, + * however, assume that the document author hasn't changed the + * category codes of the ASCII alphanumerics, but that ought to + * be a safe assumption. + * + * We also have commands for characters intended for use in document + * text, which shouldn't be interpreted literally. These are all + * in the form \\txxx (such as \\thsh which should expand to + * \#). + * + * The regular space \\tspc guards against a space occurring after + * a character that needs to be converted to a control sequence. + * (For example "# 1" becomes "\\thsh \\tspc 1") + * There's also a literal space \\fspc to guard against spaces + * in file names. + * + * This should take care of any insane file-naming schemes, such + * as <tt>bad~file name#1.tex</tt>, <tt>stupid {file} name.tex</tt>, + * <tt style="white-space: pre;">spaced out file #2.tex</tt>, + * <tt>file's stupid name.tex</tt>. + * + * To help protect against input encoding problems, non-ASCII + * characters are wrapped in \\twrp (regular text) or \\fwrp + * (file names). \\TeXOSQuery locally redefines these to + * \\texosquerynonasciiwrap and \\texosquerynonasciidetokwrap + * which may be used to provide some protection or conversion from one + * encoding to another, if required. + * + * For example, the language "français" would be returned as + * "fran\\twrp{ç}ais", which can be typeset directly with + * XeTeX or LuaTeX or through active characters with + * inputenc.sty, but the directory called <tt>Françcois</tt> would be + * returned as <tt>Fran\\fwrp{ç}cois</tt>, which will try to + * detokenize the ç character. + * + * @param string Input string. + * @param isRegularText true if the string represents text (for example, + * month names), set to false if string is something literal, + * such as a file name. + * @return The processed string + * @since 1.2 + */ + public String escapeSpChars(String string, boolean isRegularText) + { + if (compatible < 2) + { + return escapeHash(string); + } + + StringBuilder builder = new StringBuilder(); + + // This iterates over Unicode characters so we can't use a simple + // i++ increment. The offset is obtained from Character.charCount + for (int i = 0, n = string.length(); i < n; ) + { + int codepoint = string.codePointAt(i); + i += Character.charCount(codepoint); + + builder.append(escapeSpChars(codepoint, isRegularText)); + } + + return builder.toString(); + } + + /** + * Escapes file name. This should already have had the directory + * divider changed to a forward slash where necessary. + * @param filename Input string. + * @return String with characters escaped. + * @since 1.2 + */ + public String escapeFileName(String filename) + { + return escapeSpChars(filename, false); + } + + /** + * Escapes regular text. + * @param string Input string. + * @return String with characters escaped. + * @since 1.2 + */ + public String escapeText(String string) + { + return escapeSpChars(string, true); + } + + /** + * Escapes regular text. + * @param codepoint Input Unicode character. + * @return String with characters escaped. + * @since 1.2 + */ + public String escapeText(int codepoint) + { + return escapeSpChars(codepoint, true); + } + + /** + * Escapes the given Unicode character. + * All ASCII punctuation characters have a literal and textual + * command to represent them in file names and document text, + * respectively. The literal (file name) commands are prefixed + * with "f" and the textual commands are prefixed with "t". + * None of the control codes should appear in any of the + * results, but they are checked for completeness. + * @param codePoint Input code point. + * @param isRegularText true if the character is in a string representing + * text, set to false if string is a file name etc + * @return String with character escaped. + * @since 1.2 + */ + public String escapeSpChars(int codepoint, boolean isRegularText) + { + return escapeSpChars(codepoint, isRegularText ? "t" : "f"); + } + + /** + * Escapes the given Unicode character. + * As above but with the prefix supplied. + * @param codePoint Input code point. + * @param prefix The control sequence name prefix. + * @return String with character escaped. + * @since 1.2 + */ + public String escapeSpChars(int codepoint, String prefix) + { + switch (codepoint) + { + case '!': return String.format("\\%sexc ", prefix); + case '"': return String.format("\\%sdqt ", prefix); + case '#': return String.format("\\%shsh ", prefix); + case '$': return String.format("\\%sdol ", prefix); + case '%': return String.format("\\%spct ", prefix); + case '&': return String.format("\\%samp ", prefix); + case '\'': return String.format("\\%sapo ", prefix); + case '(': return String.format("\\%sopb ", prefix); + case ')': return String.format("\\%sclb ", prefix); + case '*': return String.format("\\%sast ", prefix); + case '+': return String.format("\\%spls ", prefix); + case ',': return String.format("\\%scom ", prefix); + case '-': return String.format("\\%shyn ", prefix); + case '.': return String.format("\\%sdot ", prefix); + case '/': return String.format("\\%sslh ", prefix); + case ':': return String.format("\\%scln ", prefix); + case ';': return String.format("\\%sscl ", prefix); + case '<': return String.format("\\%sles ", prefix); + case '=': return String.format("\\%seql ", prefix); + case '>': return String.format("\\%sgre ", prefix); + case '?': return String.format("\\%sque ", prefix); + case '@': return String.format("\\%satc ", prefix); + case '[': return String.format("\\%sosb ", prefix); + case '\\': return String.format("\\%sbks ", prefix); + case ']': return String.format("\\%scsb ", prefix); + case '^': return String.format("\\%scir ", prefix); + case '_': return String.format("\\%susc ", prefix); + case '`': return String.format("\\%sgrv ", prefix); + case '{': return String.format("\\%slbr ", prefix); + case '}': return String.format("\\%srbr ", prefix); + case '~': return String.format("\\%stld ", prefix); + case ' ': return String.format("\\%sspc ", prefix); + // These next few cases shouldn't occur, but + // check for them anyway. + case 0x007F: return ""; // delete control + case 0x0009: return "^^I";// tab + case 0x000A: // lf (fall through to cr) + case 0x000C: // ff + case 0x000D: return " "; // cr + default: + + if (codepoint < 32) + { + return ""; // strip control characters + } + else if (codepoint >= 32 && codepoint <= 126) + { + // ASCII letters and digits (all ASCII punctuation + // dealt with above). + return String.format("%c", codepoint); + } + else + { + // Outside Basic Latin set. + return String.format("\\%swrp{%c}", prefix, codepoint); + } + } + } + + /** + * Escapes any hashes in input string. + * Now only used if compatibility level is less than 2 (pre + * texosquery version 1.2). + * @param string Input string. + * @return String with hash escaped. + */ + public static String escapeHash(String string) + { + return string.replaceAll("#", "\\\\#"); + } + + /** + * Escapes hash from input character. + * No longer required. + * @param c Input character. + * @return String with hash escaped. + */ + public static String escapeHash(char c) + { + return String.format("%s", c == '#' ? "\\#" : c); + } + + /** + * Gets the OS name. As far as I can tell, the "os.name" + * property should return a string that just contains Basic + * Latin upper or lower case letters, so we don't need to worry + * about special characters. + * @return The OS name as string. + */ + public String getOSname() + { + return getSystemProperty("os.name", ""); + } + + /** + * Gets the OS architecture. As with the OS name, this shouldn't + * contain any special characters. + * @return The OS architecture as string. + */ + public String getOSarch() + { + return getSystemProperty("os.arch", ""); + } + + /** + * Gets the OS version. This may contain an underscore, so treat + * it like a file name. + * @return The OS version as string. + */ + public String getOSversion() + { + return escapeFileName(getSystemProperty("os.version", "")); + } + + /** + * Converts the filename string to TeX path. Since this is designed to work + * within TeX, backslashes in paths need to be replaced with forward + * slashes. + * @param filename The filename string. + * @return TeX path. + */ + public String toTeXPath(String filename) + { + if (filename == null) + { + // This shouldn't happen, but just in case... + try + { + // throw so we can get a stack trace for debugging + throw new NullPointerException(); + } + catch (NullPointerException e) + { + debug("null file name", e); + } + + return ""; + } + + // If the OS uses backslash as the directory divider, + // convert all backslashes to forward slashes. The Java regex + // means that we need four backslashes to represent a single literal + // backslash. + + if (File.separatorChar == BACKSLASH) + { + filename = filename.replaceAll("\\\\", "/"); + } + + return escapeFileName(filename); + } + + /** + * Converts the TeX path to the OS representation. + * The file name will typically be passed as a parameter through + * \\TeXOSQuery so it will have forward slashes as the directory + * divider regardless of the OS (as per \\input and + * \\includegraphics). This method converts the TeX file name + * into one that's valid for the OS. + * @param filename The filename string. + * @return The OS representation. + */ + public String fromTeXPath(String filename) + { + if (filename == null) + { + // This shouldn't happen, but just in case... + try + { + throw new NullPointerException(); + } + catch (NullPointerException e) + { + debug("null file name", e); + } + + return ""; + } + + if (compatible < 2) + { + if (File.separatorChar == BACKSLASH) + { + return filename.replaceAll("/", "\\\\"); + } + + return filename; + } + + // The file name may contain awkward characters. For example, + // the user may have a file called imagefile#1.png and + // they're trying to do, say, + // \TeXOSQuery{\result}{-p imagefile#1.png} + // If the shell escape is using bash, the hash will be + // interpreted as a comment character, so the argument + // received by texosquery will actually be "imagefile" + // since the "#1.png" part will be interpreted as a comment. + + // The user can protect the # from the shell using + // \TeXOSQuery{\result}{-p imagefile\string\#1.png} + // which bash will pass as 'imagefile#1.png', but + // perhaps another type of shell might pass it literally + // as 'imagefile\#1.png', so the following allows for + // that by simply stripping all backslashes from the file name. + // (The file name is always supplied with forward slashes as + // the directory divider regardless of the operating system.) + // We can substitute the divider at this point as well. + + StringBuilder builder = new StringBuilder(); + + for (int i = 0, n = filename.length(), offset=1; i < n; i+=offset) + { + int codepoint = filename.codePointAt(i); + offset = Character.charCount(codepoint); + + int nextIndex = i+offset; + int nextCodePoint = (nextIndex<n ? filename.codePointAt(nextIndex):0); + + if (codepoint == '/') + { + builder.appendCodePoint(File.separatorChar); + } + if (codepoint == BACKSLASH) + { + // Would anyone really want a literal backslash in a + // file name? Allow a double backslash to represent a + // literal backslash but only if the OS directory + // divider isn't a backslash. Otherwise discard + // this character. + + if (File.separatorChar != BACKSLASH && nextCodePoint == BACKSLASH) + { + builder.appendCodePoint(codepoint); + i = nextIndex; + offset = Character.charCount(nextCodePoint); + } + else if (nextCodePoint == '/') + { + // Would anyone want a literal forward slash? Allow a + // slash to be escaped just in case. + builder.appendCodePoint('/'); + i = nextIndex; + offset = Character.charCount(nextCodePoint); + } + } + else + { + builder.appendCodePoint(codepoint); + } + } + + return builder.toString(); + } + + /** + * Gets a file representation from a filename string. If the + * provided file doesn't have a parent and if it's not found in the + * current directory, kpsewhich will be used to locate it on + * TeX's path. The provided file name is assumed to have been + * passed through commands provided by texosquery.tex so the + * directory dividers should be forward slashes, even if the OS + * uses backslashes. The returned file may not exist. Any method + * that uses this method needs to check for existence. + * @param filename Filename string. + * @return File representation + * @since 1.2 + */ + public File fileFromTeXPath(String filename) + { + // Convert from TeX to the OS path representation. + filename = fromTeXPath(filename); + + File file = new File(filename); + + if (!file.exists() && file.getParent() == null) + { + // If the file doesn't exist and it doesn't have a parent + // directory, use kpsewhich to find it. + + try + { + String result = kpsewhich(filename); + + if (result != null && !"".equals(result)) + { + file = new File(fromTeXPath(result)); + } + } + catch (Exception exception) + { + // Catch all exceptions + debug(String.format("kpsewhich couldn't find the file: %s", + filename), + exception); + + // The File object will be returned even though the file + // can't be found. + } + } + + return file; + } + + /** + * Gets the user's home directory. + * @return The user home as string. + */ + public String getUserHome() + { + File dir = new File(getSystemProperty("user.home", "")); + + if (!isReadPermitted(dir)) + { + debug("Read access not permitted for the home directory"); + return ""; + } + + // The resulting path needs to be converted to a TeX path. + return toTeXPath(dir.getAbsolutePath()); + } + + /** + * Gets the current working directory. + * @return The current working directory. + */ + public String getCwd() + { + File dir = new File(getSystemProperty("user.dir", ".")); + + if (!isReadPermitted(dir)) + { + // perhaps the current directory is hidden? + debug("Read access not permitted for the current directory"); + return ""; + } + + // The resulting path needs to be converted to a TeX path. + return toTeXPath(dir.getAbsolutePath()); + } + + /** + * Gets the temporary directory. + * @return Temporary directory. + */ + public String getTmpDir() + { + String filename = getSystemProperty("java.io.tmpdir", ""); + + if ("".equals(filename)) + { + // Not set + return ""; + } + + File dir = new File(filename); + + if (!isReadPermitted(dir)) + { + debug(String.format("Read access not permitted for directory: %s", + dir)); + return ""; + } + + // The resulting path needs to be converted to a TeX path. + return toTeXPath(filename); + } + + /** + * Gets the week year for the given calendar. + * Calendar.getWeekYear() was added to Java 7, so this defaults + * to the year instead. This method needs to be overridden in + * TeXOSQueryJRE7 and TeXOSQueryJRE8. + * @return The week year + * @since 1.2 + */ + public int getWeekYear(Calendar cal) + { + return cal.get(Calendar.YEAR); + } + + /** + * Converts the day of week index returned by + * Calendar.DAY_OF_WEEK to Monday=1 based indexing. + * @param index the day of week index obtained from Calendar.DAY_OF_WEEK + * @return index with Monday=1 as the base + * @since 1.2 + */ + private int getDayOfWeekIndex(int index) + { + switch (index) + { + case Calendar.MONDAY: return 1; + case Calendar.TUESDAY: return 2; + case Calendar.WEDNESDAY: return 3; + case Calendar.THURSDAY: return 4; + case Calendar.FRIDAY: return 5; + case Calendar.SATURDAY: return 6; + case Calendar.SUNDAY: return 7; + } + + try + { + // this shouldn't happen + throw new IllegalArgumentException( + String.format("Invalid day of week index: %d", index)); + } + catch (Exception e) + { + debug(e.getMessage(), e); + } + + return 0; + } + + /** + * Gets all the date-time data for the current date-time. + * @return data in format that can be read by \\texosqueryfmtdatetime + * @since 1.2 + */ + public String getDateTimeData() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(now.getTime()); + + int hourH = cal.get(Calendar.HOUR_OF_DAY); + + int hourk = (hourH == 0 ? 24 : hourH); + + int hourK = cal.get(Calendar.HOUR); + + int hourh = (hourK == 0 ? 12 : hourK); + + TimeZone timeZone = cal.getTimeZone(); + boolean isDaylightSaving = timeZone.inDaylightTime(now); + + int timezoneoffset = cal.get(Calendar.ZONE_OFFSET); + + if (isDaylightSaving) + { + timezoneoffset += cal.get(Calendar.DST_OFFSET); + } + + // convert from offset millisec to hours and minutes + // (ignore left-over seconds and milliseconds) + + int tzm = timezoneoffset/60000; + + int tzh = tzm/60; + + tzm = tzm % 60; + + return String.format( + "{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{%d}{{%d}{%d}{%s}{%d}}", + cal.get(Calendar.ERA), + cal.get(Calendar.YEAR), + getWeekYear(cal), + cal.get(Calendar.MONTH)+1, + cal.get(Calendar.WEEK_OF_YEAR), + cal.get(Calendar.WEEK_OF_MONTH), + cal.get(Calendar.DAY_OF_YEAR), + cal.get(Calendar.DAY_OF_MONTH), + cal.get(Calendar.DAY_OF_WEEK_IN_MONTH), + getDayOfWeekIndex(cal.get(Calendar.DAY_OF_WEEK)),// Monday=1, etc + cal.get(Calendar.AM_PM), + hourH, hourk, hourK, hourh, + cal.get(Calendar.MINUTE), + cal.get(Calendar.SECOND), + cal.get(Calendar.MILLISECOND), + tzh, tzm, timeZone.getID(), + isDaylightSaving ? 1 : 0); + } + + /** + * Get the time zone names for the given locale. + * The data for each zone is provided in the form + * {id}{short name}{long name}{short dst name}\marg{long dst name} + * @param localeTag The locale + * @return list of zone information for the locale + * @since 1.2 + */ + + public String getTimeZones(String localeTag) + { + Locale locale; + + if (localeTag == null || "".equals(localeTag)) + { + locale = Locale.getDefault(); + } + else + { + locale = getLocale(localeTag); + } + + StringBuilder builder = new StringBuilder(); + + String[] zones = TimeZone.getAvailableIDs(); + + for (int i = 0; i < zones.length; i++) + { + TimeZone tz = TimeZone.getTimeZone(zones[i]); + + builder.append(String.format("{{%s}{%s}{%s}{%s}{%s}}", + escapeFileName(tz.getID()), + escapeText(tz.getDisplayName(false, TimeZone.SHORT, locale)), + escapeText(tz.getDisplayName(false, TimeZone.LONG, locale)), + escapeText(tz.getDisplayName(true, TimeZone.SHORT, locale)), + escapeText(tz.getDisplayName(true, TimeZone.LONG, locale)))); + } + + return builder.toString(); + } + + /** + * Gets the current date in PDF format. (The same format as + * \pdfcreationdate.) + * @return The current date. + */ + public String pdfnow() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(now.getTime()); + + return pdfDate(cal); + } + + /** + * Gets the date in PDF format. + * @param calendar A calendar object. + * @return Date in PDF format. + */ + public String pdfDate(Calendar calendar) + { + String tz = String.format("%1$tz", calendar); + + if (compatible < 2) + { + return String.format( + "D:%1$tY%1$tm%1td%1$tH%1$tM%1$tS%2$s'%3$s'", + calendar, + tz.substring(0, 3), + tz.substring(3)); + } + else + { + // Need to ensure D : + or - and ' have category code 12 + // The simplest way to deal with this is to pass + // everything after the "D" to escapeFileName since + // the sign is hidden in the format. + + return String.format("\\pdfd %s", + escapeFileName( + String.format( + ":%1$tY%1$tm%1td%1$tH%1$tM%1$tS%2$s'%3$s'", + calendar, + tz.substring(0, 3), + tz.substring(3)) + )); + + } + } + + /** + * Gets the date of a file in PDF format. + * @param file File. + * @return The date in PDF format. + */ + public String pdfDate(File file) + { + try + { + if (!file.exists()) + { + debug(String.format( + "Unable to get timestamp for file (no such file): %s", + file.toString())); + return ""; + } + + if (!isReadPermitted(file)) + { + debug(String.format("No read access for file: %s", file)); + return ""; + } + + long millisecs = file.lastModified(); + + if (millisecs > ZERO) + { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(millisecs); + + return pdfDate(calendar); + } + + // I/O error has occurred (already checked for file + // existence and read permission, so it's something weird). + // Perhaps the file is corrupt or the user has an eccentric OS that + // doesn't support file modification timestamps. + debug(String.format( + "Unable to get timestamp for file (I/O error): %s", + file.toString())); + } + catch (Exception exception) + { + // Catch all possible exceptions, including security + // exception. + + debug(String.format( + "Unable to get timestamp for file: %s", + file.toString()), + exception); + } + + // Unsuccessful + return ""; + } + + /** + * Gets the file length in bytes. + * @param file The file. + * @return The length as a string. + */ + public String getFileLength(File file) + { + try + { + if (!file.exists()) + { + debug(String.format( + "Unable to get the size of file (no such file): %s", + file.toString())); + return ""; + } + + if (!isReadPermitted(file)) + { + debug(String.format("No read access for file: %s", file)); + return ""; + } + + return String.format("%d", file.length()); + + } + catch (Exception exception) + { + // Catch all possible exceptions, including security + // exceptions. + + debug(String.format("Unable to get the size of file: %s", + file.toString()), + exception); + } + + // Unsuccessful + return ""; + } + + /** + * Sort the given list of file names. Java 8 has a better sort + * method so this is overridden in the TeXOSQueryJRE8 class. + * @param list The list of file names to be sorted + * @param directory The directory in which the files are + * contained + * @param sortType How to order the list + */ + public void sortFileList(String[] list, File directory, + FileSortType sortType) + { + Arrays.sort(list, new FileSortComparator(directory, sortType)); + } + + /** + * Checks the directory used for file listings. The JRE5 version + * just returns the argument. The other versions convert the + * directory to a canonical path and check it's permitted. (The + * JRE7 and 8 versions are more restrictive.) + */ + protected File checkDirectoryListing(File dir) throws IOException + { + return dir; + } + + /** + * Gets the list of files from a directory. This uses + * getFilterFileList to filter out files prohibited by the + * openin_any setting. Note that the separator isn't escaped as + * the user may want some actual TeX code. For example, the + * separator might need to be a double backslash. + * The user will need to take the appropriate precautions + * to protect it from expansion during the shell escape. + * @param separator Separator. + * @param directory Directory (root not permitted). + * @param sortType How to sort the file list + * @param listType The type of files to include in the list + * @return List as a string. + */ + public String getFileList(String separator, File directory, + FileSortType sortType, FileListType listType) + { + return getFilterFileList(separator, ".*", directory, sortType, listType); + } + + /** + * Gets a filtered list of files from directory. + * Files with read access prohibited by openin_any or the OS are + * omitted from the list. The regular expression is anchored, + * so ".*foo" will only match file names that end with "foo". + * + * For security reasons, as from v1.2, the directory must have a + * parent (otherwise malicious code could try to perform a + * recursive search across the filing system, which would hog + * resources). To allow for backward compatibility, the insecure + * JRE5 version doesn't have this new restriction. + * + * @param separator Separator. + * @param regex Regular expression. + * @param directory Directory. + * @param sortType How to sort the file list + * @param listType The type of files to include in the list + * @return Filtered list as string. + */ + public String getFilterFileList(String separator, + final String regex, File directory, + FileSortType sortType, final FileListType listType) + { + if (directory == null) + { + // shouldn't happen, but just in case... + + debug("Unable to list contents (null directory)"); + return ""; + } + + // Check for existence and that the given File is actually a directory. + + if (!directory.exists()) + { + debug(String.format( + "Unable to list contents (no such directory): %s", + directory.toString())); + return ""; + } + + if (!directory.isDirectory()) + { + debug(String.format( + "Unable to list contents (not a directory): %s", + directory.toString())); + return ""; + } + + try + { + // security check (converts to full canonical path with JRE7 or 8) + + directory = checkDirectoryListing(directory); + } + catch (Exception e) + { + debug(String.format("Unable to list contents of: %s", + directory.getAbsolutePath()), e); + return ""; + } + + if (!isReadPermitted(directory)) + { + debug(String.format("No read access for directory: %s", directory)); + return ""; + } + + if ((regex == null) || ("".equals(regex))) + { + // null or empty regular expression forbidden (use ".*" for + // all files, "" means only match a file with an empty + // filename, which doesn't make much sense). + + debug("Null or empty regular expression in getFilterFileList"); + return ""; + } + + StringBuilder builder = new StringBuilder(); + + try + { + String[] list = directory.list( + new FilenameFilter() + { + @Override + public boolean accept(File dir, String name) + { + File file = new File(dir, name); + + if (!isReadPermitted(file)) + { + debug(String.format("No read access for file: %s", file)); + return false; + } + + switch (listType) + { + case FILE_LIST_DIRECTORIES_ONLY: + + if (!file.isDirectory()) return false; + + break; + case FILE_LIST_REGULAR_FILES_ONLY: + + if (file.isDirectory()) return false; + + break; + } + + return name.matches(regex); + } + }); + + if (list != null) + { + if (sortType != FileSortType.FILE_SORT_DEFAULT) + { + sortFileList(list, directory, sortType); + } + + for (int i = 0; i < list.length; i++) + { + if (i > 0) + { + builder.append(separator); + } + + if (list[i].contains(separator)) + { + builder.append(String.format("{%s}", escapeFileName(list[i]))); + } + else + { + builder.append(escapeFileName(list[i])); + } + } + + } + + return builder.toString(); + } + catch (Exception exception) + { + // Catch all possible exceptions + debug(String.format("Unable to list contents of '%s' using regex: %s", + directory.toString(), regex), + exception); + } + + // Unsuccessful + return ""; + } + + /** + * Recursive file listing. This method must have the CWD or a + * descendent as the starting directory. It will return list of + * files relative to the starting directory where the basename + * matches the supplied regular expression. Hidden files/directories + * and symbolic links are skipped regardless of the openin_any setting. + * Files without read access are also omitted from the list. + * + * This method requires the java.nio.file library, which was + * introduced in Java 7, so this isn't available for the JRE5 + * version. + * + * @param separator separator to use in returned list + * @param regex regular expression used to match file basenames + * @param directory starting directory (must be cwd or a + * descendent of cwd) + * @return list of relative paths + */ + public String walk(String separator, + String regex, File directory, + FileSortType sortType) + { + debug("walk requires at least JRE 7 version"); + return ""; + } + + /** + * Gets the file URI. + * @param file The file. + * @return The URI. + */ + public String fileURI(File file) + { + if (file == null) + { + // This shouldn't happen, but just in case... + debug("null file passed to fileURI"); + return ""; + } + + if (!file.exists()) + { + debug(String.format("can't obtain URI of file (no such file): %s", + file.toString())); + return ""; + } + + if (!isReadPermitted(file)) + { + debug(String.format("No read access for file: %s", file)); + return ""; + } + + try + { + return escapeFileName(file.getCanonicalFile().toURI().toString()); + } + catch (Exception exception) + { + debug(String.format("Can't obtain URI of file: %s", file.toString()), + exception); + } + + // Unsuccessful + return ""; + } + + /** + * Gets the full TeX file path name from File object. + * @param file The file. + * @return The path. + */ + public String filePath(File file) + { + if (file == null) + { + // This shouldn't happen, but just in case... + debug("null file passed to filePath"); + return ""; + } + + if (!file.exists()) + { + debug(String.format( + "Can't obtain full file path (no such file): %s", + file.toString())); + return ""; + } + + if (!isReadPermitted(file)) + { + debug(String.format( + "Can't obtain full file path (no read access): %s", + file.toString())); + return ""; + } + + try + { + return toTeXPath(file.getCanonicalPath()); + } + catch (Exception exception) + { + debug(String.format( + "Can't obtain full path for file: %s", file.toString()), + exception); + } + + // Unsuccessful + return ""; + } + + /** + * Gets the path for the file's parent. + * @param file The file. + * @return The path. + * @since 1.1 + */ + public String parentPath(File file) + { + if (file == null) + { + // This shouldn't happen, but just in case... + debug("null file passed to filePath"); + return ""; + } + + if (!file.exists()) + { + debug(String.format( + "Can't obtain full parent path for file (no such file): %s", + file.toString())); + return ""; + } + + if (!isReadPermitted(file)) + { + debug(String.format( + "Can't obtain full path for file (no read access): %s", + file.toString())); + return ""; + } + + try + { + File parent = file.getCanonicalFile().getParentFile(); + + if (parent == null) + { + // No parent? If getCanonicalFile fails it throws an + // exception, so no parent would presumably mean the + // file's in the root directory. + + debug(String.format( + "No parent found for file: %s", file.toString())); + return ""; + } + + return toTeXPath(parent.getAbsolutePath()); + + } + catch (Exception exception) + { + debug(String.format( + "Can't obtain full parent path for file: %s", file.toString()), + exception); + } + + // Unsuccessful + return ""; + } + + /** + * Gets the script for the given locale. Java only introduced + * support for language scripts in version 1.7, so this returns + * null here. The Java 7 and 8 support needs to override this method. + * @param locale The locale + * @return The language script associated with the given locale or + * null if not available + * @since 1.2 + */ + public String getScript(Locale locale) + { + return null; + } + + /** + * Gets the language tag for the given locale. + * @param locale The locale or null for the default locale + * @return The language tag + * @since 1.2 + */ + public String getLanguageTag(Locale locale) + { + if (locale == null) + { + locale = Locale.getDefault(); + } + + String tag = locale.getLanguage(); + + String country = locale.getCountry(); + + if (country != null && !"".equals(country)) + { + tag = String.format("%s-%s", tag, country); + } + + String variant = locale.getVariant(); + + if (variant != null && !"".equals(variant)) + { + tag = String.format("%s-%s", tag, variant); + } + + return tag; + } + + /** + * Gets a string representation of the provided locale. + * @param locale The provided locale. + * @return String representation. + */ + public String getLocale(Locale locale) + { + return getLocale(locale, false); + } + + /** + * Gets a POSIX representation of the provided locale, converting the code + * set if possible. If the boolean argument is true, this + * attempts to convert the code set to a identifier that stands + * a better chance of being recognised by inputenc.sty. For + * example, UTF-8 will be converted to utf8. None of TeX's + * special characters should occur in any of the locale + * information, but we'd better treat it like a file name just in + * case. + * @param locale The provided locale. + * @param convertCodeset Boolean value to convert the code set. + * @return String representation. + */ + public String getLocale(Locale locale, boolean convertCodeset) + { + String identifier = ""; + + if (locale == null) + { + // No locale provided, return empty string + debug("null locale"); + return ""; + } + + String language = locale.getLanguage(); + + if (language == null) + { + // No language provided for the locale. The language + // part will be omitted from the returned string. + debug(String.format("No language for locale: %s", locale.toString())); + } + else + { + identifier = language; + } + + String country = locale.getCountry(); + + if (country == null || "".equals(country)) + { + // No country is associated with the locale. The + // country part will be omitted from the returned + // string. This is just information, not an error. + + info(String.format("No region for locale: %s", locale.toString())); + } + else + { + if ("".equals(identifier)) + { + // The identifier hasn't been set (no language + // provided), so just set it to the country code. + identifier = country; + } + else + { + // Append the country code to the identifier. + identifier = identifier.concat("-").concat(country); + } + } + + String codeset = getCodeSet(convertCodeset); + + identifier = identifier.concat(".").concat(codeset); + + // Find the script if available. This is used as the modifier part + // but it's better to use a language tag if the script is + // needed. + + String script = getScript(locale); + + if (script == null || "".equals(script)) + { + // Script information is missing. Ignore it. + // This is just an advisory message. + + info(String.format("No script available for locale: %s", + locale.toString())); + } + else + { + // Append the script. This will be a four letter string + // (if it's not empty). + identifier = identifier.concat("@").concat(script); + } + + return escapeFileName(identifier); + } + + /** + * Gets default file encoding. (Don't escape it here or it will cause + * a problem when called in getLocale.) + * @param convertCodeset If true convert codeset to fit + * inputenc.sty + * @return the file encoding. + * @since 1.2 + */ + public String getCodeSet(boolean convertCodeset) + { + // Get the OS default file encoding or "UTF-8" if not set. + + String codeset = getSystemProperty("file.encoding", "UTF-8"); + + // The codeset should not be null here as a default has + // been provided if the property is missing. + + if (convertCodeset) + { + // If conversion is required, change to lower case + // and remove any hyphens. + codeset = codeset.toLowerCase().replaceAll("-", ""); + } + + return codeset; + } + + /** + * Gets the two-letter alpha region code from the numeric code. + * (Java doesn't seem to recognise the numeric codes.) + * @param ISO 3166-1 numeric code + * @return ISO 3166-1 alpha code + * @since 1.2 + */ + public String getRegionAlpha2Code(int code) + { + switch (code) + { + case 4: return "AF"; + case 8: return "AL"; + case 10: return "AQ"; + case 12: return "DZ"; + case 16: return "AS"; + case 20: return "AD"; + case 24: return "AO"; + case 28: return "AG"; + case 31: return "AZ"; + case 32: return "AR"; + case 36: return "AU"; + case 40: return "AT"; + case 44: return "BS"; + case 48: return "BH"; + case 50: return "BD"; + case 51: return "AM"; + case 52: return "BB"; + case 56: return "BE"; + case 60: return "BM"; + case 64: return "BT"; + case 68: return "BO"; + case 70: return "BA"; + case 72: return "BW"; + case 74: return "BV"; + case 76: return "BR"; + case 84: return "BZ"; + case 86: return "IO"; + case 90: return "SB"; + case 92: return "VG"; + case 96: return "BN"; + case 100: return "BG"; + case 104: return "MM"; + case 108: return "BI"; + case 112: return "BY"; + case 116: return "KH"; + case 120: return "CM"; + case 124: return "CA"; + case 132: return "CV"; + case 136: return "KY"; + case 140: return "CF"; + case 144: return "LK"; + case 148: return "TD"; + case 152: return "CL"; + case 156: return "CN"; + case 158: return "TW"; + case 162: return "CX"; + case 166: return "CC"; + case 170: return "CO"; + case 174: return "KM"; + case 175: return "YT"; + case 178: return "CG"; + case 180: return "CD"; + case 184: return "CK"; + case 188: return "CR"; + case 191: return "HR"; + case 192: return "CU"; + case 196: return "CY"; + case 203: return "CZ"; + case 204: return "BJ"; + case 208: return "DK"; + case 212: return "DM"; + case 214: return "DO"; + case 218: return "EC"; + case 222: return "SV"; + case 226: return "GQ"; + case 231: return "ET"; + case 232: return "ER"; + case 233: return "EE"; + case 234: return "FO"; + case 238: return "FK"; + case 239: return "GS"; + case 242: return "FJ"; + case 246: return "FI"; + case 248: return "AX"; + case 250: return "FR"; + case 254: return "GF"; + case 258: return "PF"; + case 260: return "TF"; + case 262: return "DJ"; + case 266: return "GA"; + case 268: return "GE"; + case 270: return "GM"; + case 275: return "PS"; + case 276: return "DE"; + case 288: return "GH"; + case 292: return "GI"; + case 296: return "KI"; + case 300: return "GR"; + case 304: return "GL"; + case 308: return "GD"; + case 312: return "GP"; + case 316: return "GU"; + case 320: return "GT"; + case 324: return "GN"; + case 328: return "GY"; + case 332: return "HT"; + case 334: return "HM"; + case 336: return "VA"; + case 340: return "HN"; + case 344: return "HK"; + case 348: return "HU"; + case 352: return "IS"; + case 356: return "IN"; + case 360: return "ID"; + case 364: return "IR"; + case 368: return "IQ"; + case 372: return "IE"; + case 376: return "IL"; + case 380: return "IT"; + case 384: return "CI"; + case 388: return "JM"; + case 392: return "JP"; + case 398: return "KZ"; + case 400: return "JO"; + case 404: return "KE"; + case 408: return "KP"; + case 410: return "KR"; + case 414: return "KW"; + case 417: return "KG"; + case 418: return "LA"; + case 422: return "LB"; + case 426: return "LS"; + case 428: return "LV"; + case 430: return "LR"; + case 434: return "LY"; + case 438: return "LI"; + case 440: return "LT"; + case 442: return "LU"; + case 446: return "MO"; + case 450: return "MG"; + case 454: return "MW"; + case 458: return "MY"; + case 462: return "MV"; + case 466: return "ML"; + case 470: return "MT"; + case 474: return "MQ"; + case 478: return "MR"; + case 480: return "MU"; + case 484: return "MX"; + case 492: return "MC"; + case 496: return "MN"; + case 498: return "MD"; + case 499: return "ME"; + case 500: return "MS"; + case 504: return "MA"; + case 508: return "MZ"; + case 512: return "OM"; + case 516: return "NA"; + case 520: return "NR"; + case 524: return "NP"; + case 528: return "NL"; + case 531: return "CW"; + case 533: return "AW"; + case 534: return "SX"; + case 535: return "BQ"; + case 540: return "NC"; + case 548: return "VU"; + case 554: return "NZ"; + case 558: return "NI"; + case 562: return "NE"; + case 566: return "NG"; + case 570: return "NU"; + case 574: return "NF"; + case 578: return "NO"; + case 580: return "MP"; + case 581: return "UM"; + case 583: return "FM"; + case 584: return "MH"; + case 585: return "PW"; + case 586: return "PK"; + case 591: return "PA"; + case 598: return "PG"; + case 600: return "PY"; + case 604: return "PE"; + case 608: return "PH"; + case 612: return "PN"; + case 616: return "PL"; + case 620: return "PT"; + case 624: return "GW"; + case 626: return "TL"; + case 630: return "PR"; + case 634: return "QA"; + case 638: return "RE"; + case 642: return "RO"; + case 643: return "RU"; + case 646: return "RW"; + case 652: return "BL"; + case 654: return "SH"; + case 659: return "KN"; + case 660: return "AI"; + case 662: return "LC"; + case 663: return "MF"; + case 666: return "PM"; + case 670: return "VC"; + case 674: return "SM"; + case 678: return "ST"; + case 682: return "SA"; + case 686: return "SN"; + case 688: return "RS"; + case 690: return "SC"; + case 694: return "SL"; + case 702: return "SG"; + case 703: return "SK"; + case 704: return "VN"; + case 705: return "SI"; + case 706: return "SO"; + case 710: return "ZA"; + case 716: return "ZW"; + case 724: return "ES"; + case 728: return "SS"; + case 729: return "SD"; + case 732: return "EH"; + case 740: return "SR"; + case 744: return "SJ"; + case 748: return "SZ"; + case 752: return "SE"; + case 756: return "CH"; + case 760: return "SY"; + case 762: return "TJ"; + case 764: return "TH"; + case 768: return "TG"; + case 772: return "TK"; + case 776: return "TO"; + case 780: return "TT"; + case 784: return "AE"; + case 788: return "TN"; + case 792: return "TR"; + case 795: return "TM"; + case 796: return "TC"; + case 798: return "TV"; + case 800: return "UG"; + case 804: return "UA"; + case 807: return "MK"; + case 818: return "EG"; + case 826: return "GB"; + case 831: return "GG"; + case 832: return "JE"; + case 833: return "IM"; + case 834: return "TZ"; + case 840: return "US"; + case 850: return "VI"; + case 854: return "BF"; + case 858: return "UY"; + case 860: return "UZ"; + case 862: return "VE"; + case 876: return "WF"; + case 882: return "WS"; + case 887: return "YE"; + case 894: return "ZM"; + } + + // not recognised, return the code as a string + debug(String.format("Unrecognised numeric region code: %d", code)); + return String.format("%d", code); + } + + /** + * Gets the locale from the given language tag. Since Java didn't + * support BCP47 language tags until v1.7, we can't use + * Locale.forLanguageTag(String) here. (The Java 7 and 8 support + * will need to override this method.) Only parse for language + * code, country code and variant. Grandfathered, irregular and private + * tags not supported. + * @param languageTag The language tag + * @return The locale that closest matches the language tag + * @since 1.2 + */ + public Locale getLocale(String languageTag) + { + // The BCP47 syntax is described in + // https://tools.ietf.org/html/bcp47#section-2.1 + // This is a match for a subset of the regular syntax. + // Only the language tag, the region and the variant are + // captured. + // Note: named capturing groups was introduced in Java 7, so we + // can't use them here. + Pattern p = Pattern.compile( + "(?:([a-z]{2,3}(?:-[a-z]{2,3})*))+(?:-[A-Z][a-z]{3})?(?:-([A-Z]{2}|[0-9]{3}))?(?:-([a-zA-Z0-9]{5,8}|[0-9][a-zA-Z0-9]{3}))?(?:-.)*"); + + Matcher m = p.matcher(languageTag); + + if (m.matches()) + { + String language = m.group(1); + String region = m.group(2); + String variant = m.group(3); + + try + { + region = getRegionAlpha2Code(Integer.parseInt(region)); + } + catch (NumberFormatException e) + { + // ignore, alpha region code was supplied + } + + // Language won't be null as the pattern requires it, but + // the region and variant might be. + + if (region == null) + { + // There isn't a Locale constructor that allows a + // variant without a region, so don't bother checking + // variant for null here. + + return new Locale(language); + } + + if (variant == null) + { + return new Locale(language, region); + } + + return new Locale(language, region, variant); + } + + debug(String.format("Can't parse language tag: %s", languageTag)); + + // strip anything to a hyphen and try that + String[] split = languageTag.split("-", 1); + + return new Locale(split[0]); + } + + /** + * Gets all numerical information for the given locale. If the + * given locale tag is null or empty, the default locale is used. The + * information is returned with each item grouped to make it + * easier to parse in TeX. This is an abridged version of + * getLocaleData(). + * @param localeTag the tag identifying the locale or null for + * the default locale + * @return locale numerical information: language tag, + * number group separator, decimal separator, exponent separator, + * grouping conditional (1 if locale uses number grouping + * otherwise 0), + * currency code (e.g. GBP), regional currency identifier (e.g. IMP), + * currency symbol (e.g. \\twrp{&0x00A3;}), currency TeX code (e.g. + * \\texosquerycurrency{pound}), monetary decimal separator. + * @since 1.2 + */ + public String getNumericalInfo(String localeTag) + { + Locale locale; + + if (localeTag == null || "".equals(localeTag)) + { + locale = Locale.getDefault(); + } + else + { + locale = getLocale(localeTag); + } + + DecimalFormatSymbols fmtSyms + = DecimalFormatSymbols.getInstance(locale); + + // ISO 4217 code + String currencyCode = fmtSyms.getInternationalCurrencySymbol(); + + // Currency symbol + String currency = fmtSyms.getCurrencySymbol(); + + // Check for known unofficial currency codes + + String localeCurrencyCode = currencyCode; + + String countryCode = locale.getCountry(); + + if (countryCode != null && !"".equals(countryCode)) + { + if (countryCode.equals("GG") || countryCode.equals("GGY") + || countryCode.equals("831")) + {// Guernsey + localeCurrencyCode = "GGP"; + currency = POUND_STRING; + } + else if (countryCode.equals("JE") || countryCode.equals("JEY") + || countryCode.equals("832")) + {// Jersey + localeCurrencyCode = "JEP"; + currency = POUND_STRING; + } + else if (countryCode.equals("IM") || countryCode.equals("IMN") + || countryCode.equals("833")) + {// Isle of Man + localeCurrencyCode = "IMP"; + currency = String.format("M%s", POUND_STRING); + } + else if (countryCode.equals("KI") || countryCode.equals("KIR") + || countryCode.equals("296")) + {// Kiribati + localeCurrencyCode = "KID"; + currency = "$"; + } + else if (countryCode.equals("TV") || countryCode.equals("TUV") + || countryCode.equals("798")) + {// Tuvaluan + localeCurrencyCode = "TVD"; + currency = "$"; + } + // Transnistrian ruble omitted as it conflicts with ISO + // 4217 so omitted. There's also no country code for + // Transnistria. Other currencies don't have an associated + // region code (for example, Somaliland) or don't have a + // known unofficial currency code (for example, Alderney). + } + + // Convert known Unicode currency symbols to commands that + // may be redefined in TeX + + String texCurrency = getTeXCurrency(currency); + + NumberFormat numFormat = NumberFormat.getNumberInstance(locale); + + // Currency codes should always be three letter upper case + // A-Z characters, so no need to escape them. + + return String.format( + "{%s}{%s}{%s}{%s}{%d}{%s}{%s}{%s}{%s}{%s}", + escapeFileName(getLanguageTag(locale)), + escapeText(fmtSyms.getGroupingSeparator()), + escapeText(fmtSyms.getDecimalSeparator()), + escapeText(fmtSyms.getExponentSeparator()), + numFormat.isGroupingUsed() ? 1 : 0, + currencyCode, + localeCurrencyCode, + escapeText(currency), + texCurrency,// already escaped + escapeText(fmtSyms.getMonetaryDecimalSeparator())); + } + + /** + * Gets the currency with known symbols replaced by TeX commands + * provided by texosquery.tex. Some of the conditions in this + * method test for archaic currency symbols. It seems very + * unlikely that any of those cases would actually occur, but + * they're included for completeness. + * @param currency The original currency string + * @return The TeX version + * @since 1.2 + */ + public String getTeXCurrency(String currency) + { + StringBuilder builder = new StringBuilder(); + + for (int i = 0, n = currency.length(); i < n; ) + { + int codepoint = currency.codePointAt(i); + i += Character.charCount(codepoint); + + switch (codepoint) + { + case DOLLAR_CHAR: + builder.append("\\texosquerycurrency{dollar}"); + break; + case CENT_CHAR: + builder.append("\\texosquerycurrency{cent}"); + break; + case POUND_CHAR: + builder.append("\\texosquerycurrency{pound}"); + break; + case CURRENCY_CHAR: + builder.append("\\texosquerycurrency{sign}"); + break; + case YEN_CHAR: + builder.append("\\texosquerycurrency{yen}"); + break; + case ECU_CHAR: + builder.append("\\texosquerycurrency{ecu}"); + break; + case COLON_CURRENCY_CHAR: + builder.append("\\texosquerycurrency{colon}"); + break; + case CRUZEIRO_CHAR: + builder.append("\\texosquerycurrency{cruzeiro}"); + break; + case FRANC_CHAR: + builder.append("\\texosquerycurrency{franc}"); + break; + case LIRA_CHAR: + builder.append("\\texosquerycurrency{lira}"); + break; + case MILL_CURRENCY_CHAR: + builder.append("\\texosquerycurrency{mill}"); + break; + case NAIRA_CHAR: + builder.append("\\texosquerycurrency{naira}"); + break; + case PESETA_CHAR: + builder.append("\\texosquerycurrency{peseta}"); + break; + case LEGACY_RUPEE_CHAR: + case RUPEE_CHAR: + builder.append("\\texosquerycurrency{rupee}"); + break; + case WON_CHAR: + builder.append("\\texosquerycurrency{won}"); + break; + case NEW_SHEQEL_CHAR: + builder.append("\\texosquerycurrency{newsheqel}"); + break; + case DONG_CHAR: + builder.append("\\texosquerycurrency{dong}"); + break; + case EURO_CHAR: + builder.append("\\texosquerycurrency{euro}"); + break; + case KIP_CHAR: + builder.append("\\texosquerycurrency{kip}"); + break; + case TUGRIK_CHAR: + builder.append("\\texosquerycurrency{tugrik}"); + break; + case DRACHMA_CHAR: + builder.append("\\texosquerycurrency{drachma}"); + break; + case GERMAN_PENNY_CHAR: + builder.append("\\texosquerycurrency{germanpenny}"); + break; + case PESO_CHAR: + builder.append("\\texosquerycurrency{peso}"); + break; + case GUARANI_CHAR: + builder.append("\\texosquerycurrency{guarani}"); + break; + case AUSTRAL_CHAR: + builder.append("\\texosquerycurrency{austral}"); + break; + case HRYVNIA_CHAR: + builder.append("\\texosquerycurrency{hryvnia}"); + break; + case CEDI_CHAR: + builder.append("\\texosquerycurrency{cedi}"); + break; + case LIVRE_TOURNOIS_CHAR: + builder.append("\\texosquerycurrency{livretournois}"); + break; + case SPESMILO_CHAR: + builder.append("\\texosquerycurrency{spesmilo}"); + break; + case TENGE_CHAR: + builder.append("\\texosquerycurrency{tenge}"); + break; + case TURKISH_LIRA_CHAR: + builder.append("\\texosquerycurrency{turkishlira}"); + break; + case NORDIC_MARK_CHAR: + builder.append("\\texosquerycurrency{nordicmark}"); + break; + case MANAT_CHAR: + builder.append("\\texosquerycurrency{manat}"); + break; + case RUBLE_CHAR: + builder.append("\\texosquerycurrency{ruble}"); + break; + default: + builder.append(escapeText(codepoint)); + } + } + + return builder.toString(); + } + + /** Gets the standalone month names for the locale data. + * These are only available for Java 8, so just return the + * month names used in the date format instead. The JRE8 version + * needs to override this method. + * @param cal The calendar + * @param locale The locale + * @return month names + * @since 1.2 + */ + public String getStandaloneMonths(Calendar cal, Locale locale) + { + // can't use Calendar.getDisplayName() as it's not available + // with Java 5. + DateFormatSymbols dateFmtSyms = DateFormatSymbols.getInstance(locale); + + StringBuilder monthNamesGroup = new StringBuilder(); + + String[] names = dateFmtSyms.getMonths(); + + for (int i = 0; i < 12; i++) + { + monthNamesGroup.append(String.format("{%s}", escapeText(names[i]))); + } + + return monthNamesGroup.toString(); + } + + /** Gets the standalone short month names for the locale data. + * These are only available for Java 8, so just return the + * month names used in the date format instead. The JRE8 version + * needs to override this method. + * @param cal The calendar + * @param locale The locale + * @return short month names + * @since 1.2 + */ + public String getStandaloneShortMonths(Calendar cal, Locale locale) + { + // can't use Calendar.getDisplayName() as it's not available + // with Java 5. + DateFormatSymbols dateFmtSyms = DateFormatSymbols.getInstance(locale); + + StringBuilder shortMonthNamesGroup = new StringBuilder(); + + String[] names = dateFmtSyms.getShortMonths(); + + for (int i = 0; i < 12; i++) + { + shortMonthNamesGroup.append(String.format("{%s}", + escapeText(names[i]))); + } + + return shortMonthNamesGroup.toString(); + } + + /** Gets the standalone day names for the locale data. + * These are only available for Java 8, so just return the + * names used in the date format instead. The JRE8 version + * needs to override this method. + * @param cal The calendar + * @param locale The locale + * @return day of week names + * @since 1.2 + */ + public String getStandaloneWeekdays(Calendar cal, Locale locale) + { + DateFormatSymbols dateFmtSyms = DateFormatSymbols.getInstance(locale); + + String[] names = dateFmtSyms.getWeekdays(); + + // Be consistent with pgfcalendar: + + return String.format("{%s}{%s}{%s}{%s}{%s}{%s}{%s}", + escapeText(names[Calendar.MONDAY]), + escapeText(names[Calendar.TUESDAY]), + escapeText(names[Calendar.WEDNESDAY]), + escapeText(names[Calendar.THURSDAY]), + escapeText(names[Calendar.FRIDAY]), + escapeText(names[Calendar.SATURDAY]), + escapeText(names[Calendar.SUNDAY])); + } + + /** Gets the standalone short day names for the locale data. + * These are only available for Java 8, so just return the + * names used in the date format instead. The JRE8 version + * needs to override this method. + * @param cal The calendar + * @param locale The locale + * @return day of week names + * @since 1.2 + */ + public String getStandaloneShortWeekdays(Calendar cal, Locale locale) + { + DateFormatSymbols dateFmtSyms = DateFormatSymbols.getInstance(locale); + + String[] names = dateFmtSyms.getShortWeekdays(); + + // Be consistent with pgfcalendar: + + return String.format("{%s}{%s}{%s}{%s}{%s}{%s}{%s}", + escapeText(names[Calendar.MONDAY]), + escapeText(names[Calendar.TUESDAY]), + escapeText(names[Calendar.WEDNESDAY]), + escapeText(names[Calendar.THURSDAY]), + escapeText(names[Calendar.FRIDAY]), + escapeText(names[Calendar.SATURDAY]), + escapeText(names[Calendar.SUNDAY])); + } + + /** + * Converts date/time pattern to a form that's easier for TeX to + * parse. This replaces the placeholders with <tt>\\patdtf{n}{c}</tt> where c + * is the placeholder character and n is the number of + * occurrences of c in the placeholder. (For example, + * "<tt>dd-MMM-yyyy</tt>" is converted to + * <tt>\\patdtf{2}{d}-\\patdtf{3}{M}-\\patdtf{4}{y}</tt>). The + * query command \\TeXOSQuery in texosquery.tex will expand \\patdtf + * to the longer \\texosquerydtf to avoid conflict. This can then be + * redefined as appropriate. (See the "Pattern Formats" section + * of the TeX documented code for more detail.) + * @param localeFormat The date/time pattern + * @return TeX code + * @since 1.2 + */ + public String formatDateTimePattern(Format localeFormat) + { + SimpleDateFormat fmt = null; + + try + { + fmt = (SimpleDateFormat)localeFormat; + + if (fmt == null) + { + throw new NullPointerException(); + } + } + catch (Exception e) + { + // this shouldn't happen + debug(String.format("Invalid argument: %s", localeFormat), e); + return ""; + } + + String pattern = fmt.toPattern(); + + StringBuilder builder = new StringBuilder(); + + int prev = 0; + int fieldLen = 0; + boolean inString = false; + + for (int i = 0, n = pattern.length(), offset=1; i < n; i = i+offset) + { + int codepoint = pattern.codePointAt(i); + offset = Character.charCount(codepoint); + + int nextIndex = i+offset; + int nextCodePoint = (nextIndex < n ? pattern.codePointAt(nextIndex):0); + + if (inString) + { + if (codepoint == '\'') + { + if (nextCodePoint != '\'') + { + // reached the end of the string + builder.append('}'); + inString = false; + } + else + { + // literal ' + builder.append("\\patapo "); + i = nextIndex; + offset = Character.charCount(nextCodePoint); + } + } + else + { + // still inside the string + builder.append(escapeText(codepoint)); + } + } + else if (codepoint == prev) + { + fieldLen++; + } + else + { + switch (codepoint) + { + case '\'': // quote + + if (prev != 0) + { + builder.append(String.format( + "\\patdtf{%d}{%c}", fieldLen, prev)); + prev = 0; + fieldLen = 0; + } + + // start of the string + builder.append("\\patstr{"); + inString = true; + + break; + case 'G': // era + case 'y': // year + case 'Y': // week year + case 'M': // month in year (context sensitive) + case 'L': // month in year (standalone) + case 'w': // week in year + case 'W': // week in month + case 'D': // day in year + case 'd': // day in month + case 'F': // day of week in month + case 'E': // day name in week + case 'u': // day number of week (1 = Mon) + case 'a': // am/pm marker + case 'H': // hour in day (0-23) + case 'k': // hour in day (1-24) + case 'K': // hour in am/pm (0-11) + case 'h': // hour in am/pm (1-12) + case 'm': // minute in hour + case 's': // second in minute + case 'S': // millisecond + case 'z': // time zone (locale) + case 'Z': // time zone (RFC 822) + case 'X': // time zone (ISO 8601) + prev = codepoint; + fieldLen = 1; + break; + default: + // prev doesn't need escaping as it will be one + // of the above letter cases. + + if (prev == 0) + { + builder.append(escapeText(codepoint)); + } + else + { + builder.append(String.format( + "\\patdtf{%d}{%c}%s", fieldLen, prev, + escapeText(codepoint))); + } + prev = 0; + fieldLen = 0; + } + } + } + + if (prev != 0) + { + builder.append(String.format( + "\\patdtf{%d}{%c}", fieldLen, prev)); + } + + return builder.toString(); + } + + /** + * Converts numeric pattern to a form that's easier for TeX to parse. + * @param numFormat the numeric pattern + * @return TeX code + * @since 1.2 + */ + public String formatNumberPattern(Format numFormat) + { + DecimalFormat fmt = null; + + try + { + fmt = (DecimalFormat)numFormat; + + if (fmt == null) + { + throw new NullPointerException(); + } + } + catch (Exception e) + { + // this shouldn't happen + debug(String.format("Invalid argument: %s", numFormat), e); + return ""; + } + + String pattern = fmt.toPattern(); + + // Is there a +ve;-ve sub-pattern pair? + // This is a bit awkward as a semi-colon could appear + // literally within a string. + + String positive = null; + String negative = null; + + StringBuilder builder = new StringBuilder(); + boolean inString = false; + + for (int i = 0, n = pattern.length(), offset=1; i < n; i = i+offset) + { + int codepoint = pattern.codePointAt(i); + offset = Character.charCount(codepoint); + + int nextIndex = i+offset; + int nextCodePoint = (nextIndex < n ? pattern.codePointAt(nextIndex):0); + + if (inString) + { + if (codepoint == '\'') + { + builder.appendCodePoint(codepoint); + + if (nextCodePoint == '\'') + { + // literal ' + builder.appendCodePoint(nextCodePoint); + i = nextIndex; + offset = Character.charCount(nextCodePoint); + } + else + { + inString = false; + } + } + else + { + builder.appendCodePoint(codepoint); + } + } + else if (codepoint == '\'') + { + inString = true; + builder.appendCodePoint(codepoint); + } + else if (codepoint == ';') + { + if (positive == null) + { + positive = builder.toString(); + builder = new StringBuilder(); + } + else + { + debug(String.format("Too many ; found in pattern: %s", + pattern)); + } + } + else + { + builder.appendCodePoint(codepoint); + } + } + + if (positive == null) + { + positive = builder.toString(); + } + else if (builder.length() > 0) + { + negative = builder.toString(); + } + + if (negative == null) + { + return String.format("\\patnumfmt{%s}", + formatNumberSubPattern(positive)); + } + else + { + return String.format("\\patpmnumfmt{%s}{%s}", + formatNumberSubPattern(positive), + formatNumberSubPattern(negative)); + } + } + + /** + * Converts the sub-pattern of a numeric format. + * @param pattern The sub-pattern + * @return TeX code + * @since 1.2 + */ + private String formatNumberSubPattern(String pattern) + { + if (pattern == null || "".equals(pattern)) + { + return ""; + } + + // Is this currency? + + Pattern p = Pattern.compile("(.*(?:[^'](?:'')+){0,1})("+CURRENCY_CHAR + +"{1,2})(.*)"); + Matcher m = p.matcher(pattern); + + if (m.matches()) + { + return formatCurrencyPattern(m.group(1), + (m.group(2).length() == 2), m.group(3)); + } + + // Is this a percentage? + + p = Pattern.compile("(.*(?:[^'](?:'')+){0,1})([%"+PERMILLE_CHAR+"])(.*)"); + m = p.matcher(pattern); + + if (m.matches()) + { + boolean percent = ("%".equals(m.group(2))); + + return formatPercentagePattern(m.group(1), m.group(3), + percent ? "patppct" : "patppml", + percent ? "patspct" : "patspml"); + } + + // must be a number + + return formatNumericPattern(pattern); + } + + /** + * Converts the currency format. + * @param pre The pre-symbol pattern + * @param international Determines if the international currency + * symbol should be used + * @param post The post-symbol pattern + * @return TeX code + * @since 1.2 + */ + private String formatCurrencyPattern(String pre, boolean international, + String post) + { + if (post == null || "".equals(post)) + { + pre = formatNumericPattern(pre); + + // currency symbol is a suffix + if (international) + { + return String.format("\\patsicur{%s}{}", pre); + } + else + { + return String.format("\\patscur{%s}{}", pre); + } + } + else if (pre == null || "".equals(pre)) + { + // currency symbol is a prefix + + post = formatNumericPattern(post); + + if (international) + { + return String.format("\\patpicur{%s}{}", post); + } + else + { + return String.format("\\patpcur{%s}{}", post); + } + } + else + { + // What do we do here? If pre contains '#' or '0' assume + // a suffix currency otherwise a prefix currency. + + pre = formatNumericPattern(pre); + post = formatNumericPattern(post); + + if (pre.matches(".*[0#].*")) + { + // suffix, pre is the number and post is trailing + // text + if (international) + { + return String.format("\\patsicur{%s}{%s}", pre, post); + } + else + { + return String.format("\\patscur{%s}{%s}", pre, post); + } + } + else + { + // prefix, post is the number and pre is leading + // text + if (international) + { + return String.format("\\patpicur{%s}{%s}", post, pre); + } + else + { + return String.format("\\patpcur{%s}{%s}", post, pre); + } + } + } + } + + /** + * Converts percentage format. + * @param pre The pre-symbol pattern + * @param post The post-symbol pattern + * @param prefixCs The control sequence name to use if the symbol is a + * prefix + * @param suffixCs The control sequence name to use if the symbol is a + * suffix + * @return TeX code + * @since 1.2 + */ + private String formatPercentagePattern(String pre, String post, + String prefixCs, String suffixCs) + { + if (post == null || "".equals(post)) + { + pre = formatNumericPattern(pre); + + // symbol is a suffix + + return String.format("\\%s{%s}{}", suffixCs, pre); + } + else if (pre == null || "".equals(pre)) + { + // symbol is a prefix + + post = formatNumericPattern(post); + + return String.format("\\%s{%s}{}", prefixCs, post); + } + else + { + pre = formatNumericPattern(pre); + post = formatNumericPattern(post); + + if (pre.matches(".*[0#].*")) + { + // suffix, pre is the number and post is trailing + // text + + return String.format("\\%s{%s}{%s}", suffixCs, pre, post); + } + else + { + // prefix, post is the number and pre is leading + // text + + return String.format("\\%s{%s}{%s}", prefixCs, post, pre); + } + } + } + + /** + * Converts the numeric format. + * @param pattern The sub-pattern + * @return TeX code + * @since 1.2 + */ + private String formatNumericPattern(String pattern) + { + if (pattern == null || "".equals(pattern)) + { + return ""; + } + + // Split around exponent (if present) + + Pattern p = Pattern.compile("(.*(?:[^'](?:'')+?){0,1})(E.*)?"); + Matcher m = p.matcher(pattern); + + if (!m.matches()) + { + debug(String.format( + "Can't match number format sub-pattern '%s' against regexp: %s", + pattern, p)); + return ""; + } + + String pre = m.group(1); + String post = m.group(2); + + if (pre == null && post == null) + { + // empty pattern + return ""; + } + + if (post == null) + { + return formatDecimalPattern(pre); + } + + return String.format("\\patsinumfmt{%s}{%s}", + formatDecimalPattern(pre), + formatIntegerPattern(post, true)); + } + + /** + * Converts a decimal pattern. + * @param pattern The pattern + * @return TeX code + * @since 1.2 + */ + private String formatDecimalPattern(String pattern) + { + // split on the decimal point (if present) + + Pattern p = Pattern.compile("(.*?(?:[^'](?:'')){0,1})(?:\\.(.*))?"); + + Matcher m = p.matcher(pattern); + + if (!m.matches()) + { + debug(String.format( + "Can't match decimal pattern '%s' against regexp: %s", + pattern, p)); + return ""; + } + + + String pre = m.group(1); + String post = m.group(2); + + if (pre == null && post == null) + { + // empty pattern + return ""; + } + + if (post == null) + { + return formatIntegerPattern(pre, true); + } + + return String.format("\\patdecfmt{%s}{%s}", + formatIntegerPattern(pre, true), + formatIntegerPattern(post, false)); + } + + + /** + * Convert an integer pattern. The aim here is to have a number + * formatting command defined in TeX that will be passed a number + * with either leading or trailing zeros padded to 10 digits. + * TeX can't handle numbers higher than 2147483647, so any digits + * in the pattern beyond that are discarded. This means defining + * a command that effectively takes 10 arguments (with a bit of + * trickery to get around the 9-arg maximum). Each digit can then + * be rendered using either \\patdgt (always display the digit) + * or \\patdgtnz (only display the digit if it isn't a + * non-significant zero). + * + * These short commands will be converted to longer ones that are + * less likely to cause conflict when \\TeXOSQuery is used. + * (See the "Pattern Formats" section of the documented code for + * more details.) + * @param pattern The pattern + * @param leadPadding Determines if leading padding needs taking + * into account + * @return TeX code + * @since 1.2 + */ + private String formatIntegerPattern(String pattern, boolean leadPadding) + { + boolean inString = false; + + int digitCount = 0; + int groupCount = -1; + + // count the number of digits + + for (int i = 0, n = pattern.length(), offset=1; i < n; i = i+offset) + { + int codepoint = pattern.codePointAt(i); + offset = Character.charCount(codepoint); + + int nextIndex = i+offset; + int nextCodePoint = (nextIndex < n ? pattern.codePointAt(nextIndex):0); + + if (inString) + { + if (codepoint == '\'') + { + if (nextCodePoint != '\'') + { + inString = false; + i = nextIndex; + offset = Character.charCount(nextCodePoint); + } + } + } + else if (codepoint == '\'') + { + inString = true; + } + else if (codepoint == '#' || codepoint == '0') + { + digitCount++; + + if (groupCount > -1) groupCount++; + } + else if (codepoint == ',') + { + groupCount=0; + } + } + + int digitIndex = (leadPadding ? MAX_DIGIT_FORMAT : 0); + + inString = false; + + StringBuilder builder = new StringBuilder(); + + for (int i = 0, n = pattern.length(), offset=1; i < n; i = i+offset) + { + int codepoint = pattern.codePointAt(i); + offset = Character.charCount(codepoint); + + int nextIndex = i+offset; + int nextCodePoint = (nextIndex < n ? pattern.codePointAt(nextIndex):0); + + switch (codepoint) + { + case '\'': + + if (!inString) + { + inString = true; + + builder.append("\\patstr{"); + } + else if (nextCodePoint == '\'') + { + builder.append("\\patapo "); + i = nextIndex; + offset = Character.charCount(nextCodePoint); + } + else + { + builder.append("}"); + inString = false; + } + break; + case '0': + + if (leadPadding) + { + if (digitIndex > MAX_DIGIT_FORMAT) + { + // too many digit markers in the pattern, + // discard + } + else if (digitIndex > digitCount) + { + // not enough digit markers in the pattern + // pad with # + + for ( ; digitIndex > digitCount; digitIndex--) + { + builder.append("\\patdgtnz "); + + if (groupCount > 0 && ((digitIndex-1) % groupCount) == 0) + { + builder.append("\\patngp "); + } + } + + builder.append("\\patdgt "); + } + else + { + builder.append("\\patdgt "); + } + + digitIndex--; + } + else + { + digitIndex++; + + if (digitIndex > MAX_DIGIT_FORMAT) + { + // too many digit markers in the pattern, + // discard + } + else if (digitIndex == digitCount) + { + builder.append("\\patdgt "); + + // not enough digit markers in the pattern + // pad with # + + for ( ; digitIndex < MAX_DIGIT_FORMAT; digitIndex++) + { + builder.append("\\patdgtnz "); + } + } + else + { + builder.append("\\patdgt "); + } + } + break; + case '#': + + if (leadPadding) + { + if (digitIndex > MAX_DIGIT_FORMAT) + { + // too many digit markers in the pattern, + // discard + } + else if (digitIndex > digitCount) + { + // not enough digit markers in the pattern + // pad with # + + for ( ; digitIndex > digitCount; digitIndex--) + { + builder.append("\\patdgtnz "); + + if (groupCount > 0 && ((digitIndex-1) % groupCount) == 0) + { + builder.append("\\patngp "); + } + } + + builder.append("\\patdgtnz "); + } + else + { + builder.append("\\patdgtnz "); + } + + digitIndex--; + } + else + { + digitIndex++; + + if (digitIndex > MAX_DIGIT_FORMAT) + { + // too many digit markers in the pattern, + // discard + } + else if (digitIndex == digitCount) + { + builder.append("\\patdgtnz "); + + // not enough digit markers in the pattern + // pad with # + + for ( ; digitIndex < MAX_DIGIT_FORMAT; digitIndex++) + { + builder.append("\\patdgtnz "); + } + } + else + { + builder.append("\\patdgtnz "); + } + } + break; + case '-': + builder.append("\\patmsg "); + break; + case ',': + + if (digitIndex <= digitCount) + { + builder.append("\\patngp "); + } + + break; + default: + builder.append(escapeText(codepoint)); + } + } + + return builder.toString(); + } + + /** + * Gets all available data for the given locale. If the + * given locale tag is null, the default locale is used. The + * information is returned with grouping to make it + * easier to parse in TeX. (Each block is grouped, with each + * element within the block also grouped.) + * + * The standalone month names and day of week names are new + * to Java 8, so we can't use them for earlier versions. + * @param localeTag the language tag identifying the locale or null for + * the default locale + * @return locale data in grouped blocks: + * <ol> + * <li>language tag, language name, language name in given locale, + * country name, country name in given locale, variant name, + * variant name in given locale. + * <li> full date, long date, medium date, short date, + * first day of the week index. + * <li> full date, long date, medium date, short date patterns. + * <li> full time, long time, medium time, short time. + * <li> full time, long time, medium time, short time patterns. + * <li> weekday names. + * <li> short weekday names. + * <li> month names + * <li> short month names. + * <li> standalone week day names. + * <li> standalone short week day names. + * <li> standalone month names. + * <li> standalone short month names. + * <li> number group separator, + * decimal separator, exponent separator, grouping flag, ISO 4217 currency + * identifier (e.g. GBP), region currency identifier (usually the same as + * the ISO 4217 code, but may be an unofficial currency code, such as IMP), + * currency symbol (e.g. &0x00A3;), TeX currency symbol, monetary decimal + * separator, percent symbol, per mille symbol. + * <li> number format, integer format, currency format, + * percent format. + * </ol> + * @since 1.2 + */ + public String getLocaleData(String localeTag) + { + Locale locale; + + if (localeTag == null || "".equals(localeTag)) + { + locale = Locale.getDefault(); + } + else + { + locale = getLocale(localeTag); + } + + String languageName = locale.getDisplayLanguage(); + + if (languageName == null) + { + languageName = ""; + } + + String localeLanguageName = locale.getDisplayLanguage(locale); + + if (localeLanguageName == null) + { + localeLanguageName = ""; + } + + String countryName = locale.getDisplayCountry(); + + if (countryName == null) + { + countryName = ""; + } + + String localeCountryName = locale.getDisplayCountry(locale); + + if (localeCountryName == null) + { + localeCountryName = ""; + } + + String variantName = locale.getDisplayVariant(); + + if (variantName == null) + { + variantName = ""; + } + + String localeVariantName = locale.getDisplayVariant(locale); + + if (localeVariantName == null) + { + localeVariantName = ""; + } + + String langRegionGroup = String.format("{%s}{%s}{%s}{%s}{%s}{%s}{%s}", + escapeFileName(getLanguageTag(locale)), + escapeText(languageName), + escapeText(localeLanguageName), + escapeText(countryName), + escapeText(localeCountryName), + escapeText(variantName), + escapeText(localeVariantName)); + + DateFormat dateFullFormat = DateFormat.getDateInstance( + DateFormat.FULL, locale); + + DateFormat dateLongFormat = DateFormat.getDateInstance( + DateFormat.LONG, locale); + + DateFormat dateMediumFormat = DateFormat.getDateInstance( + DateFormat.MEDIUM, locale); + + DateFormat dateShortFormat = DateFormat.getDateInstance( + DateFormat.SHORT, locale); + + DateFormat timeFullFormat = DateFormat.getTimeInstance( + DateFormat.FULL, locale); + + DateFormat timeLongFormat = DateFormat.getTimeInstance( + DateFormat.LONG, locale); + + DateFormat timeMediumFormat = DateFormat.getTimeInstance( + DateFormat.MEDIUM, locale); + + DateFormat timeShortFormat = DateFormat.getTimeInstance( + DateFormat.SHORT, locale); + + DateFormat dateTimeFullFormat = DateFormat.getDateTimeInstance( + DateFormat.FULL, DateFormat.FULL, locale); + + DateFormat dateTimeLongFormat = DateFormat.getDateTimeInstance( + DateFormat.LONG, DateFormat.LONG, locale); + + DateFormat dateTimeMediumFormat = DateFormat.getDateTimeInstance( + DateFormat.MEDIUM, DateFormat.MEDIUM, locale); + + DateFormat dateTimeShortFormat = DateFormat.getDateTimeInstance( + DateFormat.SHORT, DateFormat.SHORT, locale); + + // first day of the week index consistent with pgfcalendar + // (0 = Monday, etc) + int firstDay = 0; + + Calendar cal = Calendar.getInstance(locale); + cal.setTimeInMillis(now.getTime()); + + switch (cal.getFirstDayOfWeek()) + { + case Calendar.MONDAY: + firstDay = 0; + break; + case Calendar.TUESDAY: + firstDay = 1; + break; + case Calendar.WEDNESDAY: + firstDay = 2; + break; + case Calendar.THURSDAY: + firstDay = 3; + break; + case Calendar.FRIDAY: + firstDay = 4; + break; + case Calendar.SATURDAY: + firstDay = 5; + break; + case Calendar.SUNDAY: + firstDay = 6; + break; + } + + String dateGroup = String.format("{%s}{%s}{%s}{%s}{%d}", + escapeText(dateFullFormat.format(now)), + escapeText(dateLongFormat.format(now)), + escapeText(dateMediumFormat.format(now)), + escapeText(dateShortFormat.format(now)), + firstDay); + + String dateFmtGroup = String.format("{%s}{%s}{%s}{%s}", + formatDateTimePattern(dateFullFormat), + formatDateTimePattern(dateLongFormat), + formatDateTimePattern(dateMediumFormat), + formatDateTimePattern(dateShortFormat)); + + String timeGroup = String.format("{%s}{%s}{%s}{%s}", + escapeText(timeFullFormat.format(now)), + escapeText(timeLongFormat.format(now)), + escapeText(timeMediumFormat.format(now)), + escapeText(timeShortFormat.format(now))); + + String timeFmtGroup = String.format("{%s}{%s}{%s}{%s}", + formatDateTimePattern(timeFullFormat), + formatDateTimePattern(timeLongFormat), + formatDateTimePattern(timeMediumFormat), + formatDateTimePattern(timeShortFormat)); + + String dateTimeGroup = String.format("{%s}{%s}{%s}{%s}", + escapeText(dateTimeFullFormat.format(now)), + escapeText(dateTimeLongFormat.format(now)), + escapeText(dateTimeMediumFormat.format(now)), + escapeText(dateTimeShortFormat.format(now))); + + String dateTimeFmtGroup = String.format("{%s}{%s}{%s}{%s}", + formatDateTimePattern(dateTimeFullFormat), + formatDateTimePattern(dateTimeLongFormat), + formatDateTimePattern(dateTimeMediumFormat), + formatDateTimePattern(dateTimeShortFormat)); + + DateFormatSymbols dateFmtSyms = DateFormatSymbols.getInstance(locale); + + String[] names = dateFmtSyms.getWeekdays(); + + // Be consistent with pgfcalendar: + + String weekdayNamesGroup = String.format( + "{%s}{%s}{%s}{%s}{%s}{%s}{%s}", + escapeText(names[Calendar.MONDAY]), + escapeText(names[Calendar.TUESDAY]), + escapeText(names[Calendar.WEDNESDAY]), + escapeText(names[Calendar.THURSDAY]), + escapeText(names[Calendar.FRIDAY]), + escapeText(names[Calendar.SATURDAY]), + escapeText(names[Calendar.SUNDAY])); + + names = dateFmtSyms.getShortWeekdays(); + + String shortWeekdayNamesGroup = String.format( + "{%s}{%s}{%s}{%s}{%s}{%s}{%s}", + escapeText(names[Calendar.MONDAY]), + escapeText(names[Calendar.TUESDAY]), + escapeText(names[Calendar.WEDNESDAY]), + escapeText(names[Calendar.THURSDAY]), + escapeText(names[Calendar.FRIDAY]), + escapeText(names[Calendar.SATURDAY]), + escapeText(names[Calendar.SUNDAY])); + + StringBuilder monthNamesGroup = new StringBuilder(); + + names = dateFmtSyms.getMonths(); + + for (int i = 0; i < 12; i++) + { + // skip 13th month (Calendar.UNDECIMBER) + monthNamesGroup.append(String.format("{%s}", escapeText(names[i]))); + } + + StringBuilder shortMonthNamesGroup = new StringBuilder(); + + names = dateFmtSyms.getShortMonths(); + + for (int i = 0; i < 12; i++) + { + shortMonthNamesGroup.append(String.format("{%s}", + escapeText(names[i]))); + } + + // Get numerical data (as with getNumericalInfo) + DecimalFormatSymbols fmtSyms + = DecimalFormatSymbols.getInstance(locale); + + // ISO 4217 code + String currencyCode = fmtSyms.getInternationalCurrencySymbol(); + + // Currency symbol + String currency = fmtSyms.getCurrencySymbol(); + + // Check for known unofficial currency codes + + String localeCurrencyCode = currencyCode; + + String countryCode = locale.getCountry(); + + if (countryCode != null && !"".equals(countryCode)) + { + if (countryCode.equals("GG") || countryCode.equals("GGY") + || countryCode.equals("831")) + {// Guernsey + localeCurrencyCode = "GGP"; + currency = POUND_STRING; + } + else if (countryCode.equals("JE") || countryCode.equals("JEY") + || countryCode.equals("832")) + {// Jersey + localeCurrencyCode = "JEP"; + currency = POUND_STRING; + } + else if (countryCode.equals("IM") || countryCode.equals("IMN") + || countryCode.equals("833")) + {// Isle of Man + localeCurrencyCode = "IMP"; + currency = String.format("M%s", POUND_STRING); + } + else if (countryCode.equals("KI") || countryCode.equals("KIR") + || countryCode.equals("296")) + {// Kiribati + localeCurrencyCode = "KID"; + currency = "$"; + } + else if (countryCode.equals("TV") || countryCode.equals("TUV") + || countryCode.equals("798")) + {// Tuvaluan + localeCurrencyCode = "TVD"; + currency = "$"; + } + // Transnistrian ruble omitted as it conflicts with ISO + // 4217. There's also no country code for + // Transnistria. Other currencies don't have an associated + // region code (for example, Somaliland) or don't have a + // known unofficial currency code (for example, Alderney). + } + + // Convert known Unicode currency symbols to commands that + // may be redefined in TeX + + String texCurrency = getTeXCurrency(currency); + + NumberFormat numFormat = NumberFormat.getNumberInstance(locale); + NumberFormat intFormat = NumberFormat.getIntegerInstance(locale); + NumberFormat curFormat = NumberFormat.getCurrencyInstance(locale); + NumberFormat pcFormat = NumberFormat.getPercentInstance(locale); + + String numGroup = String.format( + "{%s}{%s}{%s}{%d}{%s}{%s}{%s}{%s}{%s}{%s}{%s}", + escapeText(fmtSyms.getGroupingSeparator()), + escapeText(fmtSyms.getDecimalSeparator()), + escapeText(fmtSyms.getExponentSeparator()), + numFormat.isGroupingUsed() ? 1 : 0, + currencyCode, + localeCurrencyCode, + escapeText(currency), + texCurrency,// already escaped + escapeText(fmtSyms.getMonetaryDecimalSeparator()), + escapeText(fmtSyms.getPercent()), + escapeText(fmtSyms.getPerMill())); + + String numFmtGroup = String.format("{%s}{%s}{%s}{%s}", + formatNumberPattern(numFormat), + formatNumberPattern(intFormat), + formatNumberPattern(curFormat), + formatNumberPattern(pcFormat)); + + return String.format( + "{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}", + langRegionGroup, + dateGroup, + dateFmtGroup, + timeGroup, + timeFmtGroup, + dateTimeGroup, + dateTimeFmtGroup, + weekdayNamesGroup, + shortWeekdayNamesGroup, + monthNamesGroup, + shortMonthNamesGroup, + getStandaloneWeekdays(cal, locale), + getStandaloneShortWeekdays(cal, locale), + getStandaloneMonths(cal, locale), + getStandaloneShortMonths(cal, locale), + numGroup, numFmtGroup); + } + + /** + * Prints the syntax usage. + */ + protected void syntax() + { + System.out.println(String.format("Usage: %s [<options>] <actions>", name)); + + System.out.println(); + System.out.println("Cross-platform OS query application"); + System.out.println("for use with TeX's shell escape."); + System.out.println(); + System.out.println("Each query displays the result in a single line."); + System.out.println("An empty string is printed if the requested"); + System.out.println("information is unavailable or not permitted."); + System.out.println("Multiple actions group the results."); + System.out.println(); + System.out.println("See the manual (texdoc texosquery) for further details."); + + System.out.println(); + System.out.println("Options:"); + System.out.println(); + + System.out.println("-h or --help or -help"); + System.out.println("\tDisplay this help message and exit."); + System.out.println(); + + System.out.println("-v or --version or -version"); + System.out.println("\tDisplay version information and exit."); + System.out.println(); + + System.out.println("--nodebug"); + System.out.println("\tNo debugging messages (default)"); + System.out.println(); + + System.out.println("--debug [<n>] or -debug [<n>]"); + System.out.println("\tDisplay debugging messages on STDOUT."); + System.out.println("\t<n> should be an integer:"); + System.out.println("\t0: no debugging (same as --nodebug)"); + System.out.println("\t1: basic debugging messages"); + System.out.println("\t2: additionally display stack trace."); + System.out.println(String.format("\tIf omitted %d is assumed", DEFAULT_DEBUG_LEVEL)); + System.out.println(); + + System.out.println("--compatible <n> or -compat <n>"); + System.out.println("\tCompatibility setting."); + System.out.println("\t<n> should be \"latest\" (default) or an integer:"); + + for (int i = 0; i < DEFAULT_COMPATIBLE; i++) + { + System.out.println(String.format("\t%d: version 1.%d", i, i)); + } + + System.out.println(); + System.out.println("General actions:"); + System.out.println(); + + for (QueryAction action : AVAILABLE_ACTIONS) + { + if (action.getType() == QueryActionType.GENERAL_ACTION) + { + System.out.println(action.help()); + } + } + + System.out.println(); + System.out.println("Locale actions:"); + System.out.println(); + + for (QueryAction action : AVAILABLE_ACTIONS) + { + if (action.getType() == QueryActionType.LOCALE_ACTION) + { + System.out.println(action.help()); + } + } + + System.out.println(); + System.out.println("File actions:"); + System.out.println(); + System.out.println("Paths should use / for the directory divider."); + System.out.println("TeX's openin_any setting is checked before attempting"); + System.out.println("to access file information."); + System.out.println(); + + for (QueryAction action : AVAILABLE_ACTIONS) + { + if (action.getType() == QueryActionType.FILE_ACTION) + { + System.out.println(action.help()); + } + } + } + + /** + * Prints the version. + */ + protected void version() + { + System.out.println(String.format("%s %s %s", name, VERSION_NUMBER, + VERSION_DATE)); + System.out.println("Copyright 2016 Nicola Talbot"); + System.out.println("License LPPL 1.3+ (http://ctan.org/license/lppl1.3)"); + } + + /** + * Prints the information with optional grouping. + * @param numActions Add grouping if number of actions > 1 + * @param info Information to print + * @since 1.2 + */ + protected void print(int numActions, String info) + { + if (compatible == 0) + { + // version 1.0 didn't use grouping + System.out.println(info); + } + else + { + if (numActions > 1) + { + System.out.println(String.format("{%s}", info)); + } + else + { + System.out.println(info); + } + } + } + + /** + * Find the action corresponding to the name (the command line + * switch). Once the action has been found, a copy must be + * returned since the same action may be used multiple times with + * different arguments. + * @param action The command line switch (either the short or long + * form) + * @return a copy of the predefined action or null if not found + * @since 1.2 + */ + private QueryAction getAction(String action) + { + for (int i = 0; i < AVAILABLE_ACTIONS.length; i++) + { + if (AVAILABLE_ACTIONS[i].isAction(action)) + { + return AVAILABLE_ACTIONS[i].copy(); + } + } + + return null; + } + + public static int parseArgVal(String[] args, int i, Object[] argVal) + { + String[] sp; + + if (args[i].startsWith("--")) + { + sp = args[i].split("=", 2); + } + else + { + sp = new String[]{args[i]}; + } + + argVal[0] = sp[0]; + + if (sp.length == 2) + { + argVal[1] = sp[1]; + return i; + } + + if (i == args.length-1 || args[i+1].startsWith("-")) + { + argVal[1] = null; + return i; + } + + argVal[1] = args[++i]; + + return i; + } + + public static int parseArgInt(String[] args, int i, Object[] argVal) + { + i = parseArgVal(args, i, argVal); + + if (argVal[1] != null) + { + try + { + argVal[1] = new Integer((String)argVal[1]); + } + catch (NumberFormatException e) + { + throw new IllegalArgumentException(String.format( + "Invalid '%s' value: %s", argVal[0], argVal[1]), e); + } + } + + return i; + } + + public static boolean isArg(String arg, String shortArg, String longArg) + { + return arg.equals("-"+shortArg) || arg.equals("--"+longArg) + || arg.startsWith("--"+longArg+"="); + } + + + public static boolean isArg(String arg, String longArg) + { + return arg.equals("--"+longArg) || arg.startsWith("--"+longArg+"="); + } + + /** + * Process command line arguments. Options must come before + * actions. (The copied QueryAction objects retain the settings + * from the time of their creation.) + * @param args Command line arguments. + * @since 1.2 + */ + public void processArgs(String[] args) + { + Vector<QueryAction> actions = new Vector<QueryAction>(); + Object[] argVal = new Object[2]; + + for (int i = 0; i < args.length; i++) + { + QueryAction action = getAction(args[i]); + + if (action != null) + { + try + { + i = action.parseArgs(args, i)-1; + actions.add(action); + } + catch (IllegalArgumentException e) + { + debug(e.getMessage(), e); + throw e; + } + catch (Throwable e) + { + debug(e.getMessage(), e); + throw new IllegalArgumentException(e.getMessage(), e); + } + } + else if (args[i].equals("-h") || args[i].equals("--help") + || args[i].equals("-help")) + { + syntax(); + System.exit(0); + } + else if (args[i].equals("-v") || args[i].equals("--version") + || args[i].equals("-version")) + { + version(); + System.exit(0); + } + else if (args[i].equals("--nodebug")) + { + if (actions.size() > 0) + { + throw new IllegalArgumentException(String.format( + "Options must come before actions. Found option: %s", args[i])); + } + + debugLevel = 0; + } + else if (isArg(args[i], "debug", "debug")) + { + if (actions.size() > 0) + { + throw new IllegalArgumentException(String.format( + "Options must come before actions. Found option: %s", args[i])); + } + + i = parseArgInt(args, i, argVal); + + if (argVal[1] == null) + { + debugLevel = DEFAULT_DEBUG_LEVEL; + } + else + { + debugLevel = ((Integer)argVal[1]).intValue(); + + if (debugLevel < 0) + { + throw new IllegalArgumentException(String.format( + "Invalid debug level: %s", args[i])); + } + } + } + else if (args[i].equals("--compatible") || args[i].equals("-compat")) + { + if (actions.size() > 0) + { + throw new IllegalArgumentException(String.format( + "Options must come before actions. Found option: %s", args[i])); + } + + i = parseArgVal(args, i, argVal); + + if (argVal[1] == null) + { + throw new IllegalArgumentException(String.format( + "<level> expected after: %s", args[i])); + } + + if (argVal[1].equals("latest")) + { + compatible = DEFAULT_COMPATIBLE; + } + else + { + try + { + compatible = Integer.parseInt((String)argVal[1]); + } + catch (NumberFormatException e) + { + throw new IllegalArgumentException(String.format( + "Invalid %s argument (\"latest\" or %d to %d required): %s", + argVal[0], 0, DEFAULT_COMPATIBLE, argVal[1]), e); + } + } + } + else + { + throw new IllegalArgumentException(String.format( + "Unknown option: %s%nTry %s --help", args[i], name)); + } + } + + int numActions = actions.size(); + + if (numActions == 0) + { + throw new IllegalArgumentException(String.format( + "One or more actions required.%nTry %s --help", name)); + } + + for (QueryAction action : actions) + { + try + { + print(numActions, action.doAction(compatible)); + } + catch (Throwable e) + { + // Any errors should've been picked up by the action, + // so this is most likely a runtime error that needs + // to be reported. + + System.err.println("Fatal error: "+e.getMessage()); + + if (debugLevel < DEBUG_STACK_TRACE_LEVEL) + { + System.err.println(String.format( + "Use --debug %d to obtain stack trace", + DEBUG_STACK_TRACE_LEVEL)); + } + + debug(String.format("Action failed: %s", action.getInvocation()), + e); + System.exit(1); + } + } + } + + private final QueryAction[] AVAILABLE_ACTIONS = new QueryAction[] + { + new QueryAction("cwd", "c", QueryActionType.FILE_ACTION, + "Display current working directory") + { + public String action() + { + return getCwd(); + } + }, + new QueryAction("userhome", "m", QueryActionType.FILE_ACTION, + "Display user's home directory") + { + public String action() + { + return getUserHome(); + } + }, + new QueryAction("tmpdir", "t", QueryActionType.FILE_ACTION, + "Display temporary directory") + { + public String action() + { + return getTmpDir(); + } + }, + new QueryAction("osname", "o", QueryActionType.GENERAL_ACTION, + "Display OS name") + { + public String action() + { + return getOSname(); + } + }, + new QueryAction("osversion", "r", QueryActionType.GENERAL_ACTION, + "Display OS version") + { + public String action() + { + return getOSversion(); + } + }, + new QueryAction("osarch", "a", QueryActionType.GENERAL_ACTION, + "Display OS architecture") + { + public String action() + { + return getOSarch(); + } + }, + new QueryAction("pdfnow", "n", QueryActionType.GENERAL_ACTION, + "Display current date-time in PDF format") + { + public String action() + { + return pdfnow(); + } + }, + new QueryAction("locale", "L", QueryActionType.LOCALE_ACTION, + "Display POSIX locale information") + { + public String action() + { + return getLocale(Locale.getDefault()); + } + }, + new QueryAction("locale-lcs", "l", QueryActionType.LOCALE_ACTION, + "Display POSIX style locale information with lower case codeset") + { + public String action() + { + return getLocale(Locale.getDefault(), true); + } + }, + new QueryAction("codeset-lcs", "C", QueryActionType.GENERAL_ACTION, + "Lower case codeset with hyphens stripped", 2) + { + public String action() + { + return escapeFileName(getCodeSet(true)); + } + }, + new QueryAction("bcp47", "b", QueryActionType.LOCALE_ACTION, + "Display locale as BCP47 tag", 2) + { + public String action() + { + return escapeFileName(getLanguageTag(null)); + } + }, + new QueryAction("numeric", "N", 1, 0, "[locale]", + QueryActionType.LOCALE_ACTION, + "Display locale numeric information", 2) + { + public String action() + { + return getNumericalInfo(getOptionalArgument(0)); + } + }, + new QueryAction("locale-data", "D", 1, 0, "[locale]", + QueryActionType.LOCALE_ACTION, + "Display all available locale information", 2) + { + public String action() + { + return getLocaleData(getOptionalArgument(0)); + } + }, + new QueryAction("date-time", "M", + QueryActionType.GENERAL_ACTION, + "Display all the current date-time data", 2) + { + public String action() + { + return getDateTimeData(); + } + }, + new QueryAction("time-zones", "Z", 1, 0, "[locale]", + QueryActionType.LOCALE_ACTION, + "Display all available time zone information", 2) + { + public String action() + { + return getTimeZones(getOptionalArgument(0)); + } + }, + new QueryAction("pdfdate", "d", 0, 1, "<file>", + QueryActionType.FILE_ACTION, + "Display date stamp of <file> in PDF format") + { + public String action() + { + return pdfDate(fileFromTeXPath(getRequiredArgument(0))); + } + }, + new QueryAction("filesize", "s", 0, 1, "<file>", + QueryActionType.FILE_ACTION, + "Display size of <file> in bytes") + { + public String action() + { + return getFileLength(fileFromTeXPath(getRequiredArgument(0))); + } + }, + new QueryAction("list", "i", 1, 2, "<sep> <dir> [<sort>]", + QueryActionType.FILE_ACTION, + String.format("Display list of all files in <dir> separated by <sep>. If <sort> is omitted, the default order is used otherwise <sort> may be one of the following: %s", + FileSortType.getFileSortOptions())) + { + public String action() + { + return getFileList(getRequiredArgument(0), + new File(fromTeXPath(getRequiredArgument(1))), + FileSortType.getFileSortType(getOptionalArgument(0)), + FileListType.FILE_LIST_ANY); + } + }, + new QueryAction("filterlist", "f", 1, 3, "<sep> <regex> <dir> [<sort>]", + QueryActionType.FILE_ACTION, + String.format("Display list of files in <dir> that fully match <regex> separated by <sep>. If <sort> is omitted, the default order is used otherwise <sort> may be one of the following: %s", + FileSortType.getFileSortOptions())) + { + public String action() + { + return getFilterFileList( + getRequiredArgument(0), + getRequiredArgument(1), + new File(fromTeXPath(getRequiredArgument(2))), + FileSortType.getFileSortType(getOptionalArgument(0)), + FileListType.FILE_LIST_ANY); + } + }, + new QueryAction("list-dir", "id", 1, 2, "<sep> <dir> [<sort>]", + QueryActionType.FILE_ACTION, + String.format("Display list of all sub-directories in <dir> separated by <sep>. If <sort> is omitted, the default order is used otherwise <sort> may be one of the following: %s", + FileSortType.getFileSortOptions())) + { + public String action() + { + return getFileList(getRequiredArgument(0), + new File(fromTeXPath(getRequiredArgument(1))), + FileSortType.getFileSortType(getOptionalArgument(0)), + FileListType.FILE_LIST_DIRECTORIES_ONLY); + } + }, + new QueryAction("filterlist-dir", "fd", 1, 3, "<sep> <regex> <dir> [<sort>]", + QueryActionType.FILE_ACTION, + String.format("Display list of sub-directories in <dir> that fully match <regex> separated by <sep>. If <sort> is omitted, the default order is used otherwise <sort> may be one of the following: %s", + FileSortType.getFileSortOptions())) + { + public String action() + { + return getFilterFileList( + getRequiredArgument(0), + getRequiredArgument(1), + new File(fromTeXPath(getRequiredArgument(2))), + FileSortType.getFileSortType(getOptionalArgument(0)), + FileListType.FILE_LIST_DIRECTORIES_ONLY); + } + }, + new QueryAction("list-regular", "ir", 1, 2, "<sep> <dir> [<sort>]", + QueryActionType.FILE_ACTION, + String.format("Display list of all regular files in <dir> separated by <sep>. If <sort> is omitted, the default order is used otherwise <sort> may be one of the following: %s", + FileSortType.getFileSortOptions())) + { + public String action() + { + return getFileList(getRequiredArgument(0), + new File(fromTeXPath(getRequiredArgument(1))), + FileSortType.getFileSortType(getOptionalArgument(0)), + FileListType.FILE_LIST_REGULAR_FILES_ONLY); + } + }, + new QueryAction("filterlist-regular", "fr", 1, 3, "<sep> <regex> <dir> [<sort>]", + QueryActionType.FILE_ACTION, + String.format("Display list of regular files in <dir> that fully match <regex> separated by <sep>. If <sort> is omitted, the default order is used otherwise <sort> may be one of the following: %s", + FileSortType.getFileSortOptions())) + { + public String action() + { + return getFilterFileList( + getRequiredArgument(0), + getRequiredArgument(1), + new File(fromTeXPath(getRequiredArgument(2))), + FileSortType.getFileSortType(getOptionalArgument(0)), + FileListType.FILE_LIST_REGULAR_FILES_ONLY); + } + }, + new QueryAction("walk", "w", 1, 3, "<sep> <regex> <dir> [<sort>]", + QueryActionType.FILE_ACTION, + String.format("Display list of regular non-hidden files in <dir> (descending sub-directories) that fully match <regex> separated by <sep>. The starting directory <dir> may not be outside the current working directory. This action is not available for texosquery-jre5. If <sort> is omitted, the default order is used otherwise <sort> may be one of the following: %s", + FileSortType.getFileSortOptions()), 2) + { + public String action() + { + return walk( + getRequiredArgument(0), + getRequiredArgument(1), + new File(fromTeXPath(getRequiredArgument(2))), + FileSortType.getFileSortType(getOptionalArgument(0))); + } + }, + new QueryAction("uri", "u", 0, 1, "<file>", + QueryActionType.FILE_ACTION, "Display the URI of <file>") + { + public String action() + { + return fileURI(fileFromTeXPath(getRequiredArgument(0))); + } + }, + new QueryAction("path", "p", 0, 1, "<file>", + QueryActionType.FILE_ACTION, "Display the canonical path of <file>") + { + public String action() + { + return filePath(fileFromTeXPath(getRequiredArgument(0))); + } + }, + new QueryAction("dirname", "e", 0, 1, "<file>", + QueryActionType.FILE_ACTION, + "Display the canonical path of the parent of <file>") + { + public String action() + { + return parentPath(fileFromTeXPath(getRequiredArgument(0))); + } + } + }; + + /** + * Application name. + */ + private String name; + + public static final int DEFAULT_COMPATIBLE=2; + + private static final String VERSION_NUMBER = "1.2"; + private static final String VERSION_DATE = "2017-03-23"; + private static final char BACKSLASH = '\\'; + private static final long ZERO = 0L; + + /** + * Initialise current date-time for consistency. + */ + + private Date now = new Date(); + + /** + * openin_any settings + */ + private static final char OPENIN_UNSET=0; // unset + private static final char OPENIN_A='a'; // any + private static final char OPENIN_R='r'; // restricted + private static final char OPENIN_P='p'; // paranoid + + private char openin = OPENIN_UNSET; + + private File texmfoutput = null; + + /** + * Debug level. (0 = no debugging, 1 or more print error messages to + * STDERR, 2 or more include stack trace, 3 or more include + * informational messages.) + */ + private int debugLevel = 0; + + public static final int DEFAULT_DEBUG_LEVEL=3; + public static final int DEBUG_ERROR_LEVEL=1; + public static final int DEBUG_STACK_TRACE_LEVEL=2; + public static final int DEBUG_INFO_LEVEL=3; + + /** + * Compatibility mode. Version 1.2 replaces escapeHash with + * escapeSpChars, which switches to using \\fhsh etc. Provide a + * mode to restore the previous behaviour. + */ + private int compatible = DEFAULT_COMPATIBLE; + + // TeX can only go up to 2147483647, so set the maximum number + // of digits provided for the number formatter. + + private static final int MAX_DIGIT_FORMAT=10; + + // Dollar symbol + private static final char DOLLAR_CHAR=0x0024; + + // Cent symbol + private static final char CENT_CHAR=0x00A2; + + // Pound symbol + private static final char POUND_CHAR=0x00A3; + + // Pound symbol as a string + private static final String POUND_STRING=""+POUND_CHAR; + + // Currency symbol + private static final char CURRENCY_CHAR=0x00A4; + + // Yen symbol + private static final char YEN_CHAR=0x00A5; + + // ECU symbol + private static final char ECU_CHAR=0x20A0; + + // Colon currency symbol + private static final char COLON_CURRENCY_CHAR=0x20A1; + + // Cruzeiro symbol + private static final char CRUZEIRO_CHAR=0x20A2; + + // Franc symbol + private static final char FRANC_CHAR=0x20A3; + + // Lira symbol + private static final char LIRA_CHAR=0x20A4; + + // Mill currency symbol + private static final char MILL_CURRENCY_CHAR=0x20A5; + + // Naira symbol + private static final char NAIRA_CHAR=0x20A6; + + // Peseta symbol + private static final char PESETA_CHAR=0x20A7; + + // Legacy rupee symbol + private static final char LEGACY_RUPEE_CHAR=0x20A8; + + // Won symbol + private static final char WON_CHAR=0x20A9; + + // New sheqel symbol + private static final char NEW_SHEQEL_CHAR=0x20AA; + + // Dong symbol + private static final char DONG_CHAR=0x20AB; + + // Euro symbol + private static final char EURO_CHAR=0x20AC; + + // Kip symbol + private static final char KIP_CHAR=0x20AD; + + // Tugrik symbol + private static final char TUGRIK_CHAR=0x20AE; + + // Drachma symbol + private static final char DRACHMA_CHAR=0x20AF; + + // German penny symbol + private static final char GERMAN_PENNY_CHAR=0x20B0; + + // Peso symbol + private static final char PESO_CHAR=0x20B1; + + // Guarani symbol + private static final char GUARANI_CHAR=0x20B2; + + // Austral symbol + private static final char AUSTRAL_CHAR=0x20B3; + + // Hryvnia symbol + private static final char HRYVNIA_CHAR=0x20B4; + + // Cedi symbol + private static final char CEDI_CHAR=0x20B5; + + // Livre tournois symbol + private static final char LIVRE_TOURNOIS_CHAR=0x20B6; + + // Spesmilo symbol + private static final char SPESMILO_CHAR=0x20B7; + + // Tenge symbol + private static final char TENGE_CHAR=0x20B8; + + // Official rupee symbol + private static final char RUPEE_CHAR=0x20B9; + + // Turkish lira symbol + private static final char TURKISH_LIRA_CHAR=0x20BA; + + // Nordic mark symbol + private static final char NORDIC_MARK_CHAR=0x20BB; + + // Manat symbol + private static final char MANAT_CHAR=0x20BC; + + // Ruble symbol + private static final char RUBLE_CHAR=0x20BD; + + // Per mille symbol + private static final char PERMILLE_CHAR=0x2030; +} diff --git a/Master/texmf-dist/source/support/texosquery/java/TeXOSQueryJRE5.java b/Master/texmf-dist/source/support/texosquery/java/TeXOSQueryJRE5.java new file mode 100644 index 00000000000..15c6bd6c50a --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/TeXOSQueryJRE5.java @@ -0,0 +1,54 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +import java.io.BufferedReader; +import java.util.Locale; +import java.util.Calendar; +import java.text.DecimalFormatSymbols; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * Main class. Supports Java 5 onwards. + * @author Nicola Talbot + * @version 1.2 + * @since 1.2 + */ +public class TeXOSQueryJRE5 extends TeXOSQuery +{ + public TeXOSQueryJRE5() + { + super("texosquery-jre5"); + } + + /** + * Main method. + * @param args Command line arguments. + */ + public static void main(String[] args) + { + try + { + (new TeXOSQueryJRE5()).processArgs(args); + } + catch (IllegalArgumentException e) + { + System.err.println(e.getMessage()); + System.exit(1); + } + } +} diff --git a/Master/texmf-dist/source/support/texosquery/java/TeXOSQueryJRE7.java b/Master/texmf-dist/source/support/texosquery/java/TeXOSQueryJRE7.java new file mode 100644 index 00000000000..0abb09d0aa6 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/TeXOSQueryJRE7.java @@ -0,0 +1,197 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +import java.util.Locale; +import java.util.Locale.Builder; +import java.util.Calendar; +import java.io.Serializable; +import java.io.File; +import java.io.IOException; + +/** + * Main class. Supports Java 7 onwards. + * @author Nicola Talbot + * @version 1.2 + * @since 1.2 + */ +public class TeXOSQueryJRE7 extends TeXOSQuery +{ + public TeXOSQueryJRE7() + { + super("texosquery"); + } + + /** + * Converts the given directory to a canonical path + * and checks to make sure it has a parent directory. + * @param dir the directory to check + * @return the canonical path + * @throws IOException if directory can't be converted to a + * canonical path or if the canonical path doesn't have a parent + * directory or is outside the current working directory + */ + @Override + protected File checkDirectoryListing(File dir) throws IOException + { + dir = dir.getCanonicalFile(); + + if (dir.getParentFile() == null) + { + throw new IOException(String.format( + "Listing on root directory not permitted: %s", dir)); + } + + File cwd = new File(getSystemProperty("user.dir", ".")); + + if (!cwd.equals(dir) && !isFileInTree(dir, cwd)) + { + throw new IOException(String.format( + "Listing outside cwd path not permitted: %s", dir)); + } + + return dir; + } + + /** + * Recursive file listing. This method must have the CWD or a + * descendent as the starting directory. It will return list of + * files relative to the starting directory where the basename + * matches the supplied regular expression. Hidden files/directories + * and symbolic links are skipped regardless of the openin_any setting. + * Files without read access are also omitted from the list. + * + * @param separator separator to use in returned list + * @param regex regular expression used to match file basenames + * @param directory starting directory (must be cwd or a + * descendent of cwd) + * @return list of relative paths + */ + @Override + public String walk(String separator, + String regex, File directory, + FileSortType sortType) + { + try + { + return FileWalkVisitor.walk(this, separator, + regex, directory, sortType); + } + catch (Exception e) + { + debug(String.format("Can't walk directory: %s", + directory.toString()), e); + } + + return ""; + } + + /** + * Gets the script for the given locale. + * @param locale The locale + * @return The language script associated with the given locale or null if not available + */ + @Override + public String getScript(Locale locale) + { + return locale.getScript(); + } + + /** + * Gets the locale from the given language tag. + * @param languageTag The language tag + * @return The locale that closest matches the language tag + */ + @Override + public Locale getLocale(String languageTag) + { + Locale locale = Locale.forLanguageTag(languageTag); + + // Locale.forLanguageTag() doesn't recognise + // numeric regions. So test for a numeric region. + + String region = locale.getCountry(); + + try + { + region = getRegionAlpha2Code(Integer.parseInt(region)); + } + catch (NumberFormatException e) + { + // region isn't numeric, so we don't need to do anything + // else + return locale; + } + + Locale.Builder builder = new Locale.Builder(); + builder.setLocale(locale); + builder.setRegion(region); + + return builder.build(); + } + + /** + * Gets the language tag for the given locale. + * @param locale The locale or null for the default locale + * @return The language tag + */ + @Override + public String getLanguageTag(Locale locale) + { + if (locale == null) + { + locale = Locale.getDefault(); + } + + return locale.toLanguageTag(); + } + + /** + * Gets the week year for the given calendar. + * @return The week year + */ + @Override + public int getWeekYear(Calendar cal) + { + try + { + return cal.isWeekDateSupported() ? + cal.getWeekYear() : cal.get(Calendar.YEAR); + } + catch (UnsupportedOperationException e) + { + // shouldn't happen with the above conditional, but just in + // case... + + debug(e.getMessage(), e); + return cal.get(Calendar.YEAR); + } + } + + /** + * Main method. + * @param args Command line arguments. + */ + public static void main(String[] args) + { + try + { + (new TeXOSQueryJRE7()).processArgs(args); + } + catch (IllegalArgumentException e) + { + System.err.println(e.getMessage()); + System.exit(1); + } + } +} diff --git a/Master/texmf-dist/source/support/texosquery/java/TeXOSQueryJRE8.java b/Master/texmf-dist/source/support/texosquery/java/TeXOSQueryJRE8.java new file mode 100644 index 00000000000..ab65d64bbf5 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/java/TeXOSQueryJRE8.java @@ -0,0 +1,377 @@ +/* + Copyright (C) 2016 Nicola L.C. Talbot + www.dickimaw-books.com + + This work may be distributed and/or modified under the + conditions of the LaTeX Project Public License, either version 1.3 + of this license or (at your option) any later version. + The latest version of this license is in + http://www.latex-project.org/lppl.txt + and version 1.3 or later is part of all distributions of LaTeX + version 2005/12/01 or later. +*/ +package com.dickimawbooks.texosquery; + +import java.util.Locale; +import java.util.Locale.Builder; +import java.util.Calendar; +import java.util.Map; +import java.util.Arrays; +import java.io.File; +import java.io.IOException; + +/** + * Main class. Supports Java 8 onwards. + * @author Nicola Talbot + * @version 1.2 + * @since 1.2 + */ +public class TeXOSQueryJRE8 extends TeXOSQuery +{ + public TeXOSQueryJRE8() + { + super("texosquery-jre8"); + } + + /** + * Converts the given directory to a canonical path + * and checks to make sure it has a parent directory. + * @param dir the directory to check + * @return the canonical path + * @throws IOException if directory can't be converted to a + * canonical path or if the canonical path doesn't have a parent + * directory or is outside the current working directory + */ + @Override + protected File checkDirectoryListing(File dir) throws IOException + { + dir = dir.getCanonicalFile(); + + if (dir.getParentFile() == null) + { + throw new IOException(String.format( + "Listing on root directory not permitted: %s", dir)); + } + + File cwd = new File(getSystemProperty("user.dir", ".")); + + if (!cwd.equals(dir) && !isFileInTree(dir, cwd)) + { + throw new IOException(String.format( + "Listing outside cwd path not permitted: %s", dir)); + } + + return dir; + } + + /** + * Recursive file listing. This method must have the CWD or a + * descendent as the starting directory. It will return list of + * files relative to the starting directory where the basename + * matches the supplied regular expression. Hidden files/directories + * and symbolic links are skipped regardless of the openin_any setting. + * Files without read access are also omitted from the list. + * + * @param separator separator to use in returned list + * @param regex regular expression used to match file basenames + * @param directory starting directory (must be cwd or a + * descendent of cwd) + * @return list of relative paths + */ + @Override + public String walk(String separator, + String regex, File directory, + FileSortType sortType) + { + try + { + return FileWalkVisitor.walk(this, separator, + regex, directory, sortType); + } + catch (Exception e) + { + debug(String.format("Can't walk directory: %s", + directory.toString()), e); + } + + return ""; + } + + + /** + * Gets the script for the given locale. + * @param locale The locale + * @return The language script associated with the given locale or null if not available + */ + @Override + public String getScript(Locale locale) + { + return locale.getScript(); + } + + /** + * Gets the locale from the given language tag. + * @param languageTag The language tag + * @return The locale that closest matches the language tag + */ + @Override + public Locale getLocale(String languageTag) + { + Locale locale = Locale.forLanguageTag(languageTag); + + // Locale.forLanguageTag() doesn't recognise + // numeric regions. So test for a numeric region. + + String region = locale.getCountry(); + + try + { + region = getRegionAlpha2Code(Integer.parseInt(region)); + } + catch (NumberFormatException e) + { + // region isn't numeric, so we don't need to do anything + // else + return locale; + } + + Locale.Builder builder = new Locale.Builder(); + builder.setLocale(locale); + builder.setRegion(region); + + return builder.build(); + } + + /** + * Gets the language tag for the given locale. + * @param locale The locale or null for the default locale + * @return The language tag + */ + @Override + public String getLanguageTag(Locale locale) + { + if (locale == null) + { + locale = Locale.getDefault(); + } + + return locale.toLanguageTag(); + } + + /** + * Gets the week year for the given calendar. + * @return The week year + */ + @Override + public int getWeekYear(Calendar cal) + { + try + { + return cal.isWeekDateSupported() ? + cal.getWeekYear() : cal.get(Calendar.YEAR); + } + catch (UnsupportedOperationException e) + { + // shouldn't happen with the above conditional, but just in + // case... + + debug(e.getMessage(), e); + return cal.get(Calendar.YEAR); + } + } + + /** Gets the standalone month names for the locale data. + * These are only available for Java 8, so just return the + * month names used in the date format instead. + * @param cal The calendar + * @param locale The locale + * @return month names + */ + public String getStandaloneMonths(Calendar cal, Locale locale) + { + Map<String,Integer> map = cal.getDisplayNames(Calendar.MONTH, + Calendar.LONG_STANDALONE, locale); + + // Is the map order? Not sure so save in an array + + String[] names = new String[12]; + + for (Map.Entry<String,Integer> entry : map.entrySet()) + { + int idx = entry.getValue().intValue(); + + if (idx < 12) + {// Java has a 13th month that we're ignoring + names[idx] = entry.getKey(); + } + } + + StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < names.length; i++) + { + builder.append(String.format("{%s}", escapeText(names[i]))); + } + + return builder.toString(); + } + + /** Gets the standalone short month names for the locale data. + * @param cal The calendar + * @param locale The locale + * @return month names + */ + public String getStandaloneShortMonths(Calendar cal, Locale locale) + { + Map<String,Integer> map = cal.getDisplayNames(Calendar.MONTH, + Calendar.SHORT_STANDALONE, locale); + + // Is the map order? Not sure so save in an array + + String[] names = new String[12]; + + for (Map.Entry<String,Integer> entry : map.entrySet()) + { + int idx = entry.getValue().intValue(); + + if (idx < names.length) + { + names[idx] = entry.getKey(); + } + } + + StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < names.length; i++) + { + builder.append(String.format("{%s}", escapeText(names[i]))); + } + + return builder.toString(); + } + + + /** Gets the standalone week day names for the locale data. + * @param cal The calendar + * @param locale The locale + * @return week day names + */ + public String getStandaloneWeekdays(Calendar cal, Locale locale) + { + Map<String,Integer> map = cal.getDisplayNames(Calendar.DAY_OF_WEEK, + Calendar.LONG_STANDALONE, locale); + + String[] names = new String[7]; + + for (Map.Entry<String,Integer> entry : map.entrySet()) + { + switch (entry.getValue().intValue()) + { + case Calendar.MONDAY: + names[0] = entry.getKey(); + break; + case Calendar.TUESDAY: + names[1] = entry.getKey(); + break; + case Calendar.WEDNESDAY: + names[2] = entry.getKey(); + break; + case Calendar.THURSDAY: + names[3] = entry.getKey(); + break; + case Calendar.FRIDAY: + names[4] = entry.getKey(); + break; + case Calendar.SATURDAY: + names[5] = entry.getKey(); + break; + case Calendar.SUNDAY: + names[6] = entry.getKey(); + break; + } + } + + StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < names.length; i++) + { + builder.append(String.format("{%s}", escapeText(names[i]))); + } + + return builder.toString(); + } + + /** Gets the standalone short week day names for the locale data. + * @param cal The calendar + * @param locale The locale + * @return week day names + */ + public String getStandaloneShortWeekdays(Calendar cal, Locale locale) + { + Map<String,Integer> map = cal.getDisplayNames(Calendar.DAY_OF_WEEK, + Calendar.SHORT_STANDALONE, locale); + + String[] names = new String[7]; + + for (Map.Entry<String,Integer> entry : map.entrySet()) + { + switch (entry.getValue().intValue()) + { + case Calendar.MONDAY: + names[0] = entry.getKey(); + break; + case Calendar.TUESDAY: + names[1] = entry.getKey(); + break; + case Calendar.WEDNESDAY: + names[2] = entry.getKey(); + break; + case Calendar.THURSDAY: + names[3] = entry.getKey(); + break; + case Calendar.FRIDAY: + names[4] = entry.getKey(); + break; + case Calendar.SATURDAY: + names[5] = entry.getKey(); + break; + case Calendar.SUNDAY: + names[6] = entry.getKey(); + break; + } + } + + StringBuilder builder = new StringBuilder(); + + for (int i = 0; i < names.length; i++) + { + builder.append(String.format("{%s}", escapeText(names[i]))); + } + + return builder.toString(); + } + + @Override + public void sortFileList(String[] list, File directory, + FileSortType sortType) + { + Arrays.parallelSort(list, new FileSortComparator(directory, sortType)); + } + + /** + * Main method. + * @param args Command line arguments. + */ + public static void main(String[] args) + { + try + { + (new TeXOSQueryJRE8()).processArgs(args); + } + catch (IllegalArgumentException e) + { + System.err.println(e.getMessage()); + System.exit(1); + } + } +} diff --git a/Master/texmf-dist/source/support/texosquery/texosquery-jre5.batch b/Master/texmf-dist/source/support/texosquery/texosquery-jre5.batch new file mode 100644 index 00000000000..3b307fb85b0 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/texosquery-jre5.batch @@ -0,0 +1,4 @@ + +@ECHO OFF +FOR /F %%I IN ('kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre5.jar') DO SET JARPATH=%%I +java -jar "%JARPATH%" %* diff --git a/Master/texmf-dist/source/support/texosquery/texosquery-jre8.batch b/Master/texmf-dist/source/support/texosquery/texosquery-jre8.batch new file mode 100644 index 00000000000..6e8d1547df7 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/texosquery-jre8.batch @@ -0,0 +1,4 @@ + +@ECHO OFF +FOR /F %%I IN ('kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre8.jar') DO SET JARPATH=%%I +java -Djava.locale.providers=CLDR,JRE -jar "%JARPATH%" %* diff --git a/Master/texmf-dist/source/support/texosquery/texosquery.batch b/Master/texmf-dist/source/support/texosquery/texosquery.batch new file mode 100644 index 00000000000..2ac1b43cda2 --- /dev/null +++ b/Master/texmf-dist/source/support/texosquery/texosquery.batch @@ -0,0 +1,4 @@ + +@ECHO OFF +FOR /F %%I IN ('kpsewhich --progname=texosquery --format=texmfscripts texosquery.jar') DO SET JARPATH=%%I +java -jar "%JARPATH%" %* diff --git a/Master/texmf-dist/source/support/texosquery/texosquery.dtx b/Master/texmf-dist/source/support/texosquery/texosquery.dtx index feda90f8680..a532e96c577 100644 --- a/Master/texmf-dist/source/support/texosquery/texosquery.dtx +++ b/Master/texmf-dist/source/support/texosquery/texosquery.dtx @@ -19,39 +19,98 @@ %\fi % \iffalse % Doc-Source file -% Copyright (C) 2016 Nicola Talbot, all rights reserved. +% Copyright (C) 2017 Nicola Talbot, all rights reserved. % \fi % \iffalse %<*driver> \documentclass{ltxdoc} \usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{etoolbox} +\usepackage{textcomp} \usepackage{tgtermes} +\usepackage{upquote} \usepackage{metalogo} \usepackage[colorlinks,hyperindex=false]{hyperref} +\usepackage[abbreviations,nomain,nonumberlist,nogroupskip]{glossaries-extra} -\CheckSum{269} +\makeglossaries + +\makeatletter% doc.sty interferes with upquote.sty +\def\@verbatim{\trivlist \item[]\if@minipage\else\vskip\parskip\fi + \leftskip\@totalleftmargin\rightskip\z@ + \parindent\z@\parfillskip\@flushglue\parskip\z@ + \@@par + \@tempswafalse + \def\par{\if@tempswa\hbox{}\fi\@tempswatrue\@@par + \penalty\interlinepenalty + \check@percent}% + \obeylines + \@noligs + \let\do\@makeother \dospecials} + +\renewcommand{\meta@font@select}{\rmfamily\itshape} +\makeatother + +\CheckSum{3260} \RecordChanges \PageIndex \CodelineNumbered -\IndexPrologue{} +\IndexPrologue{\clearpage\phantomsection\section*{Index}\markboth{Index}{Index}% +\addcontentsline{toc}{section}{Index}} +\setcounter{IndexColumns}{2} \renewcommand*{\usage}[1]{\hyperpage{#1}} \renewcommand*{\main}[1]{\hyperpage{#1}} +\newcommand*{\qt}[1]{``#1''} +\newcommand*{\sty}[1]{\textsf{#1}} +\newcommand*{\app}[1]{\texttt{#1}} +\newcommand*{\file}[1]{\texttt{#1}} +\providecommand*{\eTeX}{e\TeX} + \newcommand*{\shortargfmt}[1]{\texttt{-#1}} \newcommand*{\longargfmt}[1]{\texttt{-{}-#1}} \newcommand*{\shortarg}[1]{\shortargfmt{#1}% - \index{texosquery options=\texttt{texosquery} options>#1=\protect\shortargfmt{-#1}|hyperpage}} + \index{texosquery options=\app{texosquery} options>#1=\protect\shortargfmt{-#1}|hyperpage}} \newcommand*{\longarg}[1]{\longargfmt{#1}% - \index{texosquery options=\texttt{texosquery} options>#1=\protect\longargfmt{#1}|hyperpage}} + \index{texosquery options=\app{texosquery} options>#1=\protect\longargfmt{#1}|hyperpage}} \newenvironment{important} {\begin{quote}\textbf{Important Note:}} {\end{quote}} +\newenvironment{definition} + {\begin{flushleft}\ttfamily} + {\end{flushleft}} + +\setcounter{secnumdepth}{2} + +\pdfstringdefDisableCommands{\renewcommand\meta[1]{#1}} + +\glssetcategoryattribute{abbreviation}{nohyperfirst}{true} + +\setabbreviationstyle[noexpand]{short} +\newabbreviation[category=noexpand]{IETF}{IETF}{Internet Engineering Task Force} +\newabbreviation[category=noexpand]{BCP}{BCP}{Best Common Practice} +\newabbreviation[category=noexpand]{POSIX}{POSIX}{Portable Operating +System Interface} +\newabbreviation[category=noexpand]{CTAN}{CTAN}{Comprehensive \TeX\ +Archive Network} +\newabbreviation[category=noexpand]{UTF}{UTF}{Unicode Transformation +Format} +\newabbreviation[category=noexpand]{ASCII}{ASCII}{American Standard +Code for Information Interchange} +\newabbreviation[category=noexpand]{ISO}{ISO}{International +Organization for Standardization} + +\newabbreviation{OS}{OS}{operating system} +\newabbreviation{JRE}{JRE}{Java Runtime Environment} +\newabbreviation{CLDR}{CLDR}{Unicode Consortium's Common Locale Data Repository} + \begin{document} \DocInput{texosquery.dtx} \end{document} @@ -64,204 +123,1604 @@ %\author{Nicola L. C. Talbot\\ %\href{http://www.dickimaw-books.com/}{\nolinkurl{dickimaw-books.com}} %\and Paulo Cereda} -%\date{2016-07-14 (v1.1)} +%\date{2017-03-23 (v1.2)} %\maketitle % %\begin{abstract} -%\texttt{texosquery.jar} is a cross-platform Java application -%to query certain OS information designed for use in \TeX's -%shell escape mechanism. -%The accompanying \TeX\ code provides a simple interface to the -%\texttt{texosquery} Java application, which may be skipped -%if you want to explicitly use \cs{input} (but take -%care of any special characters appearing in the result). +%The \sty{texosquery} bundle provides the \app{texosquery.jar} application (and +%variations \app{texosquery-jre8.jar} and \app{texosquery-jre5.jar}) +%This is a cross-platform Java application to query certain +%\gls{OS} and locale information. The application is +%specifically designed for use within \TeX's shell escape mechanism, +%through the \cs{TeXOSQuery} command provided by the \sty{texosquery} package +%(\file{texosquery.tex} and \file{texosquery.sty}). +% +%The \cs{TeXOSQuery} command performs more than a simple piped input as it +%first changes category codes of various problematic characters and locally +%defines some short control sequences that are used in the application's result. +%These commands aren't defined outside of \cs{TeXOSQuery}, so a +%direct piped input may cause undefined control sequences. If you +%really want to use this direct method rather than using +%\cs{TeXOSQuery}, then you will need to run \app{texosquery} in +%backward compatibility mode~0 or~1 (using \texttt{\longarg{compatible} 1}). +%The first two versions of \app{texosquery} didn't use those short +%commands. %\end{abstract} % %\begin{important} %You will need \TeX's shell escape enabled, -%and you will also need the Java Runtime Environment (JRE) -%installed to use \texttt{texosquery}. +%and you will also need the \gls{JRE} installed. %\end{important} % -%If you want to rebuild the application, instructions for -%compiling the source code (including the code for this document) -%are in the accompanying \texttt{README.md} file. +%There are three variations of the \app{texosquery} application provided: +%\begin{itemize} +%\item \file{texosquery.jar}: requires at least Java~7, has medium locale +%support, obeys \texttt{openin\_any} but has additional +%restrictions imposed for security reasons (no listings outside the +%current working directory path); +%\item \file{texosquery-jre8.jar}: requires at least Java~8, has best locale +%support, obeys \texttt{openin\_any} but has additional +%restrictions imposed for security reasons (no listings outside the +%current working directory path); +%\item \file{texosquery-jre5.jar}: requires at least Java~5, has poor locale +%support (language scripts not recognised), doesn't have the walk +%action, obeys \texttt{openin\_any} but doesn't have the extra restrictions of the +%Java 7 and 8 versions for the listing functions. Note that Java~5 and~6 +%are deprecated. Old deprecated versions are considered a security +%risk. +%\end{itemize} +%The default is \file{texosquery.jar}. Throughout this document +%\app{texosquery} is used to reference the application, regardless +%which of these three jar files you've chosen to use. See +%section~\ref{sec:setup} for further details. +% +%The aim of the original version of \app{texosquery} was to provide +%a way of accessing the operating system's locale information. +%Version 1.3 of the \sty{tracklang} package provides +%\cs{TrackLangQueryEnv} which uses \app{kpsewhich} to query the +%appropriate locale environment variable (such as \verb|$LANG| +%or \verb|LC_ALL|). Unfortunately this doesn't work under Windows as +%the locale information there is stored in the registry. The Lua +%\texttt{os.setlocale(nil)} function can simply return \texttt{C} or +%\texttt{POSIX}, which isn't helpful from \sty{tracklang}'s point of +%view. Although Java has its drawbacks, it's one of the most +%ubiquitous platform-independent methods to obtain this information. +%Since it seemed overkill to write a Java application that simply +%returned the locale, I decided to add a few extra functions that +%might be of use, but accessing locale information was, and still +%is, the primary purpose of this application. +% +%Although the \gls{POSIX} environment variables, such as +%\verb|$LC_ALL|, are easy to read with \app{kpsewhich}, these days +%the \gls{IETF} \gls{BCP}~47 language tag is the more appropriate way +%of identifying a locale, so version 1.2 has added the \longarg{bcp47} +%function to support this. The \sty{tracklang} package has similarly added +%\cs{TrackLanguageTag}\marg{IETF tag}. +% +%The \sty{locale} package occasionally referenced in this document +%is still under development at the time of writing. The +%\longarg{numeric}, \longarg{locale-data}, \longarg{date-time} and +%\longarg{time-zones} options are designed to +%interface with the \sty{locale} package, so although +%\sty{texosquery} and \sty{locale} will be distributed separately, +%version 1.2 of \app{texosquery} is being +%developed alongside version 1.0 of the \sty{locale} package. +%The aim of the \sty{locale} package is to use both \sty{tracklang} +%and \sty{texosquery} to automatically set up the document language. +%For example, in the following \LaTeX\ document +%\begin{verbatim} +%\documentclass{article} +%\usepackage{locale} +%\begin{document} +%Language: \CurrentLocaleLanguageNativeName. +%Region: \CurrentLocaleRegionNativeName. +%Today: \CurrentLocaleDate. (Compare with \today.) +%Time: \CurrentLocaleTime. +%Currency Symbol: \CurrentLocaleCurrency +%Integer: +%\texosqueryfmtnumber{\CurrentLocaleIntegerPattern}{123456}{0}{0} +%Decimal: +%\texosqueryfmtnumber{\CurrentLocaleDecimalPattern}{123456}{78}{0} +%Percentage: +%\texosqueryfmtnumber{\CurrentLocalePercentPattern}{0}{65}{0} +%Currency: +%\texosqueryfmtnumber{\CurrentLocaleCurrencyPattern}{1234567}{0}{0} +%\end{document} +%\end{verbatim} +%the \sty{locale} package will automatically: +%\begin{itemize} +%\item load the \sty{textcomp} package for currency symbols (package +%option \texttt{symbols=fontawesome} will use \sty{fontawesome} +%instead); +%\item if \XeLaTeX\ or \LuaLaTeX: +% \begin{itemize} +% \item load \sty{fontspec} (unless option \texttt{fontspec=false} +% is used); +% \item load \sty{polyglossia} and use \cs{setmainlanguage} +% with options that can be determined from the language tag +% (use package option \texttt{support=babel} to use \sty{babel} +% regardless of the \LaTeX\ format); +% \end{itemize} +% otherwise: +% \begin{itemize} +% \item load \sty{inputenc} (default file encoding obtained from +% \app{texosquery}'s \longarg{codeset-lcs} action); +% \item load \sty{fontenc} (font encoding obtained using +% \sty{tracklang} to query the language script); +% \item load \sty{babel} with the appropriate language label (use +% \texttt{support=none} to prevent this); +% \end{itemize} +%\item load \sty{datetime2} with the \texttt{useregional=text} +%option (use \texttt{datetime2=false} to prevent this). +%\end{itemize} +% +%The generic \texttt{locale.tex} code doesn't load the above packages, but can +%still obtain information about the locale: +%\begin{verbatim} +%\input locale + +%Language: \CurrentLocaleLanguageNativeName. +%Region: \CurrentLocaleRegionNativeName. +%Today: \CurrentLocaleDate. (Compare with \today.) +%Time: \CurrentLocaleTime. +%Currency Symbol: \CurrentLocaleCurrency +%Integer: +%\texosqueryfmtnumber{\CurrentLocaleIntegerPattern}{123456}{0}{0} +%Decimal: +%\texosqueryfmtnumber{\CurrentLocaleDecimalPattern}{123456}{78}{0} +%Percentage: +%\texosqueryfmtnumber{\CurrentLocalePercentPattern}{0}{65}{0} +%Currency: +%\texosqueryfmtnumber{\CurrentLocaleCurrencyPattern}{1234567}{0}{0} +%\bye +%\end{verbatim} % +%So that's the reasoning behind the new v1.2 actions. Hopefully the +%new \sty{locale} package will be uploaded to \gls{CTAN} shortly after the +%new version of \sty{texosquery}. +% +%\clearpage %\tableofcontents +%\clearpage % %\section{texosquery.jar: the Java application} -%The \texttt{texosquery} Java command line application looks up +%The \app{texosquery} Java command line application looks up %certain system information that may be of use in \TeX\ -%documents. All this information can easily be obtained using +%documents. This information can be obtained using %native commands, but the Java application allows an -%OS-independent approach with results that can easily be +%\gls{OS}-independent approach with results that can easily be %captured by \TeX's shell-escape without having to strip -%formatting information. +%formatting information. It also uses control sequence markup to indicate +%whether characters should be interpreted literally (such as in file names) or +%if they should obey their current category code (such as +%punctuation occurring in textual information) or if they should be +%interpreted in some other way (such as pattern markup). This markup +%is expanded by \cs{TeXOSQuery} when it performs the piped shell +%escape. % %\begin{important} -%\texttt{texosquery} provides read-only actions, and I don't +%\app{texosquery} provides read-only actions, and I don't %intend adding any actions that modify system settings or files. %\end{important} % -%Since the application is designed to work with \TeX, each -%function will display the result on a single line without -%formatting. (For multiple results, each line is grouped -%from v1.1.) A blank line (or empty group) will be displayed -%if the information isn't available. A forward slash is always -%used as a directory divider, regardless of the operating -%system, so the result can be used, for example, in \cs{input} or -%\cs{includegraphics}. +%Since the application is designed to work with \TeX\ (through +%\cs{TeXOSQuery} defined in \file{texosquery.tex}) each action (indicated +%by a command line switch) will display the result on a single line. +%For multiple results, each line is grouped. A blank line (or empty group) +%will be displayed if the information isn't available or is prohibited. +%A forward slash (\cs{fslh}) is always used as a directory divider, +%regardless of the operating system, so the result can be used, for example, +%in \cs{input} or \cs{includegraphics}. +% +%For example, I have a 64-bit Linux operating system installed on my +%computer, so I could use \app{uname} in a bash terminal: +%\begin{verbatim} +%uname -o -r +%\end{verbatim} +%which (for me) produces: +%\begin{verbatim} +%4.1.13-100.fc21.x86_64 GNU/Linux +%\end{verbatim} +%I could also run \app{texosquery} directly from the bash terminal: +%\begin{verbatim} +%texosquery -o -r +%\end{verbatim} +%which produces the rather more cryptic: +%\begin{verbatim} +%{Linux} +%{4\fdot 1\fdot 13\fhyn 100\fdot fc21\fdot x86\fusc 64} +%\end{verbatim} +%However \app{texosquery} isn't intended for this direct use. It's +%intended for use with \cs{TeXOSQuery} provided by +%\file{texosquery.tex}. Here's a plain \TeX\ document: +%\begin{verbatim} +%\input texosquery +%\TeXOSQuery{\result}{-o -r} +%\def\parseresult#1#2{OS Name: {\tt #1}. OS Version: {\tt #2}.} +%\ifx\result\empty +% Query failed! +%\else +% \expandafter\parseresult\result +%\fi +%\bye +%\end{verbatim} +%The markup commands, such as \cs{fusc}, are now converted to +%literal characters with category code 12 (\qt{other}), so the +%underscore isn't a problem. This document is now also platform independent +%(as long as \app{texosquery} and a recent version of the \gls{JRE} are +%installed). Unlike \app{uname}, \app{texosquery} also obeys the order of the +%command line switches, which makes it easier to define the helper +%command (\cs{parseresult} in the above) that processes the result. +% +%\subsection{Installation and Setup} +%\label{sec:setup} +% +%Installation is best done through your \TeX\ package manager. +%However if for some reason you need to install this package +%manually the instructions are below. If you install through your +%package manager, Windows users will probably find that the +%\file{.jar} files have been converted to \file{.exe} (with the +%\file{.bat} files omitted) and Unix-like users may find that the +%bash scripts are missing the \file{.sh} extension (these are actually +%symbolic links to the distributed \file{.sh} files). See +%section~\ref{sec:setuptest} to test that the package has been +%successfully installed. +% +%Even if you use your \TeX\ distribution's package manager to +%install this package, you may still need to edit the +%\file{texosquery.cfg} file (see step~\ref{itm:cfg} below). If you don't have write permission for +%this file you can copy it to \meta{TEXMFHOME}\file{/tex/generic/texosquery/} +%(that directory path may need to be created if it doesn't already +%exist). You can find the correct value of \meta{TEXMFHOME} using +%\begin{verbatim} +%kpsewhich -var-value=TEXMFHOME +%\end{verbatim} +%You can find where the package manager has put \file{texosquery.cfg} using +%\begin{verbatim} +%kpsewhich texosquery.cfg +%\end{verbatim} +% +%This bundle contains the following files: +%\begin{itemize} +%\item \file{texosquery.dtx} +% +%The DTX file contains the source code for this +%document, and also the files: +%\begin{itemize} +%\item\file{texosquery.tex} (generic \TeX\ code) +%\item\file{texosquery.sty} (\LaTeX\ package wrapper) +%\item\file{texosquery.cfg} (configuration file) +%\end{itemize} +%The bash scripts (which will need the extensions removed): +%\begin{itemize} +%\item\file{texosquery-jre8.sh} +%\item\file{texosquery.sh} +%\item\file{texosquery-jre5.sh} +%\end{itemize} +%Windows batch files (which will need the extensions changed to +%\file{.bat}) +%\begin{itemize} +%\item\file{texosquery-jre8.batch} +%\item\file{texosquery.batch} +%\item\file{texosquery-jre5.batch} +%\end{itemize} +% +%\item \file{texosquery.ins} The driver file used to extract all the +%above files contained in \file{texosquery.dtx}. +% +%\item The three different versions of the \app{texosquery} +%application: \file{texosquery-jre8.jar}, \file{texosquery.jar} and +%\file{texosquery-jre5.jar}. The source code for these is contained in +%the \file{java} sub-directory. +% +%\item \file{texosquery.pdf} This PDF document. +%\item \file{README.md} The README file in markdown format. +%\item \file{CHANGES} Lists major changes for each version. +%\end{itemize} +% +%To install manually (\meta{TEXMF} indicates the TEXMF directory): +%\begin{enumerate} +%\item Run +%\begin{verbatim} +%tex texosquery.ins +%\end{verbatim} +%to extract the \file{.tex}, \file{.sty}, \file{.cfg}, \file{.sh} +%and \file{.batch} files. +% +%\begin{description} +%\item[Windows] Change the extension of the \file{.batch} files to +%\file{.bat} (\TeX\ on Windows prohibits the creation of \file{.bat} +%files). Move the \file{.bat} files to somewhere on +%your system's path. (You may omit the \file{.bat} files you don't +%need.) The \file{.sh} files may be deleted. +% +%\item[Unix-like] Make the \file{.sh} files executable: +%\begin{verbatim} +%chmod u+x texosquery*.sh +%\end{verbatim} +%Move the \file{.sh} files to somewhere on your path \emph{without} the +%\file{.sh} extension. (If the \file{.sh} extension is retained, you +%will have to edit the \file{texosquery.cfg} file to include it.) +%For example (if \verb|~/bin| is included in \verb|$PATH|): +%\begin{verbatim} +%mv texosquery-jre8.sh ~/bin/texosquery-jre8 +%\end{verbatim} +%(You may omit the \file{.sh} files you don't need.) +%The \file{.batch} files may be deleted. +%\end{description} +% +%\item Move \file{texosquery.tex} to +%\meta{TEXMF}\file{/tex/generic/texosquery/} +% +%\item\label{itm:cfg} Edit \file{texosquery.cfg} so that \cs{TeXOSInvokerName} is +%defined to the application of your choice. For example, if you have +%Java 8 installed: +%\begin{verbatim} +%\def\TeXOSInvokerName{texosquery-jre8} +%\end{verbatim} +%Or if you only have Java 5 or 6 installed: +%\begin{verbatim} +%\def\TeXOSInvokerName{texosquery-jre5} +%\end{verbatim} +%You can find out your Java version by running the following in your +%command prompt or terminal: +%\begin{verbatim} +%java -version +%\end{verbatim} +%If the version number starts with \texttt{1.8} then you have Java 8 +%installed, if it starts with \texttt{1.7} then you have Java 7, +%etc. +% +%\item Move \file{texosquery.cfg} to +%\meta{TEXMF}\file{/tex/generic/texosquery/} +%\item Move \file{texosquery.sty} to +%\meta{TEXMF}\file{/tex/latex/texosquery/} +%\item Move the \file{.jar} files to +%\meta{TEXMF}\file{/scripts/texosquery/} +%\end{enumerate} +% +%\subsection{Installation Test} +%\label{sec:setuptest} +% +%To test the installation: +%\begin{enumerate} +%\item In the +%\href{http://www.dickimaw-books.com/latex/novices/html/terminal.html}{command +%prompt or terminal} do: +%\begin{verbatim} +%texosquery -b +%\end{verbatim} +%(Replace \texttt{texosquery} with the command that matches the value +%of \cs{TeXOSInvokerName} in the \hyperref[itm:cfg]{\file{texosquery.cfg} file} +%described in section~\ref{sec:setup}.) +%The above command should display the system's +%default locale. For me, this simply displays the line: +%\begin{verbatim} +%en-GB +%\end{verbatim} +%If you get an \texttt{Unknown option +%\textquotesingle-b\textquotesingle} error, then your \gls{OS} is +%picking up an old version of \app{texosquery}. Check the version +%number with the \shortarg{v} switch. +%\begin{verbatim} +%texosquery -v +%\end{verbatim} +%If you get a \qt{command not found} or \qt{bad command or file name} error, +%then recheck the installation steps in section~\ref{sec:setup} and +%make sure that the executable file has been placed on your system's +%path. +% +%If this test is successful, try the next step. +%\item Create the following plain \TeX\ document called \file{test.tex}: +%\begin{verbatim} +%\input texosquery +%\TeXOSQuery{\result}{-b}\result +%\bye +%\end{verbatim} +%and compile using: +%\begin{verbatim} +%pdftex --shell-escape test +%\end{verbatim} +% +%Alternatively, create the follow \LaTeX\ document called +%\file{test.tex}: +%\begin{verbatim} +%\documentclass{article} +%\usepackage{texosquery} +%\begin{document} +%\TeXOSQuery{\result}{-b}\result +%\end{document} +%\end{verbatim} +%and compile using: +%\begin{verbatim} +%pdflatex --shell-escape test +%\end{verbatim} +% +%In both cases, the resulting PDF file \file{test.pdf} should show the default +%locale. If not check the transcript \file{test.log} which should +%include something like \verb"(|texosquery -b)" or \verb"(|texosquery-jre8 -b)" +%etc. If it simply has the line: +%\begin{verbatim} +%TeXOSQuery: texosquery -b +%\end{verbatim} +%(or similar) then the dry run mode was on, which means the shell escape wasn't +%used. Check that the \longarg{shell-escape} switch was used when +%calling \app{pdftex} or \app{pdflatex}. +% +%If you are using \app{texosquery} or \app{texosquery-jre8} and your +%chosen application has been added to the restricted list, make sure +%that the line +%\begin{verbatim} +%\TeXOSQueryAllowRestricted +%\end{verbatim} +%hasn't been commented out in the \file{texosquery.cfg} file and try +%the above example documents in restricted mode. (Note that +%\app{texosquery-jre5} should not be added to the restricted list as +%Java 5 and 6 are now deprecated and considered security risks, so +%the above command should be commented out in the +%\file{texosquery.cfg} file if \cs{TeXOSInvokerName} has been set to +%\app{texosquery-jre5}.) +%\end{enumerate} % +%\subsection{Accessing file information} +%\label{sec:fileaccess} %If an input file name is required (for example, with the %\longargfmt{pdfdate} argument described below) then the file may be in %the current working directory, relative to the current directory %(with forward slash \texttt{/} as the directory divider), an absolute path %(again with forward slash) or on \TeX's path (in -%which case, \texttt{kpsewhich} is used to locate it). +%which case, \app{kpsewhich} is used to locate it). As from version +%1.2, \app{texosquery} honours the \texttt{openin\_any} attribute set in the +%\file{texmf.cnf} configuration file. This value is fetched using +%\begin{verbatim} +%kpsewhich -var-value=openin_any +%\end{verbatim} +%(You can find the configuration files using \texttt{kpsewhich -a +%texmf.cnf}) For example, suppose the file \file{/tmp/.test} +%exists. If the \texttt{openin\_any} attribute is set to \qt{\texttt{a}} +%(any file), then (assuming the operating system allows read-access +%to that file) the \app{texosquery} file-reading operations will +%be permitted. For example +%\begin{verbatim} +%texosquery --pdfdate /tmp/.test +%\end{verbatim} +%will return the file modification date in PDF date-time format. However, if +%\texttt{openin\_any} is set to \qt{\texttt{r}} (restricted), the read +%access will be denied because the file is considered hidden so an +%empty result is returned. Similarly, if \texttt{openin\_any} is set +%to \qt{\texttt{p}} (paranoid), the read access will be denied again +%because the file is hidden but also because the file has an +%absolute path that isn't under \texttt{\$TEXMFOUTPUT} (assuming +%that environment variable hasn't been set to \file{/tmp}). +% +%\subsection{Return Values} +%\label{sec:returnvalues} +%The return values may include literal text where special characters +%need to have their category code changed to 12 (for example, file names) +%but the return values may also include \TeX\ code that needs to be +%processed by \TeX, either during the shell escape or deferred for +%later (such as date-time or numeric patterns). This means that the +%result from the shell escape can't be automatically detokenized. +% +%Therefore, as from version 1.2, the return values include short +%control sequences that are locally defined by \cs{TeXOSQuery} and +%so are only valid within that command's scope. For example, +%\cs{fcln} expands to a colon (\texttt{:}) with category code 12 +%whereas \cs{tcln} expands to a colon according to its current +%meaning. Note that this has changed from earlier versions which +%simply returned the actual characters, which may or may not have +%had the category code set to 12 at the start of \cs{TeXOSQuery}. To +%reproduce the original behaviour, use the compatibility mode +%(\longarg{compatible}) with the level set to 0 or 1. +%For the full list of shortcut commands, see the +%definition of \hyperlink{enableshortcs}{\cs{@texosquery@enableshortcs}}. +% +%The output produced by the \app{texosquery} application +%will be returned using the system's default input +%encoding. (For example, \gls{UTF}-8.) You will need to ensure that your \TeX\ +%document uses the same encoding if you want to typeset any of the +%results that may contain non-ASCII characters. You can determine +%the default encoding with \texttt{texosquery \shortarg{C}}, which is +%formatted to match the options used by the \sty{inputenc} package. +%(For example, \texttt{uft8} for \gls*{UTF}-8.) +% +%To test the file encoding rerun the plain \TeX\ or \LaTeX\ test +%file in section~\ref{sec:setuptest} with +%\shortarg{N} instead of \shortarg{b}. Most currency symbols are +%outside the ASCII set, so this should return a non-ASCII character. +%If you happen to have \$ as your currency, +%then try \texttt{en-GB} or \texttt{en-IE} which have \pounds\ and +%\texteuro, respectively. \LaTeX\ users may need to load +%\sty{inputenc} and \sty{fontenc}. \XeLaTeX\ and \LuaLaTeX\ users may need to load +%\sty{fontspec}. % -%Command line invocation: -%\begin{flushleft}\ttfamily -%texosquery \meta{action} ... -%\end{flushleft} -%Available actions (at least one required): +%You can change the default encoding by invoking the Java Virtual +%Machine with the option \texttt{-Dfile.encoding=}\meta{codeset}. +%For example, bash users can modify the \file{texosquery} (or +%\file{texosquery.sh}) script to set the encoding to \gls*{UTF}-8 as follows: +%\begin{verbatim} +%#!/bin/sh +% +%jarpath=`kpsewhich --progname=texosquery --format=texmfscripts texosquery.jar` +%java -Dfile.encoding=UTF-8 -jar "$jarpath" "$@" +%\end{verbatim} +%Similarly for the corresponding \file{.bat} file for Windows users. +% +%If the script file can't be modified or you have only \file{.exe} +%instead of \file{.jar} files then you can set the +%\href{https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html#tooloptions}{\texttt{JAVA\_TOOL\_OPTIONS} environment variable}. +%For example: +%\begin{verbatim} +%declare -x JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8 +%\end{verbatim} +%Note that, unlike the edit to the bash or \file{.bat} file, this will +%affect all your Java applications. +% +%\subsection{Locales} +%\label{sec:locales} +%The options that have a locale identifier as an argument need the +%identifier formatted as a \emph{regular} +%\href{https://tools.ietf.org/html/bcp47}{IETF BCP 47 language tag} that uses +%hyphens as separators. \gls{POSIX} style locales (with underscores +%replaced by hyphens, for example \texttt{fr-BE.utf8@euro}) +%are only used as a return value in the \longarg{locale} and +%\longarg{locale-lcs} options. +% +%\href{http://www.oracle.com/technetwork/java/javase/java8locales-2095355.html}{\textbf{Not +%all locales are supported by Java.}} +%For example, Irish is supported but Scottish and Welsh aren't supported by +%the \gls{JRE}. The \gls{CLDR} can be accessed with Java~8, but +%\href{http://openjdk.java.net/jeps/252}{the CLDR isn't +%enabled by default}. It can be turned on using the system property +%\texttt{java.locale.providers}, which may provide additional +%support. For example, although Welsh isn't supported by the JRE, +%it is supported with the \gls{CLDR}, so both Java~8 and the CLDR +%locale provider are required for that language. The proposed +%Java~9 should have the CLDR enabled by default. +% +%The bash script \file{texosquery-jre8} (or \file{texosquery-jre8.sh}) +%automatically sets \texttt{java.locale.providers} to \texttt{CLDR,JRE}. +%Alternatively, the \texttt{JAVA\_TOOL\_OPTIONS} environment variable +%can be set to +%\begin{verbatim} +%-Djava.locale.providers=CLDR,JRE +%\end{verbatim} +%which will enable it for all installed Java applications. +%If you need to set multiple options, these can be combined +%in the value of \texttt{JAVA\_TOOL\_OPTIONS}. +%For example +%\begin{verbatim} +%-Djava.locale.providers=CLDR,JRE -Dfile.encoding=UTF-8 +%\end{verbatim} +% +%You may find that the results are different depending on the data +%provider. For example with \texttt{java.locale.providers} set to +%\texttt{JRE,CLDR} then +%\begin{verbatim} +%texosquery -D en-GB +%\end{verbatim} +%displays the long date in the form \qt{06 November 2016} and the +%medium date in the form \qt{06-Nov-2016}, but with the ordering +%reversed to \texttt{CLDR,JRE} (so that the \gls{CLDR} is queried first) +%then the long date is now in the form \qt{6 November 2016} and the +%medium date is in the form \qt{6 Nov 2016}. +% +%Note that \app{texosquery} can only access locale information +%provided by Java. For example, Java currently doesn't +%provide any methods to access telephone codes. +% +%\subsection{Command line invocation} +%The syntax for the command line invocation of \app{texosquery} +%is: +%\begin{definition} +%texosquery \oarg{options} \meta{action} ... +%\end{definition} +%The syntax for \app{texosquery-jre8} is exactly the same except +%for the application name: +%\begin{definition} +%texosquery-jre8 \oarg{options} \meta{action} ... +%\end{definition} +%Similarly for \app{texosquery-jre5}. (Bash users may need the +%\file{.sh} extension if it wasn't removed from the script name +%during the \hyperref[sec:setup]{installation setup}.) Available actions are +%described below. At least one action is required. +% +%Available options (must come before actions): %\begin{description} -%\item[\shortarg{L} or \longarg{locale}] Display the locale -%information in the form -%\begin{flushleft}\ttfamily +%\item[\shortarg{h} or \longarg{help} or \shortarg{help}] Displays help message and +%exits. +%\item[\shortarg{v} or \longarg{version} or \shortarg{version}] Displays version +%information and exits. +%\item[\longarg{nodebug}] No debugging information. Only command +%line syntax errors are written to STDERR. (Default.) +%\item[\longarg{debug} \oarg{n} or \shortarg{debug} \oarg{n}] Set the debugging level, where +%\meta{n} is a non-negative integer. +%If \meta{n} is omitted, 3 is assumed. If \meta{n} is 0, then +%debugging information is suppressed (equivalent to +%\longarg{nodebug}). If \meta{n} $\geq 1$, error messages are +%written to STDERR. If \meta{n} $\geq 2$, any exceptions encountered +%will additionally write the stack trace to STDERR. If \meta{n} +%$\geq 3$ non-error informational messages are included. +%\item[\longarg{compatible} \meta{n} or \shortarg{compat} \meta{n}] +%Set the compatibility mode. +%The argument should be either a non-negative integer (0 for version +%1.0, 1 for version 1.1, etc) or the keyword \texttt{latest} to +%indicate the latest version (default). Note that the compatibility +%mode only affects the available actions and the display style of the +%result, and does not change security features. For example, the check for the +%\texttt{openin\_any} setting was only introduced to version 1.2, but this +%is still checked even if the compatibility mode is set to 0 or 1. +%\end{description} +% +%If multiple actions are given, they will be processed in the +%order specified in the command line invocation. Each result will +%be displayed on a separate line. As from v1.1, if there are +%multiple actions, each result will be grouped. This makes it easier +%to process the results in \TeX. For example: +%\begin{verbatim} +%texosquery -l +%\end{verbatim} +%This just produces (for me): +%\begin{verbatim} +%en\fhyn GB\fdot utf8 +%\end{verbatim} +%(which expands to \texttt{en-GB.utf8} when used with \cs{TeXOSQuery}) whereas +%\begin{verbatim} +%texosquery -l -o +%\end{verbatim} +%produces: +%\begin{verbatim} +%{en\fhyn GB\fdot utf8} +%{Linux} +%\end{verbatim} +%To reproduce the v1.0 display use \longarg{compatible}\texttt{ 0}. +%(This will also explicitly use the punctuation characters rather +%than replacing them with the control sequence markup, such as +%\cs{fhyn} or \cs{fdot}.) +% +%Note that unavailable information will produce an empty group. +%For example (assuming \file{nofile} doesn't exist or doesn't have +%read access): +%\begin{verbatim} +%texosquery -l -d nofile +%\end{verbatim} +%produces: +%\begin{verbatim} +%{en\fhyn GB\fdot utf8} +%{} +%\end{verbatim} +%whereas +%\begin{verbatim} +%texosquery -d nofile +%\end{verbatim} +%just displays an empty line. +% +%If you're puzzled as to why an empty line has been returned, try +%rerunning the command with \longarg{debug} for further information. +%Available actions are listed below. +% +%\subsubsection{Action \shortarg{b} or \longarg{bcp47}} +%(New to version 1.2.) This action displays the \gls{BCP}~47 language tag. +%For example, my locale is \texttt{en-GB} (English in the United +%Kingdom), so +%\begin{verbatim} +%texosquery -b +%\end{verbatim} +%Simply returns: +%\begin{verbatim} +%en\fhyn GB +%\end{verbatim} +%(which expands to \texttt{en-GB} with \cs{TeXOSQuery}) +%whereas a user whose default locale is set to Swiss German with the +%new orthography would get: +%\begin{verbatim} +%de\fhyn CH\fhyn 1996 +%\end{verbatim} +%(which expands to \texttt{de-CH-1996} with \cs{TeXOSQuery}). +% +%\subsubsection{Action \shortarg{L} or \longarg{locale}} +% +%This action displays the locale information in the \gls{POSIX} form +%\begin{definition} %\meta{lang}-\meta{region}.\meta{codeset}@\meta{modifier} -%\end{flushleft} -%where \meta{lang} is the ISO code for the language (e.g.\ +%\end{definition} +%where \meta{lang} is the \gls{ISO} code for the language (e.g.\ %\texttt{en}), %\meta{region} is the ISO code for the region (e.g.\ \texttt{GB}), %\meta{codeset} is the default code set (e.g.\ \texttt{UTF-8}) % and \meta{modifier} is the modifier. Elements may be omitted % if unavailable. For example, \texttt{en-GB.UTF-8} has the % \meta{modifier} omitted, and \texttt{en} has all but the language -% omitted. -%\item[\shortarg{l} or \longarg{locale-lcs}] As the above but the -%codeset (if present) is converted to lower case and any hyphens are -%stripped. For example, if \longargfmt{locale} returns -%\texttt{en-GB.UTF-8}, then \longargfmt{locale-lcs} would return -%\texttt{en-GB.utf8}. -%\item[\shortarg{c} or \longarg{cwd}] Displays the current working -%directory. -%\item[\shortarg{m} or \longarg{userhome}] Displays the user's home -%directory. -%\item[\shortarg{t} or \longarg{tmpdir}] Displays the temporary -%directory. -%\item[\shortarg{o} or \longarg{osname}] Displays the operating -%system name. -%\item[\shortarg{r} or \longarg{osversion}] Displays the operating -%system version. -%\item[\shortarg{a} or \longarg{osarch}] Displays the operating -%system architecture. -%\item[\shortarg{n} or \longarg{pdfnow}] Displays the current -% date and time in PDF format. For example +% omitted. As above, the punctuation characters will actually be +% returned using the control sequences \cs{fhyn} (hyphen), \cs{fdot} +% (dot) and \cs{fatc} (at). +% +%\subsubsection{Action \shortarg{l} or \longarg{locale-lcs}} +% +%This action is similar to \longarg{locale}, but the codeset is converted to +%lower case and any hyphens are stripped. For example, if \longargfmt{locale} +%returns \texttt{en-GB.UTF-8}, then \longargfmt{locale-lcs} would return +%\texttt{en-GB.utf8}. As above, the punctuation characters will actually be +% returned using the control sequences \cs{fhyn} (hyphen), \cs{fdot} +% (dot) and \cs{fatc} (at). +% +%\subsubsection{Action \shortarg{C} or \longarg{codeset-lcs}} +% +%(New to version 1.2.) +%This action returns just the codeset converted to lower case with hyphens +%stripped. For example, my default file encoding is \gls{UTF}-8, so %\begin{verbatim} -%D:20160704131006+01'00' +%texosquery -C %\end{verbatim} -%Note that some, but not all, \TeX\ formats provide +%returns +%\begin{verbatim} +%utf8 +%\end{verbatim} +%This action is used by the \sty{locale} package to determine the +%option to use when it needs to automatically load the +%\sty{inputenc} package. +% +%\subsubsection{Action \shortarg{o} or \longarg{osname}} +% +%This action displays the operating system name. For example, for me this +%produces: +%\begin{verbatim} +%Linux +%\end{verbatim} +% +%\subsubsection{Action \shortarg{r} or \longarg{osversion}} +% +%This action displays the operating system version. For example, for me this +%produces: +%\begin{verbatim} +%4\fdot 1\fdot 13\fhyn 100\fdot fc21\fdot x86\fusc 64 +%\end{verbatim} +%(which expands to \texttt{4.1.13-100.fc21.x86\_64} when used with +%\cs{TeXOSQuery}). +% +%\subsubsection{Action \shortarg{a} or \longarg{osarch}} +% +%This action displays the operating system architecture. For example, for me +%this produces: +%\begin{verbatim} +%amd64 +%\end{verbatim} +% +%\subsubsection{Action \shortarg{M} or \longarg{date-time}} +%(New to version 1.2.) +%This action displays all the current date time data in a format +%suitable for use in \cs{texosqueryfmtdatetime}. (See +%section~\ref{sec:applydatetimepatterns}.) +% +%\subsubsection{Action \shortarg{Z} \oarg{locale} or +%\longarg{time-zones} \oarg{locale}} +%(New to version 1.2.) +%This action displays all of the time zone mappings +%for the given locale (or the default if \meta{locale} is omitted) in the format +%\begin{definition} +%\{\marg{id$_1$}\marg{short name}\marg{long +%name}\marg{dst short name}\marg{dst long name}\}\ldots +%\{\marg{id$_{n}$}\marg{short name}\marg{long +%name}\marg{dst short name}\marg{dst long name}\} +%\end{definition} +%The \meta{id} is the unique label used by Java to identify the time +%zone (such as \texttt{Europe/London}) as used in the time zone +%information returned by \shortarg{M} (\longarg{date-time}). +% +%\subsubsection{Action \shortarg{n} or \longarg{pdfnow}} +% +%This action displays the current date and time in PDF format. For example +%\begin{verbatim} +%\pdfd \fcln 20160704131006\fpls 01\fapo 00\fapo +%\end{verbatim} +%This uses the shorthand tags \cs{pdfd}, \cs{fcln}, \cs{fpls} and +%\cs{fapo} that +%are locally redefined by +%\cs{TeXOSQuery} to produce a \texttt{D}, a colon (\texttt{:}), a +%plus sign (\texttt{+}) and an apostrophe (\texttt{\textquotesingle}) +%with the category code set to 12 to make it consistent with +%\cs{pdfcreationdate}. This also allows +%for situations where the punctuation characters have been made +%active (for example, through \sty{babel}). +% +%Some, but not all, \TeX\ formats provide %\cs{pdfcreationdate}, which is more efficient than using the shell %escape, but this can be used %as a fallback method for those that don't (for example, \XeTeX). -%\item[\shortarg{d} \meta{file} or \longarg{pdfdate} \meta{file}] -% Displays the last modified time stamp of the given file in PDF format or a blank line +% +%Note that versions 1.0 and 1.1 didn't use \cs{pdfd} etc but simply used +%the actual characters. For example: +%\begin{verbatim} +%D:20160704131006+01'00' +%\end{verbatim} +%If you want to reproduce this format, use \longarg{compatible} +%with the level set to 0 or 1. +% +%\subsubsection{Action \shortarg{d} \meta{file} or \longarg{pdfdate} +%\meta{file}} +% +%This action displays the last modified time stamp of the given file in PDF format or a blank line % if the file doesn't exist or the file permissions prohibit this % action. %Again some, but not all, \TeX\ formats provide %\cs{pdffilemoddate}\marg{file}, which is more efficient than using %the shell escape. -%\item[\shortarg{s} \meta{file} or \longarg{filesize} \meta{file}] -% Displays the size in bytes of the given file or a blank line -% if the file doesn't exist or the file permissions prohibit this -% action. -%Some, but not all, \TeX\ formats provide +% +%As with \longarg{pdfnow} this now uses \cs{pdfd} etc which are converted +%by \cs{TeXOSQuery} to characters with the category code set to 12. +% +%This action obeys the \texttt{openin\_any} setting, so if access to +%\meta{file} is forbidden by this setting, the result will be empty. +% +%\subsubsection{Action \shortarg{s} \meta{file} or \longarg{filesize} +%\meta{file}} +% +%This action displays the size in bytes of the given file or an +%empty string if the file doesn't exist or the file permissions prohibit this +%action. Some, but not all, \TeX\ formats provide %\cs{pdffilesize}\marg{file}, which is more efficient than using %the shell escape. -%\item[\shortarg{i} \meta{sep} \meta{dir} or \longarg{list} -%\meta{sep} \meta{dir}] -%List all files in the given directory with the output on a single +% +%This action obeys the \texttt{openin\_any} setting, so if access to +%\meta{file} is forbidden by this setting, the result will be empty. +% +%\subsubsection{Action \shortarg{c} or \longarg{cwd}} +% +%This action displays the current working directory. This obeys the +%\texttt{openin\_any} setting, so this action will return an empty +%string if this file information is forbidden by that setting. +% +%\subsubsection{Action \shortarg{m} or \longarg{userhome}} +% +%This action displays the user's home directory. This obeys the +%\texttt{openin\_any} setting, so this action will return an empty +%string if this file information is forbidden by that setting. +% +%\subsubsection{Action \shortarg{t} or \longarg{tmpdir}} +% +%This action displays the temporary directory. This obeys the +%\texttt{openin\_any} setting, so this action will return an empty +%string if this file information is forbidden by that setting. +% +%\subsubsection{Action \shortarg{i} \meta{sep} \meta{dir} \oarg{sort} or \longarg{list} +%\meta{sep} \meta{dir} \oarg{sort}} +% +%This action lists all files in the given directory with the output on a single %line using \meta{sep} as the separator between entries. Note that %the list doesn't include the full path, just the file names. -%\item[\shortarg{f} \meta{sep} \meta{regex} \meta{dir} or -%\longarg{filterlist} \meta{sep} \meta{regex} \meta{dir}] -%Like the above but only lists those files whose name matches the -%regular expression given in \meta{regex}. Note that this tests for a -%complete match on the file name (not including path). For example, +% +%\begin{important} +%As from v1.2, new restrictions have been placed on the value of \meta{dir} +%for security reasons. For all three applications, +%\app{texosquery-jre8}, \app{texosquery} and \app{texosquery-jre5}, +%the \texttt{openin\_any} setting is checked. If read access to +%\meta{dir} is forbidden by the \texttt{openin\_any} setting, then +%this action returns an empty string. \emph{Additionally}, +%regardless of \texttt{openin\_any}, the more restrictive +%applications, \app{texosquery-jre8} and \app{texosquery}, prohibit a +%value of \meta{dir} that's outside the current working directory +%path (e.g.\ \texttt{..}) or that has no parent directory (e.g.\ \texttt{/}). +%Both \app{texosquery-jre8} and \app{texosquery} check the +%\emph{canonical path} of \meta{dir}, so if \meta{dir} is a symbolic +%link, the target path is checked. +% +%This is a security feature to prevent +%any malicious code that might try to recursively list the contents +%of the entire filing system, which would hog resources, or that +%might try to discover files outside the current working directory. An +%exception is made for \app{texosquery-jre5} since that application +%is already considered insecure (due to Java 5 and 6 being +%deprecated), so if you really need \meta{dir} as, say \texttt{..} (the +%parent directory) or \texttt{/} (the root directory), you can use +%\app{texosquery-jre5} (by redefining \cs{TeXOSInvokerName} before +%using \cs{TeXOSQuery}) although this isn't recommended. It will +%still obey the \texttt{openin\_any} setting, so the listing still +%won't work with \app{texosquery-jre5} if the \texttt{openin\_any} +%setting is set to \texttt{p} (paranoid). +%\end{important} +% +%As from version 1.2, there is now an optional argument \meta{sort}, +%which indicates how the returned list should be sorted. If omitted +%\texttt{default} is assumed. Available values of \meta{sort}: +%\begin{description} +%\item[\texttt{default}] Use the default order. This is typically in +%alphabetical order, but depends on the operating system or +%\gls{JRE}. +%\item[\texttt{date-ascending}] Order by file modified date from +%oldest to newest. This option has synonyms \texttt{date} and +%\texttt{date-asc}. +%\item[\texttt{date-descending}] Order by file modified date from +%newest to oldest. You may use the shorter \texttt{date-des} +%value instead. +%\item[\texttt{size-ascending}] Order by file size from +%smallest to largest. This option has synonyms \texttt{size} and +%\texttt{size-asc}. +%\item[\texttt{size-descending}] Order by file size from +%largest to smallest. You may use the shorter \texttt{size-des} +%value instead. +%\item[\texttt{name-ascending}] Order by file name (case-sensitive) +%alphabetically. This option has synonyms \texttt{name} and +%\texttt{name-asc}. +%\item[\texttt{name-descending}] Order by file name (case-sensitive) +%in reverse alphabetic order. You may use the shorter +%\texttt{name-des} value instead. +%\item[\texttt{iname-ascending}] Order by file name (case-insensitive) +%alphabetically. This option has synonyms \texttt{iname} and +%\texttt{iname-asc}. +%\item[\texttt{iname-descending}] Order by file name (case-insensitive) +%in reverse alphabetic order. You may use the shorter +%\texttt{iname-des} value instead. +%\item[\texttt{ext-ascending}] Order by file extension (case-sensitive) +%alphabetically. If files have the same extension, they are ordered +%by name. This option has synonyms \texttt{ext} and +%\texttt{ext-asc}. +%\item[\texttt{ext-descending}] Order by file extension (case-sensitive) +%in reverse alphabetic order. If files have the same extension, they are +%ordered by name (reverse alphabetic order). You may use the shorter +%\texttt{ext-des} value instead. +%\end{description} +% +%This action obeys the \texttt{openin\_any} setting for all the +%listed files as well as for the directory \meta{dir}, so if access to +%a file in the directory is forbidden, the file will be omitted from +%the list. (This action is equivalent to the following with +%\meta{regex} set to \texttt{.*} to match all files.) +% +%If you want to excluded hidden dot files (where they aren't +%automatically excluded by \texttt{openin\_any}), use the +%\longarg{filterlist} action described below with \meta{regex} set +%to \verb|[^\.].*|. (Remember that you'll need to use \cs{string} +%when using the shell escape, as noted below.) +% +%\begin{important} +%Unlike most of the return values the \meta{sep} part here isn't +%escaped, so take care if \meta{sep} contains any commands. For +%example, if you want to use \verb|\\| as the separator, you'll need +%to use \verb|\string\noexpand\string\\| in the \meta{sep} part +%within \cs{TeXOSQuery}. +%\end{important} +% +%For example: +%\begin{verbatim} +%\TeXOSQueryFileList{\result}{\string\noexpand\string\\}{.} +%\end{verbatim} +%calls (through the shell escape): +%\begin{verbatim} +%texosquery -i '\noexpand\\' '.' +%\end{verbatim} +%(the two \cs{string} commands have detokenized their arguments) +%so \app{texosquery} uses \verb|\noexpand\\| as the separator in the +%returned list, but this list is expanded as it's read in. However +%\cs{noexpand} prevents the \verb|\\| from being expanded, so the +%separator becomes just \verb|\\| which may be (re)defined before the +%resulting list is processed. +% +%Note that \cs{TeXOSQueryFileList} automatically adds the single +%quotes around the arguments. If \cs{TeXOSQuery} is used explicitly, +%these quotes would need to be added as appropriate. +% +%\subsubsection{Action \shortarg{id} \meta{sep} \meta{dir} +%\oarg{sort} or \longarg{list-dir} +%\meta{sep} \meta{dir} \oarg{sort}} +% +%This action is like \longarg{list} but only includes sub-directories +%of \meta{dir}. The caveats and security notes for \longarg{list} also apply +%here. +% +%\subsubsection{Action \shortarg{ir} \meta{sep} \meta{dir} +%\oarg{sort} or \longarg{list-regular} +%\meta{sep} \meta{dir} \oarg{sort}} +% +%This action is like \longarg{list} but only includes regular files. +%The caveats and security notes for \longarg{list} also apply here. +% +%\subsubsection{Action \shortarg{f} \meta{sep} \meta{regex} \meta{dir} +%\oarg{sort} or \longarg{filterlist} \meta{sep} \meta{regex} \meta{dir} +%\oarg{sort}} +% +%This action is like \longarg{list} but only lists those files whose name +%matches the +%\href{http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html}{regular expression} given in \meta{regex}. Note that +%since this uses Java's \texttt{String.matches} method this tests for a +%\emph{complete} match on the file name (not including directory path). For example, %if \meta{regexp} is \texttt{foo.*}, it will only match files whose %name starts with \texttt{foo} (for example, \texttt{foobar} will -%match but \texttt{barfoo} won't). -%\item[\shortarg{u} \meta{file} or \longarg{uri} \meta{file}] -%Displays the URI of the given file or a blank line if the file -%doesn't exist or the file permissions prohibit this action. -%Note that this may include in a percent character in the result. The \TeX\ -%command \cs{TeXOSQuery} protects against this by changing the -%category code, but if you explicitly call \texttt{texosquery} -%using the shell escape, you'll need to be careful of this. -%\item[\shortarg{p} \meta{file} or \longarg{path} \meta{file}] -%Displays the canonical path of the given file or a blank line if -%the file doesn't exist or the file permissions prohibit this -%action. -%\item[\shortarg{e} \meta{file} or \longarg{dirname} \meta{file}] +%match but \texttt{barfoo} won't). Use \texttt{.*foo.*} to match all +%files that contain \texttt{foo} in the name (so \texttt{foobar} and +%\texttt{barfoo} will both match). +% +%\begin{important} +%You can't have an empty regular expression. You can use the regular +%expression \texttt{.*} to match all files (which is what +%\longarg{list} does). +%\end{important} +% +%As from version 1.2, this action now has an optional argument +%\meta{sort}, which indicates how to sort the returned list. The +%available values for \meta{sort} are the same as for +%\longarg{list}, described above. +% +%The caveats and security notes for \longarg{list} also apply here. +% +%\subsubsection{Action \shortarg{fd} \meta{sep} \meta{regex} \meta{dir} +%\oarg{sort} or \longarg{filterlist-dir} \meta{sep} \meta{regex} \meta{dir} +%\oarg{sort}} +% +%This action is like \longarg{filterlist} but only includes +%sub-directories of \meta{dir}. +% +%The caveats and security notes for \longarg{list} also apply here. +% +%\subsubsection{Action \shortarg{fr} \meta{sep} \meta{regex} \meta{dir} +%\oarg{sort} or \longarg{filterlist-regular} \meta{sep} \meta{regex} \meta{dir} +%\oarg{sort}} +% +%This action is like \longarg{filterlist} but only includes +%regular files. +% +%The caveats and security notes for \longarg{list} also apply here. +% +%\subsubsection{Action \shortarg{w} \meta{sep} \meta{regex} \meta{dir} +%\oarg{sort} or \longarg{walk} +%\meta{sep} \meta{regex} \meta{dir} \oarg{sort}} +% +%(New to version 1.2. Not available with \app{texosquery-jre5}.) +% +%This action starts from the directory \meta{dir} \emph{which must +%be on the current working directory's path} and returns a list +%separated by \meta{sep} of all the regular files whose basename matches +%the regular expression \meta{regex} (as for the filtered file +%listings described above), recursively descending +%sub-directories. Any files or sub-directories that are hidden, unreadable +%or symbolic links are skipped. The list is sorted +%according to \meta{sort}, which is as for the file listing actions +%described above. Note that \meta{dir} is first converted to its +%canonical path, so if \meta{dir} is a symbolic link, the +%security check will test if the \emph{target} path is on the +%current working directory path. +% +%As with the above file listings, the separator \meta{sep} isn't +%escaped so take care if \meta{sep} contains any commands. The +%resulting list will consist of paths relative to \meta{dir}. +% +%\begin{important} +%This action requires at least Java 7 so it's not available with +%\file{texosquery-jre5.jar}. +%\end{important} +% +%\subsubsection{Action \shortarg{u} \meta{file} or \longarg{uri} +%\meta{file}} +% +%This action displays the URI of the given file or an empty string if the file +%doesn't exist or if the file permissions or the +%\texttt{openin\_any} setting prohibit read access. +% +%\subsubsection{Action \shortarg{p} \meta{file} or \longarg{path} +%\meta{file}} +% +%This action displays the canonical path of the given file or an +%empty string if the file doesn't exist or if the file permissions +%or the \texttt{openin\_any} setting prohibit this action. +% +%\subsubsection{Action \shortarg{e} \meta{file} or \longarg{dirname} +%\meta{file}} +% %(New to v1.1.) -%Displays the canonical path of the given file's parent (that is, the -%directory containing \meta{file}) or a blank line if -%the file doesn't exist or the file permissions prohibit this +%This action displays the canonical path of the given file's parent (that is, the +%directory containing \meta{file}) or an empty string if +%the file doesn't exist or if the file permissions or the +%\texttt{openin\_any} setting prohibits this %action. Note that this is different to the Unix-like -%\texttt{dirname} command, which will return a relative path if +%\app{dirname} command, which will return a relative path if %\meta{file} isn't an absolute path. -%\item[\shortarg{h} or \longarg{help}] Displays help message and -%exits. -%\item[\shortarg{v} or \longarg{version}] Displays version -%information and exits. -%\end{description} % -%If multiple options are given, they will be processed in the -%order specified in the command line invocation. Each result will -%be displayed on a separate line. As from v1.1, if there are -%multiple actions, each result will be grouped. This makes it easier -%to process the results in \TeX. For example: +%\subsubsection{Action \shortarg{N} \oarg{language tag} or \longarg{numeric} +%\oarg{language tag}} +% +%(New to v1.2.) This action displays: +%\begin{definition} +%\marg{locale tag}\marg{group sep}\marg{decimal sep}\marg{exp +%sep}\marg{use group}\marg{currency code}\marg{regional currency +%code}\marg{currency sym}\marg{\TeX\ currency}\marg{currency sep} +%\end{definition} +%for the \meta{language tag} given in the optional argument. If omitted, the +%default locale is assumed. The returned values are: +%\begin{itemize} +%\item \meta{tag} the language tag. +%\item \meta{group sep} the numeric group separator. +%\item \meta{decimal sep} the decimal separator. +%\item \meta{exp sep} the exponent separator. +%\item \meta{use group} \texttt{1} if the locale uses number +%grouping otherwise \texttt{0}. +%\item \meta{currency code} the ISO 4217 currency code. +%\item \meta{regional currency code} either the ISO 4217 currency +%code or an unofficial code. The only unofficial codes returned are: +%GGP (Guernsey pound), JEP (Jersey pound), IMP (Isle of Man +%pound), KID (Kiribati dollar) and TVD (Tuvaluan dollar). +%\item \meta{currency sym} the currency symbol. (This may sometimes be +%the same as \meta{currency code}.) Non-ASCII characters will be +%marked up with \cs{twrp} (see below). +%\item \meta{\TeX\ currency} the currency symbol using \TeX\ code +%provided by \sty{texosquery}. +%This is obtained by substituting known Unicode +%currency symbols occurring in \meta{currency sym} with +%\cs{texosquerycurrency}\marg{xxx}, which expands to the control +%sequence given by the name \texttt{texosquerycurrency}\meta{xxx}. +%These commands are defined in \file{texosquery.tex}. Since there are no generic \TeX\ commands +%available for all these symbols (except \$), these commands will need to be +%redefined as appropriate but are provided in the event that there's +%no UTF-8 support. There is a limited check for some known currency +%commands, such as \cs{texteuro} or \cs{euro}, but if an appropriate +%currency command can't be found, the +%\cs{texosquerycurrency}\meta{xxx} commands will be defined to +%simply the currency label (usually the same as the \meta{xxx} +%part). +% +%\item \meta{currency sep} the currency decimal separator. +%\end{itemize} +%The language tag should conform to \gls{IETF} \gls{BCP}~47. See +%\url{http://docs.oracle.com/javase/8/docs/api/java/util/Locale.html} +%for further details. If you are using \app{texosquery-jre5}, +%only the language, region and variant elements will be recognised +%since the language tag support was introduced in Java~7. +% +%For example: %\begin{verbatim} -%texosquery -l +%texosquery -N en-GB %\end{verbatim} -%This just produces (for me): +%produces %\begin{verbatim} -%en-GB.utf8 +%{en-GB}{,}{.}{E}{1}{GBP}{GBP}{\twrp{£}}{\texosquerycurrency{pound}}{.} %\end{verbatim} -%whereas +%The \cs{twrp} command is used by \app{texosquery} to markup a +%non-\gls{ASCII} character. This command is one of the shorthands only +%defined within \cs{TeXOSQuery}. In this case it's a shortcut for +%the command \cs{texosquerynonasciiwrap}. By default this just does its +%argument, but it may be redefined to perform some other action such +%as converting from one encoding to another. +% +%In most cases the \meta{regional currency code} will be the same +%as \meta{currency} code. A few non-ambiguous unofficial codes +%are known by \app{texosquery} and may be used if the country code +%is recognised. For example, %\begin{verbatim} -%texosquery -l -n +%texosquery -N en-IM %\end{verbatim} -%produces: +%produces %\begin{verbatim} -%{en-GB.utf8} -%{D:20160714112732+01'00'} +%{en-IM}{,}{.}{E}{1}{GBP}{IMP}{M\twrp{£}}{M\texosquerycurrency{pound}}{.} %\end{verbatim} -%Note that unavailable information will produce an empty group. -%For example (assuming \texttt{nofile} doesn't exist): +% +%If Java doesn't support the given locale, the currency code will +%appear as \texttt{XXX} with the symbol \textcurrency\ (generic +%currency sign). +% +%\begin{important} +%This option and the following (\longarg{locale-data}) are best used +%with \XeTeX\ or \LuaTeX\ to deal with the non-\gls{ASCII} characters. +%Make sure the file encoding used by Java matches the \TeX\ file. +%\end{important} +% +%(See section~\ref{sec:locales} for the difference in locale +%providers.) +% +%\subsubsection{Action \shortarg{D} \oarg{language tag} or +%\longarg{locale-data} \oarg{language tag}} +% +%(New to v1.2.) This action provides more +%extensive information than \longarg{numeric}. +%The result has nested groups to assist parsing. +%Again the \meta{language tag} may be omitted. For example, %\begin{verbatim} -%texosquery -l -d nofile -n +%texosquery --locale-data %\end{verbatim} -%produces: +%For the default locale or %\begin{verbatim} -%{en-GB.utf8} -%{} -%{D:20160714112732+01'00'} +%texosquery --locale-data en-GB %\end{verbatim} -%whereas +%for the locale identified by \texttt{en-GB}. +%As with all the other actions, the result is written to STDOUT on a +%single line. Its overall length and the use of the shortcut +%commands used by \app{texosquery} to markup certain elements mean +%that it's not particularly human-readable, but it's designed to be +%easy for \TeX\ to interpret. The information is returned in the +%following format: +%\begin{definition} +%\marg{locale block}\marg{current date block}\marg{date pattern +%block}\marg{current time block}\allowbreak\marg{time pattern +%block}\marg{current date time block}\marg{date time pattern block}\marg{days +%of the week block}\marg{abbreviated dates of the week +%block}\marg{month names block}\marg{abbreviated month names +%block}\marg{standalone days of the week block}\marg{abbreviated +%standalone days of the week block}\marg{standalone month names +%block}\marg{abbreviated standalone month names block}\marg{numeric +%block}\marg{numeric patterns block} +%\end{definition} +%There may seem to be some repetition here with the month and week +%day names, but with \app{texosquery-jre8}, the second set are the +%standalone version (for example, for a column header). In some +%languages, these may be different from the names used in the date +%format. Since this is new to Java 8, it's not supported in +%\file{texosquery.jar} or \file{texosquery-jre5.jar} and they simply reproduce +%the non-standalone names. +% +%The information supplied with this option is quite complex, +%but it's used by the \sty{locale} package to set up all the +%required information for each locale used in the document. +%Any non-\gls{ASCII} characters are marked up with \cs{twrp}, +%which is locally defined by \cs{TeXOSQuery} to expand to +%\cs{texosquerynonasciiwrap}. This may be redefined to deal with the +%characters if necessary. For example, if the character needs to be +%converted from one encoding to another. +% +%The blocks are: +%\begin{description} +%\item \meta{locale block} +% +%The locale information in the form: +%\begin{definition} +%\marg{tag}\marg{language name}\marg{locale language +%name}\marg{region name}\marg{locale region name}\marg{variant +%name}\marg{locale variant name} +%\end{definition} +%The \meta{tag} is the language tag (the same format as \longarg{bcp47}). +% +%The \meta{language name} is the language name in the operating +%system's default locale. +% +%The \meta{locale language name} is the language name in +%the locale's language. +% +%For example, my locale is \texttt{en-GB}, so if I use %\begin{verbatim} -%texosquery -d nofile +%texosquery -D en-GB %\end{verbatim} -%just displays an empty line. +%then both \meta{language name} and \meta{locale language name} will +%be \texttt{English}, but if I use: +%\begin{verbatim} +%texosquery -D fr-GB +%\end{verbatim} +%then \meta{language name} will be \texttt{French} and the \meta{locale +%language name} will be \texttt{fran\cs{twrp}\char`\{\c{c}\char`\}ais} (note the non-ASCII +%character has been marked up). The locale tag \verb|fr-GB| +%indicates that I'm writing in French but I'm in the United Kingdom +%(so the currency should be GBP). +% +%The \meta{region name} is the region's name in the operating +%system's default language. +% +%The \meta{locale region name} is the region's name in the locale's language. +% +%So for me with \texttt{-D en-GB} I get +%\verb|United\tspc Kingdom| for both \meta{region name} and +%\meta{locale region name}. This illustrates another of the +%shorthand commands that \app{texosquery} uses that's only locally +%defined within \cs{TeXOSQuery}. In this case, \cs{tspc} just expands +%to a space. This is used to avoid accidentally discarding any +%intentional spaces that might follow a command name or any +%intentional consecutive spaces. +% +%If, however, I use \texttt{-D fr-GB} I still get +%\verb|United\tspc Kingdom| in \meta{region name}, but \meta{locale +%region name} is now \verb|Royaume-Uni|. +% +%The \meta{variant name} is the language's variant. For example, +%with \verb|de-CH-1996| (Swiss German using the new orthography), +%the variant is 1996. There's no variant in \verb|en-GB| so this +%value is empty for me. +% +%The \meta{locale variant name} is the variant in the locale's +%language. In the case of \verb|de-CH-1996| this is still 1996. +% +%\item \meta{current date block} +% +%This returns the current date in four different formats and also an +%integer that indicates the first day of the week in the given +%locale: +%\begin{definition} +%\marg{full date}\marg{long date}\marg{medium date}\marg{short +%date}\marg{first day} +%\end{definition} +%The actual date formats depend on the locale. For example, with +%\texttt{en-GB} the \meta{full date} is (assuming today is +%2016-11-08): +%\begin{verbatim} +%Tuesday,\tspc 8\tspc November\tspc 2016 +%\end{verbatim} +%(Tuesday, 8 November 2016). +%The \meta{long date} is +%\begin{verbatim} +%08\tspc November\tspc 2016 +%\end{verbatim} +%(08 November 2016). +%The \meta{medium date} is +%\begin{verbatim} +%08\thyn Nov\thyn 2016 +%\end{verbatim} +%(08-Nov-2016). +%The \meta{short date} is +%\begin{verbatim} +%08\tslh 11\tslh 16 +%\end{verbatim} +%(08/11/2016). +%Note that there's a difference between using the \gls{CLDR} locale data +%and the JRE data. If I'm using the Java~7 compatible +%\app{texosquery.jar} which only uses JRE locale data, then I get +%the above results, but if I use \file{texosquery-jre8.sh} which +%sets \texttt{java.locale.providers} to \texttt{CLDR,JRE} then I get +%a slightly different result. The \meta{long date} is +%\begin{verbatim} +%8\tspc November\tspc 2016 +%\end{verbatim} +%(8 November 2016) +%and the \meta{medium date} is +%\begin{verbatim} +%8\tspc Nov\tspc 2016 +%\end{verbatim} +%(8 Nov 2016). +%The \meta{medium date} may be numeric or may be an abbreviated +%form of \meta{long date}, depending on the language and the locale +%provider. Some languages aren't supported by \gls{JRE} but are supported +%by \gls{CLDR}. (Some aren't supported by either, but there's a +%chance that those languages will eventually be added to the CLDR.) +%For example, if I use \texttt{-D cy-GB} with the JRE as the locale +%provider I just get the \texttt{en-GB} dates, but if I use the CLDR +%provider I get Welsh dates. +% +%Note that the proposed Java~9 should automatically use the CLDR as +%the locale provider, which is being increasingly adopted by +%applications as a common data repository. +% +%The first day of the week index is zero-based starting with Monday. +%This is done in order to be compatible with \sty{pgfcalendar}. For +%example, with \texttt{-D en-GB} \meta{first day} is 0 (Monday), but +%with \texttt{pt-BR} \meta{first day} is 6 (Sunday). The +%\sty{locale} package provides a way of converting the index to +%Monday=1 or Sunday=1 indexing. +% +%\item \meta{date pattern block} +% +%The pattern used to format the full date, long date, medium +%date and short date. This is in the form: +% +%\marg{full pattern}\marg{long pattern}\marg{medium +%pattern}\marg{short pattern} +% +%Each pattern uses shorthand mark-up that's only locally defined +%within \cs{TeXOSQuery}. These short commands are expanded to longer +%commands provided by \file{texosquery.tex} to avoid name clashing +%with other packages. When used directly in the document text, these +%expand to reproduce the pattern. +% +%For example, with \texttt{-D en-GB} I get the following +%pattern for the short date: +%\begin{verbatim} +%\patdtf{2}{d}\tslh \patdtf{2}{M}\tslh \patdtf{2}{y} +%\end{verbatim} +%When parsed by \cs{TeXOSQuery}, this is internally converted to +%\begin{verbatim} +%\texosquerydtf{2}{d}/\texosquerydtf{2}{M}/\texosquerydtf{2}{y} +%\end{verbatim} +%But default this simply expands to \texttt{dd/MM/yy} but may be +%used in the first argument of \cs{texosqueryfmtdatetime}. See +%sections~\ref{sec:patternformats} and \ref{sec:applydatetimepatterns} for +%further details. +% +%\item \meta{current time block} +% +%The current time provided in various formats suitable to the +%given locale: +%\begin{definition} +%\marg{full time}\marg{long time}\marg{medium time}\marg{short time} +%\end{definition} +%As with the current date, the actual format depends on the locale +%and the locale provider. For example, with \texttt{en-GB} I get: +%\begin{verbatim} +%{15:59:41\tspc o\csq clock\tspc GMT}{15:59:41\tspc GMT}{15:59:41}{15:59} +%\end{verbatim} +%with the \gls{JRE}. If I switch to \gls{CLDR} (\file{texosquery-jre8.sh}) I get: +%\begin{verbatim} +%{16:00:51\tspc Greenwich\tspc Mean\tspc Time}{16:00:51\tspc GMT}{16:00:51}{16:00} +%\end{verbatim} +% +%\item \meta{time pattern block} +% +%The pattern used to format the full time, long time, medium +%time and short time. +% +%\marg{full time pattern}\marg{long time pattern}\marg{medium time +%pattern}\marg{short time pattern} +% +%Again, when used with \cs{TeXOSQuery}, the short commands, such as +%\cs{patdtf}, are internally converted. +%They're not defined outside that scope. +% +%\item \meta{current date time block} +% +%The current date and time provided in various formats suitable to the +%given locale: +%\begin{definition} +%\marg{full date time}\marg{long date time}\marg{medium date +%time}\marg{short date time} +%\end{definition} +%This may simply be the date and time from above separated by +%a space. +% +%\item \meta{date time pattern block} +% +%The pattern used to format the full date time, long date time, medium +%date time and short date time. This may simply be the date and +%time patterns from above separated by a space. +%\begin{definition} +%\marg{full date time pattern}\marg{long date time +%pattern}\marg{medium date time pattern}\marg{short date time pattern} +%\end{definition} +% +%\item \meta{days of the week block} +% +%The week day names (starting with Monday for consistency with +%\sty{pgfcalendar}) in the locale's language. Non-\gls{ASCII} characters are marked up with +%\cs{twrp}. +%\begin{definition} +%\marg{Monday}\marg{Tuesday}\marg{Wednesday}\marg{Thursday}\marg{Friday}\marg{Saturday}\marg{Sunday} +%\end{definition} +%\item \meta{abbreviated days of the week block} +% +%As above, but abbreviated. +% +%\item \meta{month names block} +% +%The month names. +% +%\item \meta{abbreviated month names block} +% +%The abbreviated month names. +% +%\item \meta{standalone days of the week block} +% +%The week day names when used in a standalone context (for example, a +%column header). This may be the same as the earlier \meta{days of +%the week block} (and will be the same for \file{texosquery.jar} and +%\file{texosquery-jre5.jar}). The standalone support was +%introduced to Java~8. +% +%\item \meta{abbreviated standalone days of the week block} +% +%As above, but abbreviated. +% +%\item \meta{standalone month names block} +% +%The month names when used in a standalone context (for example, a +%column header). This may be the same as the earlier \meta{month +%names block} (and will be the same for \file{texosquery.jar} and +%\file{texosquery-jre5.jar}). The standalone support was +%introduced to Java~8. +% +%\item \meta{abbreviated standalone month names block} +% +%As above but abbreviated. +% +%\item \meta{numeric block} +% +%The numeric data similar to \longarg{numeric} but it's +%missing the \meta{tag} (which is provided in the earlier +%\meta{locale block}) and there are two extra items: +%\begin{definition} +%\marg{group sep}\marg{decimal sep}\marg{exp +%sep}\marg{use group}\marg{currency code}\marg{regional currency +%code}\marg{currency sym}\marg{currency tex}\marg{currency sep} +%\marg{percent sym}\marg{per mill sym} +%\end{definition} +%See above for the elements that are also provided in +%\longarg{numeric}. The additional elements are \meta{percent sym} +%and \meta{per mill sym}, which are the percent and +%per-mill symbols, respectively. The percent symbol \verb|%| has its +%category code changed to 12 by \cs{TeXOSQuery}. As with other +%non-ASCII characters, the per-mill symbol will be marked up with +%\cs{twrp}. +% +%\item \meta{numeric patterns block} +% +%The patterns used to format decimals, integers, currency and +%percentages. +%\begin{definition} +%\marg{decimal pattern}\marg{integer pattern}\marg{currency +%pattern}\marg{percentages pattern} +%\end{definition} +%As with the date and time patterns, when used with \cs{TeXOSQuery}, the +%short commands, such as \cs{patdgt}, are internally converted. +%They're not defined outside that scope. +% +%If a pattern is used directly in the text, it will expand to the +%original pattern padded to ten digits. (Eleven digit integers are outside +%\TeX's maximum number range.) +% +%Any of these numeric patterns may be used in the first argument of +%the low-level user command \cs{texosqueryfmtnumber} described in +%section~\ref{sec:applynumpatterns}. This command uses the following +%macros: +%\begin{definition} +%\cs{texosquerypatfmtcurrencysign} +%\end{definition} +%The currency sign (defaults to \verb|\$|). For example, when parsing the previous +%\meta{numeric block}, this command can be redefined to the \marg{currency sym} or +%\marg{currency tex} elements. +% +%\begin{definition} +%\cs{texosquerypatfmtgroupsep} +%\end{definition} +%The group separator (defaults to \verb|,|). For example, when parsing the previous +%\meta{numeric block}, this command can be redefined to the +%\marg{group sep} element. +% +%\begin{definition} +%\cs{texosquerypatfmtdecsep} +%\end{definition} +%The decimal separator (defaults to \verb|.|). For example, when parsing the previous +%\meta{numeric block}, this command can be redefined to the +%\marg{dec sep} element. +% +%\begin{definition} +%\cs{texosquerypatfmtcurdecsep} +%\end{definition} +%The monetary decimal separator (defaults to \verb|.|). For example, when parsing the previous +%\meta{numeric block}, this command can be redefined to the +%\marg{currency sep} element. +% +%\begin{definition} +%\cs{texosquerypatfmtexp} +%\end{definition} +%The exponent sign (defaults to \texttt{E}). For example, when parsing the previous +%\meta{numeric block}, this command can be redefined to the +%\marg{exp sep} element. +% +%\begin{definition} +%\cs{texosquerypatfmtpercentsign} +%\end{definition} +%The percent symbol. For example, when parsing the previous +%\meta{numeric block}, this command can be redefined to the +%\marg{percent sym} element. +% +%\begin{definition} +%\cs{texosquerypatfmtpermillsign} +%\end{definition} +%The per-mill symbol. For example, when parsing the previous +%\meta{numeric block}, this command can be redefined to the +%\marg{per-mill sym} element. +% +%\begin{definition} +%\cs{texosquerypatfmticurrencysign} +%\end{definition} +%The international currency sign. This is defined as \texttt{¤} by +%default, unless the command \cs{textcurrency} has been defined, in +%which case that's used instead. If the UTF-8 character ¤ is +%available and \cs{textcurrency} hasn't been defined before +%\sty{texosquery} was input, then you will need to redefine this +%command as appropriate. +% +%\begin{definition} +%\cs{texosquerypatfmtminus} +%\end{definition} +%The minus sign. +% +%\begin{definition} +%\cs{texosquerypatfmtplus} +%\end{definition} +%The plus sign. +% +%\end{description} % %\section{texosquery.tex: generic \TeX\ code} -%You can run \texttt{texosquery} directly from \TeX's shell escape. +%\label{sec:tex} +%You can run \app{texosquery} directly from \TeX's shell escape. %For example: %\begin{verbatim} %\input|"texosquery --locale" %\end{verbatim} -%However, \texttt{texosquery.tex} provides generic \TeX\ code to do -%this for you and store the result in a control sequence. +%However, \app{texosquery} uses markup commands in some of +%the results which need to be defined first. The file +%\file{texosquery.tex} provides generic \TeX\ code to do +%this for you and stores the result in a control sequence. % %Plain \TeX\ users can input this file through the usual \cs{input} %method: @@ -281,58 +1740,74 @@ %The commands described below are all fragile. %\end{important} % -%The basic command to run \texttt{texosquery} and capture its output +%The basic command to run \app{texosquery} and capture its output %in a control sequence is: %\DescribeMacro\TeXOSQuery -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQuery}\marg{cs}\marg{args} -%\end{flushleft} +%\end{definition} %where \meta{cs} is the control sequence in which to store the %result and \meta{args} are the command line arguments to pass to -%\texttt{texosquery}. This first locally changes the category code -%of some problematic characters that may appear in the result. -%The only special characters that aren't changed are the backslash -%\verb|\|, curly braces \verb|{| and \verb|}|, and hash \verb|#|. -%(\texttt{texosquery.jar} will replace \verb|#| with \verb|\#| in places -%where it might possibly occur in the result, but in general it's -%best to avoid these characters in file names.) -% -%There are some short cut commands for convenience, described below. -%If any of these commands cause an error message in the form: +%\app{texosquery}. This first locally changes the category code +%of some problematic characters and defines the short markup +%commands that \app{texosquery} uses to identify characters that +%need to be interpreted literally (for example, in file names). +%These commands will automatically be expanded by \cs{TeXOSQuery} +%when the result is input. For example %\begin{verbatim} -%I can't find file `|texosquery'. +%texosquery -n %\end{verbatim} -%then check that you have the shell escape on. If the error -%persists with the shell escape enabled -%(and not restricted), check that \texttt{texosquery} is on -%your system's path. To do this, open a command prompt or terminal and -%type \texttt{texosquery}. If it isn't installed correctly, there will be a -%message like: +%produces %\begin{verbatim} -%`texosquery' is not recognised +%\pdfd \fcln 20161129221559\fpls 00\fapo 00\fapo %\end{verbatim} -%or +%but when used with %\begin{verbatim} -%texosquery: command not found +%\TeXOSQuery{\result}{texosquery -n} %\end{verbatim} -%If this happens, check the installation. (Instructions are -%in the accompanying \texttt{README.md} file.) +%the \cs{result} command will be set to +%\begin{verbatim} +%D:20161129221559+00'00' +%\end{verbatim} +%where the characters \texttt{D} \text{:} \texttt{+} and +%\texttt{\textquotesingle} all have category code 12 (other). % -%Dry run mode is determined by the conditional -%\DescribeMacro\ifTeXOSQueryDryRun +%If the command failed, \meta{cs} will be set to empty. It's best to +%always test for success after using \cs{TeXOSQuery} (or one of the +%shortcut commands described below). For example: %\begin{verbatim} -%\ifTeXOSQueryDryRun +%\TeXOSQuery{\result}{-b} +%\ifx\result\empty +% Failed! +%\else +% Result: \result. +%\fi %\end{verbatim} -%If true, the shell escape won't be used and the requested command -%invocation will be printed in the transcript file prefixed with +% +%Failure can occur because the dry run mode was on, or it can occur +%if the query was denied (for example, forbidden file access), +%or if there's a syntax error in the system call. As from +%version 1.2, \app{texosquery} checks the \texttt{openin\_any} +%setting, which may forbid read access. Java's security manager +%or the filing system may also forbid read access. +% +%To determine the cause of the error, first inspect the log file to +%check if the shell escape was used. In the above example, if +%the shell escape was permitted, then the log file should include %\begin{verbatim} -%TeXOSQuery: +%(|texosquery -b) %\end{verbatim} -%(the control sequence \meta{cs} will be set to empty). -%This conditional will automatically be switched on unless -%\cs{shellescape} or \cs{pdfshellescape} is 1. (If -%\texttt{texosquery.jar} is later allowed on the restricted list, -%newer versions may change this default.) +%Copy and paste the system call (\verb|texosquery -b| in +%the above case) into your +%\href{http://www.dickimaw-books.com/latex/novices/html/terminal.html}{command +%prompt or terminal} and insert +%the \longarg{debug} switch at the start of the argument list. For +%example: +%\begin{verbatim} +%texosquery --debug -b +%\end{verbatim} +%This should help determine whether it's a syntax error or a query forbidden +%by the operating system. % %If multiple queries are required, it's more efficient to %perform them all in one go. For example: @@ -351,118 +1826,297 @@ %\end{verbatim} %(Make sure you have at least v1.1 for this to work correctly.) % +%\begin{important} +%Take care of characters that have a special meaning to your shell. +%For example, bash interprets \verb|#| as a comment. For example, if +%you have a file called \texttt{image\#1.png}, then you can't simply +%do +%\begin{verbatim} +%\TeXOSQuery{\result}{-p image#1.png} +%\end{verbatim} +%since bash will pass this as +%\begin{verbatim} +%texosquery.sh -p image +%\end{verbatim} +%(The \verb|#1.png| part is treated as a comment.) Nor can you do +%\begin{verbatim} +%\TeXOSQuery{\result}{-p image\#1.png} +%\end{verbatim} +%as \TeX\ will replace the \verb|\#| with \verb|#| when passing the +%command invocation to the shell. The only way to deal with this +%situation is to do +%\begin{verbatim} +%\TeXOSQuery{\result}{-p image\string\#1.png} +%\end{verbatim} +%to protect the \verb|#| character from both \TeX\ and the shell. +%\end{important} +% +%Dry run mode is determined by the conditional +%\DescribeMacro\ifTeXOSQueryDryRun +%\begin{verbatim} +%\ifTeXOSQueryDryRun +%\end{verbatim} +%If true, the shell escape won't be used and the requested command +%invocation will be printed in the transcript file prefixed with +%\begin{verbatim} +%TeXOSQuery: +%\end{verbatim} +%(the control sequence \meta{cs} will be set to empty). +% +%\begin{important} +%Remember that a query can still fail even if the dry run mode is +%off. +%\end{important} +% +%Note that if you switch off the dry run mode when the +%shell escape setting forbids the execution of \app{texosquery}, +%then you'll get the rather annoying error: +%\begin{verbatim} +%runpopen command not allowed: texosquery +% +%! I can't find file `"|texosquery -b"'. +%\TeXOSQueryInvoker ...TeXOSInvokerName \space #1" +% +%\TeXOSQuery ...noexpand #1{\TeXOSQueryInvoker {#2} +% }}\x \fi +%l.5 \TeXOSQuery{\result}{-b} +% ^^M +%(Press Enter to retry, or Control-D to exit) +%\end{verbatim} +%By default, the dry run mode is only switched off if the +%unrestricted shell escape mode is on (detected through +%\cs{shellescape} or \cs{pdfshellescape}). +% +%If \app{texosquery} is added to the restricted list, you can add +%\begin{verbatim} +%\TeXOSQueryAllowRestricted +%\end{verbatim} +%to the \file{texosquery.cfg} file. (This command can't be used +%outside of that file.) +% +%If you get the above error, then: +%\begin{itemize} +%\item make sure you don't have +%\cs{TeXOSQueryAllowRestricted} in your \file{texosquery.cfg} +%file; +%\item make sure you run \TeX\ with the shell escape enabled; +%\item check the definition of \cs{TeXOSInvokerName}; +%\item try using the application directly from the command prompt or +%terminal. For example, in the above message, the bit between +%\texttt{\textasciigrave\textquotedbl\textbar} and +%\texttt{\textquotedbl\textquotesingle} (that is, \texttt{texosquery-jre8 -b}) +%shows the attempted system call. Copy and paste it directly +%into your operating system's +%\href{http://www.dickimaw-books.com/latex/novices/html/terminal.html}{command +%prompt or terminal} and to check the application has been installed +%correctly. +%\end{itemize} +% +%\DescribeMacro\TeXOSInvokerName +%The \cs{TeXOSQuery} command uses \cs{TeXOSInvokerName} to reference the +%application name. This defaults to \app{texosquery} but needs to be +%redefined to reflect the particular system call that's required. +%For example, \texttt{texosquery.sh} (Unix-like with Java~7) or +%\texttt{texosquery-jre8} (Windows with Java~8). This redefinition +%can be done in the configuration file \file{texosquery.cfg} for a +%system-wide setting. See section~\ref{sec:setup} for further +%details. +% +%\begin{important} +%Some of the shortcut commands listed below require extra arguments after the +%relevant switch. These are automatically enclosed in single-quotes +%to protect any spaces. If the argument actually contains any single-quote +%characters, make sure you use \verb|\string\'| to prevent +%interference. +% +%Since a file name reference may need to be obtained from \cs{jobname}, +%which sometimes includes double-quotes, the first double-quote pair +%found is stripped in file name arguments. Any other double-quotes +%will need to be protected in the same manner as single-quotes +%(but this shouldn't be an issue if you use a safe file naming scheme). +%All paths should use a forward slash for the directory divider. +%\end{important} +% +%\subsection{Locale} %The locale (\shortarg{l} or \longarg{locale-lcs}) information can be %obtained using: %\DescribeMacro\TeXOSQueryLocale -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQueryLocale}\marg{cs} -%\end{flushleft} +%\end{definition} %Note that this uses the lower case codeset form, which has a better -%chance of matching the encoding names used by the \texttt{inputenc} +%chance of matching the encoding names used by the \sty{inputenc} %package. If you want the unprocessed codeset name, you can do: -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQuery}\marg{cs}\{\shortarg{L}\} -%\end{flushleft} +%\end{definition} +%If you just want the codeset in the same form as +%\longarg{locale-lcs} you can do: +%\begin{definition} +%\cs{TeXOSQuery}\marg{cs}\{\shortarg{C}\} +%\end{definition} % -%The current working directory (\shortarg{c} or \longarg{cwd}) can -%be obtained using: -%\DescribeMacro\TeXOSQueryCwd -%\begin{flushleft}\ttfamily -%\cs{TeXOSQueryCwd}\marg{cs} -%\end{flushleft} +%The \gls{IETF} \gls{BCP}~47 language tag (\shortarg{b} or \longarg{bcp47}) +%can be obtained using: +%\DescribeMacro\TeXOSQueryLangTag +%\begin{definition} +%\cs{TeXOSQueryLangTag}\marg{cs} +%\end{definition} % -%The home directory (\shortarg{m} or \longarg{userhome}) can -%be obtained using: -%\DescribeMacro\TeXOSQueryHome -%\begin{flushleft}\ttfamily -%\cs{TeXOSQueryHome}\marg{cs} -%\end{flushleft} +%The numeric separators and currency symbols (\shortarg{N} or +%\longarg{numeric}) can be obtained using +%\DescribeMacro\TeXOSQueryNumeric +%\begin{definition} +%\cs{TeXOSQueryNumeric}\marg{cs}\marg{locale} +%\end{definition} +%The \meta{locale} should be a valid language tag or may be empty +%for the system's default locale. Similarly for the command below. % -%The temporary directory (\shortarg{t} or \longarg{tmpdir}) can -%be obtained using: -%\DescribeMacro\TeXOSQueryTmpDir -%\begin{flushleft}\ttfamily -%\cs{TeXOSQueryTmpDir}\marg{cs} -%\end{flushleft} +%All the locale data (\shortarg{D} or \longarg{locale-data}) can be +%obtained using +%\DescribeMacro\TeXOSQueryLocaleData +%\begin{definition} +%\cs{TeXOSQueryLocaleData}\marg{cs}\marg{locale} +%\end{definition} % +%\subsection{Operating System Information} %The OS name (\shortarg{o} or \longarg{osname}) can %be obtained using: %\DescribeMacro\TeXOSQueryName -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQueryName}\marg{cs} -%\end{flushleft} +%\end{definition} % %The OS version (\shortarg{r} or \longarg{osversion}) can %be obtained using: %\DescribeMacro\TeXOSQueryVersion -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQueryVersion}\marg{cs} -%\end{flushleft} +%\end{definition} % %The OS architecture (\shortarg{a} or \longarg{osarch}) can %be obtained using: %\DescribeMacro\TeXOSQueryArch -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQueryArch}\marg{cs} -%\end{flushleft} +%\end{definition} +% +%\subsection{Dates and Times} +%The current date and time information (\shortarg{M} or +%\longarg{date-time}) can be obtained using: +%\DescribeMacro\TeXOSQueryDateTime +%\begin{definition} +%\cs{TeXOSQueryDateTime}\marg{cs} +%\end{definition} +%Example usage: +%\begin{verbatim} +%\texosquerydefpattern{\pattern}{\%2d/\%2M/\%4y \%2H:\%2m:\%2s} +% +%\TeXOSQueryDateTime{\datetimedata} +% +%\ifx\datetimedata\empty +% Query Failed! +%\else +% \expandafter\texosqueryfmtdatetime\expandafter\pattern\datetimedata +%\fi +%\end{verbatim} +%Note that commands such as \cs{texosqueryfmtpatMMM} will need to be +%defined to produce textual elements. See +%sections~\ref{sec:patternformats} and \ref{sec:applydatetimepatterns} for +%further details. +% +%The time zone mappings (\shortarg{Z} or +%\longarg{time-zones}) can be obtained using: +%\DescribeMacro\TeXOSQueryTimeZones +%\begin{definition} +%\cs{TeXOSQueryTimeZones}\marg{cs}\marg{locale} +%\end{definition} +%Leave \meta{locale} empty if the default locale is required. % %The current date-time stamp in PDF format (\shortarg{n} or %\longarg{pdfnow}) can be obtained using: %\DescribeMacro\TeXOSQueryNow -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQueryNow}\marg{cs} -%\end{flushleft} +%\end{definition} %This is provided for the benefit of users who don't have %\cs{pdfcreationdate} defined by their \TeX\ format (for example, -%\XeTeX). As from v1.1, this ensures that the initial \texttt{D} has -%category code 12 (which won't happen if \cs{TeXOSQuery} is used -%explicitly). -% -%\begin{important} -%The remaining commands all require extra arguments after the -%relevant switch. These are automatically enclosed in single-quotes -%to protect any spaces. If the argument actually contains any single-quote -%characters, make sure you use \verb|\string\'| to prevent -%interference. \emph{However, in general it's a very bad idea to use -%quotes as part of a file name (rather than using them as -%delimiters).} -%Since the file name may need to be obtained from \cs{jobname}, -%which sometimes includes double-quotes, the first double-quote pair -%found is stripped in file name arguments. Any other double-quotes -%will need to be protected in the same manner as single-quotes -%(but, again, this shouldn't be an issue if you use a safe -%file naming scheme). Any paths should use a -%forward slash for the directory divider. -%\end{important} +%\XeTeX). % %The modification date-time stamp in PDF format for a file %(\shortarg{d} or \longarg{pdfdate}) can be obtained using: %\DescribeMacro\TeXOSQueryFileDate -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQueryFileDate}\marg{cs}\marg{filename} -%\end{flushleft} +%\end{definition} %where \meta{filename} is the name of the file. %This is provided for the benefit of users who don't have -%\cs{pdffilemoddate} defined by their \TeX\ format. As from v1.1, -%this ensures that the initial \texttt{D} has category code 12 (which -%won't happen if \cs{TeXOSQuery} is used explicitly). +%\cs{pdffilemoddate} defined by their \TeX\ format. +% +%\subsection{File Operations} +%The current working directory (\shortarg{c} or \longarg{cwd}) can +%be obtained using: +%\DescribeMacro\TeXOSQueryCwd +%\begin{definition} +%\cs{TeXOSQueryCwd}\marg{cs} +%\end{definition} +% +%The home directory (\shortarg{m} or \longarg{userhome}) can +%be obtained using: +%\DescribeMacro\TeXOSQueryHome +%\begin{definition} +%\cs{TeXOSQueryHome}\marg{cs} +%\end{definition} +% +%The temporary directory (\shortarg{t} or \longarg{tmpdir}) can +%be obtained using: +%\DescribeMacro\TeXOSQueryTmpDir +%\begin{definition} +%\cs{TeXOSQueryTmpDir}\marg{cs} +%\end{definition} % %The size in bytes of a file %(\shortarg{s} or \longarg{filesize}) can be obtained using: %\DescribeMacro\TeXOSQueryFileSize -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQueryFileSize}\marg{cs}\marg{filename} -%\end{flushleft} +%\end{definition} %where \meta{filename} is the name of the file. %This is provided for the benefit of users who don't have %\cs{pdffilesize} defined by their \TeX\ format. % +%The URI of a file +%(\shortarg{u} or \longarg{uri}) can be obtained using: +%\DescribeMacro\TeXOSQueryFileURI +%\begin{definition} +%\cs{TeXOSQueryFileURI}\marg{cs}\marg{filename} +%\end{definition} +%where \meta{filename} is the name of the file. +%(Any percent symbols \verb|%| contained in the URI will have +%their category code set to 12.) +% +%The canonical path of a file +%(\shortarg{p} or \longarg{path}) can be obtained using: +%\DescribeMacro\TeXOSQueryFilePath +%\begin{definition} +%\cs{TeXOSQueryFilePath}\marg{cs}\marg{filename} +%\end{definition} +%where \meta{filename} is the name of the file. +% +%The canonical path of a file's parent +%(\shortarg{e} or \longarg{dirname}) can be obtained using: +%\DescribeMacro\TeXOSQueryDirName +%\begin{definition} +%\cs{TeXOSQueryDirName}\marg{cs}\marg{filename} +%\end{definition} +%where \meta{filename} is the name of the file. +% %The list of files in a given directory %(\shortarg{i} or \longarg{list}) can be obtained using: %\DescribeMacro\TeXOSQueryFileList -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQueryFileList}\marg{cs}\marg{sep}\marg{dir} -%\end{flushleft} +%\end{definition} %where \meta{sep} is the separator and \meta{dir} is the directory name. %For example: %\begin{verbatim} @@ -471,12 +2125,23 @@ %will store a comma-separated list of all the files contained in the %current directory in the control sequence \cs{result}. % +%To omit directories (\shortarg{ir} or \longarg{list-regular}): +%\DescribeMacro\TeXOSQueryRegularFileList +%\begin{definition} +%\cs{TeXOSQueryRegularFileList}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%To omit regular files (\shortarg{id} or \longarg{list-dir}): +%\DescribeMacro\TeXOSQuerySubDirFileList +%\begin{definition} +%\cs{TeXOSQuerySubDirList}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +% %A filtered list of files in a given directory %(\shortarg{f} or \longarg{filterlist}) can be obtained using: %\DescribeMacro\TeXOSQueryFilterFileList -%\begin{flushleft}\ttfamily +%\begin{definition} %\cs{TeXOSQueryFilterFileList}\marg{cs}\marg{sep}\marg{regex}\marg{dir} -%\end{flushleft} +%\end{definition} %where \meta{regex} is a regular expression. \emph{Take care of any backslashes %in the regular expression!} %For example, to list only those files that have an extension: @@ -484,42 +2149,406 @@ %\TeXOSQueryFilterFileList{\result}{,}{.+\string\..*}{.} %\end{verbatim} %Note the use of \verb|\string\.| to ensure that \cs{.} isn't -%interpreted as a command. Another example, list only \texttt{.png} -%and \texttt{.jpg} files in the directory called \texttt{images}: +%interpreted as a command. Another example, list only \file{.png} +%and \file{.jpg} files in the directory called \file{images}: %\begin{verbatim} %\TeXOSQueryFilterFileList{\result}{,}{.+\string\.(jpg|png)}{images} %\end{verbatim} % -%The URI of a file -%(\shortarg{u} or \longarg{uri}) can be obtained using: -%\DescribeMacro\TeXOSQueryFileURI -%\begin{flushleft}\ttfamily -%\cs{TeXOSQueryFileURI}\marg{cs}\marg{filename} -%\end{flushleft} -%where \meta{filename} is the name of the file. -%(Any percent symbols \verb|%| contained in the URI will have -%their category code set to 12.) +%\begin{important} +%Unlike most of the return values the \meta{sep} part here isn't +%escaped, so take care if \meta{sep} contains any commands. For +%example, if you want to use \verb|\\| as the separator, you'll need +%to use \verb|\string\noexpand\string\\| in the \meta{sep} part. +%\begin{verbatim} +%\TeXOSQueryFilterFileList{\result}{\string\noexpand\string\\}{.*\string\.tex}{.} +%\end{verbatim} +%\end{important} % -%The canonical path of a file -%(\shortarg{p} or \longarg{path}) can be obtained using: -%\DescribeMacro\TeXOSQueryFilePath -%\begin{flushleft}\ttfamily -%\cs{TeXOSQueryFilePath}\marg{cs}\marg{filename} -%\end{flushleft} -%where \meta{filename} is the name of the file. +%If you want the list sorted, you can use the following which set +%the optional \meta{sort} argument. % -%The canonical path of a file's parent -%(\shortarg{e} or \longarg{dirname}) can be obtained using: -%\DescribeMacro\TeXOSQueryDirName -%\begin{flushleft}\ttfamily -%\cs{TeXOSQueryDirName}\marg{cs}\marg{filename} -%\end{flushleft} -%where \meta{filename} is the name of the file. +%Order by last modified date starting with the oldest (\texttt{date-ascending}): +%\DescribeMacro\TeXOSQueryFileListDateAsc +%\begin{definition} +%\cs{TeXOSQueryFileListDateAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListDateAsc +%\begin{definition} +%\cs{TeXOSQueryRegularFileListDateAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListDateAsc +%\begin{definition} +%\cs{TeXOSQuerySubDirListDateAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListDateAsc +%\begin{definition} +%\cs{TeXOSQueryFilterFileListDateAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or for the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListDateAsc +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListDateAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or for the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListDateAsc +%\begin{definition} +%\cs{TeXOSQueryFilterSubDirListDateAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%Order by last modified date starting with the newest (\texttt{date-descending}): +%\DescribeMacro\TeXOSQueryFileListDateDes +%\begin{definition} +%\cs{TeXOSQueryFileListDateDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListDateDes +%\begin{definition} +%\cs{TeXOSQueryRegularFileListDateDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListDateDes +%\begin{definition} +%\cs{TeXOSQuerySubDirListDateDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListDateDes +%\begin{definition} +%\cs{TeXOSQueryFilterFileListDateDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListDateDes +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListDateDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListDateDes +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListDateDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%Order by file size starting with the smallest (\texttt{size-ascending}): +%\DescribeMacro\TeXOSQueryFileListSizeAsc +%\begin{definition} +%\cs{TeXOSQueryFileListSizeAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListSizeAsc +%\begin{definition} +%\cs{TeXOSQueryRegularFileListSizeAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListSizeAsc +%\begin{definition} +%\cs{TeXOSQuerySubDirListSizeAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListSizeAsc +%\begin{definition} +%\cs{TeXOSQueryFilterFileListSizeAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListSizeAsc +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListSizeAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListSizeAsc +%\begin{definition} +%\cs{TeXOSQueryFilterSubDirListSizeAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%Order by file size starting with the largest (\texttt{size-descending}): +%\DescribeMacro\TeXOSQueryFileListSizeDes +%\begin{definition} +%\cs{TeXOSQueryFileListSizeDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListSizeDes +%\begin{definition} +%\cs{TeXOSQueryRegularFileListSizeDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListSizeDes +%\begin{definition} +%\cs{TeXOSQuerySubDirListSizeDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListSizeDes +%\begin{definition} +%\cs{TeXOSQueryFilterFileListSizeDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListSizeDes +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListSizeDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListSizeDes +%\begin{definition} +%\cs{TeXOSQueryFilterSubDirListSizeDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +% +%Order by file name in alphabetical order (\texttt{name-ascending}): +%\DescribeMacro\TeXOSQueryFileListNameAsc +%\begin{definition} +%\cs{TeXOSQueryFileListNameAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListNameAsc +%\begin{definition} +%\cs{TeXOSQueryRegularFileListNameAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListNameAsc +%\begin{definition} +%\cs{TeXOSQuerySubDirListNameAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListNameAsc +%\begin{definition} +%\cs{TeXOSQueryFilterFileListNameAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListNameAsc +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListNameAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListNameAsc +%\begin{definition} +%\cs{TeXOSQueryFilterSubDirListNameAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%Order by file name in reverse alphabetical order (\texttt{name-descending}): +%\DescribeMacro\TeXOSQueryFileListNameDes +%\begin{definition} +%\cs{TeXOSQueryFileListNameDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListNameDes +%\begin{definition} +%\cs{TeXOSQueryRegularFileListNameDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListNameDes +%\begin{definition} +%\cs{TeXOSQuerySubDirListNameDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListNameDes +%\begin{definition} +%\cs{TeXOSQueryFilterFileListNameDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListNameDes +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListNameDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListNameDes +%\begin{definition} +%\cs{TeXOSQueryFilterSubDirListNameDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +% +%Order by file name in case-insensitive alphabetical order +%(\texttt{iname-ascending}): +%\DescribeMacro\TeXOSQueryFileListNameIgnoreCaseAsc +%\begin{definition} +%\cs{TeXOSQueryFileListNameIgnoreCaseAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListNameIgnoreCaseAsc +%\begin{definition} +%\cs{TeXOSQueryRegularFileListNameIgnoreCaseAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListNameIgnoreCaseAsc +%\begin{definition} +%\cs{TeXOSQuerySubDirListNameIgnoreCaseAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListNameIgnoreCaseAsc +%\begin{definition} +%\cs{TeXOSQueryFilterFileListNameIgnoreCaseAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListNameIgnoreCaseAsc +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListNameIgnoreCaseAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListNameIgnoreCaseAsc +%\begin{definition} +%\cs{TeXOSQueryFilterSubDirListNameIgnoreCaseAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%Order by file name in reverse case-insensitive alphabetical order +%(\texttt{iname-descending}): +%\DescribeMacro\TeXOSQueryFileListNameIgnoreCaseDes +%\begin{definition} +%\cs{TeXOSQueryFileListNameIgnoreCaseDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListNameIgnoreCaseDes +%\begin{definition} +%\cs{TeXOSQueryRegularFileListNameIgnoreCaseDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListNameIgnoreCaseDes +%\begin{definition} +%\cs{TeXOSQuerySubDirListNameIgnoreCaseDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListNameIgnoreCaseDes +%\begin{definition} +%\cs{TeXOSQueryFilterFileListNameIgnoreCaseDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListNameIgnoreCaseDes +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListNameIgnoreCaseDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListNameIgnoreCaseDes +%\begin{definition} +%\cs{TeXOSQueryFilterSubDirListNameIgnoreCaseDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%Order by file extension in alphabetical order (\texttt{ext-ascending}): +%\DescribeMacro\TeXOSQueryFileListExtAsc +%\begin{definition} +%\cs{TeXOSQueryFileListExtAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListExtAsc +%\begin{definition} +%\cs{TeXOSQueryRegularFileListExtAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListExtAsc +%\begin{definition} +%\cs{TeXOSQuerySubDirListExtAsc}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListExtAsc +%\begin{definition} +%\cs{TeXOSQueryFilterFileListExtAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListExtAsc +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListExtAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListExtAsc +%\begin{definition} +%\cs{TeXOSQueryFilterSubDirListExtAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%Order by file extension in reverse alphabetical order (\texttt{ext-descending}): +%\DescribeMacro\TeXOSQueryFileListExtDes +%\begin{definition} +%\cs{TeXOSQueryFileListExtDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the regular files only list: +%\DescribeMacro\TeXOSQueryRegularFileListExtDes +%\begin{definition} +%\cs{TeXOSQueryRegularFileListExtDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or the sub-directories only list: +%\DescribeMacro\TeXOSQuerySubDirListExtDes +%\begin{definition} +%\cs{TeXOSQuerySubDirListExtDes}\marg{cs}\marg{sep}\marg{dir} +%\end{definition} +%or for the filtered list: +%\DescribeMacro\TeXOSQueryFilterFileListExtDes +%\begin{definition} +%\cs{TeXOSQueryFilterFileListExtDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered regular files only list: +%\DescribeMacro\TeXOSQueryFilterRegularFileListExtDes +%\begin{definition} +%\cs{TeXOSQueryFilterRegularFileListExtDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or the filtered sub-directories only list: +%\DescribeMacro\TeXOSQueryFilterSubDirListExtDes +%\begin{definition} +%\cs{TeXOSQueryFilterSubDirListExtDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%A recursive filtered list of regular files starting from a given directory +%on the current working path +%(\shortarg{w} or \longarg{alk}) can be obtained using: +%\DescribeMacro\TeXOSQueryWalk +%\begin{definition} +%\cs{TeXOSQueryWalk}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%where \meta{regex} is as for the filtered listings described above. +% +%To sort according to last modified date: +%\DescribeMacro\TeXOSQueryWalkDateAsc +%\begin{definition} +%\cs{TeXOSQueryWalkDateAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or in reverse order: +%\DescribeMacro\TeXOSQueryWalkDateDes +%\begin{definition} +%\cs{TeXOSQueryWalkDateDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%To sort according to file size: +%\DescribeMacro\TeXOSQueryWalkSizeAsc +%\begin{definition} +%\cs{TeXOSQueryWalkSizeAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or in reverse order: +%\DescribeMacro\TeXOSQueryWalkSizeDes +%\begin{definition} +%\cs{TeXOSQueryWalkSizeDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} % -%\StopEventually{\phantomsection +%To sort according to path name (case-sensitive): +%\DescribeMacro\TeXOSQueryWalkNameAsc +%\begin{definition} +%\cs{TeXOSQueryWalkNameAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or in reverse order: +%\DescribeMacro\TeXOSQueryWalkNameDes +%\begin{definition} +%\cs{TeXOSQueryWalkNameDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%To sort according to path name (case-insensitive): +%\DescribeMacro\TeXOSQueryWalkNameIgnoreCaseAsc +%\begin{definition} +%\cs{TeXOSQueryWalkNameIgnoreCaseAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or in reverse order: +%\DescribeMacro\TeXOSQueryWalkNameIgnoreCaseDes +%\begin{definition} +%\cs{TeXOSQueryWalkNameIgnoreCaseDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%To sort according to file extension: +%\DescribeMacro\TeXOSQueryWalkExtAsc +%\begin{definition} +%\cs{TeXOSQueryWalkExtAsc}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +%or in reverse order: +%\DescribeMacro\TeXOSQueryWalkExtDes +%\begin{definition} +%\cs{TeXOSQueryWalkExtDes}\marg{cs}\marg{sep}\marg{regex}\marg{dir} +%\end{definition} +% +%\setcounter{secnumdepth}{3} +%\StopEventually{\clearpage\printabbreviations +%\clearpage\phantomsection %\addcontentsline{toc}{section}{Change History}% %\PrintChanges -%\addcontentsline{toc}{section}{\indexname}% %\PrintIndex %} % @@ -544,14 +2573,91 @@ % \end{macrocode} % Check if already loaded. % \begin{macrocode} -\ifx\TeXOSQuery\undefined -\else +\ifx\TeXOSQuery\undefined \else \@texosquery@restore@at \expandafter\endinput \fi % \end{macrocode} +% Version info. +% \begin{macrocode} +\expandafter\def\csname ver@texosquery.tex\endcsname{2017/03/23 v1.2 (NLCT)} +% \end{macrocode} +% +%\begin{macro}{\@texosquery@warn} +%\changes{1.2}{2017-03-23}{added check for tracklang's warning command} +%Generate warning message. Use \sty{tracklang}'s warning if +%available (so that the warnings can be disabled for both packages +%at the same time). +% \begin{macrocode} +\ifx\@tracklang@pkgwarn\undefined + \ifx\PackageWarning\undefined + \def\@texosquery@warn#1{% + {% + \newlinechar=`\^^J + \def\MessageBreak{^^J}% + \message{^^Jtexosquery Warning: #1 on line \the\inputlineno.^^J}% + }% + } + \else + \def\@texosquery@warn#1{% + \PackageWarning{texosquery}{#1}% + } + \fi +\else + \def\@texosquery@warn#1{% + \@tracklang@pkgwarn{texosquery}{#1}% + } +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@err} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\PackageError\undefined + \def\@texosquery@err#1#2{% + \errhelp{#2}% + \errmessage{texosquery: #1}} +\else + \def\@texosquery@err#1#2{\PackageError{texosquery}{#1}{#2}} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@ifundef} +%This is defined in the same way as \sty{tracklang}'s +%\cs{@tracklang@ifundef}. (Can't assume \sty{tracklang} has been +%loaded.) +% \begin{macrocode} +\long\def\@texosquery@ifundef#1#2#3{% + \ifcsname#1\endcsname + \expandafter\ifx\csname #1\endcsname\relax + #2% + \else + #3% + \fi + \else + \expandafter\ifx\csname #1\endcsname\relax + #2% + \else + #3% + \fi + \fi +} +\ifx\ifcsname\undefined + \long\def\@texosquery@ifundef#1#2#3{% + \expandafter\ifx\csname #1\endcsname\relax + #2% + \else + #3% + \fi + } +\fi +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\TeXOSInvokerName} -%The name of the \texttt{texosquery} application. +%The name of the \app{texosquery} application. % \begin{macrocode} \def\TeXOSInvokerName{texosquery} % \end{macrocode} @@ -571,32 +2677,899 @@ % %\begin{macro}{\ifTeXOSQueryDryRun} %Provide a dry-run mode. -%\changes{1.1}{2016-07-14}{dry run mode only false by default if with -%unrestricted mode} +%\changes{1.1}{2016-07-14}{dry run mode only false by default if +%used in unrestricted mode} +% \begin{macrocode} +\newif\ifTeXOSQueryDryRun \TeXOSQueryDryRuntrue +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryAllowRestricted} +%\changes{1.2}{2017-03-23}{new} +%The default behaviour only switches off the dry-run mode if the +%shell escape is unrestricted. The configuration file may override +%this with \cs{TeXOSQueryAllowRestricted}, which will allow +%the dry run mode to be switched off if restricted mode is detected. +% \begin{macrocode} +\def\TeXOSQueryAllowRestricted{% + \def\@texosquery@allowrestricted##1##2{##1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryDenyRestricted} +%\changes{1.2}{2017-03-23}{new} +%Switch it off. +% \begin{macrocode} +\def\TeXOSQueryDenyRestricted{% + \def\@texosquery@allowrestricted##1##2{##2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@allowrestricted} +%\changes{1.2}{2017-03-23}{new} +%Initialise to prevent shell escape in restricted mode. % \begin{macrocode} -\newif\ifTeXOSQueryDryRun -\TeXOSQueryDryRuntrue +\def\@texosquery@allowrestricted#1#2{#2}% % \end{macrocode} %\end{macro} % -%If shell escape is unrestricted, automatically switch off dry-run mode. +%Load the configuration file if it exists. +%\changes{1.2}{2017-03-23}{added texosquery.cfg} +% \begin{macrocode} +\openin0=texosquery.cfg \ifeof0\relax \else + \closein0\relax + \begingroup + \newlinechar=`\^^J + \message{^^JTeXOSQuery: reading configuration file^^J}% + \endgroup + \input texosquery.cfg +\fi +% \end{macrocode} +%Disable cfg-only commands: +% \begin{macrocode} +\def\TeXOSQueryAllowRestricted{% + \@texosquery@warn{\string\TeXOSQueryAllowRestricted\space + ignored (only allowed in texosquery.cfg)}% +} +\def\TeXOSQueryDenyRestricted{% + \@texosquery@warn{\string\TeXOSQueryDenyRestricted\space + ignored (only allowed in texosquery.cfg)}% +} +% \end{macrocode} +% +%If shell escape is unrestricted, automatically switch off dry-run +%mode, unless the cfg file has allowed it. % \begin{macrocode} \ifx\shellescape\undefined \ifx\pdfshellescape\undefined \else \ifnum\pdfshellescape=1\relax \TeXOSQueryDryRunfalse + \else + \@texosquery@allowrestricted + {% + \ifnum\pdfshellescape=2\relax + \TeXOSQueryDryRunfalse + \fi + } + {} \fi \fi \else \ifnum\shellescape=1\relax \TeXOSQueryDryRunfalse + \else + \@texosquery@allowrestricted + {% + \ifnum\shellescape=2\relax + \TeXOSQueryDryRunfalse + \fi + } + {} + \fi +\fi +% \end{macrocode} +% +%\begin{macro}{\@texosquery@edef} +%Need to provide some protection (if available) against non-ASCII characters +%that have been made active by \sty{inputenc} when reading in the +%results of the shell escape. This command may be defined before loading +%\sty{texosquery}, otherwise it's set to \cs{protected@edef}, if +%defined, or \cs{edef}. +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\@texosquery@edef\undefined + \ifx\protected@edef\undefined + \let\@texosquery@edef\edef + \else + \let\@texosquery@edef\protected@edef \fi \fi % \end{macrocode} +%\end{macro} +% +%Provide some utility commands. (Can't use \cs{@gobble} etc, as we +%may not be using \LaTeX.) +%\begin{macro}{\@texosquery@gobble} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@gobble#1{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@texosquery@firstofone} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@firstofone#1{#1} +% \end{macrocode} +%\end{macro} +% +%The results obtained from \app{texosquery} may be file names for +%use in commands like \cs{input} or \cs{includegraphics} or they may +%be text that needs typesetting (such as month names) or they may be +%date-time patterns or numeric patterns or they may be PDF date-time +%strings, which may need to have the category code of the initial +%\qt{D} set to 12 for parsing commands that include this character +%in the argument syntax. +% +%This means that we need to take special characters into account, +%but the way they are dealt with vary according to context. For +%example, \verb|#| needs to have the category code set to 12 if it's +%part of a file name. If an image file is called, say, +%\verb|test_imagefile#.png| then the following doesn't work: +%\begin{verbatim} +%\includegraphics{test\_imagefile\#} +%\end{verbatim} +%It needs to be +%\begin{verbatim} +%\includegraphics{test\string_imagefile\string#} +%\end{verbatim} +%or +%\begin{verbatim} +%\includegraphics{\detokenize{test_imagefile#}} +%\end{verbatim} +%The first two versions of \sty{texosquery} try to deal with this by +%simply changing the category code of \verb|_| to 12 and getting +%\app{texosquery} to replace all instances of \verb|#| with +%\verb|\#|. This hash substitution doesn't work with the above image +%example so version 1.2 introduced a new command that +%\app{texosquery} could use instead of \verb|\#| that expands to +%\verb|\string#|. This now solves the problem for file names that +%are obtained through \app{texosquery}, but \app{texosquery} doesn't +%solely return file names. It also returns text that needs +%typesetting and it also returns numeric patterns, which in their +%raw form include \verb|#| as a digit identifier. +% +%This means that we can't simply detokenize the result from +%\app{texosquery}. Instead \app{texosquery} replaces problematic +%characters with control sequences \emph{according to context}. +%For example, \cs{texosqueryhash} is used in a file name context, +%\cs{texosquerytexthash} is used in a textual context and +%\cs{texosquerypatdigitnozero} in a numeric pattern context. +% +%These long control sequence names clutter the results when testing +%the application directly in a terminal, so the Java code uses short +%forms that are locally defined by \cs{TeXOSQuery} to expand to the +%longer forms. +% +%\begin{macro}{\texosquerynonasciiwrap} +%\changes{1.2}{2017-03-23}{new} +%Allow a way to deal with non-ASCII characters returned by +%\app{texosquery}. \cs{TeXOSQuery} locally defines \cs{twrp} +%to this command. By default this just does its argument +%but may be redefined. For example, if the document uses a different +%file encoding to Java, then this command might need to be redefined +%to perform the appropriate conversion. +% \begin{macrocode} +\def\texosquerynonasciiwrap#1{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerynonasciidetokwrap} +%\changes{1.2}{2017-03-23}{new} +%We also need to allow for non-ASCII characters in file names. In +%this case the argument needs detokenizing. With \eTeX, we can +%simply use \cs{detokenize} but we need to allow for plain +%non-extended \TeX, so check for the existence of \cs{detokenize} +%first. +% \begin{macrocode} +\ifx\detokenize\undefined +% \end{macrocode} +%This won't work for characters consisting of multiple octets, +%but if users want UTF-8 support then they really need \eTeX\ at the +%very least (but ideally \XeTeX\ or \LuaTeX). +% \begin{macrocode} + \def\texosquerynonasciidetokwrap#1{\string#1} +\else + \def\texosquerynonasciidetokwrap#1{\detokenize{#1}} +\fi +% \end{macrocode} +%\end{macro} +% +%Now define commands used in \cs{TeXOSQuery} for various escaped characters. +%The literal versions are for file names. The textual versions are +%for use within the document text. For completeness, all the ASCII +%punctuation characters have both a literal and textual version. +%This helps to protect against \sty{babel} shorthands etc. +% +%\begin{macro}{\texosquerybackslash} +%\changes{1.2}{2017-03-23}{new} +%Literal backslash. +% \begin{macrocode} +\edef\texosquerybackslash{\expandafter\@texosquery@gobble\string\\} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextbackslash} +%\changes{1.2}{2017-03-23}{new} +%Textual backslash. +% \begin{macrocode} +\ifx\textbackslash\undefined + \def\texosquerytextbackslash{\texosquerybackslash} +\else + \def\texosquerytextbackslash{\noexpand\textbackslash} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryleftbrace} +%\changes{1.2}{2017-03-23}{new} +%Literal left brace. +% \begin{macrocode} +\edef\texosqueryleftbrace{\expandafter\@texosquery@gobble\string\{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextleftbrace} +%\changes{1.2}{2017-03-23}{new} +%Textual left brace. +% \begin{macrocode} +\def\texosquerytextleftbrace{\{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryrightbrace} +%\changes{1.2}{2017-03-23}{new} +%Literal right brace. +% \begin{macrocode} +\edef\texosqueryrightbrace{\expandafter\@texosquery@gobble\string\}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextrightbrace} +%\changes{1.2}{2017-03-23}{new} +%Textual right brace. +% \begin{macrocode} +\def\texosquerytextrightbrace{\}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryhash} +%\changes{1.2}{2017-03-23}{new} +%Literal hash. +% \begin{macrocode} +\edef\texosqueryhash{\expandafter\@texosquery@gobble\string\#} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytexthash} +%\changes{1.2}{2017-03-23}{new} +%Textual hash. +% \begin{macrocode} +\def\texosquerytexthash{\#} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryunderscore} +%\changes{1.2}{2017-03-23}{new} +%Literal underscore. +% \begin{macrocode} +\edef\texosqueryunderscore{\expandafter\@texosquery@gobble\string\_} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextunderscore} +%\changes{1.2}{2017-03-23}{new} +%Textual underscore. +% \begin{macrocode} +\def\texosquerytextunderscore{\_} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerybacktick} +%\changes{1.2}{2017-03-23}{new} +%Literal grave. +% \begin{macrocode} +\edef\texosquerybacktick{\string`} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextbacktick} +%\changes{1.2}{2017-03-23}{new} +%Textual open quote. +% \begin{macrocode} +\def\texosquerytextbacktick{`} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryclosequote} +%\changes{1.2}{2017-03-23}{new} +%Literal apostrophe. +% \begin{macrocode} +\edef\texosqueryclosequote{\string'} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextclosequote} +%\changes{1.2}{2017-03-23}{new} +%Textual apostrophe / single closing quote. +% \begin{macrocode} +\def\texosquerytextclosequote{'} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerydoublequote} +%\changes{1.2}{2017-03-23}{new} +%Literal double-quote. +% \begin{macrocode} +\edef\texosquerydoublequote{\string"} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextdoublequote} +%\changes{1.2}{2017-03-23}{new} +%Textual double-quote. +% \begin{macrocode} +\def\texosquerytextdoublequote{"} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycolon} +%\changes{1.2}{2017-03-23}{new} +%Literal colon. +% \begin{macrocode} +\edef\texosquerycolon{\string:} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextcolon} +%\changes{1.2}{2017-03-23}{new} +%Textual colon. +% \begin{macrocode} +\def\texosquerytextcolon{:} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerysemicolon} +%\changes{1.2}{2017-03-23}{new} +%Literal semi-colon. +% \begin{macrocode} +\edef\texosquerysemicolon{\string;} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextsemicolon} +%\changes{1.2}{2017-03-23}{new} +%Textual semi-colon. +% \begin{macrocode} +\def\texosquerytextsemicolon{;} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryequals} +%\changes{1.2}{2017-03-23}{new} +%Literal equals. +% \begin{macrocode} +\edef\texosqueryequals{\string=} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextequals} +%\changes{1.2}{2017-03-23}{new} +%Textual equals. +% \begin{macrocode} +\def\texosquerytextequals{=} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryslash} +%\changes{1.2}{2017-03-23}{new} +%Literal slash. +% \begin{macrocode} +\edef\texosqueryslash{\string/} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextslash} +%\changes{1.2}{2017-03-23}{new} +%Textual slash. +% \begin{macrocode} +\def\texosquerytextslash{/} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryhyphen} +%\changes{1.2}{2017-03-23}{new} +%Literal hyphen. +% \begin{macrocode} +\edef\texosqueryhyphen{\string-} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytexthyphen} +%\changes{1.2}{2017-03-23}{new} +%Textual hyphen. +% \begin{macrocode} +\def\texosquerytexthyphen{-} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryplus} +%\changes{1.2}{2017-03-23}{new} +%Literal plus. +% \begin{macrocode} +\edef\texosqueryplus{\string+} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextplus} +%\changes{1.2}{2017-03-23}{new} +%Textual plus. +% \begin{macrocode} +\def\texosquerytextplus{+} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryperiod} +%\changes{1.2}{2017-03-23}{new} +%Literal period. +% \begin{macrocode} +\edef\texosqueryperiod{\string.} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextperiod} +%\changes{1.2}{2017-03-23}{new} +%Textual period. +% \begin{macrocode} +\def\texosquerytextperiod{.} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycomma} +%\changes{1.2}{2017-03-23}{new} +%Literal comma. +% \begin{macrocode} +\edef\texosquerycomma{\string,} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextcomma} +%\changes{1.2}{2017-03-23}{new} +%Textual comma. +% \begin{macrocode} +\def\texosquerytextcomma{,} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryopenparen} +%\changes{1.2}{2017-03-23}{new} +%Literal open bracket. +% \begin{macrocode} +\edef\texosqueryopenparen{\string(} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextopenparen} +%\changes{1.2}{2017-03-23}{new} +%Textual open bracket. +% \begin{macrocode} +\def\texosquerytextopenparen{(} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycloseparen} +%\changes{1.2}{2017-03-23}{new} +%Literal close bracket. +% \begin{macrocode} +\edef\texosquerycloseparen{\string)} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextcloseparen} +%\changes{1.2}{2017-03-23}{new} +%Textual close bracket. +% \begin{macrocode} +\def\texosquerytextcloseparen{)} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryopensq} +%\changes{1.2}{2017-03-23}{new} +%Literal open square bracket. +% \begin{macrocode} +\edef\texosqueryopensq{\string[} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextopensq} +%\changes{1.2}{2017-03-23}{new} +%Textual open square bracket. +% \begin{macrocode} +\def\texosquerytextopensq{[} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryclosesq} +%\changes{1.2}{2017-03-23}{new} +%Literal close square bracket. +% \begin{macrocode} +\edef\texosqueryclosesq{\string]} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextclosesq} +%\changes{1.2}{2017-03-23}{new} +%Textual close square bracket. +% \begin{macrocode} +\def\texosquerytextclosesq{]} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryasterisk} +%\changes{1.2}{2017-03-23}{new} +%Literal asterisk. +% \begin{macrocode} +\edef\texosqueryasterisk{\string*} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextasterisk} +%\changes{1.2}{2017-03-23}{new} +%Textual asterisk. +% \begin{macrocode} +\def\texosquerytextasterisk{*} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryatchar} +%\changes{1.2}{2017-03-23}{new} +%Literal at character. +% \begin{macrocode} +\edef\texosqueryatchar{\string @} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextatchar} +%\changes{1.2}{2017-03-23}{new} +%Textual at character. +% \begin{macrocode} +\def\texosquerytextatchar{@} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerybar} +%\changes{1.2}{2017-03-23}{new} +%Literal bar. +% \begin{macrocode} +\edef\texosquerybar{\string|} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextbar} +%\changes{1.2}{2017-03-23}{new} +%Textual bar. +% \begin{macrocode} +\ifx\undefined\textbar + \def\texosquerytextbar{|} +\else + \def\texosquerytextbar{\ifmmode|\else\textbar\fi} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerylessthan} +%\changes{1.2}{2017-03-23}{new} +%Literal less than. +% \begin{macrocode} +\edef\texosquerylessthan{\string<} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextlessthan} +%\changes{1.2}{2017-03-23}{new} +%Textual less than. +% \begin{macrocode} +\ifx\undefined\textless + \def\texosquerytextlessthan{<} +\else + \def\texosquerytextlessthan{\ifmmode<\else\textless\fi} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerygreaterthan} +%\changes{1.2}{2017-03-23}{new} +%Literal greater than. +% \begin{macrocode} +\edef\texosquerygreaterthan{\string>} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextgreaterthan} +%\changes{1.2}{2017-03-23}{new} +%Textual greater than. +% \begin{macrocode} +\ifx\undefined\textgreater + \def\texosquerytextgreaterthan{>} +\else + \def\texosquerytextgreaterthan{\ifmmode<\else\textgreater\fi} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytilde} +%\changes{1.2}{2017-03-23}{new} +%Literal tilde. +% \begin{macrocode} +\edef\texosquerytilde{\string~} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytexttilde} +%\changes{1.2}{2017-03-23}{new} +%Textual tilde. +% \begin{macrocode} +\ifx\textasciitilde\undefined + \def\texosquerytexttilde{\string~} +\else + \def\texosquerytexttilde{\textasciitilde} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycircum} +%\changes{1.2}{2017-03-23}{new} +%Literal circumflex. +% \begin{macrocode} +\edef\texosquerycircum{\string^} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextcircum} +%\changes{1.2}{2017-03-23}{new} +%Textual circumflex. +% \begin{macrocode} +\ifx\textasciicircum\undefined + \def\texosquerytextcircum{\string^} +\else + \def\texosquerytextcircum{\textasciicircum} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryampersand} +%\changes{1.2}{2017-03-23}{new} +%Literal ampersand. +% \begin{macrocode} +\edef\texosqueryampersand{\string&} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextampersand} +%\changes{1.2}{2017-03-23}{new} +%Textual ampersand. +% \begin{macrocode} +\def\texosquerytextampersand{\&} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerydollar} +%\changes{1.2}{2017-03-23}{new} +%Literal dollar. (This could just be defined as \verb|\string$|, but +%that plays havoc with the syntax highlighting!) +% \begin{macrocode} +\edef\texosquerydollar{\expandafter\@texosquery@gobble\string\$} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextdollar} +%\changes{1.2}{2017-03-23}{new} +%Textual dollar. +% \begin{macrocode} +\def\texosquerytextdollar{\$} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerypercent} +%\changes{1.2}{2017-03-23}{new} +%Literal percent. +% \begin{macrocode} +\edef\texosquerypercent{\expandafter\@texosquery@gobble\string\%} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextpercent} +%\changes{1.2}{2017-03-23}{new} +%Textual percent. +% \begin{macrocode} +\def\texosquerytextpercent{\%} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryexclam} +%\changes{1.2}{2017-03-23}{new} +%Literal exclamation. +% \begin{macrocode} +\edef\texosqueryexclam{\string!} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextexclam} +%\changes{1.2}{2017-03-23}{new} +%Textual exclamation. +% \begin{macrocode} +\def\texosquerytextexclam{!} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryquestion} +%\changes{1.2}{2017-03-23}{new} +%Literal question mark. +% \begin{macrocode} +\edef\texosqueryquestion{\string?} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextquestion} +%\changes{1.2}{2017-03-23}{new} +%Textual question mark. +% \begin{macrocode} +\def\texosquerytextquestion{?} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\texosqueryliteralspace} +%\changes{1.2}{2017-03-23}{new} +%Literal space. +% \begin{macrocode} +\edef\texosqueryliteralspace{\expandafter\string\space} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytextspace} +%\changes{1.2}{2017-03-23}{new} +%Textual space. (Don't allow it to expand while it's being fetched +%from \cs{texosquery} just in case it disappears.) +% \begin{macrocode} +\def\texosquerytextspace{\noexpand\space} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@D} +%\changes{1.2}{2017-03-23}{new} +%The \verb|D| identifier in PDF date-time formats need to have +%category code 12. This is only used by methods that return results +%in the form: +% +%\verb|D:|\meta{YYYY}\meta{MM}\marg{DD}\meta{HH}\meta{mm}\meta{ss}\meta{TZh}\verb|'|\meta{TZm}\verb|'| +% \begin{macrocode} +\edef\@texosquery@D{\string D} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@enableshortcs} +%\changes{1.2}{2017-03-23}{new} +%\hypertarget{enableshortcs}{Enable shortcut commands.} +% \begin{macrocode} +\def\@texosquery@enableshortcs{% +% \end{macrocode} +%Thesre are for the date-time and numeric patterns. +% \begin{macrocode} + \def\patdtf{\noexpand\texosquerydtf}% + \def\patpmnumfmt{\noexpand\texosquerypatplusminus}% + \def\patnumfmt{\noexpand\texosquerypatnum}% + \def\patsinumfmt{\noexpand\texosquerypatsinum}% + \def\patdecfmt{\noexpand\texosquerypatdec}% + \def\patpcur{\noexpand\texosquerypatprefixcurrency}% + \def\patpicur{\noexpand\texosquerypatprefixicurrency}% + \def\patscur{\noexpand\texosquerypatsuffixcurrency}% + \def\patsicur{\noexpand\texosquerypatsuffixicurrency}% + \def\patstr{\noexpand\texosquerypatstr}% + \def\patapo{\noexpand\texosquerypatquote}% + \def\patdgt{\noexpand\texosquerypatdigit}% + \def\patdgtnz{\noexpand\texosquerypatdigitnozero}% + \def\patmsg{\noexpand\texosquerypatminus}% + \def\patngp{\noexpand\texosquerypatgroupsep}% + \def\patppct{\noexpand\texosquerypatprefixpercent}% + \def\patspct{\noexpand\texosquerypatsuffixpercent}% + \def\patppml{\noexpand\texosquerypatprefixpermill}% + \def\patspml{\noexpand\texosquerypatsuffixpermill}% +% \end{macrocode} +%Hook to adjust the processing of non-ASCII characters. +% \begin{macrocode} + \def\twrp{\texosquerynonasciiwrap}% + \def\fwrp{\texosquerynonasciidetokwrap}% +% \end{macrocode} +%Locally redefine some more commands that may occur in +%\app{texosquery}'s return value (via the \texttt{escapeSpChars} +%method in \file{TeXOSQuery.java}). The \texttt{t} prefix indicates +%textual commands and the \texttt{f} prefix indicates literal +%characters, for example, in file names. +% \begin{macrocode} + \let\fbks\texosquerybackslash + \let\tbks\texosquerytextbackslash + \let\flbr\texosqueryleftbrace + \let\tlbr\texosquerytextleftbrace + \let\frbr\texosqueryrightbrace + \let\trbr\texosquerytextrightbrace + \let\fhsh\texosqueryhash + \let\thsh\texosquerytexthash + \let\fusc\texosqueryunderscore + \let\tusc\texosquerytextunderscore + \let\fgrv\texosquerybacktick + \let\tgrv\texosquerytextbacktick + \let\fapo\texosqueryclosequote + \let\tapo\texosquerytextclosequote + \let\fdqt\texosquerydoublequote + \let\tdqt\texosquerytextdoublequote + \let\fspc\texosqueryliteralspace + \let\tspc\texosquerytextspace + \let\fcln\texosquerycolon + \let\tcln\texosquerytextcolon + \let\fscl\texosquerysemicolon + \let\tscl\texosquerytextsemicolon + \let\feql\texosqueryequals + \let\teql\texosquerytextequals + \let\fhyn\texosqueryhyphen + \let\thyn\texosquerytexthyphen + \let\fpls\texosqueryplus + \let\tpls\texosquerytextplus + \let\ftld\texosquerytilde + \let\ttld\texosquerytexttilde + \let\fcir\texosquerycircum + \let\tcir\texosquerytextcircum + \let\famp\texosqueryampersand + \let\tamp\texosquerytextampersand + \let\fslh\texosqueryslash + \let\tslh\texosquerytextslash + \let\fpct\texosquerypercent + \let\tpct\texosquerytextpercent + \let\fexc\texosqueryexclam + \let\texc\texosquerytextexclam + \let\fque\texosqueryquestion + \let\tque\texosquerytextquestion + \let\fles\texosquerylessthan + \let\tles\texosquerytextlessthan + \let\fgre\texosquerygreaterthan + \let\tgre\texosquerytextgreaterthan + \let\fdol\texosquerydollar + \let\tdol\texosquerytextdollar + \let\fdot\texosqueryperiod + \let\tdot\texosquerytextperiod + \let\fcom\texosquerycomma + \let\tcom\texosquerytextcomma + \let\fopb\texosqueryopenparen + \let\topb\texosquerytextopenparen + \let\fclb\texosquerycloseparen + \let\tclb\texosquerytextcloseparen + \let\fosb\texosqueryopensq + \let\tosb\texosquerytextopensq + \let\fcsb\texosqueryclosesq + \let\tcsb\texosquerytextclosesq + \let\fast\texosqueryasterisk + \let\tast\texosquerytextasterisk + \let\fatc\texosqueryatchar + \let\tatc\texosquerytextatchar + \let\pdfd\@texosquery@D +} +% \end{macrocode} +%\end{macro} % %\begin{macro}{\TeXOSQuery} -%Use \texttt{texosquery} with the option given in the second +%Use \app{texosquery} with the option given in the second %argument and store the result in control sequence given in the %first argument. % \begin{macrocode} @@ -611,10 +3584,15 @@ \begingroup \endlinechar=-1\relax % \end{macrocode} -%Just in case the result contains any awkward characters that have -%some special meaning to \TeX. (Can't really protect against hash, -%backslash or curly braces, but they're unlikely to occur unless -%the user has a very wacky and inappropriate file naming scheme.) +%Locally redefine short commands used by \app{texosquery} +% \begin{macrocode} + \@texosquery@enableshortcs +% \end{macrocode} +%Change the category code of some potentially awkward characters. +%(This should no longer be an issue with the new commands that +%are now used in the returned text, but \app{texosquery} might be run with the +%backward compatibility mode on, so this is +%still needed just in case.) % \begin{macrocode} \catcode`\-=12\relax \catcode`\_=12\relax @@ -622,20 +3600,376 @@ \catcode`\~=12\relax \catcode`\$=12\relax \catcode`\&=12\relax - \catcode`\"=12\relax - \catcode`\'=12\relax \catcode`\.=12\relax \catcode`\/=12\relax \catcode`\:=12\relax + \catcode`\"=12\relax + \catcode`\'=12\relax \catcode`\;=12\relax \catcode`\%=12\relax \everyeof{\noexpand}\relax - \edef\x{\endgroup\def\noexpand#1{\TeXOSQueryInvoker{#2}}}\x + \@texosquery@edef\x{\endgroup\def\noexpand#1{\TeXOSQueryInvoker{#2}}}\x \fi } % \end{macrocode} %\end{macro} % +%\subsubsection{Currency} +%The \meta{\TeX\ currency} element of \longarg{numeric} and +%\longarg{locale-data} identifies the currency symbol using +%\begin{definition} +%\cs{texosquerycurrency}\marg{label} +%\end{definition} +%which simply expands to the appropriate command. +%\begin{macro}{\texosquerycurrency} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrency#1{% + \expandafter\noexpand\csname texosquerycurrency#1\endcsname +} +% \end{macrocode} +%\end{macro} +% +%Provide the currency commands that may be returned +%\app{texosquery} (on expansion of \cs{texosquerycurrency}). +%Most of these will need redefining as there's no appropriate +%generic code to use as a default. +%The \sty{fontawesome} package has the most support for currency +%symbols, so these are checked first. +%\begin{macro}{\texosquerycurrencydollar} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\faDollar\undefined + \def\texosquerycurrencydollar{\$} +\else + \def\texosquerycurrencydollar{\faDollar} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencycent} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\textcent\undefined + \def\texosquerycurrencycent{cent} +\else + \def\texosquerycurrencycent{\textcent} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencypound} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\faGbp\undefined + \ifx\pounds\undefined + \def\texosquerycurrencypound{pound} + \else + \def\texosquerycurrencypound{\pounds} + \fi +\else + \def\texosquerycurrencypound{\faGbp} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencysign} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\textcurrency\undefined + \def\texosquerycurrencysign{currency-sign} +\else + \def\texosquerycurrencysign{\textcurrency} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyyen} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\faYen\undefined + \ifx\textyen\undefined + \def\texosquerycurrencyyen{yen} + \else + \def\texosquerycurrencyyen{\textyen} + \fi +\else + \def\texosquerycurrencyyen{\faYen} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyecu} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencyecu{ecu} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencycolon} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencycolon{colon} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencycruzeiro} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencycruzeiro{cruzeiro} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyfranc} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencyfranc{franc} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencylira} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\textlira\undefined + \def\texosquerycurrencylira{lira} +\else + \def\texosquerycurrencylira{\textlira} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencymill} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencymill{mill} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencynaira} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\textnaira\undefined + \def\texosquerycurrencynaira{naira} +\else + \def\texosquerycurrencynaira{\textnaira} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencypeseta} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencypeseta{peseta} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyrupee} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\faRupee\undefined + \def\texosquerycurrencyrupee{rupee} +\else + \def\texosquerycurrencyrupee{\faRupee} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencywon} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\faWon\undefined + \ifx\textwon\undefined + \def\texosquerycurrencywon{won} + \else + \def\texosquerycurrencywon{\textwon} + \fi +\else + \def\texosquerycurrencywon{\faWon} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencynewsheqel} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\faSheqel\undefined + \def\texosquerycurrencynewsheqel{newsheqel} +\else + \def\texosquerycurrencynewsheqel{\faSheqel} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencydong} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\textdong\undefined + \def\texosquerycurrencydong{dong} +\else + \def\texosquerycurrencydong{\textdong} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyeuro} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\faEuro\undefined + \ifx\texteuro\undefined + \ifx\euro\undefined + \def\texosquerycurrencyeuro{euro} + \else + \def\texosquerycurrencyeuro{\euro} + \fi + \else + \def\texosquerycurrencyeuro{\texteuro} + \fi +\else + \def\texosquerycurrencyeuro{\faEuro} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencykip} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencykip{kip} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencytugrik} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencytugrik{tugrik} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencydrachma} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencydrachma{drachma} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencygermanpenny} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencygermanpenny{german-penny} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencypeso} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\textpeso\undefined + \def\texosquerycurrencypeso{peso} +\else + \def\texosquerycurrencypeso{\textpeso} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyguarani} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\textguarani\undefined + \def\texosquerycurrencyguarani{guarani} +\else + \def\texosquerycurrencyguarani{\textguarani} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyaustral} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencyaustral{austral} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyhryvnia} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencyhryvnia{hryvnia} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencycedi} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\textcolonmonetary\undefined + \def\texosquerycurrencycedi{cedi} +\else + \def\texosquerycurrencycedi{\textcolonmonetary} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencylivretournois} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencylivretournois{livre-tournois} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyspesmilo} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencyspesmilo{spesmilo} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencytenge} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencytenge{tenge} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyrupee} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencyrupee{rupee} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyturkishlira} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\faTurkishLira\undefined + \def\texosquerycurrencyturkishlira{turkish-lira} +\else + \def\texosquerycurrencyturkishlira{\faTurkishLira} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencynordicmark} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencynordicmark{nordic-mark} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencymanat} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerycurrencymanat{manat} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerycurrencyruble} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\ifx\faRuble\undefined + \def\texosquerycurrencyruble{ruble} +\else + \def\texosquerycurrencyruble{\faRuble} +\fi +% \end{macrocode} +%\end{macro} +% +%\subsubsection{Shortcut Commands} %Now for some convenient shortcuts so the user doesn't have to %remember the command line options. \cs{string} is used in %case the hyphen character has been made active. @@ -647,6 +3981,37 @@ % \end{macrocode} %\end{macro} % +%\begin{macro}{\TeXOSQueryLangTag} +%Query the language tag and store the result in the control sequence +%provided in the argument. +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\TeXOSQueryLangTag#1{\TeXOSQuery{#1}{\string-b}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryNumeric} +%Query the numeric settings for the locale given in the second +%argument and store the result in the control sequence +%provided in the argument. Leave the second argument empty for the +%default locale. +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\TeXOSQueryNumeric#1#2{\TeXOSQuery{#1}{\string-N #2}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryLocaleData} +%Query the data for the locale given in the second +%argument and store the result in the control sequence +%provided in the argument. Leave the second argument empty for the +%default locale. +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\TeXOSQueryLocaleData#1#2{\TeXOSQuery{#1}{\string-D #2}} +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\TeXOSQueryCwd} %Query the current working directory. % \begin{macrocode} @@ -689,18 +4054,36 @@ % \end{macrocode} %\end{macro} % +%\begin{macro}{\TeXOSQueryDateTime} +%\changes{1.2}{2017-03-23}{new} +%Query the current date and time. +% \begin{macrocode} +\def\TeXOSQueryDateTime#1{% + \TeXOSQuery{#1}{\string-M}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryTimeZones} +%\changes{1.2}{2017-03-23}{new} +%Query the current time zone mappings. Leave the second argument +%empty for the default locale. +% \begin{macrocode} +\def\TeXOSQueryTimeZones#1#2{% + \TeXOSQuery{#1}{\string-Z #2}% +} +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\TeXOSQueryNow} %\changes{1.1}{2016-07-14}{changed catcode of D to 12} %Query the current time stamp. % \begin{macrocode} \def\TeXOSQueryNow#1{% % \end{macrocode} -% The \texttt{D} needs category code 12. (Don't need to worry about -% \texttt{Z} as \texttt{texosquery.jar} uses \texttt{+00'00'} for -% UTC+0.) This change can't be done with the other catcode changes -% in \cs{TeXOSQuery}, as this is only appropriate for the PDF dates. -% Save and restore the catcode rather than fiddle around with -% scoping. +% The \texttt{D} needs category code 12 just in case +% \app{texosquery} is running in a backward compatibility mode that +% doesn't use \cs{pdfd}. % \begin{macrocode} \edef\@texosquery@restore@D{% \noexpand\catcode`\noexpand\D=\the\catcode`\D\relax}% @@ -733,6 +4116,11 @@ %Query the time stamp of the file given in the second argument. % \begin{macrocode} \def\TeXOSQueryFileDate#1#2{% +% \end{macrocode} +% The \texttt{D} needs category code 12 just in case +% \app{texosquery} is running in a backward compatibility mode that +% doesn't use \cs{pdfd}. +% \begin{macrocode} \edef\@texosquery@restore@D{% \noexpand\catcode`\noexpand\D=\the\catcode`\D\relax}% \catcode`\D=12\relax @@ -750,13 +4138,354 @@ % \end{macrocode} %\end{macro} % +%\begin{macro}{\@texosquery@filelist} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@filelist#1#2#3#4#5{\TeXOSQuery{#1}{% + \string#2 \string'#3\string' + \string'\texosquerystripquotes{#4}\string' #5}} +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\TeXOSQueryFileList} %List all files in the directory given in the third argument, %separated by the second argument. % \begin{macrocode} -\def\TeXOSQueryFileList#1#2#3{\TeXOSQuery{#1}{% - \string-i \string'#2\string' - \string'\texosquerystripquotes{#3}\string'}} +\def\TeXOSQueryFileList#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListDateAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by date. +% \begin{macrocode} +\def\TeXOSQueryFileListDateAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{date}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListDateDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by date in descending order. +% \begin{macrocode} +\def\TeXOSQueryFileListDateDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{date\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListSizeAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by size. +% \begin{macrocode} +\def\TeXOSQueryFileListSizeAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{size}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListSizeDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by size in descending order. +% \begin{macrocode} +\def\TeXOSQueryFileListSizeDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{size\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListNameAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by name. +% \begin{macrocode} +\def\TeXOSQueryFileListNameAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{name}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListNameDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by name in descending order. +% \begin{macrocode} +\def\TeXOSQueryFileListNameDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{name\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListNameIgnoreCaseAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by case-insensitive name. +% \begin{macrocode} +\def\TeXOSQueryFileListNameIgnoreCaseAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{iname}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListNameIgnoreCaseDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by case-insensitive name in descending order. +% \begin{macrocode} +\def\TeXOSQueryFileListNameIgnoreCaseDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{iname\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListExtAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by extension. +% \begin{macrocode} +\def\TeXOSQueryFileListExtAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{ext}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFileListExtDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by extension in descending order. +% \begin{macrocode} +\def\TeXOSQueryFileListExtDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{ext\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileList} +%List all regular files. +% \begin{macrocode} +\def\TeXOSQueryRegularFileList#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirList} +%List all sub-directories. +% \begin{macrocode} +\def\TeXOSQuerySubDirList#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListDateAsc} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by date. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListDateAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{date}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListDateAsc} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by date. +% \begin{macrocode} +\def\TeXOSQuerySubDirListDateAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{date}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListDateDes} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by date in descending order. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListDateDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{date\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListDateDes} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by date in descending order. +% \begin{macrocode} +\def\TeXOSQuerySubDirListDateDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{date\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListSizeAsc} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by size. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListSizeAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{size}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListSizeAsc} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by size. +% \begin{macrocode} +\def\TeXOSQuerySubDirListSizeAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{size}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListSizeDes} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by size in descending order. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListSizeDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{size\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListSizeDes} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by size in descending order. +% \begin{macrocode} +\def\TeXOSQuerySubDirListSizeDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{size\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListNameAsc} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by file name. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListNameAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{name}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListNameAsc} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by file name. +% \begin{macrocode} +\def\TeXOSQuerySubDirListNameAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{name}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListNameDes} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by file name in descending order. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListNameDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{name\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListNameDes} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by name in descending order. +% \begin{macrocode} +\def\TeXOSQuerySubDirListNameDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{name\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListNameIgnoreCaseAsc} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by file case-insensitive name. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListNameIgnoreCaseAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{iname}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListNameIgnoreCaseAsc} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by file case-insensitive name. +% \begin{macrocode} +\def\TeXOSQuerySubDirListNameIgnoreCaseAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{iname}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListNameIgnoreCaseDes} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by file case-insensitive name in descending order. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListNameIgnoreCaseDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{iname\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListNameIgnoreCaseDes} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by case-insensitive name in descending order. +% \begin{macrocode} +\def\TeXOSQuerySubDirListNameIgnoreCaseDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{iname\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListExtAsc} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by file extension. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListExtAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{ext}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListExtAsc} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by file extension. +% \begin{macrocode} +\def\TeXOSQuerySubDirListExtAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{ext}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryRegularFileListExtDes} +%\changes{1.2}{2017-03-23}{new} +%List all regular files sorted by file extension in descending order. +% \begin{macrocode} +\def\TeXOSQueryRegularFileListExtDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{ext\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQuerySubDirListExtDes} +%\changes{1.2}{2017-03-23}{new} +%List all sub-directories sorted by extension in descending order. +% \begin{macrocode} +\def\TeXOSQuerySubDirListExtDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{ext\string-des}% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\@texosquery@filterfilelist} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@filterfilelist#1#2#3#4#5#6{% + \TeXOSQuery{#1}% + {% + \string#2 \string'#3\string' \string'#4\string' + \string'\texosquerystripquotes{#5}\string' #6% + }% +} % \end{macrocode} %\end{macro} % @@ -766,9 +4495,455 @@ %expression used to filter the list. \emph{Take care of backslashes %in the regular expression!} % \begin{macrocode} -\def\TeXOSQueryFilterFileList#1#2#3#4{\TeXOSQuery{#1}{% - \string-f \string'#2\string' \string'#3\string' - \string'\texosquerystripquotes{#4}\string'}} +\def\TeXOSQueryFilterFileList#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListDateAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by date. +% \begin{macrocode} +\def\TeXOSQueryFilterFileListDateAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{date}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListDateDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by date in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterFileListDateDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{date\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListSizeAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by size. +% \begin{macrocode} +\def\TeXOSQueryFilterFileListSizeAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{size}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListSizeDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by size in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterFileListSizeDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{size\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListNameAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file name. +% \begin{macrocode} +\def\TeXOSQueryFilterFileListNameAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{name}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListNameDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by name in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterFileListNameDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{name\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListNameIgnoreCaseAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file name (case-insensitive). +% \begin{macrocode} +\def\TeXOSQueryFilterFileListNameIgnoreCaseAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{iname}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListNameIgnoreCaseDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by name in descending order (case-insensitive). +% \begin{macrocode} +\def\TeXOSQueryFilterFileListNameIgnoreCaseDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{iname\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListExtAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file extension. +% \begin{macrocode} +\def\TeXOSQueryFilterFileListExtAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{ext}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterFileListExtDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by extension in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterFileListExtDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{ext\string-des}% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\TeXOSQueryFilterRegularFileList} +%Filtered list or regular files. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileList#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterSubDirList} +%Filtered list of sub-directories. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirList#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterSubDirListDateAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by file date. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListDateAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{date}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListDateAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by file date. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListDateAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{date}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterSubDirListDateDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by file date in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListDateDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{date\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListDateDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by file date in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListDateDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{date\string-des}% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\TeXOSQueryFilterSubDirListSizeAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by file size. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListSizeAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{size}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListSizeAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by file size. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListSizeAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{size}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterSubDirListSizeDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by file size in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListSizeDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{size\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListSizeDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by file size in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListSizeDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{size\string-des}% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\TeXOSQueryFilterSubDirListNameAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by file name. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListNameAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{name}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListNameAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by file name. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListNameAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{name}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterSubDirListNameDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by file name in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListNameDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{name\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListNameDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by file name in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListNameDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{name\string-des}% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\TeXOSQueryFilterSubDirListNameIgnoreCaseAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by case-insensitive file name. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListNameIgnoreCaseAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{iname}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListNameIgnoreCaseAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by case-insensitive file name. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListNameIgnoreCaseAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{iname}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterSubDirListNameIgnoreCaseDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by case-insensitive file name in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListNameIgnoreCaseDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{iname\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListNameIgnoreCaseDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by case-insensitive file name in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListNameIgnoreCaseDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{iname\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterSubDirListExtAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by file extension. (Added for +%completeness as directories don't tend to have extensions.) +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListExtAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{ext}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListExtAsc} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by file extension. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListExtAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{ext}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterSubDirListExtDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of sub-directories by file extension in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterSubDirListExtDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{ext\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryFilterRegularFileListExtDes} +%\changes{1.2}{2017-03-23}{new} +%Filtered sort of regular files by file extension in descending order. +% \begin{macrocode} +\def\TeXOSQueryFilterRegularFileListExtDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{ext\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@walk} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@walk#1#2#3#4#5{% + \TeXOSQuery{#1}% + {% + \string-w \string'#2\string' \string'#3\string' + \string'\texosquerystripquotes{#4}\string' #5% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalk} +%\changes{1.2}{2017-03-23}{new} +%Recursive filtered listing of regular files. +% \begin{macrocode} +\def\TeXOSQueryWalk#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkDateAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by date. +% \begin{macrocode} +\def\TeXOSQueryWalkDateAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{date}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkDateDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by date in descending order. +% \begin{macrocode} +\def\TeXOSQueryWalkDateDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{date\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkSizeAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file size. +% \begin{macrocode} +\def\TeXOSQueryWalkSizeAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{size}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkSizeDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file size in descending order. +% \begin{macrocode} +\def\TeXOSQueryWalkSizeDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{size\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkNameAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file name. +% \begin{macrocode} +\def\TeXOSQueryWalkNameAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{name}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkNameDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file name in descending order. +% \begin{macrocode} +\def\TeXOSQueryWalkNameDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{name\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkNameIgnoreCaseAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file name (case-insensitive). +% \begin{macrocode} +\def\TeXOSQueryWalkNameIgnoreCaseAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{iname}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkNameIgnoreCaseDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file name (case-insensitive) in descending order. +% \begin{macrocode} +\def\TeXOSQueryWalkNameIgnoreCaseDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{iname\string-des}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkExtAsc} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file extension. +% \begin{macrocode} +\def\TeXOSQueryWalkExtAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{ext}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\TeXOSQueryWalkExtDes} +%\changes{1.2}{2017-03-23}{new} +%As above, but sort by file extension in descending order. +% \begin{macrocode} +\def\TeXOSQueryWalkExtDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{ext\string-des}% +} % \end{macrocode} %\end{macro} % @@ -798,6 +4973,2550 @@ % \end{macrocode} %\end{macro} % +%\subsubsection{Pattern Formats} +%\label{sec:patternformats} +%There are two basic types of patterns: date/time or numeric. +%A pattern is stored in a control sequence using custom markup +%that's easier for \TeX\ to parse than it would be to parse +%strings in the form \verb|YYYY-MM| or \verb|#,##0|. This internal +%pattern format can be obtained through capturing the output +%of \app{texosquery}'s \shortarg{D} action, but patterns can also be +%constructed using +%\begin{definition} +%\cs{texosquerydefpattern}\marg{cs}\marg{pattern specs} +%\end{definition} +%The pattern is stored in \meta{cs}. The \meta{pattern specs} depend +%on whether a date-time or numeric pattern is required. +%For a date-time pattern, each date/time element is identified +%using +%\begin{definition} +%\cs{texosquerydtf}\marg{n}\marg{identifier} +%\end{definition} +%where \meta{identifier} identifies the element type (such as +%\verb|M| for month or \verb|s| for seconds) and \meta{n} +%indicates how the element should be formatted, where \meta{n} +%is an integer from 1 to 4. For example if \meta{n} is 2 +%and \meta{identifier} is \verb|M|, then this indicates the +%\verb|MM| format, which produces a two-digit number. +% +%Since it's rather cumbersome to keep typing \cs{texosquerydtf} +%and it can make for rather hard to read code, +%\cs{texosquerydefpattern} locally redefines \verb|\%| to expand to +%\cs{texosquerydtf}. This means that if you do, for example: +%\begin{verbatim} +%\texosquerydefpattern{\pattern}{\%2d/\%2M/\%4y} +%\end{verbatim} +%then \cs{pattern} is defined to +%\begin{verbatim} +%\texosquerydtf 2d/\texosquerydtf 2M/\texosquerydtf 4y +%\end{verbatim} +%When simply used within the document, this just expands to the +%pattern format. For example: +%\begin{verbatim} +%Pattern: \pattern. +%\end{verbatim} +%will display \qt{Pattern: dd/MM/yyyy} in the PDF. However, +%when used with \cs{texosqueryfmtdatetime}, the definition +%of \cs{texosquerydtf} changes to reproduce the required +%date/time element. +% +%For example: +%\begin{verbatim} +%\texosquerydefpattern{\pattern}{\%2d/\%2M/\%4y \%2H:\%2m:\%2s \%2Z} +% +%Pattern: \pattern. +% +%\TeXOSQueryDateTime{\datetimedata} +% +%\ifx\datetimedata\empty +% Query Failed! +%\else +% \expandafter\texosqueryfmtdatetime\expandafter\pattern\datetimedata +%\fi +%\end{verbatim} +% +%The numeric patterns are rather more complicated. The +%\meta{pattern specs} now needs to use the following formats: +% +%\begin{definition} +%\cs{texosquerypatnum}\marg{+ve/-ve numeric pattern} +%\end{definition} +%This is a numeric pattern applied to a number regardless of +%whether the number is positive or negative. (If negative, the +%minus sign is automatically inserted.) This is rather a long +%and cumbersome command to type, so \cs{texosquerydefpattern} +%locally defines \cs{numfmt} to expand to it. +% +%\begin{definition} +%\cs{texosquerypatplusminus}\marg{+ve numeric pattern}\marg{-ve numeric +%pattern} +%\end{definition} +%This provides a pattern \meta{+ve numeric pattern} to use if the +%number is positive and a patter \meta{-ve numeric pattern} to use +%if the number is negative. Again \cs{texosquerydefpattern} +%locally defines a shortcut, \cs{pmnumfmt}, to expand to this +%command. +% +%\begin{definition} +%\cs{texosquerypatsinum}\marg{decimal pattern}\marg{mantissa +%pattern} +%\end{definition} +%This provides a pattern to use for SI numbers where \meta{decimal +%pattern} is a pattern for the decimal number part (before the +%exponent symbol) and \meta{mantissa} is the pattern for the integer +%part in the mantissa (after the exponent symbol). +%The locally defined shortcut is \cs{sinumfmt}. The \meta{decimal +%pattern} will typically be in the form: +%\begin{definition} +%\cs{texosquerypatdec}\marg{integer pattern}\marg{fraction pattern} +%\end{definition} +%This indicates a decimal pattern where the \meta{integer pattern} +%is applied to the part before the decimal separator and +%\meta{fraction pattern} is applied to the part after the separator. The shortcut is \cs{decfmt}. +% +%\begin{definition} +%\cs{texosquerypatprefixcurrency}\marg{decimal pattern}\marg{text} +%\end{definition} +%This indicates a currency pattern with a prefixed currency symbol where \meta{text} is inserted +%before the currency symbol. The shortcut is \cs{pcur}. +%The \meta{decimal pattern} will typically use +%\cs{texosquerypatdec}\marg{int}\meta{frac}. (Similarly for the +%following.) +% +%\begin{definition} +%\cs{texosquerypatprefixicurrency}\marg{decimal pattern}\marg{text} +%\end{definition} +%This indicates an international currency pattern with a prefixed +%international currency symbol where \meta{text} is inserted +%before the symbol. The shortcut is \cs{picur}. +% +%\begin{definition} +%\cs{texosquerypatsuffixcurrency}\marg{decimal pattern}\marg{text} +%\end{definition} +%This indicates a currency pattern with a suffixed international +%currency symbol where \meta{text} is inserted +%after the currency symbol. The shortcut is \cs{scur}. +% +%\begin{definition} +%\cs{texosquerypatsuffixicurrency}\marg{decimal pattern}\marg{text} +%\end{definition} +%This indicates an international currency pattern with a suffixed +%international currency symbol where \meta{text} is inserted +%after the symbol. The shortcut is \cs{sicur}. +% +%\begin{definition} +%\cs{texosquerypatprefixpercent}\marg{decimal pattern}\marg{text} +%\end{definition} +%This indicates a percentage pattern with a prefixed percent symbol where \meta{text} is inserted +%before the symbol. The shortcut is \cs{ppct}. +% +%\begin{definition} +%\cs{texosquerypatsuffixpercent}\marg{decimal pattern}\marg{text} +%\end{definition} +%This indicates a percentage pattern with a suffixed percent symbol where \meta{text} is inserted +%after the symbol. The shortcut is \cs{spct}. +% +%\begin{definition} +%\cs{texosquerypatprefixpermill}\marg{decimal pattern}\marg{text} +%\end{definition} +%This indicates a per-mill pattern with a prefixed per-mill symbol where \meta{text} is inserted +%before the symbol. The shortcut is \cs{ppml}. +% +%\begin{definition} +%\cs{texosquerypatsuffixpermill}\marg{decimal pattern}\marg{text} +%\end{definition} +%This indicates a per-mill pattern with a suffixed per-mill symbol where \meta{text} is inserted +%after the symbol. The shortcut is \cs{spml}. +% +%\begin{important} +%The integer parts \meta{integer part}, \meta{fraction part} +%and \meta{mantissa} must have \emph{exactly} ten digit identifiers. +%(\TeX\ can't reach 11 digit numbers.) +%\end{important} +% +%There are two types of digit identifiers: +%\begin{definition} +%\cs{texosquerypatdigit} +%\end{definition} +%This indicates a digit that must be displayed, even if it's not +%significant (for example a leading zero). The shortcut command is \verb|\0| (backslash zero). +% +%\begin{definition} +%\cs{texosquerypatdigitnozero} +%\end{definition} +%This indicates a digit that should only be displayed if it's +%significant. (For example, if it's a leading zero, it's not shown.) +%The shortcut command is \verb|\#| (backslash hash). +% +%The number group separator can be inserted using +%\begin{definition} +%\cs{texosquerypatgroupsep} +%\end{definition} +%The shortcut command is \verb|\,| (backslash comma). +% +%The sign can be inserted using +%\begin{definition} +%\cs{texosquerypatminus} +%\end{definition} +%This ensures the sign is displayed even if the number is positive. +%The shortcut command is \verb|\-| (backslash hyphen). +% +%Here's an example of a decimal pattern: +%\begin{verbatim} +%\texosquerydefpattern{\numpattern}{% +% \numfmt{\decfmt{\#\,\#\#\#\,\#\#\#\,\#\#\0}{\0\#\#\#\#\#\#\#\#\#}}} +%\end{verbatim} +%The pattern can be applied to a number using \cs{texosqueryfmtnumber}: +%\begin{verbatim} +%\texosqueryfmtnumber{\numpattern}{123}{4567}{2} +%\end{verbatim} +%which produces: 12,345.67 (the group and decimal separators can be +%redefined as appropriate). +% +%Here's an example of a scientific number: +%\begin{verbatim} +%\texosquerydefpattern{\sinumpattern}{% +% \sinumfmt +% {\decfmt{\#\,\#\#\#\,\#\#\#\,\#\#\0}{\0\#\#\#\#\#\#\#\#\#}}% +% {\-\#\#\#\#\#\#\#\#\0\0}% +%} +%\end{verbatim} +%The pattern can be applied to a number: +%\begin{verbatim} +%\texosqueryfmtnumber{\sinumpattern}{1}{234567}{3} +%\end{verbatim} +%which produces: 1.234567E+03 +% +%Here's an integer pattern: +%\begin{verbatim} +%\texosquerydefpattern{\intpattern}{% +% \patnumfmt{\#\,\#\#\#\,\#\#\#\,\#\#\0}} +%\end{verbatim} +%The pattern applied to a number: +%\begin{verbatim} +%\texosqueryfmtnumber{\intpattern}{123}{4567}{2} +%\end{verbatim} +%which produces: 12,345 (the fractional part has been omitted). +% +%Here's a currency pattern that applies a different format for +%positive and negative numbers: +%\begin{verbatim} +%\texosquerydefpattern{\curpattern}{% +% \pmnumfmt +% {\pcur{\decfmt{\#\,\#\#\#\,\#\#\#\,\#\#\0}{\0\0\#\#\#\#\#\#\#\#}}{}}% +% {\pcur{\decfmt{\#\,\#\#\#\,\#\#\#\,\#\#\0}{\0\0\#\#\#\#\#\#\#\#}}{\-}}} +%\end{verbatim} +%This uses the \meta{text} part of \cs{pcur} to insert the sign +%before the currency symbol (but only for negative values). +%\begin{verbatim} +%\texosqueryfmtnumber{\curpattern}{-1234567}{0}{0} +%\end{verbatim} +%This produces: $-$\$12,345,678.00 (again the symbol and separators +%can be redefined as appropriate). +% +%Here's an example of a percentage pattern: +%\begin{verbatim} +%\texosquerydefpattern{\pcpattern}{% +% \numfmt{\spct{\#\,\#\#\#\,\#\#\#\,\#\#\0}{}}} +%\end{verbatim} +%The pattern can similarly be applied to a number using +%\cs{texosqueryfmtnumber}. +% +%\begin{macro}{\texosquerydtf} +%\changes{1.2}{2017-03-23}{new} +%Date/time format placeholder. The second argument is the +%placeholder character and the first argument is the number of +%occurrences of that character in the placeholder. The default +%definition just converts it back to pattern format used by +%Java's +%\href{http://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html}{SimpleDateFormat +%class}. The pattern interprets $\ge4$ as a single case, so this +%will only produce a maximum of four characters. +% \begin{macrocode} +\def\texosquerydtf#1#2{% + \ifcase#1 + \or + #2% + \or + #2#2% + \or + #2#2#2% + \else + #2#2#2#2% + \fi +} +% \end{macrocode} +%\end{macro} +% +%The following commands are used to display the pattern in the +%document text to reproduce the pattern string recognised by Java. +%This is provided for debugging to check the pattern. In most cases +%the pattern will be applied to a number rather than simply +%displayed. +% +%\begin{macro}{\texosquerypatstr} +%\changes{1.2}{2017-03-23}{new} +%Quoted string contained in number format. +% \begin{macrocode} +\def\texosquerypatstr#1{'#1'} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatquote} +%\changes{1.2}{2017-03-23}{new} +%Literal quote contained in number format. +% \begin{macrocode} +\def\texosquerypatquote{''} +% \end{macrocode} +%\end{macro} +%Number format place holders. +%\begin{macro}{\texosquerypatplusminus} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatplusminus#1#2{#1;#2} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatnum} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatnum#1{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatsinum} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatsinum#1#2{#1E#2} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatdec} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatdec#1#2{#1.#2} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatprefixcurrency} +%\changes{1.2}{2017-03-23}{new} +%First argument is a number, the second is optional text before the +%currency symbol. This will require UTF-8 support otherwise it will +%need redefining as appropriate. (Similarly for the other currency +%commands and for the per-mill commands.) +% \begin{macrocode} +\def\texosquerypatprefixcurrency#1#2{#2¤#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatprefixicurrency} +%\changes{1.2}{2017-03-23}{new} +%As above but use international currency symbol. +% \begin{macrocode} +\def\texosquerypatprefixicurrency#1#2{#2¤¤#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatsuffixcurrency} +%\changes{1.2}{2017-03-23}{new} +%First argument is a number, the second is optional text after the +%currency symbol. +% \begin{macrocode} +\def\texosquerypatsuffixcurrency#1#2{#1¤#2} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatsuffixicurrency} +%\changes{1.2}{2017-03-23}{new} +%As above but use international currency symbol. +% \begin{macrocode} +\def\texosquerypatsuffixicurrency#1#2{#1¤¤#2} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatdigit} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatdigit{0} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatdigitnozero} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatdigitnozero{\#} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatminus} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatminus{-} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatgroupsep} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatgroupsep{,} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatprefixpercent} +%\changes{1.2}{2017-03-23}{new} +%The first argument is the value, the second argument is optional +%text before the percent symbol. +% \begin{macrocode} +\def\texosquerypatprefixpercent#1#2{#2\%#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatsuffixpercent} +%\changes{1.2}{2017-03-23}{new} +%The first argument is the value, the second argument is optional +%text after the percent symbol. +% \begin{macrocode} +\def\texosquerypatsuffixpercent#1#2{#1\%#2} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatprefixpermill} +%\changes{1.2}{2017-03-23}{new} +%The first argument is the value, the second argument is optional +%text before the per-mill symbol. +% \begin{macrocode} +\def\texosquerypatprefixpermill#1#2{#2‰#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatsuffixpermill} +%\changes{1.2}{2017-03-23}{new} +%The first argument is the value, the second argument is optional +%text after the per-mill symbol. +% \begin{macrocode} +\def\texosquerypatsuffixpermill#1#2{#1‰#2} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@pattern@shortcuts} +%Provide much shorter cuts for the convenience of directly defining +%patterns with \cs{texosquerydefpattern}. +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@pattern@shortcuts{% + \def\%{\noexpand\texosquerydtf}% + \def\0{\noexpand\texosquerypatdigit}% + \def\#{\noexpand\texosquerypatdigitnozero}% + \def\-{\noexpand\texosquerypatminus}% + \def\,{\noexpand\texosquerypatgroupsep}% + \def\numfmt{\noexpand\texosquerypatnum}% + \def\pmnumfmt{\noexpand\texosquerypatplusminus}% + \def\sinumfmt{\noexpand\texosquerypatsinum}% + \def\decfmt{\noexpand\texosquerypatdec}% + \def\pcur{\noexpand\texosquerypatprefixcurrency}% + \def\picur{\noexpand\texosquerypatprefixicurrency}% + \def\scur{\noexpand\texosquerypatsuffixcurrency}% + \def\sicur{\noexpand\texosquerypatsuffixicurrency}% + \def\ppct{\noexpand\texosquerypatprefixpercent}% + \def\spct{\noexpand\texosquerypatsuffixpercent}% + \def\ppml{\noexpand\texosquerypatprefixpermill}% + \def\spml{\noexpand\texosquerypatsuffixpermill}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerydefpattern} +%Define a new pattern using the shortcut markup. The first argument +%is the name of the control sequence in which to store the pattern +%provided in the second argument. Be careful of any fragile commands +%within the second argument. They will need protecting! +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerydefpattern#1#2{% + \begingroup + \@texosquery@pattern@shortcuts + \@texosquery@edef\x{\endgroup\def\noexpand#1{#2}}\x +} +% \end{macrocode} +%\end{macro} +% +% +%\subsubsection{Applying Date-Time Patterns} +%\label{sec:applydatetimepatterns} +%In order to apply date-time patterns, we need all the information about the +%date or time we're trying to format. +%\begin{enumerate} +%\item Era needed by the \texttt{G} designator. Java +%identifies the era by an integer (0 = BC and 1 = AD). +%\item Era text (e.g. AD) can be supplied by a macro. +%\item Year needed by the \texttt{y} designator. +%\item Week year needed by the \texttt{Y} designator. +%\item Month in year needed by the \texttt{M} or \texttt{L} +%designators. +%\item Month name needed by the \texttt{M} or \texttt{L} +%designators. This can be provided as macros that convert the month +%number to the name. Four macros are needed: short, full, standalone +%short and standalone full. +%\item Week in year needed by the \texttt{w} designator. +%\item Week in month needed by the \texttt{W} designator. +%\item Day in year needed by the \texttt{D} designator. +%\item Day in month needed by the \texttt{d} designator. +%\item Day of week in month needed by the \texttt{F} designator. +%\item Day name in week needed by the \texttt{E} designator. +%This can be provided as a macros that accepts the day of week +%number. The full form is needed for 4 letter patterns otherwise a +%short form. +%\item Day number of week (1 = Monday, 7 = Sunday) needed by the +%\texttt{u} designator. This means that +%the above day of week name macros needs to use Monday=1 base indexing. +%This means that \cs{pgfcalendarweekdayname} can't be used directly. +%\item AM/PM identifier needed by the \texttt{a} +%designator. Assume 0 = AM and 1 = PM to match Java. +%\item AM/PM text can be provided by a macro. +%\item Hour of the day (0-23) needed by the \texttt{H} +%designator. +%\item Hour in day (1-24) needed by the \texttt{k} +%designator. +%\item Hour in am/pm (0-11) needed by the \texttt{K} designator. +%\item Hour in am/pm (1-12) needed by the \texttt{h} designator. +%\item Minute in hour needed by the \texttt{m} designator. +%\item Second in minute needed by the \texttt{s} designator. +%\item Millisecond needed by the \texttt{S} designator. +%\item Time zone needed by the \texttt{z}, \texttt{Z} and \texttt{X} +%designators. This will require macros for converting the time zone +%to each of those formats. +%\end{enumerate} +%Supply a general utility command that has enough arguments to pass +%all the above information. A higher level user command can then be +%provided that determines all the arguments to provide an easier +%interface. +% +%The arguments need to be the pattern followed by +%\marg{era id}\marg{year}\marg{week year}\marg{month}\marg{week in +%year}\marg{week in month}\marg{day in year}\marg{day in month}\marg{day of +%week in month}\marg{day number of week}\marg{am/pm id}\marg{hour of day +%(H)}\marg{hour in day (k)}\marg{hour in am/pm (K)}\marg{hour in +%am/pm (h)}\marg{minute in hour}\marg{second in minute}\marg{millisecond}\marg{time zone} +%The arguments must all be integers except for the time zone which +%must be in the form +%\marg{TZh}\marg{TZm}\marg{id}\marg{dst flag}. These are the time zone hour and +%min offsets, time zone ID and daylight saving flag (1 if daylight +%saving in effect otherwise 0). These arguments can all be +%obtained using the \longarg{date-time} / \shortarg{M} action. +% +%We'll need some helper macros to get around the nine argument +%maximum limit. +% +%\begin{macro}{\texosqueryfmtdatetime} +%\changes{1.2}{2017-03-23}{new} +%The general utility command to format a pattern. The first argument +%is the pattern. After that are the date-time data arguments. +% \begin{macrocode} +\def\texosqueryfmtdatetime#1{% + \def\@texosquery@fmt@dt@pattern{#1}% + \@texosquery@fmt@getera +} +% \end{macrocode} +%\end{macro} +% +%All the remaining arguments except for the time zone must be +%integers. These are padded using \cs{@texosquery@paddigits}. +% +%\begin{macro}{\@texosquery@fmt@getera} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getera#1{% + \edef\@texosquery@fmt@G{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getyear +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getyear} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getyear#1{% + \edef\@texosquery@fmt@y{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getweekyear +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getweekyear} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getweekyear#1{% + \edef\@texosquery@fmt@Y{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getmonth +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getmonth} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getmonth#1{% + \edef\@texosquery@fmt@M{\@texosquery@paddigits{#1}}% + \let\@texosquery@fmt@L\@texosquery@fmt@M + \@texosquery@fmt@getweekinyear +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getweekinyear} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getweekinyear#1{% + \edef\@texosquery@fmt@w{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getweekinmonth +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getweekinmonth} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getweekinmonth#1{% + \edef\@texosquery@fmt@W{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getdayinyear +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getdayinyear} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getdayinyear#1{% + \edef\@texosquery@fmt@D{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getdayinmonth +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getdayinmonth} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getdayinmonth#1{% + \edef\@texosquery@fmt@d{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getdayofweekinmonth +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getdayofweekinmonth} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getdayofweekinmonth#1{% + \edef\@texosquery@fmt@F{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getdaynumberofweek +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getdaynumberofweek} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getdaynumberofweek#1{% + \edef\@texosquery@fmt@u{\@texosquery@paddigits{#1}}% + \let\@texosquery@fmt@E\@texosquery@fmt@u + \@texosquery@fmt@getampm +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getampm} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getampm#1{% + \edef\@texosquery@fmt@a{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gethourindayH +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@gethourindayH} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@gethourindayH#1{% + \edef\@texosquery@fmt@H{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gethourindayk +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@gethourindayk} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@gethourindayk#1{% + \edef\@texosquery@fmt@k{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gethourinampmK +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@gethourinampmK} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@gethourinampmK#1{% + \edef\@texosquery@fmt@K{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gethourinampmh +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@gethourinampmh} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@gethourinampmh#1{% + \edef\@texosquery@fmt@h{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getminute +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getminute} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getminute#1{% + \edef\@texosquery@fmt@m{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getsecond +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getsecond} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getsecond#1{% + \edef\@texosquery@fmt@s{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getmillisecond +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@getmillisecond} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@getmillisecond#1{% + \edef\@texosquery@fmt@S{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gettimezone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@gettimezone} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@gettimezone#1{% + \def\@texosquery@fmt@Z{#1}% + \def\@texosquery@fmt@z{#1}% + \def\@texosquery@fmt@X{#1}% +% \end{macrocode} +%All data now supplied. Temporarily redefine pattern markup and +%process the pattern. +% \begin{macrocode} + \begingroup + \@texosquery@setup@dtpattern + \@texosquery@fmt@dt@pattern + \endgroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@setup@dtpattern} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@setup@dtpattern{% + \let\texosquerydtf\@texosquery@fmt@dtf + \let\texosquerypatstr\texosquerypatfmtstr + \let\texosquerypatquote\texosquerypatfmtquote +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@paddigits@pos} +%\changes{1.2}{2017-03-23}{new} +%Pad positive number to 10 digits. \TeX\ can't reach 11 digits, so this is +%the maximum representation. +% \begin{macrocode} +\def\@texosquery@paddigits@pos#1{% + \ifnum#1<10 + 000000000\number#1 + \else + \ifnum#1<100 + 00000000\number#1 + \else + \ifnum#1<1000 + 0000000\number#1 + \else + \ifnum#1<10000 + 000000\number#1 + \else + \ifnum#1<100000 + 00000\number#1 + \else + \ifnum#1<1000000 + 0000\number#1 + \else + \ifnum#1<10000000 + 000\number#1 + \else + \ifnum#1<100000000 + 00\number#1 + \else + \ifnum#1<1000000000 + 0\number#1 + \else + \number#1 + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@paddigits} +%\changes{1.2}{2017-03-23}{new} +%This will expand to 11 characters (sign followed by 10 digits). +% \begin{macrocode} +\def\@texosquery@paddigits#1{% + \ifnum#1<0 +% \end{macrocode} +%Move the minus sign outside. +% \begin{macrocode} + -\expandafter\@texosquery@paddigits@pos\expandafter + {\@texosquery@gobble#1}% + \else + +\@texosquery@paddigits@pos{#1}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@paddigits@trailing} +%\changes{1.2}{2017-03-23}{new} +%Pad trailing zeros. +% \begin{macrocode} +\def\@texosquery@paddigits@trailing#1{% + \expandafter\@texosquery@tenoften@then@gobble + #10000000000\@texosquery@end@tenoften +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@tenoften@then@gobble} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@tenoften@then@gobble#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7#8#9% + \@texosquery@lastoften@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@lastoften@gobble} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@lastoften@gobble#1#2\@texosquery@end@tenoften{#1} +% \end{macrocode} +%\end{macro} +% +%Provide commands to select certain digits. (Sign not included.) +% +%\begin{macro}{\@texosquery@firstoften} +%\changes{1.2}{2017-03-23}{new} +%First of ten. +% \begin{macrocode} +\def\@texosquery@firstoften#1#2#3#4#5#6#7#8#9{% + #1% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@secondoften} +%\changes{1.2}{2017-03-23}{new} +%Second of ten. +% \begin{macrocode} +\def\@texosquery@secondoften#1#2#3#4#5#6#7#8#9{% + #2% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@thirdoften} +%\changes{1.2}{2017-03-23}{new} +%Third of ten. +% \begin{macrocode} +\def\@texosquery@thirdoften#1#2#3#4#5#6#7#8#9{% + #3% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fourthoften} +%\changes{1.2}{2017-03-23}{new} +%Fourth of ten. +% \begin{macrocode} +\def\@texosquery@fourthoften#1#2#3#4#5#6#7#8#9{% + #4% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fifthoften} +%\changes{1.2}{2017-03-23}{new} +%Fifth of ten. +% \begin{macrocode} +\def\@texosquery@fifthoften#1#2#3#4#5#6#7#8#9{% + #5% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@sixthoften} +%\changes{1.2}{2017-03-23}{new} +%Sixth of ten. +% \begin{macrocode} +\def\@texosquery@sixthoften#1#2#3#4#5#6#7#8#9{% + #6% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@seventhoften} +%\changes{1.2}{2017-03-23}{new} +%Seventh of ten. +% \begin{macrocode} +\def\@texosquery@seventhoften#1#2#3#4#5#6#7#8#9{% + #7% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@eighthoften} +%\changes{1.2}{2017-03-23}{new} +%Eighth of ten. +% \begin{macrocode} +\def\@texosquery@eighthoften#1#2#3#4#5#6#7#8#9{% + #8% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@ninthoften} +%\changes{1.2}{2017-03-23}{new} +%Ninth of ten. +% \begin{macrocode} +\def\@texosquery@ninthoften#1#2#3#4#5#6#7#8#9{% + #9% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@tenthoften} +%\changes{1.2}{2017-03-23}{new} +%Tenth of ten. +% \begin{macrocode} +\def\@texosquery@tenthoften#1#2#3#4#5#6#7#8#9{% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%Now macros to select first $n$ of ten. +% +%\begin{macro}{@texosquery@firsttwooften} +%\changes{1.2}{2017-03-23}{new} +%First two of ten. +% \begin{macrocode} +\def\@texosquery@firsttwooften#1#2#3#4#5#6#7#8#9{% + #1#2% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@firstthreeoften} +%\changes{1.2}{2017-03-23}{new} +%First three of ten. +% \begin{macrocode} +\def\@texosquery@firstthreeoften#1#2#3#4#5#6#7#8#9{% + #1#2#3% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@firstfouroften} +%\changes{1.2}{2017-03-23}{new} +%First four of ten. +% \begin{macrocode} +\def\@texosquery@firstfouroften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@firstfiveoften} +%\changes{1.2}{2017-03-23}{new} +%First five of ten. +% \begin{macrocode} +\def\@texosquery@firstfiveoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@firstsixoften} +%\changes{1.2}{2017-03-23}{new} +%First six of ten. +% \begin{macrocode} +\def\@texosquery@firstsixoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@firstsevenoften} +%\changes{1.2}{2017-03-23}{new} +%First seven of ten. +% \begin{macrocode} +\def\@texosquery@firstsevenoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@firsteightoften} +%\changes{1.2}{2017-03-23}{new} +%First eight of ten. +% \begin{macrocode} +\def\@texosquery@firsteightoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7#8% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@firstnineoften} +%\changes{1.2}{2017-03-23}{new} +%First nine of ten. +% \begin{macrocode} +\def\@texosquery@firstnineoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7#8#9% +% \end{macrocode} +%Grab tenth argument and discard. +% \begin{macrocode} + \@texosquery@gobble +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@alltenoften} +%\changes{1.2}{2017-03-23}{new} +%All ten. +% \begin{macrocode} +\def\@texosquery@alltenoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7#8#9% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%Select last $n$ of ten. +% +%\begin{macro}{@texosquery@lasttwooften} +%\changes{1.2}{2017-03-23}{new} +%Last two of ten. +% \begin{macrocode} +\def\@texosquery@lasttwooften#1#2#3#4#5#6#7#8#9{% + #9% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@lastthreeoften} +%\changes{1.2}{2017-03-23}{new} +%Last three of ten. +% \begin{macrocode} +\def\@texosquery@lastthreeoften#1#2#3#4#5#6#7#8#9{% + #8#9% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@lastfouroften} +%\changes{1.2}{2017-03-23}{new} +%Last four of ten. +% \begin{macrocode} +\def\@texosquery@lastfouroften#1#2#3#4#5#6#7#8#9{% + #7#8#9% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@lastfiveoften} +%\changes{1.2}{2017-03-23}{new} +%Last five of ten. +% \begin{macrocode} +\def\@texosquery@lastfiveoften#1#2#3#4#5#6#7#8#9{% + #6#7#8#9% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@lastsixoften} +%\changes{1.2}{2017-03-23}{new} +%Last six of ten. +% \begin{macrocode} +\def\@texosquery@lastsixoften#1#2#3#4#5#6#7#8#9{% + #5#6#7#8#9% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@lastsevenoften} +%\changes{1.2}{2017-03-23}{new} +%Last seven of ten. +% \begin{macrocode} +\def\@texosquery@lastsevenoften#1#2#3#4#5#6#7#8#9{% + #4#5#6#7#8#9% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@lasteightoften} +%\changes{1.2}{2017-03-23}{new} +%Last eight of ten. +% \begin{macrocode} +\def\@texosquery@lasteightoften#1#2#3#4#5#6#7#8#9{% + #3#4#5#6#7#8#9% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{@texosquery@lastnineoften} +%\changes{1.2}{2017-03-23}{new} +%Last nine of ten. +% \begin{macrocode} +\def\@texosquery@lastnineoften#1#2#3#4#5#6#7#8#9{% + #2#3#4#5#6#7#8#9% + \@texosquery@firstofone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmtminus} +%\changes{1.2}{2017-03-23}{new} +%Minus symbol for use in date-time patterns. +% \begin{macrocode} +\def\@texosquery@fmtminus{\texosquerypatfmtminus} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmtplus} +%\changes{1.2}{2017-03-23}{new} +%Plus symbol for use in date-time patterns. Omit by default. +% \begin{macrocode} +\def\@texosquery@fmtplus{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmtsign} +%\changes{1.2}{2017-03-23}{new} +%Plus or minus sign for use in date-time patterns. +% \begin{macrocode} +\def\@texosquery@fmtsign#1{% + \ifx#1+\@texosquery@fmtplus\else\@texosquery@fmtminus\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@atleastonedigit} +%\changes{1.2}{2017-03-23}{new} +%At least one digit with leading zeros removed. +% \begin{macrocode} +\def\@texosquery@atleastonedigit#1{% + \ifnum#1<0 + \@texosquery@fmtminus\number-#1 + \else + \number#1 + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@atleastfourdigits} +%\changes{1.2}{2017-03-23}{new} +%At least four digits, possible padded with zeros to make up four. The first +%argument is the sign, then follow the ten digits. +% \begin{macrocode} +\def\@texosquery@atleastfourdigits#1{% + \@texosquery@at@leastfourdigits#1\@texosquery@end@atleastfourdigits +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@at@leastfourdigits} +%\changes{1.2}{2017-03-23}{new} +%At least four digits, possible padded with zeros to make up four. The first +%argument is the sign, then follow the ten digits. +% \begin{macrocode} +\def\@texosquery@at@leastfourdigits#1#2\@texosquery@end@atleastfourdigits{% + \@texosquery@fmtsign{#1}% + \ifnum#2<1000 + \@texosquery@lastfouroften#2% + \else + \number#2 + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@threedigitsexactly} +%\changes{1.2}{2017-03-23}{new} +%Exactly three digits. +% \begin{macrocode} +\def\@texosquery@threedigitsexactly#1{% + \@texosquery@threedigits@exactly#1\@texosquery@threedigits@exactly +}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@threedigits@exactly} +%\changes{1.2}{2017-03-23}{new} +%Exactly three digits. +% \begin{macrocode} +\def\@texosquery@threedigits@exactly#1#2\@texosquery@threedigits@exactly{% + \@texosquery@fmtsign{#1}% + \@texosquery@lastthreeoften#2% +}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@twodigitsexactly} +%\changes{1.2}{2017-03-23}{new} +%Exactly two digits. +% \begin{macrocode} +\def\@texosquery@twodigitsexactly#1{% + \@texosquery@twodigits@exactly#1\@texosquery@twodigits@exactly +}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@twodigits@exactly} +%\changes{1.2}{2017-03-23}{new} +%Exactly two digits. +% \begin{macrocode} +\def\@texosquery@twodigits@exactly#1#2\@texosquery@twodigits@exactly{% + \@texosquery@fmtsign{#1}% + \@texosquery@lasttwooften#2% +}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fmt@dtf} +%\changes{1.2}{2017-03-23}{new} +%\begin{definition} +%\cs{@texosquery@fmt@dtf}\marg{n}\marg{designator} +%\end{definition} +% +%When formatting a date-time pattern \cs{texosquerydtf} will +%temporarily be redefined to this command. This command indicates +%the format obtained by \meta{n} instances of \meta{designator}. +%For example, \verb|{2}{M}| indicates the format \texttt{MM}. This +%command tests for \cs{texosqueryfmtpat}\meta{format}, which should +%take a single argument. If defined, that's used, otherwise use one +%of the numeric commands defined above. The \sty{locale} package +%defines \cs{texosqueryfmtpatMMM} and so on to use the locale's month names +%etc. +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fmt@dtf#1#2{% + \@texosquery@ifundef{@texosquery@fmt@#2}% + {\@texosquery@warn{Unknown date-time pattern designator `#2'}}% + {% + \ifcase#1 + \or + \@texosquery@ifundef{texosqueryfmtpat#2}% + {% + \expandafter\expandafter\expandafter + \@texosquery@atleastonedigit + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + {% + \csname texosqueryfmtpat#2\expandafter\expandafter\expandafter\endcsname + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + \or + \@texosquery@ifundef{texosqueryfmtpat#2#2}% + {% + \expandafter\expandafter\expandafter + \@texosquery@twodigitsexactly + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + {% + \csname texosqueryfmtpat#2#2\expandafter\expandafter\expandafter + \endcsname \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + \or + \@texosquery@ifundef{texosqueryfmtpat#2#2#2}% + {% + \expandafter\expandafter\expandafter + \@texosquery@threedigitsexactly + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + {% + \csname texosqueryfmtpat#2#2#2\expandafter\expandafter\expandafter + \endcsname \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + \else + \@texosquery@ifundef{texosqueryfmtpat#2#2#2#2}% + {% + \expandafter\expandafter\expandafter + \@texosquery@atleastfourdigits + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + {% + \csname texosqueryfmtpat#2#2#2#2\expandafter\expandafter\expandafter + \endcsname \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + \fi + }% +} +% \end{macrocode} +%\end{macro} +% +%Provide default commands for the time zone designators, since the +%time zone isn't supplied as a single integer. +% +%\begin{macro}{\texosqueryfmttimezonehr} +%\changes{1.2}{2017-03-23}{new} +%Allow for \verb|-0| so append 1 to hour in test. +% \begin{macrocode} +\def\texosqueryfmttimezonehr#1{% + \ifnum#11<0\@texosquery@fmtminus + \ifnum#1>-10 0\fi\number-#1 + \else + +\ifnum#1<10 0\fi\number#1 + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmttimezonenumhr} +%\changes{1.2}{2017-03-23}{new} +%Like the above, but don't zero-pad or prefix with plus sign. +% \begin{macrocode} +\def\texosqueryfmttimezonenumhr#1{% + \ifnum#11<0\@texosquery@fmtminus + \number-#1 + \else + \number#1 + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmttimezonemin} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosqueryfmttimezonemin#1{% + \ifnum#1<10 0\fi\number#1 +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@firstoffour} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@firstoffour#1#2#3#4{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@secondoffour} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@secondoffour#1#2#3#4{#2} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@thirdoffour} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@thirdoffour#1#2#3#4{#3} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@fourthoffour} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@fourthoffour#1#2#3#4{#4} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryshorttimezone} +%\changes{1.2}{2017-03-23}{new} +%Maps id to short time zone display name. This will need redefining +%as appropriate. The default simply expands to the ID. +%Mappings can be obtained for a particular locale using the +%\shortarg{Z} or \longarg{time-zones} action. +% \begin{macrocode} +\def\texosqueryshorttimezone#1{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryshortdstzone} +%\changes{1.2}{2017-03-23}{new} +%Maps id to short daylight saving time zone display name. This will need redefining +%as appropriate. The default simply expands to the ID followed by +%(DST). +% \begin{macrocode} +\def\texosqueryshortdstzone#1{#1 (DST)} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerylongtimezone} +%\changes{1.2}{2017-03-23}{new} +%Maps id to long time zone display name. This will need redefining +%as appropriate. The default simply expands to the ID. +% \begin{macrocode} +\def\texosquerylongtimezone#1{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerylongdstzone} +%\changes{1.2}{2017-03-23}{new} +%Maps id to long daylight saving time zone display name. This will need redefining +%as appropriate. The default simply expands to the ID followed by +%(DST). +% \begin{macrocode} +\def\texosquerylongdstzone#1{#1 (DST)} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerytimesep} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerytimesep{:} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatz} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{z} designator. +% \begin{macrocode} +\def\texosqueryfmtpatz#1{% + \expandafter\ifnum\@texosquery@fourthoffour#1=0 + \expandafter\texosqueryshorttimezone\expandafter{\@texosquery@thirdoffour#1}% + \else + \expandafter\texosqueryshortdstzone\expandafter{\@texosquery@thirdoffour#1}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatzz} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{zz} designator. +% \begin{macrocode} +\def\texosqueryfmtpatzz#1{% + \expandafter\ifnum\@texosquery@fourthoffour#1=0 + \expandafter\texosqueryshorttimezone\expandafter{\@texosquery@thirdoffour#1}% + \else + \expandafter\texosqueryshortdstzone\expandafter{\@texosquery@thirdoffour#1}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatzzz} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{zzz} designator. +% \begin{macrocode} +\def\texosqueryfmtpatzzz#1{% + \expandafter\ifnum\@texosquery@fourthoffour#1=0 + \expandafter\texosquerylongtimezone\expandafter{\@texosquery@thirdoffour#1}% + \else + \expandafter\texosquerylongdstzone\expandafter{\@texosquery@thirdoffour#1}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatzzzz} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{zzzz} designator. +% \begin{macrocode} +\def\texosqueryfmtpatzzzz#1{% + \expandafter\ifnum\@texosquery@fourthoffour#1=0 + \expandafter\texosquerylongtimezone\expandafter{\@texosquery@thirdoffour#1}% + \else + \expandafter\texosquerylongdstzone\expandafter{\@texosquery@thirdoffour#1}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatZ} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{Z} designator. +% \begin{macrocode} +\def\texosqueryfmtpatZ#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatZZ} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{ZZ} designator. +% \begin{macrocode} +\def\texosqueryfmtpatZZ#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatZZZ} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{ZZZ} designator. +% \begin{macrocode} +\def\texosqueryfmtpatZZZ#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatZZZZ} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{ZZZZ} designator. +% \begin{macrocode} +\def\texosqueryfmtpatZZZZ#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatX} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{X} designator. +% \begin{macrocode} +\def\texosqueryfmtpatX#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \texosquerytimesep + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatXX} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{XX} designator. +% \begin{macrocode} +\def\texosqueryfmtpatXX#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \texosquerytimesep + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatXXX} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{XXX} designator. +% \begin{macrocode} +\def\texosqueryfmtpatXXX#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \texosquerytimesep + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatXXXX} +%\changes{1.2}{2017-03-23}{new} +%Default time zone format for \texttt{XXXX} designator. +% \begin{macrocode} +\def\texosqueryfmtpatXXXX#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \texosquerytimesep + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpata} +%\changes{1.2}{2017-03-23}{new} +%Default am/pm designator for the \texttt{a} designator. +% \begin{macrocode} +\def\texosqueryfmtpata#1{% + \ifnum#1=0 AM\else PM\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpataa} +%\changes{1.2}{2017-03-23}{new} +%Default am/pm for the \texttt{aa} designator. Just make it the same +%as the \texttt{a} designator. +% \begin{macrocode} +\def\texosqueryfmtpataa{\texosqueryfmtpata} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpataaa} +%\changes{1.2}{2017-03-23}{new} +%Default am/pm for the \texttt{aaa} designator. Just make it the same +%as the \texttt{a} designator. +% \begin{macrocode} +\def\texosqueryfmtpataaa{\texosqueryfmtpata} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpataaaa} +%\changes{1.2}{2017-03-23}{new} +%Default am/pm for the \texttt{aaaa} designator. Just make it the same +%as the \texttt{a} designator. +% \begin{macrocode} +\def\texosqueryfmtpataaaa{\texosqueryfmtpata} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatG} +%\changes{1.2}{2017-03-23}{new} +%Default era designator for the \texttt{G} designator. +% \begin{macrocode} +\def\texosqueryfmtpatG#1{% + \ifnum#1=1 AD\else BC\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatGG} +%\changes{1.2}{2017-03-23}{new} +%Default era for the \texttt{GG} designator. Just make it the same +%as the \texttt{G} designator. +% \begin{macrocode} +\def\texosqueryfmtpatGG{\texosqueryfmtpatG} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatGGG} +%\changes{1.2}{2017-03-23}{new} +%Default era for the \texttt{GGG} designator. Just make it the same +%as the \texttt{G} designator. +% \begin{macrocode} +\def\texosqueryfmtpatGGG{\texosqueryfmtpatG} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosqueryfmtpatGGGG} +%\changes{1.2}{2017-03-23}{new} +%Default era for the \texttt{GGGG} designator. Just make it the same +%as the \texttt{G} designator. +% \begin{macrocode} +\def\texosqueryfmtpatGGGG{\texosqueryfmtpatG} +% \end{macrocode} +%\end{macro} +% +% +%\subsubsection{Applying Numeric Patterns} +%\label{sec:applynumpatterns} +% +%\begin{macro}{\texosqueryfmtnumber} +%\changes{1.2}{2017-03-23}{new} +%\begin{definition} +%\cs{texosqueryfmtnumber}\marg{pattern}\marg{int}\marg{frac}\marg{mantissa} +%\end{definition} +%General purpose low-level number formatting command. The first argument +%\meta{pattern} is the pattern. The other arguments are unformatted integers +%and must be present and not exceed 10 digits each. The \meta{frac} part must +%not start with a sign. The minus sign should go at the start of +%\meta{int} for negative numbers. The plus sign is +%optional for positive \meta{int} or \meta{mantissa} and not +%permitted in \meta{frac}. The arguments may each be the actual numerical +%value or be a single control sequence whose replacement text is +%the value. Avoid anything more complicated than that. +% +%This package doesn't provide a higher level command that can split a number +%into integer, fractional and mantissa parts. +% \begin{macrocode} +\def\texosqueryfmtnumber#1#2#3#4{% + \begingroup + \let\texosquerypatstr\texosquerypatfmtstr + \let\texosquerypatquote\texosquerypatfmtquote + \let\texosquerypatplusminus\texosquerypatfmt@plusminus + \let\texosquerypatnum\texosquerypatfmt@num + \let\texosquerypatsinum\texosquerypatfmt@sinum + \let\texosquerypatdec\texosquerypatfmt@dec + \let\texosquerypatprefixcurrency\texosquery@patfmt@prefixcurrency + \let\texosquerypatprefixicurrency\texosquery@patfmt@prefixicurrency + \let\texosquerypatsuffixcurrency\texosquery@patfmt@suffixcurrency + \let\texosquerypatsuffixicurrency\texosquery@patfmt@suffixicurrency + \let\texosquerypatdigit\texosquerypatfmt@digit + \let\texosquerypatdigitnozero\texosquerypatfmt@digitnozero + \let\texosquerypatgroupsep\texosquerypatfmt@groupsep + \let\texosquerypatprefixpercent\texosquery@patfmt@prefixpercent + \let\texosquerypatsuffixpercent\texosquery@patfmt@suffixpercent + \let\texosquerypatprefixpermill\texosquery@patfmt@prefixpermill + \let\texosquerypatsuffixpermill\texosquery@patfmt@suffixpermill + \let\texosquerypatminus\@texosquerypat@numfmt@sign + \let\texosquerypatfmt@decsep\texosquerypatfmtdecsep +% \end{macrocode} +%Allow for negative zero in the \meta{int} part. To avoid overflow, +%first check for 0 and then append 1 to the number to +%catch \verb|-0|. +% \begin{macrocode} + \edef\@texosquery@sgn{% + \ifnum#2=0 + \expandafter\ifnum#21<0 -\else+\fi + \else + \ifnum#2<0 -\else+\fi + \fi + }% +% \end{macrocode} +%Allow for arguments passed as control sequences that expand to a +%number. +% \begin{macrocode} + \edef\@texosquery@int{\expandafter\@texosquery@paddigits + \expandafter{\number#2}}% + \let\@texosquery@si@int\@texosquery@int +% \end{macrocode} +%Can't use \cs{number} here as we'll lose any leading zeros. +% \begin{macrocode} + \edef\@texosquery@frac{\expandafter\@texosquery@paddigits@trailing + \expandafter{#3}}% + \let\@texosquery@si@frac\@texosquery@frac + \edef\@texosquery@mantissa{\expandafter\@texosquery@paddigits + \expandafter{\number#4}}% +% \end{macrocode} +%Is the mantissa non-zero? +% \begin{macrocode} + \ifnum#4=0\relax + \else + \expandafter\ifx\@texosquery@sgn-% + \edef\@texosquery@int{\expandafter + \@texosquery@paddigits@pos\expandafter{\number-#2}}% + \else + \edef\@texosquery@int{\@texosquery@paddigits@pos{#2}}% + \fi +% \end{macrocode} +%Shift. +% \begin{macrocode} + \ifnum#4<0 + \expandafter\@texosquery@neg@shift\expandafter{\number-#4}% + \else + \@texosquery@pos@shift{#4}% + \fi + \expandafter\ifx\@texosquery@sgn-% + \edef\@texosquery@int{\expandafter\@texosquery@paddigits + \expandafter{\number-\@texosquery@int}}% + \else + \edef\@texosquery@int{\expandafter\@texosquery@paddigits + \expandafter{\number\@texosquery@int}}% + \fi + \edef\@texosquery@frac{\@texosquery@paddigits@trailing{\@texosquery@frac}}% + \fi + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% + \let\@texosquery@zerodigit\@texosquery@zerodigit@leading + \expandafter\ifx\@texosquery@sgn-% + \let\@texosquery@currentsign\texosquerypatfmtminus + \else + \let\@texosquery@currentsign\texosquerypatfmtplus + \fi + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + #1% + \endgroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@digitindex} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\newcount\@texosquery@digitindex +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\if@texosquery@digitfound} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\newif\if@texosquery@digitfound +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@pos@shift} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@pos@shift#1{% + \ifcase#1 + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastnineoften\@texosquery@int + \expandafter\@texosquery@firstoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastnineoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lasteightoften\@texosquery@int + \expandafter\@texosquery@firsttwooften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lasteightoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastsevenoften\@texosquery@int + \expandafter\@texosquery@firstthreeoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastsevenoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastsixoften\@texosquery@int + \expandafter\@texosquery@firstfouroften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastsixoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastfiveoften\@texosquery@int + \expandafter\@texosquery@firstfiveoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastfiveoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastfouroften\@texosquery@int + \expandafter\@texosquery@firstsixoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastfouroften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastthreeoften\@texosquery@int + \expandafter\@texosquery@firstsevenoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastthreeoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lasttwooften\@texosquery@int + \expandafter\@texosquery@firsteightoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lasttwooften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@tenthoften\@texosquery@int + \expandafter\@texosquery@firstnineoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@tenthoften\@texosquery@frac + }% + \or + \let\@texosquery@int\@texosquery@frac + \edef\@texosquery@frac{0}% +% \end{macrocode} +%Anything larger will require scientific notation. Hopefully the +%pattern supports this. +% \begin{macrocode} + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@neg@shift} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@neg@shift#1{% + \ifcase#1 + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastoneoften\@texosquery@int + \expandafter\@texosquery@firstnineoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstnineoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lasttwooften\@texosquery@int + \expandafter\@texosquery@firsteightoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firsteightoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastthreeoften\@texosquery@int + \expandafter\@texosquery@firstsevenoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstsevenoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastfouroften\@texosquery@int + \expandafter\@texosquery@firstsixoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstsixoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastfiveoften\@texosquery@int + \expandafter\@texosquery@firstfiveoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstfiveoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastsixoften\@texosquery@int + \expandafter\@texosquery@firstfouroften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstfouroften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastsevenoften\@texosquery@int + \expandafter\@texosquery@firstthreeoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstthreeoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lasteightoften\@texosquery@int + \expandafter\@texosquery@firsttwooften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firsttwooften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastnineoften\@texosquery@int + \expandafter\@texosquery@firstoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{\@texosquery@int\@texosquery@frac}% + \edef\@texosquery@int{0}% +% \end{macrocode} +%Anything beyond this will require scientific notation. Hopefully the +%pattern supports it. +% \begin{macrocode} + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquerypat@numfmt@sign} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquerypat@numfmt@sign{% + \@texosquery@currentsign + \let\@texosquery@currentsign\empty +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\texosquerypatfmtstr} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmtstr#1{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmtquote} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmtquote{'} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmt@plusminus} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmt@plusminus#1#2{% + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + \expandafter\ifx\@texosquery@sgn-% + #2% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#2}% + \fi + \else + #1% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#1}% + \fi + \fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmt@num} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmt@num#1{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmtexp} +%\changes{1.2}{2017-03-23}{new} +%Exponent symbol. Change as appropriate. +% \begin{macrocode} +\def\texosquerypatfmtexp{E} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerypatfmt@sinum} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmt@sinum#1#2{% + \let\@texosquery@int\@texosquery@si@int + \let\@texosquery@frac\@texosquery@si@frac + \let\@texosquery@current\@texosquery@int + #1% + \texosquerypatfmtexp + {\let\@texosquery@zerodigit\@texosquery@zerodigit@leading + \ifnum\@texosquery@mantissa<0\relax + \let\@texosquery@currentsign\texosquerypatfmtminus + \else + \let\@texosquery@currentsign\texosquerypatfmtplus + \fi + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@mantissa}% + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + #2}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmtdecsep} +%\changes{1.2}{2017-03-23}{new} +%Decimal separator. Change as appropriate. +% \begin{macrocode} +\def\texosquerypatfmtdecsep{.} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerypatfmtcurdecsep} +%\changes{1.2}{2017-03-23}{new} +%Currency decimal separator. Change as appropriate. +% \begin{macrocode} +\def\texosquerypatfmtcurdecsep{.} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerypatfmt@dec} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmt@dec#1#2{% + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + \let\@texosquery@zerodigit\@texosquery@zerodigit@leading + #1% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#1}% + \fi + \texosquerypatfmt@decsep + \let\@texosquery@current\@texosquery@frac + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + \let\@texosquery@zerodigit\@texosquery@zerodigit@trailing + \let\@texosquery@currentsign\empty + #2% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#2}% + \fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmtint} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmtint#1{% + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + \let\@texosquery@zerodigit\@texosquery@zerodigit@leading + #1% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#1}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@setpatdisplay} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@setpatdisplay{% + \def\texosquerypatstr##1{'##1'}% + \def\texosquerypatquote{''}% + \def\texosquerypatplusminus##1##2{##1;##2}% + \def\texosquerypatnum##1{##1}% + \def\texosquerypatsinum##1##2{##1E##2}% + \def\texosquerypatdec##1##2{##1.##2}% + \def\texosquerypatprefixcurrency##1##2{##2¤##1}% + \def\texosquerypatprefixicurrency##1##2{##2¤¤##1}% + \def\texosquerypatsuffixcurrency##1##2{##1¤##2}% + \def\texosquerypatsuffixicurrency##1##2{##1¤¤##2}% + \def\texosquerypatdigit{0}% + \def\texosquerypatdigitnozero{\#}% + \def\texosquerypatminus{-}% + \def\texosquerypatgroupsep{,}% + \def\texosquerypatprefixpercent##1##2{##2\%##1}% + \def\texosquerypatsuffixpercent##1##2{##1\%##2}% + \def\texosquerypatprefixpermill##1##2{##2‰##1}% + \def\texosquerypatsuffixpermill##1##2{##1‰##2}% + \def\texosquerypatfmt@decsep{.}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@invalidpattern} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@invalidpattern#1{% + \begingroup + \@texosquery@setpatdisplay + \@texosquery@err{10 digit specifiers expected in + numeric pattern #1. Found \number\@texosquery@digitindex}% + {Each integer element of a numeric pattern must have exactly + 10 digit specifiers (0 or \#)}% + \endgroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerypatfmtcurrencysign} +%\changes{1.2}{2017-03-23}{new} +%Currency symbol. Redefine as appropriate. +% \begin{macrocode} +\def\texosquerypatfmtcurrencysign{\$} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerypatfmticurrencysign} +%\changes{1.2}{2017-03-23}{new} +%International currency symbol. There's no generic fallback that's +%independent of the input encoding, so this uses a UTF-8 character +%on the assumption that if \cs{textcurrency} isn't available (for +%example, through \sty{textcomp}, then the user may be using \XeTeX\ +%or \LuaTeX). If this isn't the case, and there's no UTF-8 support, +%then this command will need to be redefined as appropriate. +% \begin{macrocode} +\ifx\textcurrency\undefined + \def\texosquerypatfmticurrencysign{¤} +\else + \def\texosquerypatfmticurrencysign{\textcurrency} +\fi +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquery@patfmt@prefixcurrency} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquery@patfmt@prefixcurrency#1#2{% + \let\texosquerypatfmt@decsep\texosquerypatfmtcurdecsep + #2\texosquerypatfmtcurrencysign#1% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquery@patfmt@prefixicurrency} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquery@patfmt@prefixicurrency#1#2{% + \let\texosquerypatfmt@decsep\texosquerypatfmtcurdecsep + #2\texosquerypatfmticurrencysign#1% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquery@patfmt@suffixcurrency} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquery@patfmt@suffixcurrency#1#2{% + \let\texosquerypatfmt@decsep\texosquerypatfmtcurdecsep + #1\texosquerypatfmtcurrencysign#2% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquery@patfmt@suffixicurrency} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquery@patfmt@suffixicurrency#1#2{% + \let\texosquerypatfmt@decsep\texosquerypatfmtcurdecsep + #1\texosquerypatfmticurrencysign#2% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmt@digit} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmt@digit{% + \advance\@texosquery@digitindex by 1\relax + \if@texosquery@digitfound + \else + \ifx\@texosquery@currentsign\texosquerypatfmtminus + \texosquerypatfmtminus + \let\@texosquery@currentsign\empty + \fi + \fi + \@texosquery@digitfoundtrue + \ifcase\@texosquery@digitindex + \or + \expandafter\@texosquery@firstoften\@texosquery@current + \or + \expandafter\@texosquery@secondoften\@texosquery@current + \or + \expandafter\@texosquery@thirdoften\@texosquery@current + \or + \expandafter\@texosquery@fourthoften\@texosquery@current + \or + \expandafter\@texosquery@fifthoften\@texosquery@current + \or + \expandafter\@texosquery@sixthoften\@texosquery@current + \or + \expandafter\@texosquery@seventhoften\@texosquery@current + \or + \expandafter\@texosquery@eighthoften\@texosquery@current + \or + \expandafter\@texosquery@ninthoften\@texosquery@current + \or + \expandafter\@texosquery@tenthoften\@texosquery@current + \fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmt@digitnozero} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmt@digitnozero{% + \advance\@texosquery@digitindex by 1\relax + \edef\@texosquery@digit{% + \ifcase\@texosquery@digitindex + 0% + \or + \expandafter\@texosquery@firstoften\@texosquery@current + \or + \expandafter\@texosquery@secondoften\@texosquery@current + \or + \expandafter\@texosquery@thirdoften\@texosquery@current + \or + \expandafter\@texosquery@fourthoften\@texosquery@current + \or + \expandafter\@texosquery@fifthoften\@texosquery@current + \or + \expandafter\@texosquery@sixthoften\@texosquery@current + \or + \expandafter\@texosquery@seventhoften\@texosquery@current + \or + \expandafter\@texosquery@eighthoften\@texosquery@current + \or + \expandafter\@texosquery@ninthoften\@texosquery@current + \or + \expandafter\@texosquery@tenthoften\@texosquery@current + \else + 0% + \fi + }% + \ifnum\@texosquery@digit=0\relax + \@texosquery@zerodigit + \else + \if@texosquery@digitfound + \else + \ifx\@texosquery@currentsign\texosquerypatfmtminus + \texosquerypatfmtminus + \let\@texosquery@currentsign\empty + \fi + \fi + \@texosquery@digitfoundtrue + \@texosquery@digit + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@zerodigit@leading} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@zerodigit@leading{% + \edef\@texosquery@digit{% + \ifcase\@texosquery@digitindex + 0% + \or + \expandafter\@texosquery@firstoften\@texosquery@current + \or + \expandafter\@texosquery@firsttwooften\@texosquery@current + \or + \expandafter\@texosquery@firstthreeoften\@texosquery@current + \or + \expandafter\@texosquery@firstfouroften\@texosquery@current + \or + \expandafter\@texosquery@firstfiveoften\@texosquery@current + \or + \expandafter\@texosquery@firstsixoften\@texosquery@current + \or + \expandafter\@texosquery@firstsevenoften\@texosquery@current + \or + \expandafter\@texosquery@firsteightoften\@texosquery@current + \or + \expandafter\@texosquery@firstnineoften\@texosquery@current + \or + \@texosquery@current + \else + 0% + \fi + }% + \ifnum\@texosquery@digit>0\relax + \if@texosquery@digitfound + \else + \ifx\texosquerypatminus\texosquerypatfmtminus + \texosquerypatfmtminus + \fi + \fi + \@texosquery@digitfoundtrue + 0% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@zerodigit@trailing} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@zerodigit@trailing{% + \edef\@texosquery@digit{% + \ifcase\@texosquery@digitindex + 0% + \or + \@texosquery@current + \or + \expandafter\@texosquery@lastnineoften\@texosquery@current + \or + \expandafter\@texosquery@lasteightoften\@texosquery@current + \or + \expandafter\@texosquery@lastsevenoften\@texosquery@current + \or + \expandafter\@texosquery@lastsixoften\@texosquery@current + \or + \expandafter\@texosquery@lastfiveoften\@texosquery@current + \or + \expandafter\@texosquery@lastfouroften\@texosquery@current + \or + \expandafter\@texosquery@lastthreeoften\@texosquery@current + \or + \expandafter\@texosquery@lasttwooften\@texosquery@current + \or + \expandafter\@texosquery@tenthoften\@texosquery@current + \else + 0% + \fi + }% + \ifnum\@texosquery@digit>0\relax + \if@texosquery@digitfound + \else + \ifx\texosquerypatminus\texosquerypatfmtminus + \texosquerypatfmtminus + \fi + \fi + \@texosquery@digitfoundtrue + 0% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerypatfmtminus} +%\changes{1.2}{2017-03-23}{new} +%Formatted minus sign. Redefined as appropriate. +% \begin{macrocode} +\def\texosquerypatfmtminus{\ifmmode-\else$-$\fi} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmtplus} +%\changes{1.2}{2017-03-23}{new} +%Formatted plus sign. Redefined as appropriate. +% \begin{macrocode} +\def\texosquerypatfmtplus{\ifmmode+\else$+$\fi} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmtgroupsep} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmtgroupsep{,} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquerypatfmt@groupsep} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquerypatfmt@groupsep{% + \if@texosquery@digitfound\texosquerypatfmtgroupsep\fi} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerypatfmtpercentsign} +%\changes{1.2}{2017-03-23}{new} +%Percent sign used in number format. +% \begin{macrocode} +\def\texosquerypatfmtpercentsign{\%} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquerypatfmtpermillsign} +%\changes{1.2}{2017-03-23}{new} +%Per-mill sign used in number format. Redefine as appropriate. +% \begin{macrocode} +\def\texosquerypatfmtpermillsign{‰} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@texosquery@adjust@per} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\@texosquery@adjust@per#1{% + \@texosquery@pos@shift{#1}% + \edef\@texosquery@int{\expandafter\@texosquery@paddigits + \expandafter{\number\@texosquery@int}}% + \edef\@texosquery@frac{\@texosquery@paddigits@trailing{\@texosquery@frac}}% + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\texosquery@patfmt@prefixpercent} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquery@patfmt@prefixpercent#1#2{% + \@texosquery@adjust@per{2}% + #2\texosquerypatfmtpercentsign#1% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquery@patfmt@suffixpercent} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquery@patfmt@suffixpercent#1#2{% + \@texosquery@adjust@per{2}% + #1\texosquerypatfmtpercentsign#2% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquery@patfmt@prefixpermill} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquery@patfmt@prefixpermill#1#2{% + \@texosquery@adjust@per{3}% + #2\texosquerypatfmtpermillsign#1% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\texosquery@patfmt@suffixpermill} +%\changes{1.2}{2017-03-23}{new} +% \begin{macrocode} +\def\texosquery@patfmt@suffixpermill#1#2{% + \@texosquery@adjust@per{3}% + #1\texosquerypatfmtpermillsign#2% +} +% \end{macrocode} +%\end{macro} +% %All done. %Restore the category code of \texttt{@}: % \begin{macrocode} @@ -810,7 +7529,7 @@ %\fi % %\subsection{\LaTeX\ Code} -%This is just a simple wrapper for \texttt{texosquery.tex} +%This is just a simple wrapper for \file{texosquery.tex} %so that it can be loaded using \LaTeX's standard \cs{usepackage} %method. %\iffalse @@ -821,18 +7540,160 @@ %Identify package: % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{texosquery}[2016/07/14 v1.1 (NLCT)] +\ProvidesPackage{texosquery}[2017/03/23 v1.2 (NLCT)] % \end{macrocode} -%Load \texttt{texosquery.tex}: +%Load \file{texosquery.tex}: % \begin{macrocode} \input{texosquery} % \end{macrocode} -%That's it! %\iffalse % \begin{macrocode} %</texosquery.sty> % \end{macrocode} %\fi % +%\subsection{Configuration File (\file{texosquery.cfg})} +%The configuration file. This will need to be edited as appropriate +%to the system. +%\iffalse +% \begin{macrocode} +%<*texosquery.cfg> +% \end{macrocode} +%\fi +% \begin{macrocode} + %If this configuration file is added to TeX's path, it can + %be used to set up the texosquery defaults for the installation. + + %Default application (must be installed on the operating system's + %path). Change as appropriate. Available options: + % * texosquery-jre8 (at least Java 8 required) + % * texosquery (at least Java 7 required) + % * texosquery-jre5 (at least Java 5 required) + %(bash users need to check that the .sh extension has been removed + %from the bash scripts, or add the extension to the invoker name.) +\def\TeXOSInvokerName{texosquery} + + % If the invoker name given above is on the restricted list, + % allow it to be run in restricted mode: + %\TeXOSQueryAllowRestricted +% \end{macrocode} +%\iffalse +% \begin{macrocode} +%</texosquery.cfg> +% \end{macrocode} +%\fi +%\subsection{Bash Scripts} +%These are the bash scripts for Unix-like systems. +%The first line +%\begin{verbatim} +%#!/bin/sh +%\end{verbatim} +%is added when the files are extracted by \file{texosquery.ins} +%(since \verb|\nopreamble| automatically inserts a blank line at the +%start of the file). +%\iffalse +% \begin{macrocode} +%<*texosquery.sh> +% \end{macrocode} +%\fi +%\subsubsection{\file{texosquery.sh}} +% \begin{macrocode} +jarpath=`kpsewhich --progname=texosquery --format=texmfscripts texosquery.jar` +java -jar "$jarpath" "$@" +% \end{macrocode} +%\iffalse +% \begin{macrocode} +%</texosquery.sh> +% \end{macrocode} +%\fi +% +%\iffalse +% \begin{macrocode} +%<*texosquery-jre8.sh> +% \end{macrocode} +%\fi +%\subsubsection{\file{texosquery-jre8.sh}} +% \begin{macrocode} +jarpath=`kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre8.jar` +java -Djava.locale.providers=CLDR,JRE -jar "$jarpath" "$@" +% \end{macrocode} +%\iffalse +% \begin{macrocode} +%</texosquery-jre8.sh> +% \end{macrocode} +%\fi +% +%\iffalse +% \begin{macrocode} +%<*texosquery-jre5.sh> +% \end{macrocode} +%\fi +%\subsubsection{\file{texosquery-jre5.sh}} +% \begin{macrocode} +jarpath=`kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre5.jar` +java -jar "$jarpath" "$@" +% \end{macrocode} +%\iffalse +% \begin{macrocode} +%</texosquery-jre5.sh> +% \end{macrocode} +%\fi +% +%\subsection{Windows Batch Scripts} +%These are the batch scripts for Windows. \TeX\ on Windows doesn't +%allow the creation of \file{.bat} files, so \file{.ins} file +%creates these with the extension \file{.batch} which will need to +%be changed to \file{.bat} after extraction. +%\iffalse +% \begin{macrocode} +%<*texosquery.bat> +% \end{macrocode} +%\fi +%\subsubsection{\file{texosquery.bat}} +% \begin{macrocode} +@ECHO OFF +FOR /F %%I IN ('kpsewhich --progname=texosquery --format=texmfscripts texosquery.jar') DO SET JARPATH=%%I +java -jar "%JARPATH%" %* +% \end{macrocode} +%\iffalse +% \begin{macrocode} +%</texosquery.bat> +% \end{macrocode} +%\fi +% +%\iffalse +% \begin{macrocode} +%<*texosquery-jre8.bat> +% \end{macrocode} +%\fi +%\subsubsection{\file{texosquery-jre8.bat}} +% \begin{macrocode} +@ECHO OFF +FOR /F %%I IN ('kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre8.jar') DO SET JARPATH=%%I +java -Djava.locale.providers=CLDR,JRE -jar "%JARPATH%" %* +% \end{macrocode} +%\iffalse +% \begin{macrocode} +%</texosquery-jre8.bat> +% \end{macrocode} +%\fi +% +%\iffalse +% \begin{macrocode} +%<*texosquery-jre5.bat> +% \end{macrocode} +%\fi +%\subsubsection{\file{texosquery-jre5.bat}} +% \begin{macrocode} +@ECHO OFF +FOR /F %%I IN ('kpsewhich --progname=texosquery --format=texmfscripts texosquery-jre5.jar') DO SET JARPATH=%%I +java -jar "%JARPATH%" %* +% \end{macrocode} +%\iffalse +% \begin{macrocode} +%</texosquery-jre5.bat> +% \end{macrocode} +%\fi +% %\Finale \endinput diff --git a/Master/texmf-dist/source/support/texosquery/texosquery.ins b/Master/texmf-dist/source/support/texosquery/texosquery.ins index b86ef27d4fa..a5fe73878e8 100644 --- a/Master/texmf-dist/source/support/texosquery/texosquery.ins +++ b/Master/texmf-dist/source/support/texosquery/texosquery.ins @@ -1,9 +1,8 @@ \input docstrip \preamble - texosquery - Copyright 2016 Nicola Talbot + Copyright 2017 Nicola Talbot This work may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3 @@ -18,11 +17,24 @@ The Current Maintainer of this work is Nicola Talbot. This work consists of the files texosquery.dtx and texosquery.ins - and the derived files texosquery.sty, texosquery.tex. - Additionally, the Java application texosquery.jar and bash script - texosquery + and the derived files texosquery.sty, texosquery.tex and + texosquery.cfg. Additionally, the Java applications texosquery.jar, + texosquery-jre5.jar, texosquery-jre8.jar, the bash scripts + texosquery.sh, texosquery-jre5.sh, texosquery-jre8.sh, and + the corresponding batch files. \endpreamble +%The following is to prevent a blank line from appearing +%at the start of the bash scripts (which occurs when simply using +%\nopreamble). + +\ifx\@gobble\undefined + \def\@gobble#1{} +\fi +\def\literalhash{\expandafter\@gobble\string\#} + +\def\bashpreamble{\literalhash !/bin/sh} + \askforoverwritefalse \generate @@ -39,6 +51,42 @@ \usepostamble\defaultpostamble \from{texosquery.dtx}{texosquery.tex,package}% } + \file{texosquery.cfg}% + {% + \usepreamble\defaultpreamble + \usepostamble\defaultpostamble + \from{texosquery.dtx}{texosquery.cfg,package}% + } + \file{texosquery.sh}% + {% + \usepreamble\bashpreamble\nopostamble + \from{texosquery.dtx}{texosquery.sh}% + } + \file{texosquery-jre5.sh}% + {% + \usepreamble\bashpreamble\nopostamble + \from{texosquery.dtx}{texosquery-jre5.sh}% + } + \file{texosquery-jre8.sh}% + {% + \usepreamble\bashpreamble\nopostamble + \from{texosquery.dtx}{texosquery-jre8.sh}% + } + \file{texosquery.batch}% + {% + \nopreamble\nopostamble + \from{texosquery.dtx}{texosquery.bat}% + } + \file{texosquery-jre5.batch}% + {% + \nopreamble\nopostamble + \from{texosquery.dtx}{texosquery-jre5.bat}% + } + \file{texosquery-jre8.batch}% + {% + \nopreamble\nopostamble + \from{texosquery.dtx}{texosquery-jre8.bat}% + } } \endbatchfile diff --git a/Master/texmf-dist/tex/latex/texosquery/texosquery.cfg b/Master/texmf-dist/tex/latex/texosquery/texosquery.cfg new file mode 100644 index 00000000000..9422e0c7feb --- /dev/null +++ b/Master/texmf-dist/tex/latex/texosquery/texosquery.cfg @@ -0,0 +1,62 @@ +%% +%% This is file `texosquery.cfg', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% texosquery.dtx (with options: `texosquery.cfg,package') +%% texosquery +%% Copyright 2017 Nicola Talbot +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3 +%% of this license of (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status `maintained'. +%% +%% The Current Maintainer of this work is Nicola Talbot. +%% +%% This work consists of the files texosquery.dtx and texosquery.ins +%% and the derived files texosquery.sty, texosquery.tex and +%% texosquery.cfg. Additionally, the Java applications texosquery.jar, +%% texosquery-jre5.jar, texosquery-jre8.jar, the bash scripts +%% texosquery.sh, texosquery-jre5.sh, texosquery-jre8.sh, and +%% the corresponding batch files. +%% \CharacterTable +%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +%% Digits \0\1\2\3\4\5\6\7\8\9 +%% Exclamation \! Double quote \" Hash (number) \# +%% Dollar \$ Percent \% Ampersand \& +%% Acute accent \' Left paren \( Right paren \) +%% Asterisk \* Plus \+ Comma \, +%% Minus \- Point \. Solidus \/ +%% Colon \: Semicolon \; Less than \< +%% Equals \= Greater than \> Question mark \? +%% Commercial at \@ Left bracket \[ Backslash \\ +%% Right bracket \] Circumflex \^ Underscore \_ +%% Grave accent \` Left brace \{ Vertical bar \| +%% Right brace \} Tilde \~} + + %If this configuration file is added to TeX's path, it can + %be used to set up the texosquery defaults for the installation. + + %Default application (must be installed on the operating system's + %path). Change as appropriate. Available options: + % * texosquery-jre8 (at least Java 8 required) + % * texosquery (at least Java 7 required) + % * texosquery-jre5 (at least Java 5 required) + %(bash users need to check that the .sh extension has been removed + %from the bash scripts, or add the extension to the invoker name.) +\def\TeXOSInvokerName{texosquery} + + % If the invoker name given above is on the restricted list, + % allow it to be run in restricted mode: + %\TeXOSQueryAllowRestricted +\endinput +%% +%% End of file `texosquery.cfg'. diff --git a/Master/texmf-dist/tex/latex/texosquery/texosquery.sty b/Master/texmf-dist/tex/latex/texosquery/texosquery.sty index 70381419f66..f88771a6934 100644 --- a/Master/texmf-dist/tex/latex/texosquery/texosquery.sty +++ b/Master/texmf-dist/tex/latex/texosquery/texosquery.sty @@ -5,9 +5,8 @@ %% The original source files were: %% %% texosquery.dtx (with options: `texosquery.sty,package') -%% %% texosquery -%% Copyright 2016 Nicola Talbot +%% Copyright 2017 Nicola Talbot %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 @@ -22,9 +21,11 @@ %% The Current Maintainer of this work is Nicola Talbot. %% %% This work consists of the files texosquery.dtx and texosquery.ins -%% and the derived files texosquery.sty, texosquery.tex. -%% Additionally, the Java application texosquery.jar and bash script -%% texosquery +%% and the derived files texosquery.sty, texosquery.tex and +%% texosquery.cfg. Additionally, the Java applications texosquery.jar, +%% texosquery-jre5.jar, texosquery-jre8.jar, the bash scripts +%% texosquery.sh, texosquery-jre5.sh, texosquery-jre8.sh, and +%% the corresponding batch files. %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z @@ -40,8 +41,9 @@ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} + \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{texosquery}[2016/07/14 v1.1 (NLCT)] +\ProvidesPackage{texosquery}[2017/03/23 v1.2 (NLCT)] \input{texosquery} \endinput %% diff --git a/Master/texmf-dist/tex/latex/texosquery/texosquery.tex b/Master/texmf-dist/tex/latex/texosquery/texosquery.tex index 285b6eb20c9..843196b21a7 100644 --- a/Master/texmf-dist/tex/latex/texosquery/texosquery.tex +++ b/Master/texmf-dist/tex/latex/texosquery/texosquery.tex @@ -5,9 +5,8 @@ %% The original source files were: %% %% texosquery.dtx (with options: `texosquery.tex,package') -%% %% texosquery -%% Copyright 2016 Nicola Talbot +%% Copyright 2017 Nicola Talbot %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 @@ -22,9 +21,11 @@ %% The Current Maintainer of this work is Nicola Talbot. %% %% This work consists of the files texosquery.dtx and texosquery.ins -%% and the derived files texosquery.sty, texosquery.tex. -%% Additionally, the Java application texosquery.jar and bash script -%% texosquery +%% and the derived files texosquery.sty, texosquery.tex and +%% texosquery.cfg. Additionally, the Java applications texosquery.jar, +%% texosquery-jre5.jar, texosquery-jre8.jar, the bash scripts +%% texosquery.sh, texosquery-jre5.sh, texosquery-jre8.sh, and +%% the corresponding batch files. %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z @@ -40,6 +41,7 @@ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} + \ifnum\catcode`\@=11\relax \def\@texosquery@restore@at{}% \else @@ -48,31 +50,313 @@ }% \catcode`\@=11\relax \fi -\ifx\TeXOSQuery\undefined -\else +\ifx\TeXOSQuery\undefined \else \@texosquery@restore@at \expandafter\endinput \fi +\expandafter\def\csname ver@texosquery.tex\endcsname{2017/03/23 v1.2 (NLCT)} +\ifx\@tracklang@pkgwarn\undefined + \ifx\PackageWarning\undefined + \def\@texosquery@warn#1{% + {% + \newlinechar=`\^^J + \def\MessageBreak{^^J}% + \message{^^Jtexosquery Warning: #1 on line \the\inputlineno.^^J}% + }% + } + \else + \def\@texosquery@warn#1{% + \PackageWarning{texosquery}{#1}% + } + \fi +\else + \def\@texosquery@warn#1{% + \@tracklang@pkgwarn{texosquery}{#1}% + } +\fi +\ifx\PackageError\undefined + \def\@texosquery@err#1#2{% + \errhelp{#2}% + \errmessage{texosquery: #1}} +\else + \def\@texosquery@err#1#2{\PackageError{texosquery}{#1}{#2}} +\fi +\long\def\@texosquery@ifundef#1#2#3{% + \ifcsname#1\endcsname + \expandafter\ifx\csname #1\endcsname\relax + #2% + \else + #3% + \fi + \else + \expandafter\ifx\csname #1\endcsname\relax + #2% + \else + #3% + \fi + \fi +} +\ifx\ifcsname\undefined + \long\def\@texosquery@ifundef#1#2#3{% + \expandafter\ifx\csname #1\endcsname\relax + #2% + \else + #3% + \fi + } +\fi \def\TeXOSInvokerName{texosquery} \ifx\@@input\undefined \def\TeXOSQueryInvoker#1{\input|"\TeXOSInvokerName\space#1" } \else \def\TeXOSQueryInvoker#1{\@@input|"\TeXOSInvokerName\space#1" } \fi -\newif\ifTeXOSQueryDryRun -\TeXOSQueryDryRuntrue +\newif\ifTeXOSQueryDryRun \TeXOSQueryDryRuntrue +\def\TeXOSQueryAllowRestricted{% + \def\@texosquery@allowrestricted##1##2{##1}% +} +\def\TeXOSQueryDenyRestricted{% + \def\@texosquery@allowrestricted##1##2{##2}% +} +\def\@texosquery@allowrestricted#1#2{#2}% +\openin0=texosquery.cfg \ifeof0\relax \else + \closein0\relax + \begingroup + \newlinechar=`\^^J + \message{^^JTeXOSQuery: reading configuration file^^J}% + \endgroup + \input texosquery.cfg +\fi +\def\TeXOSQueryAllowRestricted{% + \@texosquery@warn{\string\TeXOSQueryAllowRestricted\space + ignored (only allowed in texosquery.cfg)}% +} +\def\TeXOSQueryDenyRestricted{% + \@texosquery@warn{\string\TeXOSQueryDenyRestricted\space + ignored (only allowed in texosquery.cfg)}% +} \ifx\shellescape\undefined \ifx\pdfshellescape\undefined \else \ifnum\pdfshellescape=1\relax \TeXOSQueryDryRunfalse + \else + \@texosquery@allowrestricted + {% + \ifnum\pdfshellescape=2\relax + \TeXOSQueryDryRunfalse + \fi + } + {} \fi \fi \else \ifnum\shellescape=1\relax \TeXOSQueryDryRunfalse + \else + \@texosquery@allowrestricted + {% + \ifnum\shellescape=2\relax + \TeXOSQueryDryRunfalse + \fi + } + {} \fi \fi +\ifx\@texosquery@edef\undefined + \ifx\protected@edef\undefined + \let\@texosquery@edef\edef + \else + \let\@texosquery@edef\protected@edef + \fi +\fi +\def\@texosquery@gobble#1{} +\def\@texosquery@firstofone#1{#1} +\def\texosquerynonasciiwrap#1{#1} +\ifx\detokenize\undefined + \def\texosquerynonasciidetokwrap#1{\string#1} +\else + \def\texosquerynonasciidetokwrap#1{\detokenize{#1}} +\fi +\edef\texosquerybackslash{\expandafter\@texosquery@gobble\string\\} +\ifx\textbackslash\undefined + \def\texosquerytextbackslash{\texosquerybackslash} +\else + \def\texosquerytextbackslash{\noexpand\textbackslash} +\fi +\edef\texosqueryleftbrace{\expandafter\@texosquery@gobble\string\{} +\def\texosquerytextleftbrace{\{} +\edef\texosqueryrightbrace{\expandafter\@texosquery@gobble\string\}} +\def\texosquerytextrightbrace{\}} +\edef\texosqueryhash{\expandafter\@texosquery@gobble\string\#} +\def\texosquerytexthash{\#} +\edef\texosqueryunderscore{\expandafter\@texosquery@gobble\string\_} +\def\texosquerytextunderscore{\_} +\edef\texosquerybacktick{\string`} +\def\texosquerytextbacktick{`} +\edef\texosqueryclosequote{\string'} +\def\texosquerytextclosequote{'} +\edef\texosquerydoublequote{\string"} +\def\texosquerytextdoublequote{"} +\edef\texosquerycolon{\string:} +\def\texosquerytextcolon{:} +\edef\texosquerysemicolon{\string;} +\def\texosquerytextsemicolon{;} +\edef\texosqueryequals{\string=} +\def\texosquerytextequals{=} +\edef\texosqueryslash{\string/} +\def\texosquerytextslash{/} +\edef\texosqueryhyphen{\string-} +\def\texosquerytexthyphen{-} +\edef\texosqueryplus{\string+} +\def\texosquerytextplus{+} +\edef\texosqueryperiod{\string.} +\def\texosquerytextperiod{.} +\edef\texosquerycomma{\string,} +\def\texosquerytextcomma{,} +\edef\texosqueryopenparen{\string(} +\def\texosquerytextopenparen{(} +\edef\texosquerycloseparen{\string)} +\def\texosquerytextcloseparen{)} +\edef\texosqueryopensq{\string[} +\def\texosquerytextopensq{[} +\edef\texosqueryclosesq{\string]} +\def\texosquerytextclosesq{]} +\edef\texosqueryasterisk{\string*} +\def\texosquerytextasterisk{*} +\edef\texosqueryatchar{\string @} +\def\texosquerytextatchar{@} +\edef\texosquerybar{\string|} +\ifx\undefined\textbar + \def\texosquerytextbar{|} +\else + \def\texosquerytextbar{\ifmmode|\else\textbar\fi} +\fi +\edef\texosquerylessthan{\string<} +\ifx\undefined\textless + \def\texosquerytextlessthan{<} +\else + \def\texosquerytextlessthan{\ifmmode<\else\textless\fi} +\fi +\edef\texosquerygreaterthan{\string>} +\ifx\undefined\textgreater + \def\texosquerytextgreaterthan{>} +\else + \def\texosquerytextgreaterthan{\ifmmode<\else\textgreater\fi} +\fi +\edef\texosquerytilde{\string~} +\ifx\textasciitilde\undefined + \def\texosquerytexttilde{\string~} +\else + \def\texosquerytexttilde{\textasciitilde} +\fi +\edef\texosquerycircum{\string^} +\ifx\textasciicircum\undefined + \def\texosquerytextcircum{\string^} +\else + \def\texosquerytextcircum{\textasciicircum} +\fi +\edef\texosqueryampersand{\string&} +\def\texosquerytextampersand{\&} +\edef\texosquerydollar{\expandafter\@texosquery@gobble\string\$} +\def\texosquerytextdollar{\$} +\edef\texosquerypercent{\expandafter\@texosquery@gobble\string\%} +\def\texosquerytextpercent{\%} +\edef\texosqueryexclam{\string!} +\def\texosquerytextexclam{!} +\edef\texosqueryquestion{\string?} +\def\texosquerytextquestion{?} +\edef\texosqueryliteralspace{\expandafter\string\space} +\def\texosquerytextspace{\noexpand\space} +\edef\@texosquery@D{\string D} +\def\@texosquery@enableshortcs{% + \def\patdtf{\noexpand\texosquerydtf}% + \def\patpmnumfmt{\noexpand\texosquerypatplusminus}% + \def\patnumfmt{\noexpand\texosquerypatnum}% + \def\patsinumfmt{\noexpand\texosquerypatsinum}% + \def\patdecfmt{\noexpand\texosquerypatdec}% + \def\patpcur{\noexpand\texosquerypatprefixcurrency}% + \def\patpicur{\noexpand\texosquerypatprefixicurrency}% + \def\patscur{\noexpand\texosquerypatsuffixcurrency}% + \def\patsicur{\noexpand\texosquerypatsuffixicurrency}% + \def\patstr{\noexpand\texosquerypatstr}% + \def\patapo{\noexpand\texosquerypatquote}% + \def\patdgt{\noexpand\texosquerypatdigit}% + \def\patdgtnz{\noexpand\texosquerypatdigitnozero}% + \def\patmsg{\noexpand\texosquerypatminus}% + \def\patngp{\noexpand\texosquerypatgroupsep}% + \def\patppct{\noexpand\texosquerypatprefixpercent}% + \def\patspct{\noexpand\texosquerypatsuffixpercent}% + \def\patppml{\noexpand\texosquerypatprefixpermill}% + \def\patspml{\noexpand\texosquerypatsuffixpermill}% + \def\twrp{\texosquerynonasciiwrap}% + \def\fwrp{\texosquerynonasciidetokwrap}% + \let\fbks\texosquerybackslash + \let\tbks\texosquerytextbackslash + \let\flbr\texosqueryleftbrace + \let\tlbr\texosquerytextleftbrace + \let\frbr\texosqueryrightbrace + \let\trbr\texosquerytextrightbrace + \let\fhsh\texosqueryhash + \let\thsh\texosquerytexthash + \let\fusc\texosqueryunderscore + \let\tusc\texosquerytextunderscore + \let\fgrv\texosquerybacktick + \let\tgrv\texosquerytextbacktick + \let\fapo\texosqueryclosequote + \let\tapo\texosquerytextclosequote + \let\fdqt\texosquerydoublequote + \let\tdqt\texosquerytextdoublequote + \let\fspc\texosqueryliteralspace + \let\tspc\texosquerytextspace + \let\fcln\texosquerycolon + \let\tcln\texosquerytextcolon + \let\fscl\texosquerysemicolon + \let\tscl\texosquerytextsemicolon + \let\feql\texosqueryequals + \let\teql\texosquerytextequals + \let\fhyn\texosqueryhyphen + \let\thyn\texosquerytexthyphen + \let\fpls\texosqueryplus + \let\tpls\texosquerytextplus + \let\ftld\texosquerytilde + \let\ttld\texosquerytexttilde + \let\fcir\texosquerycircum + \let\tcir\texosquerytextcircum + \let\famp\texosqueryampersand + \let\tamp\texosquerytextampersand + \let\fslh\texosqueryslash + \let\tslh\texosquerytextslash + \let\fpct\texosquerypercent + \let\tpct\texosquerytextpercent + \let\fexc\texosqueryexclam + \let\texc\texosquerytextexclam + \let\fque\texosqueryquestion + \let\tque\texosquerytextquestion + \let\fles\texosquerylessthan + \let\tles\texosquerytextlessthan + \let\fgre\texosquerygreaterthan + \let\tgre\texosquerytextgreaterthan + \let\fdol\texosquerydollar + \let\tdol\texosquerytextdollar + \let\fdot\texosqueryperiod + \let\tdot\texosquerytextperiod + \let\fcom\texosquerycomma + \let\tcom\texosquerytextcomma + \let\fopb\texosqueryopenparen + \let\topb\texosquerytextopenparen + \let\fclb\texosquerycloseparen + \let\tclb\texosquerytextcloseparen + \let\fosb\texosqueryopensq + \let\tosb\texosquerytextopensq + \let\fcsb\texosqueryclosesq + \let\tcsb\texosquerytextclosesq + \let\fast\texosqueryasterisk + \let\tast\texosquerytextasterisk + \let\fatc\texosqueryatchar + \let\tatc\texosquerytextatchar + \let\pdfd\@texosquery@D +} \def\TeXOSQuery#1#2{% \ifTeXOSQueryDryRun \begingroup @@ -83,30 +367,166 @@ \else \begingroup \endlinechar=-1\relax + \@texosquery@enableshortcs \catcode`\-=12\relax \catcode`\_=12\relax \catcode`\^=12\relax \catcode`\~=12\relax \catcode`\$=12\relax \catcode`\&=12\relax - \catcode`\"=12\relax - \catcode`\'=12\relax \catcode`\.=12\relax \catcode`\/=12\relax \catcode`\:=12\relax + \catcode`\"=12\relax + \catcode`\'=12\relax \catcode`\;=12\relax \catcode`\%=12\relax \everyeof{\noexpand}\relax - \edef\x{\endgroup\def\noexpand#1{\TeXOSQueryInvoker{#2}}}\x + \@texosquery@edef\x{\endgroup\def\noexpand#1{\TeXOSQueryInvoker{#2}}}\x \fi } +\def\texosquerycurrency#1{% + \expandafter\noexpand\csname texosquerycurrency#1\endcsname +} +\ifx\faDollar\undefined + \def\texosquerycurrencydollar{\$} +\else + \def\texosquerycurrencydollar{\faDollar} +\fi +\ifx\textcent\undefined + \def\texosquerycurrencycent{cent} +\else + \def\texosquerycurrencycent{\textcent} +\fi +\ifx\faGbp\undefined + \ifx\pounds\undefined + \def\texosquerycurrencypound{pound} + \else + \def\texosquerycurrencypound{\pounds} + \fi +\else + \def\texosquerycurrencypound{\faGbp} +\fi +\ifx\textcurrency\undefined + \def\texosquerycurrencysign{currency-sign} +\else + \def\texosquerycurrencysign{\textcurrency} +\fi +\ifx\faYen\undefined + \ifx\textyen\undefined + \def\texosquerycurrencyyen{yen} + \else + \def\texosquerycurrencyyen{\textyen} + \fi +\else + \def\texosquerycurrencyyen{\faYen} +\fi +\def\texosquerycurrencyecu{ecu} +\def\texosquerycurrencycolon{colon} +\def\texosquerycurrencycruzeiro{cruzeiro} +\def\texosquerycurrencyfranc{franc} +\ifx\textlira\undefined + \def\texosquerycurrencylira{lira} +\else + \def\texosquerycurrencylira{\textlira} +\fi +\def\texosquerycurrencymill{mill} +\ifx\textnaira\undefined + \def\texosquerycurrencynaira{naira} +\else + \def\texosquerycurrencynaira{\textnaira} +\fi +\def\texosquerycurrencypeseta{peseta} +\ifx\faRupee\undefined + \def\texosquerycurrencyrupee{rupee} +\else + \def\texosquerycurrencyrupee{\faRupee} +\fi +\ifx\faWon\undefined + \ifx\textwon\undefined + \def\texosquerycurrencywon{won} + \else + \def\texosquerycurrencywon{\textwon} + \fi +\else + \def\texosquerycurrencywon{\faWon} +\fi +\ifx\faSheqel\undefined + \def\texosquerycurrencynewsheqel{newsheqel} +\else + \def\texosquerycurrencynewsheqel{\faSheqel} +\fi +\ifx\textdong\undefined + \def\texosquerycurrencydong{dong} +\else + \def\texosquerycurrencydong{\textdong} +\fi +\ifx\faEuro\undefined + \ifx\texteuro\undefined + \ifx\euro\undefined + \def\texosquerycurrencyeuro{euro} + \else + \def\texosquerycurrencyeuro{\euro} + \fi + \else + \def\texosquerycurrencyeuro{\texteuro} + \fi +\else + \def\texosquerycurrencyeuro{\faEuro} +\fi +\def\texosquerycurrencykip{kip} +\def\texosquerycurrencytugrik{tugrik} +\def\texosquerycurrencydrachma{drachma} +\def\texosquerycurrencygermanpenny{german-penny} +\ifx\textpeso\undefined + \def\texosquerycurrencypeso{peso} +\else + \def\texosquerycurrencypeso{\textpeso} +\fi +\ifx\textguarani\undefined + \def\texosquerycurrencyguarani{guarani} +\else + \def\texosquerycurrencyguarani{\textguarani} +\fi +\def\texosquerycurrencyaustral{austral} +\def\texosquerycurrencyhryvnia{hryvnia} +\ifx\textcolonmonetary\undefined + \def\texosquerycurrencycedi{cedi} +\else + \def\texosquerycurrencycedi{\textcolonmonetary} +\fi +\def\texosquerycurrencylivretournois{livre-tournois} +\def\texosquerycurrencyspesmilo{spesmilo} +\def\texosquerycurrencytenge{tenge} +\def\texosquerycurrencyrupee{rupee} +\ifx\faTurkishLira\undefined + \def\texosquerycurrencyturkishlira{turkish-lira} +\else + \def\texosquerycurrencyturkishlira{\faTurkishLira} +\fi +\def\texosquerycurrencynordicmark{nordic-mark} +\def\texosquerycurrencymanat{manat} +\ifx\faRuble\undefined + \def\texosquerycurrencyruble{ruble} +\else + \def\texosquerycurrencyruble{\faRuble} +\fi \def\TeXOSQueryLocale#1{\TeXOSQuery{#1}{\string-l}} +\def\TeXOSQueryLangTag#1{\TeXOSQuery{#1}{\string-b}} +\def\TeXOSQueryNumeric#1#2{\TeXOSQuery{#1}{\string-N #2}} +\def\TeXOSQueryLocaleData#1#2{\TeXOSQuery{#1}{\string-D #2}} \def\TeXOSQueryCwd#1{\TeXOSQuery{#1}{\string-c}} \def\TeXOSQueryHome#1{\TeXOSQuery{#1}{\string-m}} \def\TeXOSQueryTmpDir#1{\TeXOSQuery{#1}{\string-t}} \def\TeXOSQueryVersion#1{\TeXOSQuery{#1}{\string-r}} \def\TeXOSQueryArch#1{\TeXOSQuery{#1}{\string-a}} \def\TeXOSQueryName#1{\TeXOSQuery{#1}{\string-o}} +\def\TeXOSQueryDateTime#1{% + \TeXOSQuery{#1}{\string-M}% +} +\def\TeXOSQueryTimeZones#1#2{% + \TeXOSQuery{#1}{\string-Z #2}% +} \def\TeXOSQueryNow#1{% \edef\@texosquery@restore@D{% \noexpand\catcode`\noexpand\D=\the\catcode`\D\relax}% @@ -133,18 +553,1318 @@ } \def\TeXOSQueryFileSize#1#2{\TeXOSQuery{#1}{\string-s \string'\texosquerystripquotes{#2}\string'}} -\def\TeXOSQueryFileList#1#2#3{\TeXOSQuery{#1}{% - \string-i \string'#2\string' - \string'\texosquerystripquotes{#3}\string'}} -\def\TeXOSQueryFilterFileList#1#2#3#4{\TeXOSQuery{#1}{% - \string-f \string'#2\string' \string'#3\string' - \string'\texosquerystripquotes{#4}\string'}} +\def\@texosquery@filelist#1#2#3#4#5{\TeXOSQuery{#1}{% + \string#2 \string'#3\string' + \string'\texosquerystripquotes{#4}\string' #5}} +\def\TeXOSQueryFileList#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{}% +} +\def\TeXOSQueryFileListDateAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{date}% +} +\def\TeXOSQueryFileListDateDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{date\string-des}% +} +\def\TeXOSQueryFileListSizeAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{size}% +} +\def\TeXOSQueryFileListSizeDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{size\string-des}% +} +\def\TeXOSQueryFileListNameAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{name}% +} +\def\TeXOSQueryFileListNameDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{name\string-des}% +} +\def\TeXOSQueryFileListNameIgnoreCaseAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{iname}% +} +\def\TeXOSQueryFileListNameIgnoreCaseDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{iname\string-des}% +} +\def\TeXOSQueryFileListExtAsc#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{ext}% +} +\def\TeXOSQueryFileListExtDes#1#2#3{% + \@texosquery@filelist{#1}{-i}{#2}{#3}{ext\string-des}% +} +\def\TeXOSQueryRegularFileList#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{}% +} +\def\TeXOSQuerySubDirList#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{}% +} +\def\TeXOSQueryRegularFileListDateAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{date}% +} +\def\TeXOSQuerySubDirListDateAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{date}% +} +\def\TeXOSQueryRegularFileListDateDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{date\string-des}% +} +\def\TeXOSQuerySubDirListDateDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{date\string-des}% +} +\def\TeXOSQueryRegularFileListSizeAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{size}% +} +\def\TeXOSQuerySubDirListSizeAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{size}% +} +\def\TeXOSQueryRegularFileListSizeDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{size\string-des}% +} +\def\TeXOSQuerySubDirListSizeDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{size\string-des}% +} +\def\TeXOSQueryRegularFileListNameAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{name}% +} +\def\TeXOSQuerySubDirListNameAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{name}% +} +\def\TeXOSQueryRegularFileListNameDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{name\string-des}% +} +\def\TeXOSQuerySubDirListNameDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{name\string-des}% +} +\def\TeXOSQueryRegularFileListNameIgnoreCaseAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{iname}% +} +\def\TeXOSQuerySubDirListNameIgnoreCaseAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{iname}% +} +\def\TeXOSQueryRegularFileListNameIgnoreCaseDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{iname\string-des}% +} +\def\TeXOSQuerySubDirListNameIgnoreCaseDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{iname\string-des}% +} +\def\TeXOSQueryRegularFileListExtAsc#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{ext}% +} +\def\TeXOSQuerySubDirListExtAsc#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{ext}% +} +\def\TeXOSQueryRegularFileListExtDes#1#2#3{% + \@texosquery@filelist{#1}{-ir}{#2}{#3}{ext\string-des}% +} +\def\TeXOSQuerySubDirListExtDes#1#2#3{% + \@texosquery@filelist{#1}{-id}{#2}{#3}{ext\string-des}% +} +\def\@texosquery@filterfilelist#1#2#3#4#5#6{% + \TeXOSQuery{#1}% + {% + \string#2 \string'#3\string' \string'#4\string' + \string'\texosquerystripquotes{#5}\string' #6% + }% +} +\def\TeXOSQueryFilterFileList#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{}% +} +\def\TeXOSQueryFilterFileListDateAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{date}% +} +\def\TeXOSQueryFilterFileListDateDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{date\string-des}% +} +\def\TeXOSQueryFilterFileListSizeAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{size}% +} +\def\TeXOSQueryFilterFileListSizeDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{size\string-des}% +} +\def\TeXOSQueryFilterFileListNameAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{name}% +} +\def\TeXOSQueryFilterFileListNameDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{name\string-des}% +} +\def\TeXOSQueryFilterFileListNameIgnoreCaseAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{iname}% +} +\def\TeXOSQueryFilterFileListNameIgnoreCaseDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{iname\string-des}% +} +\def\TeXOSQueryFilterFileListExtAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{ext}% +} +\def\TeXOSQueryFilterFileListExtDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-f}{#2}{#3}{#4}{ext\string-des}% +} +\def\TeXOSQueryFilterRegularFileList#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{}% +} +\def\TeXOSQueryFilterSubDirList#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{}% +} +\def\TeXOSQueryFilterSubDirListDateAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{date}% +} +\def\TeXOSQueryFilterRegularFileListDateAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{date}% +} +\def\TeXOSQueryFilterSubDirListDateDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{date\string-des}% +} +\def\TeXOSQueryFilterRegularFileListDateDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{date\string-des}% +} +\def\TeXOSQueryFilterSubDirListSizeAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{size}% +} +\def\TeXOSQueryFilterRegularFileListSizeAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{size}% +} +\def\TeXOSQueryFilterSubDirListSizeDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{size\string-des}% +} +\def\TeXOSQueryFilterRegularFileListSizeDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{size\string-des}% +} +\def\TeXOSQueryFilterSubDirListNameAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{name}% +} +\def\TeXOSQueryFilterRegularFileListNameAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{name}% +} +\def\TeXOSQueryFilterSubDirListNameDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{name\string-des}% +} +\def\TeXOSQueryFilterRegularFileListNameDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{name\string-des}% +} +\def\TeXOSQueryFilterSubDirListNameIgnoreCaseAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{iname}% +} +\def\TeXOSQueryFilterRegularFileListNameIgnoreCaseAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{iname}% +} +\def\TeXOSQueryFilterSubDirListNameIgnoreCaseDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{iname\string-des}% +} +\def\TeXOSQueryFilterRegularFileListNameIgnoreCaseDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{iname\string-des}% +} +\def\TeXOSQueryFilterSubDirListExtAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{ext}% +} +\def\TeXOSQueryFilterRegularFileListExtAsc#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{ext}% +} +\def\TeXOSQueryFilterSubDirListExtDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fd}{#2}{#3}{#4}{ext\string-des}% +} +\def\TeXOSQueryFilterRegularFileListExtDes#1#2#3#4{% + \@texosquery@filterfilelist{#1}{-fr}{#2}{#3}{#4}{ext\string-des}% +} +\def\@texosquery@walk#1#2#3#4#5{% + \TeXOSQuery{#1}% + {% + \string-w \string'#2\string' \string'#3\string' + \string'\texosquerystripquotes{#4}\string' #5% + }% +} +\def\TeXOSQueryWalk#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{}% +} +\def\TeXOSQueryWalkDateAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{date}% +} +\def\TeXOSQueryWalkDateDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{date\string-des}% +} +\def\TeXOSQueryWalkSizeAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{size}% +} +\def\TeXOSQueryWalkSizeDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{size\string-des}% +} +\def\TeXOSQueryWalkNameAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{name}% +} +\def\TeXOSQueryWalkNameDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{name\string-des}% +} +\def\TeXOSQueryWalkNameIgnoreCaseAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{iname}% +} +\def\TeXOSQueryWalkNameIgnoreCaseDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{iname\string-des}% +} +\def\TeXOSQueryWalkExtAsc#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{ext}% +} +\def\TeXOSQueryWalkExtDes#1#2#3#4{% + \@texosquery@walk{#1}{#2}{#3}{#4}{ext\string-des}% +} \def\TeXOSQueryFileURI#1#2{\TeXOSQuery{#1}{\string-u \string'\texosquerystripquotes{#2}\string'}} \def\TeXOSQueryFilePath#1#2{\TeXOSQuery{#1}{\string-p \string'\texosquerystripquotes{#2}\string'}} \def\TeXOSQueryDirName#1#2{\TeXOSQuery{#1}{\string-e \string'\texosquerystripquotes{#2}\string'}} +\def\texosquerydtf#1#2{% + \ifcase#1 + \or + #2% + \or + #2#2% + \or + #2#2#2% + \else + #2#2#2#2% + \fi +} +\def\texosquerypatstr#1{'#1'} +\def\texosquerypatquote{''} +\def\texosquerypatplusminus#1#2{#1;#2} +\def\texosquerypatnum#1{#1} +\def\texosquerypatsinum#1#2{#1E#2} +\def\texosquerypatdec#1#2{#1.#2} +\def\texosquerypatprefixcurrency#1#2{#2¤#1} +\def\texosquerypatprefixicurrency#1#2{#2¤¤#1} +\def\texosquerypatsuffixcurrency#1#2{#1¤#2} +\def\texosquerypatsuffixicurrency#1#2{#1¤¤#2} +\def\texosquerypatdigit{0} +\def\texosquerypatdigitnozero{\#} +\def\texosquerypatminus{-} +\def\texosquerypatgroupsep{,} +\def\texosquerypatprefixpercent#1#2{#2\%#1} +\def\texosquerypatsuffixpercent#1#2{#1\%#2} +\def\texosquerypatprefixpermill#1#2{#2‰#1} +\def\texosquerypatsuffixpermill#1#2{#1‰#2} +\def\@texosquery@pattern@shortcuts{% + \def\%{\noexpand\texosquerydtf}% + \def\0{\noexpand\texosquerypatdigit}% + \def\#{\noexpand\texosquerypatdigitnozero}% + \def\-{\noexpand\texosquerypatminus}% + \def\,{\noexpand\texosquerypatgroupsep}% + \def\numfmt{\noexpand\texosquerypatnum}% + \def\pmnumfmt{\noexpand\texosquerypatplusminus}% + \def\sinumfmt{\noexpand\texosquerypatsinum}% + \def\decfmt{\noexpand\texosquerypatdec}% + \def\pcur{\noexpand\texosquerypatprefixcurrency}% + \def\picur{\noexpand\texosquerypatprefixicurrency}% + \def\scur{\noexpand\texosquerypatsuffixcurrency}% + \def\sicur{\noexpand\texosquerypatsuffixicurrency}% + \def\ppct{\noexpand\texosquerypatprefixpercent}% + \def\spct{\noexpand\texosquerypatsuffixpercent}% + \def\ppml{\noexpand\texosquerypatprefixpermill}% + \def\spml{\noexpand\texosquerypatsuffixpermill}% +} +\def\texosquerydefpattern#1#2{% + \begingroup + \@texosquery@pattern@shortcuts + \@texosquery@edef\x{\endgroup\def\noexpand#1{#2}}\x +} +\def\texosqueryfmtdatetime#1{% + \def\@texosquery@fmt@dt@pattern{#1}% + \@texosquery@fmt@getera +} +\def\@texosquery@fmt@getera#1{% + \edef\@texosquery@fmt@G{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getyear +} +\def\@texosquery@fmt@getyear#1{% + \edef\@texosquery@fmt@y{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getweekyear +} +\def\@texosquery@fmt@getweekyear#1{% + \edef\@texosquery@fmt@Y{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getmonth +} +\def\@texosquery@fmt@getmonth#1{% + \edef\@texosquery@fmt@M{\@texosquery@paddigits{#1}}% + \let\@texosquery@fmt@L\@texosquery@fmt@M + \@texosquery@fmt@getweekinyear +} +\def\@texosquery@fmt@getweekinyear#1{% + \edef\@texosquery@fmt@w{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getweekinmonth +} +\def\@texosquery@fmt@getweekinmonth#1{% + \edef\@texosquery@fmt@W{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getdayinyear +} +\def\@texosquery@fmt@getdayinyear#1{% + \edef\@texosquery@fmt@D{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getdayinmonth +} +\def\@texosquery@fmt@getdayinmonth#1{% + \edef\@texosquery@fmt@d{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getdayofweekinmonth +} +\def\@texosquery@fmt@getdayofweekinmonth#1{% + \edef\@texosquery@fmt@F{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getdaynumberofweek +} +\def\@texosquery@fmt@getdaynumberofweek#1{% + \edef\@texosquery@fmt@u{\@texosquery@paddigits{#1}}% + \let\@texosquery@fmt@E\@texosquery@fmt@u + \@texosquery@fmt@getampm +} +\def\@texosquery@fmt@getampm#1{% + \edef\@texosquery@fmt@a{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gethourindayH +} +\def\@texosquery@fmt@gethourindayH#1{% + \edef\@texosquery@fmt@H{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gethourindayk +} +\def\@texosquery@fmt@gethourindayk#1{% + \edef\@texosquery@fmt@k{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gethourinampmK +} +\def\@texosquery@fmt@gethourinampmK#1{% + \edef\@texosquery@fmt@K{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gethourinampmh +} +\def\@texosquery@fmt@gethourinampmh#1{% + \edef\@texosquery@fmt@h{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getminute +} +\def\@texosquery@fmt@getminute#1{% + \edef\@texosquery@fmt@m{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getsecond +} +\def\@texosquery@fmt@getsecond#1{% + \edef\@texosquery@fmt@s{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@getmillisecond +} +\def\@texosquery@fmt@getmillisecond#1{% + \edef\@texosquery@fmt@S{\@texosquery@paddigits{#1}}% + \@texosquery@fmt@gettimezone +} +\def\@texosquery@fmt@gettimezone#1{% + \def\@texosquery@fmt@Z{#1}% + \def\@texosquery@fmt@z{#1}% + \def\@texosquery@fmt@X{#1}% + \begingroup + \@texosquery@setup@dtpattern + \@texosquery@fmt@dt@pattern + \endgroup +} +\def\@texosquery@setup@dtpattern{% + \let\texosquerydtf\@texosquery@fmt@dtf + \let\texosquerypatstr\texosquerypatfmtstr + \let\texosquerypatquote\texosquerypatfmtquote +} +\def\@texosquery@paddigits@pos#1{% + \ifnum#1<10 + 000000000\number#1 + \else + \ifnum#1<100 + 00000000\number#1 + \else + \ifnum#1<1000 + 0000000\number#1 + \else + \ifnum#1<10000 + 000000\number#1 + \else + \ifnum#1<100000 + 00000\number#1 + \else + \ifnum#1<1000000 + 0000\number#1 + \else + \ifnum#1<10000000 + 000\number#1 + \else + \ifnum#1<100000000 + 00\number#1 + \else + \ifnum#1<1000000000 + 0\number#1 + \else + \number#1 + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi + \fi +} +\def\@texosquery@paddigits#1{% + \ifnum#1<0 + -\expandafter\@texosquery@paddigits@pos\expandafter + {\@texosquery@gobble#1}% + \else + +\@texosquery@paddigits@pos{#1}% + \fi +} +\def\@texosquery@paddigits@trailing#1{% + \expandafter\@texosquery@tenoften@then@gobble + #10000000000\@texosquery@end@tenoften +} +\def\@texosquery@tenoften@then@gobble#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7#8#9% + \@texosquery@lastoften@gobble +} +\def\@texosquery@lastoften@gobble#1#2\@texosquery@end@tenoften{#1} +\def\@texosquery@firstoften#1#2#3#4#5#6#7#8#9{% + #1% + \@texosquery@gobble +} +\def\@texosquery@secondoften#1#2#3#4#5#6#7#8#9{% + #2% + \@texosquery@gobble +} +\def\@texosquery@thirdoften#1#2#3#4#5#6#7#8#9{% + #3% + \@texosquery@gobble +} +\def\@texosquery@fourthoften#1#2#3#4#5#6#7#8#9{% + #4% + \@texosquery@gobble +} +\def\@texosquery@fifthoften#1#2#3#4#5#6#7#8#9{% + #5% + \@texosquery@gobble +} +\def\@texosquery@sixthoften#1#2#3#4#5#6#7#8#9{% + #6% + \@texosquery@gobble +} +\def\@texosquery@seventhoften#1#2#3#4#5#6#7#8#9{% + #7% + \@texosquery@gobble +} +\def\@texosquery@eighthoften#1#2#3#4#5#6#7#8#9{% + #8% + \@texosquery@gobble +} +\def\@texosquery@ninthoften#1#2#3#4#5#6#7#8#9{% + #9% + \@texosquery@gobble +} +\def\@texosquery@tenthoften#1#2#3#4#5#6#7#8#9{% + \@texosquery@firstofone +} +\def\@texosquery@firsttwooften#1#2#3#4#5#6#7#8#9{% + #1#2% + \@texosquery@gobble +} +\def\@texosquery@firstthreeoften#1#2#3#4#5#6#7#8#9{% + #1#2#3% + \@texosquery@gobble +} +\def\@texosquery@firstfouroften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4% + \@texosquery@gobble +} +\def\@texosquery@firstfiveoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5% + \@texosquery@gobble +} +\def\@texosquery@firstsixoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6% + \@texosquery@gobble +} +\def\@texosquery@firstsevenoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7% + \@texosquery@gobble +} +\def\@texosquery@firsteightoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7#8% + \@texosquery@gobble +} +\def\@texosquery@firstnineoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7#8#9% + \@texosquery@gobble +} +\def\@texosquery@alltenoften#1#2#3#4#5#6#7#8#9{% + #1#2#3#4#5#6#7#8#9% + \@texosquery@firstofone +} +\def\@texosquery@lasttwooften#1#2#3#4#5#6#7#8#9{% + #9% + \@texosquery@firstofone +} +\def\@texosquery@lastthreeoften#1#2#3#4#5#6#7#8#9{% + #8#9% + \@texosquery@firstofone +} +\def\@texosquery@lastfouroften#1#2#3#4#5#6#7#8#9{% + #7#8#9% + \@texosquery@firstofone +} +\def\@texosquery@lastfiveoften#1#2#3#4#5#6#7#8#9{% + #6#7#8#9% + \@texosquery@firstofone +} +\def\@texosquery@lastsixoften#1#2#3#4#5#6#7#8#9{% + #5#6#7#8#9% + \@texosquery@firstofone +} +\def\@texosquery@lastsevenoften#1#2#3#4#5#6#7#8#9{% + #4#5#6#7#8#9% + \@texosquery@firstofone +} +\def\@texosquery@lasteightoften#1#2#3#4#5#6#7#8#9{% + #3#4#5#6#7#8#9% + \@texosquery@firstofone +} +\def\@texosquery@lastnineoften#1#2#3#4#5#6#7#8#9{% + #2#3#4#5#6#7#8#9% + \@texosquery@firstofone +} +\def\@texosquery@fmtminus{\texosquerypatfmtminus} +\def\@texosquery@fmtplus{} +\def\@texosquery@fmtsign#1{% + \ifx#1+\@texosquery@fmtplus\else\@texosquery@fmtminus\fi +} +\def\@texosquery@atleastonedigit#1{% + \ifnum#1<0 + \@texosquery@fmtminus\number-#1 + \else + \number#1 + \fi +} +\def\@texosquery@atleastfourdigits#1{% + \@texosquery@at@leastfourdigits#1\@texosquery@end@atleastfourdigits +} +\def\@texosquery@at@leastfourdigits#1#2\@texosquery@end@atleastfourdigits{% + \@texosquery@fmtsign{#1}% + \ifnum#2<1000 + \@texosquery@lastfouroften#2% + \else + \number#2 + \fi +} +\def\@texosquery@threedigitsexactly#1{% + \@texosquery@threedigits@exactly#1\@texosquery@threedigits@exactly +}% +\def\@texosquery@threedigits@exactly#1#2\@texosquery@threedigits@exactly{% + \@texosquery@fmtsign{#1}% + \@texosquery@lastthreeoften#2% +}% +\def\@texosquery@twodigitsexactly#1{% + \@texosquery@twodigits@exactly#1\@texosquery@twodigits@exactly +}% +\def\@texosquery@twodigits@exactly#1#2\@texosquery@twodigits@exactly{% + \@texosquery@fmtsign{#1}% + \@texosquery@lasttwooften#2% +}% +\def\@texosquery@fmt@dtf#1#2{% + \@texosquery@ifundef{@texosquery@fmt@#2}% + {\@texosquery@warn{Unknown date-time pattern designator `#2'}}% + {% + \ifcase#1 + \or + \@texosquery@ifundef{texosqueryfmtpat#2}% + {% + \expandafter\expandafter\expandafter + \@texosquery@atleastonedigit + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + {% + \csname texosqueryfmtpat#2\expandafter\expandafter\expandafter\endcsname + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + \or + \@texosquery@ifundef{texosqueryfmtpat#2#2}% + {% + \expandafter\expandafter\expandafter + \@texosquery@twodigitsexactly + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + {% + \csname texosqueryfmtpat#2#2\expandafter\expandafter\expandafter + \endcsname \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + \or + \@texosquery@ifundef{texosqueryfmtpat#2#2#2}% + {% + \expandafter\expandafter\expandafter + \@texosquery@threedigitsexactly + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + {% + \csname texosqueryfmtpat#2#2#2\expandafter\expandafter\expandafter + \endcsname \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + \else + \@texosquery@ifundef{texosqueryfmtpat#2#2#2#2}% + {% + \expandafter\expandafter\expandafter + \@texosquery@atleastfourdigits + \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + {% + \csname texosqueryfmtpat#2#2#2#2\expandafter\expandafter\expandafter + \endcsname \expandafter\expandafter\expandafter + {\csname @texosquery@fmt@#2\endcsname}% + }% + \fi + }% +} +\def\texosqueryfmttimezonehr#1{% + \ifnum#11<0\@texosquery@fmtminus + \ifnum#1>-10 0\fi\number-#1 + \else + +\ifnum#1<10 0\fi\number#1 + \fi +} +\def\texosqueryfmttimezonenumhr#1{% + \ifnum#11<0\@texosquery@fmtminus + \number-#1 + \else + \number#1 + \fi +} +\def\texosqueryfmttimezonemin#1{% + \ifnum#1<10 0\fi\number#1 +} +\def\@texosquery@firstoffour#1#2#3#4{#1} +\def\@texosquery@secondoffour#1#2#3#4{#2} +\def\@texosquery@thirdoffour#1#2#3#4{#3} +\def\@texosquery@fourthoffour#1#2#3#4{#4} +\def\texosqueryshorttimezone#1{#1} +\def\texosqueryshortdstzone#1{#1 (DST)} +\def\texosquerylongtimezone#1{#1} +\def\texosquerylongdstzone#1{#1 (DST)} +\def\texosquerytimesep{:} +\def\texosqueryfmtpatz#1{% + \expandafter\ifnum\@texosquery@fourthoffour#1=0 + \expandafter\texosqueryshorttimezone\expandafter{\@texosquery@thirdoffour#1}% + \else + \expandafter\texosqueryshortdstzone\expandafter{\@texosquery@thirdoffour#1}% + \fi +} +\def\texosqueryfmtpatzz#1{% + \expandafter\ifnum\@texosquery@fourthoffour#1=0 + \expandafter\texosqueryshorttimezone\expandafter{\@texosquery@thirdoffour#1}% + \else + \expandafter\texosqueryshortdstzone\expandafter{\@texosquery@thirdoffour#1}% + \fi +} +\def\texosqueryfmtpatzzz#1{% + \expandafter\ifnum\@texosquery@fourthoffour#1=0 + \expandafter\texosquerylongtimezone\expandafter{\@texosquery@thirdoffour#1}% + \else + \expandafter\texosquerylongdstzone\expandafter{\@texosquery@thirdoffour#1}% + \fi +} +\def\texosqueryfmtpatzzzz#1{% + \expandafter\ifnum\@texosquery@fourthoffour#1=0 + \expandafter\texosquerylongtimezone\expandafter{\@texosquery@thirdoffour#1}% + \else + \expandafter\texosquerylongdstzone\expandafter{\@texosquery@thirdoffour#1}% + \fi +} +\def\texosqueryfmtpatZ#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +\def\texosqueryfmtpatZZ#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +\def\texosqueryfmtpatZZZ#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +\def\texosqueryfmtpatZZZZ#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +\def\texosqueryfmtpatX#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \texosquerytimesep + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +\def\texosqueryfmtpatXX#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \texosquerytimesep + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +\def\texosqueryfmtpatXXX#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \texosquerytimesep + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +\def\texosqueryfmtpatXXXX#1{% + \expandafter\texosqueryfmttimezonehr\expandafter + {\@texosquery@firstoffour#1}% + \texosquerytimesep + \expandafter\texosqueryfmttimezonemin\expandafter + {\@texosquery@secondoffour#1}% +} +\def\texosqueryfmtpata#1{% + \ifnum#1=0 AM\else PM\fi +} +\def\texosqueryfmtpataa{\texosqueryfmtpata} +\def\texosqueryfmtpataaa{\texosqueryfmtpata} +\def\texosqueryfmtpataaaa{\texosqueryfmtpata} +\def\texosqueryfmtpatG#1{% + \ifnum#1=1 AD\else BC\fi +} +\def\texosqueryfmtpatGG{\texosqueryfmtpatG} +\def\texosqueryfmtpatGGG{\texosqueryfmtpatG} +\def\texosqueryfmtpatGGGG{\texosqueryfmtpatG} +\def\texosqueryfmtnumber#1#2#3#4{% + \begingroup + \let\texosquerypatstr\texosquerypatfmtstr + \let\texosquerypatquote\texosquerypatfmtquote + \let\texosquerypatplusminus\texosquerypatfmt@plusminus + \let\texosquerypatnum\texosquerypatfmt@num + \let\texosquerypatsinum\texosquerypatfmt@sinum + \let\texosquerypatdec\texosquerypatfmt@dec + \let\texosquerypatprefixcurrency\texosquery@patfmt@prefixcurrency + \let\texosquerypatprefixicurrency\texosquery@patfmt@prefixicurrency + \let\texosquerypatsuffixcurrency\texosquery@patfmt@suffixcurrency + \let\texosquerypatsuffixicurrency\texosquery@patfmt@suffixicurrency + \let\texosquerypatdigit\texosquerypatfmt@digit + \let\texosquerypatdigitnozero\texosquerypatfmt@digitnozero + \let\texosquerypatgroupsep\texosquerypatfmt@groupsep + \let\texosquerypatprefixpercent\texosquery@patfmt@prefixpercent + \let\texosquerypatsuffixpercent\texosquery@patfmt@suffixpercent + \let\texosquerypatprefixpermill\texosquery@patfmt@prefixpermill + \let\texosquerypatsuffixpermill\texosquery@patfmt@suffixpermill + \let\texosquerypatminus\@texosquerypat@numfmt@sign + \let\texosquerypatfmt@decsep\texosquerypatfmtdecsep + \edef\@texosquery@sgn{% + \ifnum#2=0 + \expandafter\ifnum#21<0 -\else+\fi + \else + \ifnum#2<0 -\else+\fi + \fi + }% + \edef\@texosquery@int{\expandafter\@texosquery@paddigits + \expandafter{\number#2}}% + \let\@texosquery@si@int\@texosquery@int + \edef\@texosquery@frac{\expandafter\@texosquery@paddigits@trailing + \expandafter{#3}}% + \let\@texosquery@si@frac\@texosquery@frac + \edef\@texosquery@mantissa{\expandafter\@texosquery@paddigits + \expandafter{\number#4}}% + \ifnum#4=0\relax + \else + \expandafter\ifx\@texosquery@sgn-% + \edef\@texosquery@int{\expandafter + \@texosquery@paddigits@pos\expandafter{\number-#2}}% + \else + \edef\@texosquery@int{\@texosquery@paddigits@pos{#2}}% + \fi + \ifnum#4<0 + \expandafter\@texosquery@neg@shift\expandafter{\number-#4}% + \else + \@texosquery@pos@shift{#4}% + \fi + \expandafter\ifx\@texosquery@sgn-% + \edef\@texosquery@int{\expandafter\@texosquery@paddigits + \expandafter{\number-\@texosquery@int}}% + \else + \edef\@texosquery@int{\expandafter\@texosquery@paddigits + \expandafter{\number\@texosquery@int}}% + \fi + \edef\@texosquery@frac{\@texosquery@paddigits@trailing{\@texosquery@frac}}% + \fi + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% + \let\@texosquery@zerodigit\@texosquery@zerodigit@leading + \expandafter\ifx\@texosquery@sgn-% + \let\@texosquery@currentsign\texosquerypatfmtminus + \else + \let\@texosquery@currentsign\texosquerypatfmtplus + \fi + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + #1% + \endgroup +} +\newcount\@texosquery@digitindex +\newif\if@texosquery@digitfound +\def\@texosquery@pos@shift#1{% + \ifcase#1 + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastnineoften\@texosquery@int + \expandafter\@texosquery@firstoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastnineoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lasteightoften\@texosquery@int + \expandafter\@texosquery@firsttwooften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lasteightoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastsevenoften\@texosquery@int + \expandafter\@texosquery@firstthreeoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastsevenoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastsixoften\@texosquery@int + \expandafter\@texosquery@firstfouroften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastsixoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastfiveoften\@texosquery@int + \expandafter\@texosquery@firstfiveoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastfiveoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastfouroften\@texosquery@int + \expandafter\@texosquery@firstsixoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastfouroften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lastthreeoften\@texosquery@int + \expandafter\@texosquery@firstsevenoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastthreeoften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@lasttwooften\@texosquery@int + \expandafter\@texosquery@firsteightoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@lasttwooften\@texosquery@frac + }% + \or + \edef\@texosquery@int{% + \expandafter\@texosquery@tenthoften\@texosquery@int + \expandafter\@texosquery@firstnineoften\@texosquery@frac}% + \edef\@texosquery@frac{% + \expandafter\@texosquery@tenthoften\@texosquery@frac + }% + \or + \let\@texosquery@int\@texosquery@frac + \edef\@texosquery@frac{0}% + \fi +} +\def\@texosquery@neg@shift#1{% + \ifcase#1 + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastoneoften\@texosquery@int + \expandafter\@texosquery@firstnineoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstnineoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lasttwooften\@texosquery@int + \expandafter\@texosquery@firsteightoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firsteightoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastthreeoften\@texosquery@int + \expandafter\@texosquery@firstsevenoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstsevenoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastfouroften\@texosquery@int + \expandafter\@texosquery@firstsixoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstsixoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastfiveoften\@texosquery@int + \expandafter\@texosquery@firstfiveoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstfiveoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastsixoften\@texosquery@int + \expandafter\@texosquery@firstfouroften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstfouroften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastsevenoften\@texosquery@int + \expandafter\@texosquery@firstthreeoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstthreeoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lasteightoften\@texosquery@int + \expandafter\@texosquery@firsttwooften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firsttwooften\@texosquery@int + }% + \or + \edef\@texosquery@frac{% + \expandafter\@texosquery@lastnineoften\@texosquery@int + \expandafter\@texosquery@firstoften\@texosquery@frac + }% + \edef\@texosquery@int{% + \expandafter\@texosquery@firstoften\@texosquery@int + }% + \or + \edef\@texosquery@frac{\@texosquery@int\@texosquery@frac}% + \edef\@texosquery@int{0}% + \fi +} +\def\@texosquerypat@numfmt@sign{% + \@texosquery@currentsign + \let\@texosquery@currentsign\empty +} +\def\texosquerypatfmtstr#1{#1} +\def\texosquerypatfmtquote{'} +\def\texosquerypatfmt@plusminus#1#2{% + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + \expandafter\ifx\@texosquery@sgn-% + #2% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#2}% + \fi + \else + #1% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#1}% + \fi + \fi +} +\def\texosquerypatfmt@num#1{#1} +\def\texosquerypatfmtexp{E} +\def\texosquerypatfmt@sinum#1#2{% + \let\@texosquery@int\@texosquery@si@int + \let\@texosquery@frac\@texosquery@si@frac + \let\@texosquery@current\@texosquery@int + #1% + \texosquerypatfmtexp + {\let\@texosquery@zerodigit\@texosquery@zerodigit@leading + \ifnum\@texosquery@mantissa<0\relax + \let\@texosquery@currentsign\texosquerypatfmtminus + \else + \let\@texosquery@currentsign\texosquerypatfmtplus + \fi + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@mantissa}% + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + #2}} +\def\texosquerypatfmtdecsep{.} +\def\texosquerypatfmtcurdecsep{.} +\def\texosquerypatfmt@dec#1#2{% + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + \let\@texosquery@zerodigit\@texosquery@zerodigit@leading + #1% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#1}% + \fi + \texosquerypatfmt@decsep + \let\@texosquery@current\@texosquery@frac + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + \let\@texosquery@zerodigit\@texosquery@zerodigit@trailing + \let\@texosquery@currentsign\empty + #2% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#2}% + \fi +} +\def\texosquerypatfmtint#1{% + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% + \@texosquery@digitindex=0\relax + \@texosquery@digitfoundfalse + \let\@texosquery@zerodigit\@texosquery@zerodigit@leading + #1% + \ifnum\@texosquery@digitindex=10 + \else + \@texosquery@invalidpattern{#1}% + \fi +} +\def\@texosquery@setpatdisplay{% + \def\texosquerypatstr##1{'##1'}% + \def\texosquerypatquote{''}% + \def\texosquerypatplusminus##1##2{##1;##2}% + \def\texosquerypatnum##1{##1}% + \def\texosquerypatsinum##1##2{##1E##2}% + \def\texosquerypatdec##1##2{##1.##2}% + \def\texosquerypatprefixcurrency##1##2{##2¤##1}% + \def\texosquerypatprefixicurrency##1##2{##2¤¤##1}% + \def\texosquerypatsuffixcurrency##1##2{##1¤##2}% + \def\texosquerypatsuffixicurrency##1##2{##1¤¤##2}% + \def\texosquerypatdigit{0}% + \def\texosquerypatdigitnozero{\#}% + \def\texosquerypatminus{-}% + \def\texosquerypatgroupsep{,}% + \def\texosquerypatprefixpercent##1##2{##2\%##1}% + \def\texosquerypatsuffixpercent##1##2{##1\%##2}% + \def\texosquerypatprefixpermill##1##2{##2‰##1}% + \def\texosquerypatsuffixpermill##1##2{##1‰##2}% + \def\texosquerypatfmt@decsep{.}% +} +\def\@texosquery@invalidpattern#1{% + \begingroup + \@texosquery@setpatdisplay + \@texosquery@err{10 digit specifiers expected in + numeric pattern #1. Found \number\@texosquery@digitindex}% + {Each integer element of a numeric pattern must have exactly + 10 digit specifiers (0 or \#)}% + \endgroup +} +\def\texosquerypatfmtcurrencysign{\$} +\ifx\textcurrency\undefined + \def\texosquerypatfmticurrencysign{¤} +\else + \def\texosquerypatfmticurrencysign{\textcurrency} +\fi +\def\texosquery@patfmt@prefixcurrency#1#2{% + \let\texosquerypatfmt@decsep\texosquerypatfmtcurdecsep + #2\texosquerypatfmtcurrencysign#1% +} +\def\texosquery@patfmt@prefixicurrency#1#2{% + \let\texosquerypatfmt@decsep\texosquerypatfmtcurdecsep + #2\texosquerypatfmticurrencysign#1% +} +\def\texosquery@patfmt@suffixcurrency#1#2{% + \let\texosquerypatfmt@decsep\texosquerypatfmtcurdecsep + #1\texosquerypatfmtcurrencysign#2% +} +\def\texosquery@patfmt@suffixicurrency#1#2{% + \let\texosquerypatfmt@decsep\texosquerypatfmtcurdecsep + #1\texosquerypatfmticurrencysign#2% +} +\def\texosquerypatfmt@digit{% + \advance\@texosquery@digitindex by 1\relax + \if@texosquery@digitfound + \else + \ifx\@texosquery@currentsign\texosquerypatfmtminus + \texosquerypatfmtminus + \let\@texosquery@currentsign\empty + \fi + \fi + \@texosquery@digitfoundtrue + \ifcase\@texosquery@digitindex + \or + \expandafter\@texosquery@firstoften\@texosquery@current + \or + \expandafter\@texosquery@secondoften\@texosquery@current + \or + \expandafter\@texosquery@thirdoften\@texosquery@current + \or + \expandafter\@texosquery@fourthoften\@texosquery@current + \or + \expandafter\@texosquery@fifthoften\@texosquery@current + \or + \expandafter\@texosquery@sixthoften\@texosquery@current + \or + \expandafter\@texosquery@seventhoften\@texosquery@current + \or + \expandafter\@texosquery@eighthoften\@texosquery@current + \or + \expandafter\@texosquery@ninthoften\@texosquery@current + \or + \expandafter\@texosquery@tenthoften\@texosquery@current + \fi +} +\def\texosquerypatfmt@digitnozero{% + \advance\@texosquery@digitindex by 1\relax + \edef\@texosquery@digit{% + \ifcase\@texosquery@digitindex + 0% + \or + \expandafter\@texosquery@firstoften\@texosquery@current + \or + \expandafter\@texosquery@secondoften\@texosquery@current + \or + \expandafter\@texosquery@thirdoften\@texosquery@current + \or + \expandafter\@texosquery@fourthoften\@texosquery@current + \or + \expandafter\@texosquery@fifthoften\@texosquery@current + \or + \expandafter\@texosquery@sixthoften\@texosquery@current + \or + \expandafter\@texosquery@seventhoften\@texosquery@current + \or + \expandafter\@texosquery@eighthoften\@texosquery@current + \or + \expandafter\@texosquery@ninthoften\@texosquery@current + \or + \expandafter\@texosquery@tenthoften\@texosquery@current + \else + 0% + \fi + }% + \ifnum\@texosquery@digit=0\relax + \@texosquery@zerodigit + \else + \if@texosquery@digitfound + \else + \ifx\@texosquery@currentsign\texosquerypatfmtminus + \texosquerypatfmtminus + \let\@texosquery@currentsign\empty + \fi + \fi + \@texosquery@digitfoundtrue + \@texosquery@digit + \fi +} +\def\@texosquery@zerodigit@leading{% + \edef\@texosquery@digit{% + \ifcase\@texosquery@digitindex + 0% + \or + \expandafter\@texosquery@firstoften\@texosquery@current + \or + \expandafter\@texosquery@firsttwooften\@texosquery@current + \or + \expandafter\@texosquery@firstthreeoften\@texosquery@current + \or + \expandafter\@texosquery@firstfouroften\@texosquery@current + \or + \expandafter\@texosquery@firstfiveoften\@texosquery@current + \or + \expandafter\@texosquery@firstsixoften\@texosquery@current + \or + \expandafter\@texosquery@firstsevenoften\@texosquery@current + \or + \expandafter\@texosquery@firsteightoften\@texosquery@current + \or + \expandafter\@texosquery@firstnineoften\@texosquery@current + \or + \@texosquery@current + \else + 0% + \fi + }% + \ifnum\@texosquery@digit>0\relax + \if@texosquery@digitfound + \else + \ifx\texosquerypatminus\texosquerypatfmtminus + \texosquerypatfmtminus + \fi + \fi + \@texosquery@digitfoundtrue + 0% + \fi +} +\def\@texosquery@zerodigit@trailing{% + \edef\@texosquery@digit{% + \ifcase\@texosquery@digitindex + 0% + \or + \@texosquery@current + \or + \expandafter\@texosquery@lastnineoften\@texosquery@current + \or + \expandafter\@texosquery@lasteightoften\@texosquery@current + \or + \expandafter\@texosquery@lastsevenoften\@texosquery@current + \or + \expandafter\@texosquery@lastsixoften\@texosquery@current + \or + \expandafter\@texosquery@lastfiveoften\@texosquery@current + \or + \expandafter\@texosquery@lastfouroften\@texosquery@current + \or + \expandafter\@texosquery@lastthreeoften\@texosquery@current + \or + \expandafter\@texosquery@lasttwooften\@texosquery@current + \or + \expandafter\@texosquery@tenthoften\@texosquery@current + \else + 0% + \fi + }% + \ifnum\@texosquery@digit>0\relax + \if@texosquery@digitfound + \else + \ifx\texosquerypatminus\texosquerypatfmtminus + \texosquerypatfmtminus + \fi + \fi + \@texosquery@digitfoundtrue + 0% + \fi +} +\def\texosquerypatfmtminus{\ifmmode-\else$-$\fi} +\def\texosquerypatfmtplus{\ifmmode+\else$+$\fi} +\def\texosquerypatfmtgroupsep{,} +\def\texosquerypatfmt@groupsep{% + \if@texosquery@digitfound\texosquerypatfmtgroupsep\fi} +\def\texosquerypatfmtpercentsign{\%} +\def\texosquerypatfmtpermillsign{‰} +\def\@texosquery@adjust@per#1{% + \@texosquery@pos@shift{#1}% + \edef\@texosquery@int{\expandafter\@texosquery@paddigits + \expandafter{\number\@texosquery@int}}% + \edef\@texosquery@frac{\@texosquery@paddigits@trailing{\@texosquery@frac}}% + \edef\@texosquery@current{\expandafter\@texosquery@gobble\@texosquery@int}% +} +\def\texosquery@patfmt@prefixpercent#1#2{% + \@texosquery@adjust@per{2}% + #2\texosquerypatfmtpercentsign#1% +} +\def\texosquery@patfmt@suffixpercent#1#2{% + \@texosquery@adjust@per{2}% + #1\texosquerypatfmtpercentsign#2% +} +\def\texosquery@patfmt@prefixpermill#1#2{% + \@texosquery@adjust@per{3}% + #2\texosquerypatfmtpermillsign#1% +} +\def\texosquery@patfmt@suffixpermill#1#2{% + \@texosquery@adjust@per{3}% + #1\texosquerypatfmtpermillsign#2% +} \@texosquery@restore@at \endinput %% diff --git a/Master/tlpkg/libexec/ctan2tds b/Master/tlpkg/libexec/ctan2tds index 7849efcbd69..d09cd07add3 100755 --- a/Master/tlpkg/libexec/ctan2tds +++ b/Master/tlpkg/libexec/ctan2tds @@ -2293,7 +2293,7 @@ $standardsource = '(\.(bat|c|drv|dtx|fea|fdd|ins|sfd)' 'rcs', 'rcs.el|src|' . $standardsource, 'ruhyphen', '^[^.]*$|README.ru|hyphen.rules', 'selnolig', 'NULL', # not .fea - 'texosquery', '.java|' . $standardsource, + 'texosquery', 'java|\.batch$|' . $standardsource, 'thailatex', 'NULL', # no gain in splitting up 'translation-array-fr', 'NULL', # doc 'translation-chemsym-de', 'NULL', # doc @@ -2843,7 +2843,7 @@ $standardttf = '\.ttf|\.TTC'; 'texfot' => 'texfot\.pl$', 'texliveonfly' => '\.py$', 'texloganalyser' => 'texloganalyser', - 'texosquery' => 'texosquery$', + 'texosquery' => 'texosquery(|-jre[5-9])\.sh$', 'typeoutfileinfo' => '\.sh$', 'thumbpdf' => '\.pl$', 'ulqda' => '\.pl$', diff --git a/Master/tlpkg/tlpsrc/texosquery.tlpsrc b/Master/tlpkg/tlpsrc/texosquery.tlpsrc index aefd3a571c4..91407205240 100644 --- a/Master/tlpkg/tlpsrc/texosquery.tlpsrc +++ b/Master/tlpkg/tlpsrc/texosquery.tlpsrc @@ -1,2 +1,2 @@ binpattern f bin/${ARCH}/${PKGNAME} - +binpattern f bin/${ARCH}/${PKGNAME}-jre* |