summaryrefslogtreecommitdiff
path: root/support/SQLTeX
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/SQLTeX
Initial commit
Diffstat (limited to 'support/SQLTeX')
-rw-r--r--support/SQLTeX/README91
-rw-r--r--support/SQLTeX/SQLTeX.cfg51
-rw-r--r--support/SQLTeX/SQLTeX.pdfbin0 -> 271211 bytes
-rwxr-xr-xsupport/SQLTeX/SQLTeX.pl1001
-rw-r--r--support/SQLTeX/SQLTeX.tex798
-rw-r--r--support/SQLTeX/SQLTeX_r.dat29
-rwxr-xr-xsupport/SQLTeX/install69
7 files changed, 2039 insertions, 0 deletions
diff --git a/support/SQLTeX/README b/support/SQLTeX/README
new file mode 100644
index 0000000000..543249e0fc
--- /dev/null
+++ b/support/SQLTeX/README
@@ -0,0 +1,91 @@
+SQLTeX v2.0
+===========
+
+SQLTeX is a preprocessor to enable the use of SQL statements in LaTeX.
+It is a perl script that reads an input file containing the SQL commands,
+and writes a LaTeX file that can be processed with your LaTeX package.
+
+The SQL commands will be replaced by their values. It's possible to select
+a single field for substitution substitution in your LaTeX document, or to
+be used as input in another SQL command.
+
+When an SQL command returns multiple fields and or rows, the values can only
+be used for substitution in the document.
+
+Installing SQLTeX
+-----------------
+Before installing SQLTeX, you need to have it. The latest version can always
+be found at http://software.oveas.net/sqltex.
+The download consists of this readme, documentation in LaTeX and HTML format,
+an installation script for Unix (install), the Perl script SQLTeX, the
+default replace- and configuration files, and the Windows executable.
+
+On a Unix system, make sure the file install is executable by issueing
+the command:
+ bash$ chmod +x install
+then execute it with:
+ bash$ ./install
+
+The script will ask in which directory SQLTeX should be installed. If you are
+logged in as `root', the default will be /usr/local/bin, otherwise the
+current directory.
+Make sure the directory where SQLTeX is installed is in your path.
+
+For other operating systems, there is no install script, you will have to install
+it manually.
+
+On OpenVMS it would be something like:
+ $ COPY SQLTEX.PL SYS$SYSTEM:
+ $ COPY SQLTEX.CFG SYS$SYSTEM:
+ $ COPY SQLTEX_R.DAT SYS$SYSTEM:
+ $ SET FILE/PROTECTION=(W:R) SYS$SYSTEM:SQLTEX*.*
+However, on OpenVMS you also need to define the command SQLTEX by setting a symbol,
+either in the LOGIN.COM for all users who need to execute this script, or in some
+group-- or system wide login procedure, with the command:
+ $ SQLTEX :== "PERL SYS$SYSTEM:SQLTEX.PL"
+
+For more information, please refer to the LaTeX documentation.
+
+
+Requirements:
+-------------
+* Perl (http://perl.org/)
+* Perl-DBI (http://dbi.perl.org/)
+* The DBI driver for your database (see: http://search.cpan.org/search?query=DBD%3A%3A&mode=module)
+
+
+Note for MAC users:
+-------------------
+If DBI and the database driver are not yet installed, Xtools needs to be
+installed in advance, since gcc is not available in a standard install
+of Mac OS X.
+
+
+Note for Windows users:
+-----------------------
+This distribution contains an .EXE file that was generated using PAR::Packer with
+Strawberry Perl.
+The files SQLTeX.EXE, SQLTeX.cfg and SQLTeX-r.dat must be placed manually in the
+directory of your choice, all in the same direcrtory.
+
+
+Thanks to:
+==========
+Ingo Reich for the comment on Mac OS
+Johan W. Klüwer for verifying the SyBase support
+Paolo Cavallini for adding PostgreSQL support
+
+==========================================================================
+The SQL\TeX\ project is available from GitHub:
+ https://github.com/oveas/sqltex
+The latest stable release is always available at
+ http://oveas.com/freeware/overige/sqltex
+For bugs, questions and comments, please use the issue tracker available at
+ https://github.com/oveas/sqltex/issues
+
+This software is subject to the terms of the LaTeX Project Public License;
+see http://www.ctan.org/tex-archive/help/Catalogue/licenses.lppl.html
+
+Copyright (c) 2001-2016 - Oscar van Eijk, Oveas Functionality Provider
+==========================================================================
+
diff --git a/support/SQLTeX/SQLTeX.cfg b/support/SQLTeX/SQLTeX.cfg
new file mode 100644
index 0000000000..51e230c88e
--- /dev/null
+++ b/support/SQLTeX/SQLTeX.cfg
@@ -0,0 +1,51 @@
+# Pg, Sybase, Oracle, Ingres, mSQL, ...
+#
+dbdriver = mysql
+
+# SID for Oracle users, ignored for other databases
+#
+oracle_sid = ORASID
+
+# default tex- file extension
+#
+texex = tex
+
+# file name extension to insert before the last '.'
+#
+stx = _stx
+
+# Comment-sign used in the replace file(s). Leave empty to disable comments
+#
+rfile_comment = ;
+
+# Indicator of a regular expression in the replace file. The rfile_regexploc setting indicates the
+# position of the regular expression and must be part of 'rfile_regexp'
+# Refer to the documentation for more info. (see section~\ref{loops}).
+#
+rfile_regexploc = ...
+rfile_regexp = re(...)
+
+# Commend section. All SQLTeX commands start with <cmd_prefix> and are followed
+# by the actual command. Change this only if latex commands are used that conflict
+# with the defaults.
+#
+cmd_prefix = sql
+sql_open = db
+sql_field = field
+sql_row = row
+sql_params = setparams
+sql_update = update
+sql_start = start
+sql_end = end
+sql_use = use
+
+# Are the commands 'less' and/or 'ore' available on this system ?
+#
+less_av = 1
+more_av = 1
+
+# The values below are used internally only. There's no need to change these,
+# unless there are conflicts. Refer to the documentation for more info.
+#
+repl_step = OSTX
+alt_cmd_prefix = processedsqlcommand
diff --git a/support/SQLTeX/SQLTeX.pdf b/support/SQLTeX/SQLTeX.pdf
new file mode 100644
index 0000000000..127dddd413
--- /dev/null
+++ b/support/SQLTeX/SQLTeX.pdf
Binary files differ
diff --git a/support/SQLTeX/SQLTeX.pl b/support/SQLTeX/SQLTeX.pl
new file mode 100755
index 0000000000..e1adfa0767
--- /dev/null
+++ b/support/SQLTeX/SQLTeX.pl
@@ -0,0 +1,1001 @@
+################################################################################
+#
+# SQLTeX - SQL preprocessor for Latex
+#
+# File: SQLTeX
+# =====
+#
+# Purpose: This script is a preprocessor for LaTeX. It reads a LaTeX file
+# ======== containing SQL commands, and replaces them their values.
+#
+# This software is subject to the terms of the LaTeX Project Public License;
+# see http://www.ctan.org/tex-archive/help/Catalogue/licenses.lppl.html.
+#
+# Copyright: (c) 2001-2016, Oscar van Eijk, Oveas Functionality Provider
+# ========== oscar@oveas.com
+#
+# History:
+# ========
+# v1.3 Mar 16, 2001 (Initial release)
+# v1.4 May 2, 2002
+# v1.4.1 Feb 15, 2005
+# v1.5 Nov 23, 2007
+# v2.0 Jan 12, 2016
+# Refer to the documentation for changes per release
+#
+# TODO:
+# =====
+# Code is getting messy - too many globals: rewrite required
+#
+################################################################################
+#
+use strict;
+use DBI;
+use Getopt::Std;
+
+#####
+# Find out if any command-line options have been given
+# Parse them using 'Getopt'
+#
+sub parse_options {
+
+ $main::NULLallowed = 0;
+
+ if (!getopts ('c:E:NPU:Ve:fhmMo:p:r:qs:u', \%main::options)) {
+ print (&short_help (1));
+ exit(1);
+ }
+
+ if (defined $main::options{'h'}) {
+ &print_help;
+ exit(0);
+ }
+ if (defined $main::options{'V'}) {
+ &print_version;
+ exit(0);
+ }
+
+ my $optcheck = 0;
+ $optcheck++ if (defined $main::options{'E'});
+ $optcheck++ if (defined $main::options{'e'});
+ $optcheck++ if (defined $main::options{'o'});
+ die ("options \"-E\", \"-e\" and \"-o\" cannot be combined\n") if ($optcheck > 1);
+
+ $optcheck = 0;
+ $optcheck++ if (defined $main::options{'m'});
+ $optcheck++ if (defined $main::options{'M'});
+ $optcheck++ if (defined $main::options{'o'});
+ die ("options \"-m\", \"-M\" and \"-o\" cannot be combined\n") if ($optcheck > 1);
+
+ $main::NULLallowed = 1 if (defined $main::options{'N'});
+ $main::configuration{'cmd_prefix'} = $main::options{'p'} if (defined $main::options{'p'});
+
+ $main::multidoc_cnt = 0;
+ $main::multidoc = (defined $main::options{'m'} || defined $main::options{'M'});
+ $main::multidoc_id = '';
+
+ if ($main::multidoc) {
+ $main::multidoc_id = '_#M#';
+ if (defined $main::options{'M'}) {
+ $main::multidoc_id = '_#P#'
+ }
+ }
+
+}
+
+#####
+# Print the Usage: line on errors and after the '-h' switch
+#
+sub short_help ($) {
+ my $onerror = shift;
+ my $helptext = "usage: $main::myself [-cENPUVefhmopqs] <file[.$main::configuration{'texex'}]> [parameter...]\n";
+ $helptext .= " type \"$main::myself -h\" for help\n" if ($onerror);
+ return ($helptext);
+}
+
+
+#####
+# Print full help and after the '-h' switch
+#
+sub print_help {
+ my $helptext = &short_help (0);
+ $helptext .= " Options:\n";
+ $helptext .= " -c file SQLTeX configuration file.\n";
+ $helptext .= " Default is \'$main::my_location/SQLTeX.cfg\'.\n";
+ $helptext .= " -E string replace input file extension in outputfile:\n";
+ $helptext .= " \'input.tex\' will be \'input.string\'\n";
+ $helptext .= " For further notes, see option \'-e\' below\n";
+ $helptext .= " -N NULL return values allowed. By default SQLTeX\n";
+ $helptext .= " exits if a query returns an empty set\n";
+ $helptext .= " -P prompt for database password\n";
+ $helptext .= " -U user database username\n";
+ $helptext .= " -V print version number and exit\n";
+ $helptext .= " -e string add string to the output filename:\n";
+ $helptext .= " \'input.tex\' will be \"inputstring.tex\"\n";
+ $helptext .= " In \'string\', the values between curly braces \{\}\n";
+ $helptext .= " will be substituted:\n";
+ $helptext .= " Pn parameter n\n";
+ $helptext .= " M current monthname (Mon)\n";
+ $helptext .= " W current weekday (Wdy)\n";
+ $helptext .= " D current date (yyyymmdd)\n";
+ $helptext .= " DT current date and time (yyyymmddhhmmss)\n";
+ $helptext .= " T current time (hhmmss)\n";
+ $helptext .= " e.g., the command \'$main::myself -e _{P1}_{W} my_file code\'\n";
+ $helptext .= " will read \'my_file.tex\' and write \'myfile_code_Tue.tex\'\n";
+ $helptext .= " The same command, but with option \'-E\' would create the\n";
+ $helptext .= " outputfile \'myfile._code_Tuesday\'\n";
+ $helptext .= " By default (without \'-e\' or \'-E\') the outputfile\n";
+ $helptext .= " \'myfile_stx.tex\' would have been written.\n";
+ $helptext .= " The options \'-E\' and \'-e\' cannot be used together or with \'-o\'.\n";
+ $helptext .= " -f force overwrite of existing files\n";
+ $helptext .= " -h print this help message and exit\n";
+ $helptext .= " -m Multidocument mode; create one document for each parameter that is\n";
+ $helptext .= " retrieved from the database in the input document (see documentation)\n";
+ $helptext .= " This option cannot be used with \'-o\'.\n";
+ $helptext .= " -M Same as -m, but with the parameter in the filename i.s.o. a serial number\n";
+ $helptext .= " -o file specify an output file. Cannot be used with \'-E\' or \'-e\'\n";
+ $helptext .= " This option cannot be used with \'-m\'.\n";
+ $helptext .= " -p prefix prefix used in the SQLTeX file. Default is \'sql\'\n";
+ $helptext .= " (e.g. \\sqldb[user]{database}), but this can be overwritten\n";
+ $helptext .= " if it conflicts with other user-defined commands.\n";
+ $helptext .= " -q run in quiet mode\n";
+ $helptext .= " -r file specify a file that contains replace characters. This is a list with\n";
+ $helptext .= " two tab- seperated fields per line. The first field holds a string\n";
+ $helptext .= " that will be replaced in the SQL output by the second string.\n";
+ $helptext .= " By default the file \'$main::my_location/SQLTeX_r.dat\' is used.\n";
+ $helptext .= " -rn do not use a replace file. -r file and -rn are handled in the same\n";
+ $helptext .= " as they where specified on the command line.\n";
+ $helptext .= " -s server SQL server to connect to. Default is \'localhost\'\n";
+ $helptext .= " -u If the input file contains updates, execute them.\n";
+
+ $helptext .= "\n file is the input file that should be read. By default,\n";
+ $helptext .= " $main::myself looks for a file with extension \'.$main::configuration{'texex'}\'.\n";
+ $helptext .= "\n parameter(s) are substituted in the SQL statements if they contain\n";
+ $helptext .= " the string \$PAR[x] somewhere in the statement, where\n";
+ $helptext .= " \'x\' is the number of the parameter.\n";
+
+ if ($main::configuration{'less_av'}) {
+ system ("echo \"$helptext\" | less");
+ } elsif ($main::configuration{'more_av'}) {
+ system ("echo \"$helptext\" | more");
+ } else {
+ print $helptext;
+ }
+}
+
+#####
+# Print the version number
+#
+sub print_version {
+ print "$main::myself v$main::version - $main::rdate\n";
+}
+
+#####
+# If we're not running in quiet mode (-q), this routine prints a message telling
+# the user what's going on.
+#
+sub print_message ($) {
+ my $message = shift;
+ print "$message\n" unless (defined $main::options{'q'});
+}
+
+
+#####
+# If we have to prompt for a password, disable terminal echo, get the password
+# and return it to the caller
+#
+sub get_password ($$) {
+ my ($usr, $srv) = @_;
+
+ print "Password for $usr\@$srv : ";
+
+ system('stty -echo');
+ my $pwd = <STDIN>;
+ chomp $pwd;
+ system('stty echo');
+ print "\n";
+
+ return $pwd;
+}
+
+#######
+# Find the file extension for the outputfile
+#
+sub file_extension ($) {
+ my $subst = shift;
+
+ my %mn = ('Jan','01', 'Feb','02', 'Mar','03', 'Apr','04',
+ 'May','05', 'Jun','06', 'Jul','07', 'Aug','08',
+ 'Sep','09', 'Oct','10', 'Nov','11', 'Dec','12' );
+ my $sydate = localtime (time);
+ my ($wday, $mname, $dnum, $time, $year) = split(/\s+/,$sydate);
+ $dnum = "0$dnum" if ($dnum < 10);
+ while ($subst =~ /\{[a-zA-Z0-9]+\}/) {
+ my $s1 = $`;
+ my $sub = $&;
+ my $s2 = $';
+ $sub =~ s/[\{\}]//g;
+ if ($sub =~ /P[0-9]/) {
+ $sub =~ s/P//;
+ die ("insufficient parameters to substitute \{P$sub\}\n") if ($sub > $#ARGV);
+ $sub = $ARGV[$sub];
+ } elsif ($sub eq 'M') {
+ $sub = $mname;
+ } elsif ($sub eq 'W') {
+ $sub = $wday;
+ } elsif ($sub eq 'D') {
+ $sub = "$year$mn{$mname}$dnum";
+ } elsif ($sub eq 'DT') {
+ $sub = "$year$mn{$mname}$dnum$time";
+ $sub =~ s/://g;
+ } elsif ($sub eq 'T') {
+ $sub = $time;
+ $sub =~ s/://g;
+ } else {
+ die ("unknown substitution code \{$sub\}\n");
+ }
+ $subst = "$s1$sub$s2";
+ }
+ return ($subst);
+}
+
+#####
+# Declare the filenames to use in this run.
+# If a file has been entered
+#
+sub get_filenames {
+ $main::inputfile = $ARGV[0] || die "no input file specified\n";
+
+ $main::path = '';
+ while ($main::inputfile =~ /\//) {
+ $main::path .= "$`/";
+ $main::inputfile =~ s/$`\///;
+ }
+ if ($main::inputfile =~/\./) {
+ if ((!-e "$main::path$main::inputfile") && (-e "$main::path$main::inputfile.$main::configuration{'texex'}")) {
+ $main::inputfile .= ".$main::configuration{'texex'}";
+ }
+ } else {
+ $main::inputfile .= ".$main::configuration{'texex'}"
+ }
+ die "File $main::path$main::inputfile does not exist\n" if (!-e "$main::path$main::inputfile");
+
+ if (!defined $main::options{'o'}) {
+ $main::inputfile =~ /\./;
+ $main::outputfile = "$`";
+ my $lastext = "$'";
+ while ($' =~ /\./) {
+ $main::outputfile .= ".$`";
+ $lastext = "$'";
+ }
+ if (defined $main::options{'E'} || defined $main::options{'e'}) {
+ $main::configuration{'stx'} = &file_extension ($main::options{'E'} || $main::options{'e'});
+ }
+ if (defined $main::options{'E'}) {
+ $main::outputfile .= "$main::multidoc_id.$main::configuration{'stx'}";
+ } else {
+ $main::outputfile .= "$main::configuration{'stx'}$main::multidoc_id\.$lastext";
+ }
+ } else {
+ $main::outputfile = $main::options{'o'};
+ }
+
+ if (defined $main::options{'c'}) {
+ $main::configurationfile = $main::options{'c'};
+ } else {
+ $main::configurationfile = "$main::my_location/SQLTeX.cfg";
+ }
+ if (!-e $main::configurationfile) {
+ die ("Configfile $main::configurationfile does not exist\n");
+ }
+
+ if (defined $main::options{'r'}) {
+ $main::replacefile = $main::options{'r'};
+ } else {
+ $main::replacefile = "$main::my_location/SQLTeX_r.dat";
+ }
+ if (!-e $main::replacefile) {
+ warn ("replace file $main::replacefile does not exist\n") unless ($main::replacefile eq "n");
+ undef $main::replacefile;
+ }
+
+
+ return;
+}
+
+#######
+# Connect to the database
+#
+sub db_connect($$) {
+ my ($up, $db) = @_;
+ my $data_source;
+
+ $main::line =~ s/\[?$up\]?\{$db\}//;
+
+ my $un = '';
+ my $pw = '';
+ my $hn = '';
+ my @opts = split(',', $up);
+ for(my $idx = 0; $idx <= $#opts; $idx++) {
+ my $opt = $opts[$idx];
+ if ($opt =~ /=/) {
+ if ($` eq 'user') {
+ $un = $';
+ } elsif ($` eq 'passwd') {
+ $pw = $';
+ } elsif ($` eq 'host') {
+ $hn = $';
+ }
+ } else {
+ if ($idx == 0) {
+ $un = $opt;
+ } elsif ($idx == 1) {
+ $pw = $opt;
+ } elsif ($idx == 2) {
+ $hn = $opt;
+ }
+ }
+ }
+
+ $un = $main::options{'U'} if (defined $main::options{'U'});
+ $pw = &get_password ($un, $main::options{'s'} || 'localhost') if (defined $main::options{'P'});
+ $hn = $main::options{'s'} if (defined $main::options{'s'});
+
+ if ($main::configuration{'dbdriver'} eq "Pg") {
+ $data_source = "DBI:$main::configuration{'dbdriver'}:dbname=$db";
+ $data_source .= ";host=$hn" unless ($hn eq "");
+ } elsif ($main::configuration{'dbdriver'} eq "Oracle") {
+ $data_source = "DBI:$main::configuration{'dbdriver'}:$db";
+ $data_source .= ";host=$hn;sid=$main::configuration{'oracle_sid'}" unless ($hn eq "");
+ $data_source .= ";sid=$main::configuration{'oracle_sid'}";
+ } elsif ($main::configuration{'dbdriver'} eq "Ingres") {
+ $data_source = "DBI:$main::configuration{'dbdriver'}";
+ $data_source .= ":$hn" unless ($hn eq "");
+ $data_source .= ":$db";
+ } elsif ($main::configuration{'dbdriver'} eq "Sybase") {
+ $data_source = "DBI:$main::configuration{'dbdriver'}:$db";
+ $data_source .= ";server=$hn" unless ($hn eq "");
+ } else { # MySQL, mSQL, ...
+ $data_source = "DBI:$main::configuration{'dbdriver'}:database=$db";
+ $data_source .= ";host=$hn" unless ($hn eq "");
+ }
+
+ if (!defined $main::options{'q'}) {
+ my $msg = "Connect to database $db on ";
+ $msg .= $hn|| 'localhost';
+ $msg .= " as user $un" unless ($un eq '');
+ $msg .= " using a password" unless ($pw eq '');
+ &print_message ($msg);
+ }
+ $main::db_handle = DBI->connect ($data_source, $un, $pw, { RaiseError => 0, PrintError => 1 }) || &just_died (1);
+ return;
+}
+
+#####
+# Execute the SQL query and return the result in an array
+#
+sub execute_query ($) {
+ my $query = shift;
+ my (@result, @res);
+ return @result;
+}
+
+#####
+# Check if the SQL statement contains options
+# Supported options are:
+# setvar=<i>, where <i> is the list location to store the variable.
+# setarr=<i>
+#
+sub check_options ($) {
+ my $options = shift;
+ return if ($options eq '');
+ $options =~ s/\[//;
+ $options =~ s/\]//;
+
+ my @optionlist = split /,/, $options;
+ while (@optionlist) {
+ my $opt = shift @optionlist;
+ if ($opt =~ /^setvar=/i) {
+ $main::var_no = $';
+ $main::setvar = 1;
+ }
+ if ($opt =~ /^setarr=/i) {
+ $main::arr_no = $';
+ $main::setarr = 1;
+ }
+ if ($opt =~ /^fldsep=/i) {
+ $main::fldsep = qq{$'};
+ if ($main::fldsep eq 'NEWLINE') {
+ $main::fldsep = "\n";
+ }
+ }
+ if ($opt =~ /^rowsep=/i) {
+ $main::rowsep = qq{$'};
+ if ($main::rowsep eq 'NEWLINE') {
+ $main::rowsep = "\n";
+ }
+ }
+ }
+}
+
+#####
+# Replace values from the query result as specified in the replace files.
+# This is done in two steps, to prevent characters from being replaces again
+# if they occus both as key and as value.
+#
+sub replace_values ($) {
+ my $sqlresult = shift;
+ my $rk;
+
+ foreach $rk (@main::repl_order) {
+ my ($begin, $end) = split /\Q$main::configuration{'rfile_regexploc'}\E/,$main::configuration{'rfile_regexp'};
+ if ($rk =~ /^\Q$begin\E(.*)\Q$end\E$/) {
+ $sqlresult =~ s/$1/$main::repl_key{$rk}/g;
+ } else {
+ $sqlresult =~ s/\Q$rk\E/$main::repl_key{$rk}/g;
+ }
+ }
+
+ foreach $rk (keys %main::repl_key) {
+ $sqlresult =~ s/$main::repl_key{$rk}/$main::repl_val{$main::repl_key{$rk}}/g;
+ }
+ return ($sqlresult);
+}
+
+#####
+# Select multiple rows from the database. This function can have
+# the [fldsep=s] and [rowsep=s] options to define the string which
+# should be used to seperate the fields and rows.
+# By default, fields are seperated with a comma and blank (', '), and rows
+# are seperated with a newline character ('\\')
+#
+sub sql_row ($$) {
+ my ($options, $query) = @_;
+ local $main::fldsep = ', ';
+ local $main::rowsep = "\\\\";
+ local $main::setarr = 0;
+ my (@values, @return_values, $rc, $fc);
+
+ &check_options ($options);
+
+ &print_message ("Retrieving row(s) with \"$query\"");
+ $main::sql_statements++;
+ my $stat_handle = $main::db_handle->prepare ($query);
+ $stat_handle->execute ();
+
+ if ($main::setarr) {
+ &just_died (7) if (defined $main::arr[$main::arr_no]);
+ @main::arr[$main::arr_no] = ();
+ while (my $ref = $stat_handle->fetchrow_hashref()) {
+ foreach my $k (keys %$ref) {
+ $ref->{$k} = replace_values ($ref->{$k});
+ }
+ push @{$main::arr[$main::arr_no]},$ref;
+ }
+ $stat_handle->finish ();
+ return ();
+ }
+
+ while (@values = $stat_handle->fetchrow_array ()) {
+ $fc = $#values + 1;
+ if (defined $main::replacefile) {
+ my $list_cnt = 0;
+ foreach (@values) {
+ $values[$list_cnt] = replace_values ($values[$list_cnt]);
+ $list_cnt++;
+ }
+ }
+ push @return_values, (join "$main::fldsep", @values);
+ }
+ $stat_handle->finish ();
+
+ if ($#return_values < 0) {
+ &just_died (4);
+ }
+
+ $rc = $#return_values + 1;
+ if ($rc == 1) {
+ &print_message ("Found $rc row with $fc field(s)");
+ } else {
+ &print_message ("Found $rc rows with $fc fields each");
+ }
+
+ return (join "$main::rowsep", @return_values);
+
+}
+
+
+#####
+# Select a single field from the database. This function can have
+# the [setvar=n] option to define an internal variable
+#
+sub sql_field ($$) {
+ my ($options, $query) = @_;
+ local $main::setvar = 0;
+
+ &check_options ($options);
+
+ $main::sql_statements++;
+
+ &print_message ("Retrieving field with \"$query\"");
+ my $stat_handle = $main::db_handle->prepare ($query);
+ $stat_handle->execute ();
+ my @result = $stat_handle->fetchrow_array ();
+ $stat_handle->finish ();
+
+ if ($#result < 0) {
+ &just_died (4);
+ } elsif ($#result > 0) {
+ &just_died (5);
+ } else {
+ &print_message ("Found 1 value: \"$result[0]\"");
+ if ($main::setvar) {
+ &just_died (7) if (defined $main::var[$main::var_no]);
+ $main::var[$main::var_no] = $result[0];
+ return '';
+ } else {
+ if (defined $main::replacefile) {
+ return (replace_values ($result[0]));
+ } else {
+ return ($result[0]);
+ }
+ }
+ }
+}
+
+#####
+# Start a section that will be repeated for evey row that is on stack
+#
+sub sql_start ($) {
+ my $arr_no = shift;
+ &just_died (11) if (!defined $main::arr[$arr_no]);
+ if (@main::current_array) {
+ @main::current_array = ();
+ }
+ @main::loop_data = ();
+ push @main::current_array,$arr_no;
+}
+
+#####
+# Use a named variable from the stack
+#
+sub sql_use ($$) {
+ my ($field, $loop) = @_;
+ return $main::arr[$#main::current_array][$loop]->{$field};
+}
+
+
+#####
+# Stop processing the current array
+#
+sub sql_end () {
+ my $result = '';
+
+ for (my $cnt = 0; $cnt <= $#{$main::arr[$#main::current_array]}; $cnt++) {
+ for (my $lines = 0; $lines < $#{$main::loop_data[$#main::current_array]}; $lines++) {
+ my $buffered_line = ${$main::loop_data[$#main::current_array]}[$lines];
+ my $cmdPrefix = $main::configuration{'alt_cmd_prefix'};
+ while (($buffered_line =~ /\\$cmdPrefix[a-z]+(\[|\{)/) && !($buffered_line =~ /\\\\$cmdPrefix[a-z]+(\[|\{)/)) {
+ my $cmdfound = $&;
+ $cmdfound =~ s/\\//;
+
+ $buffered_line =~ /\\$cmdfound/;
+ my $lin1 = $`;
+ $buffered_line = $';
+ $buffered_line =~ /\}/;
+ my $statement = $`;
+ my $lin2 = $';
+ if ($cmdfound =~ /$main::configuration{'sql_use'}/) {
+ $buffered_line = $lin1 . &sql_use($statement, $cnt) . $lin2;
+ }
+ }
+ $result .= $buffered_line;
+ }
+ }
+
+ pop @main::current_array;
+ return $result;
+}
+
+
+
+#####
+# Select a (list of) single field(s) from the database. This list is used in
+# multidocument mode as the first parameter in all queries.
+# Currently, only 1 parameter per run is supported.
+#
+sub sql_setparams ($$) {
+ my ($options, $query) = @_;
+ my (@values, @return_values, $rc);
+
+ &check_options ($options);
+
+ &print_message ("Retrieving parameter list with \"$query\"");
+ $main::sql_statements++;
+ my $stat_handle = $main::db_handle->prepare ($query);
+ $stat_handle->execute ();
+
+ while (@values = $stat_handle->fetchrow_array ()) {
+ &just_died (9) if ($#values > 0); # Only one allowed
+ push @return_values, @values;
+ }
+ $stat_handle->finish ();
+
+ if ($#return_values < 0) {
+ &just_died (8);
+ }
+
+ $rc = $#return_values + 1;
+ &print_message ("Multidocument parameters found; $rc documents will be created: handle document $main::multidoc_cnt");
+
+ return (@return_values);
+}
+
+
+#####
+# Select a (list of) single field(s) from the database. This list is used in
+# multidocument mode as the first parameter in all queries.
+# Currently, only 1 parameter per run is supported.
+#
+sub sql_update ($$) {
+ my ($options, $query) = @_;
+ local $main::setvar = 0;
+
+ if (!defined $main::options{'u'}) {
+ &print_message ("Updates will be ignored");
+ return;
+ }
+ &check_options ($options);
+
+ &print_message ("Updating values with \"$query\"");
+ my $rc = $main::db_handle->do($query);
+ &print_message ("$rc rows updated");
+}
+
+#####
+# Some error handling (mainly cleanup stuff)
+# Files will be closed if opened, and if no sql output was written yet,
+# the outputfile will be removed.
+#
+sub just_died ($) {
+ my $step = shift;
+ my $Resurect = 0;
+
+ $Resurect = 1 if ($step == 4 && $main::NULLallowed);
+
+ if ($step >= 1 && !$Resurect) {
+# close FI;
+# close FO;
+ }
+ if ($step > 2 && !$Resurect) {
+# $main::db_handle->disconnect();
+ }
+ if ($step >= 1 && $step <= 2 && !$Resurect) {
+ unlink ("$main::path$main::outputfile");
+ }
+
+ #####
+ # Step specific exit
+ #
+ my $msg;
+ if ($step == 2) {
+ $msg = "no database opened at line $main::lcount[$main::fcount]";
+ } elsif ($step == 3) {
+ $msg = "insufficient parameters to substitute variable on line $main::lcount[$main::fcount]";
+ } elsif ($step == 4) {
+ $msg = "no result set found on line $main::lcount[$main::fcount]";
+ } elsif ($step == 5) {
+ $msg = "result set too big on line $main::lcount[$main::fcount]";
+ } elsif ($step == 6) {
+ $msg = "trying to substitute with non existing on line $main::lcount[$main::fcount]";
+ } elsif ($step == 7) {
+ $msg = "trying to overwrite an existing variable on line $main::lcount[$main::fcount]";
+ } elsif ($step == 8) {
+ $msg = "no parameters for multidocument found on line $main::lcount[$main::fcount]";
+ } elsif ($step == 9) {
+ $msg = "too many fields returned in multidocument mode on $main::lcount[$main::fcount]";
+ } elsif ($step == 10) {
+ $msg = "unrecognized command on line $main::lcount[$main::fcount]";
+ } elsif ($step == 11) {
+ $msg = "start using a non-existing array on line $main::lcount[$main::fcount]";
+ } elsif ($step == 12) {
+ $msg = "\\sqluse command encountered outside loop context on line $main::lcount[$main::fcount]";
+ }
+ if ($main::fcount > 0) {
+ for (my $fcnt = 0; $fcnt < $main::fcount; $fcnt++) {
+ $msg .= ', file included from line '.$main::lcount[$fcnt];
+ }
+ }
+ warn "$msg\n";
+ return if ($Resurect);
+ exit (1);
+}
+
+#####
+# An SQL statement was found in the input file. If multiple lines are
+# used for this query, they will be read until the '}' is found, after which
+# the query will be executed.
+#
+sub parse_command ($$$) {
+ my $cmdfound = shift;
+ my $multidoc_par = shift;
+ my $file_handle = shift;
+ my $options = '';
+ my $varallowed = 1;
+
+ $varallowed = 0 if ($cmdfound =~ /$main::configuration{'sql_open'}/);
+
+ chop $cmdfound;
+ $cmdfound =~ s/\\//;
+
+ $main::line =~ /\\$cmdfound/;
+ my $lin1 = $`;
+ $main::line = $';
+
+ while (!($main::line =~ /\}/)) {
+ chomp $main::line;
+ $main::line .= ' ';
+ $main::line .= <$file_handle>;
+ $main::lcount[$main::fcount]++;
+ }
+
+ $main::line =~ /\}/;
+ my $statement = $`;
+ my $lin2 = $';
+
+ $statement =~ s/(\[|\{)//g;
+ if ($statement =~ /\]/) {
+ $options = $`;
+ $statement = $';
+ }
+
+ if ($varallowed) {
+ if (($main::multidoc_cnt > 0) && $main::multidoc) {
+ $statement =~ s/\$PAR1/$multidoc_par/g;
+ } else {
+ for (my $i = 1; $i <= $#ARGV; $i++) {
+ $statement =~ s/\$PAR$i/$ARGV[$i]/g;
+ }
+ }
+ while ($statement =~ /\$VAR[0-9]/) {
+ my $varno = $&;
+ $varno =~ s/\$VAR//;
+ &just_died (6) if (!defined ($main::var[$varno]));
+ $statement =~ s/\$VAR$varno/$main::var[$varno]/g;
+ }
+ &just_died (3) if ($statement =~ /\$PAR/ && ($main::multidoc_cnt > 0) && $main::multidoc);
+ $statement =~ s/\{//;
+ }
+
+ if ($cmdfound =~ /$main::configuration{'sql_open'}/) {
+ &db_connect($options, $statement);
+ $main::db_opened = 1;
+ return 0;
+ }
+
+ &just_died (2) if (!$main::db_opened);
+
+ if ($cmdfound =~ /$main::configuration{'sql_field'}/) {
+ $main::line = $lin1 . &sql_field($options, $statement) . $lin2;
+ } elsif ($cmdfound =~ /$main::configuration{'sql_row'}/) {
+ $main::line = $lin1 . &sql_row($options, $statement) . $lin2;
+ } elsif ($cmdfound =~ /$main::configuration{'sql_params'}/) {
+ if ($main::multidoc) { # Ignore otherwise
+ @main::parameters = &sql_setparams($options, $statement);
+ $main::line = $lin1 . $lin2;
+ return 1; # Finish this run
+ } else {
+ $main::line = $lin1 . $lin2;
+ }
+ } elsif ($cmdfound =~ /$main::configuration{'sql_update'}/) {
+ &sql_update($options, $statement);
+ $main::line = $lin1 . $lin2;
+ } elsif ($cmdfound =~ /$main::configuration{'sql_start'}/) {
+ &sql_start($statement);
+ $main::line = $lin1 . $lin2;
+ } elsif ($cmdfound =~ /$main::configuration{'sql_use'}/) {
+ &just_died (12) if (!@main::current_array);
+ $main::line = $lin1 . "\\" . $main::configuration{'alt_cmd_prefix'} . $main::configuration{'sql_use'} . "{" . $statement . "}" . $lin2; # Restore the line, will be processed later
+ } elsif ($cmdfound =~ /$main::configuration{'sql_end'}/) {
+ $main::line = $lin1 . &sql_end() . $lin2;
+ } else {
+ &just_died (10);
+ }
+
+ return 0;
+}
+
+sub read_input($$$$) {
+ my ($input_file, $output_handle, $multidoc_par) = @_;
+
+ $main::fcount++;
+ $main::lcount[$main::fcount] = 0;
+
+ if (!-e $main::path . $input_file) {
+ die "input file $main::path$input_file not found";
+ }
+ print_message("Processing file $main::path$input_file...");
+ open (my $fileIn, "<$main::path$input_file");
+
+ while ($main::line = <$fileIn>) {
+ $main::lcount[$main::fcount]++;
+ next if ($main::line =~ /^\s*%/);
+ if ($main::line =~ /(.*?)(\\in(put|clude))(\s*?)\{(.*?)\}(.*)/) {
+ print $output_handle "$1" unless ($output_handle == -1);
+ &read_input($5, $output_handle, $multidoc_par);
+ return if ($main::restart);
+ print $output_handle "$6\n" unless ($output_handle == -1);
+ }
+ my $cmdPrefix = $main::configuration{'cmd_prefix'};
+ while (($main::line =~ /\\$cmdPrefix[a-z]+(\[|\{)/) && !($main::line =~ /\\\\$cmdPrefix[a-z]+(\[|\{)/)) {
+ if (&parse_command($&, $multidoc_par, $fileIn) && $main::multidoc && ($main::multidoc_cnt == 0)) {
+ close $fileIn;
+ $main::fcount--;
+ $main::restart = 1;
+ return;
+ }
+ }
+ if (@main::current_array && $#main::current_array >= 0) {
+ push @{$main::loop_data[$#main::current_array]}, $main::line;
+ } else {
+ print $output_handle "$main::line" unless ($main::multidoc && ($main::multidoc_cnt == 0));
+ }
+ }
+ $main::fcount--;
+ close $fileIn;
+}
+
+#####
+# Process the input file
+# When multiple documents should be written, this routine is
+# multiple times.
+# The first time, it only builds a list with parameters that will be
+# used for the next executions
+#
+sub process_file {
+ my $multidoc_par = '';
+
+ if ($main::multidoc && ($main::multidoc_cnt > 0)) {
+ if (!defined($main::saved_outfile_template)) {
+ $main::saved_outfile_template = $main::outputfile;
+ }
+ $main::saved_outfile_template = $main::outputfile if ($main::multidoc_cnt == 1); # New global name; should be a static
+ $main::outputfile = $main::saved_outfile_template if ($main::multidoc_cnt > 1);
+ $main::outputfile =~ s/\#M\#/$main::multidoc_cnt/;
+ $main::outputfile =~ s/\#P\#/$main::parameters[($main::multidoc_cnt-1)]/;
+ $multidoc_par = @main::parameters[$main::multidoc_cnt - 1];
+ }
+ my $fileOut;
+ if ($main::multidoc && ($main::multidoc_cnt == 0)) {
+ $fileOut = -1;
+ } else {
+ open ($fileOut, ">$main::path$main::outputfile");
+ }
+
+ $main::sql_statements = 0;
+ $main::db_opened = 0;
+ $main::fcount = -1;
+ $main::restart = 0;
+
+ &read_input($main::path . $main::inputfile, $fileOut, $multidoc_par);
+
+ if ($main::multidoc) {
+ $main::multidoc = 0 if (($main::multidoc_cnt++) > $#main::parameters);
+ return if ($main::multidoc);
+ }
+
+ close $fileOut;
+}
+
+## Main:
+
+#####
+# Default config values, will be overwritten with SQLTeX.cfg
+#
+%main::configuration = (
+ 'dbdriver' => 'mysql'
+ ,'oracle_sid' => 'ORASID'
+ ,'texex' => 'tex'
+ ,'stx' => '_stx'
+ ,'rfile_comment' => ';'
+ ,'rfile_regexploc' => '...'
+ ,'rfile_regexp' => 're(...)'
+ ,'cmd_prefix' => 'sql'
+ ,'sql_open' => 'db'
+ ,'sql_field' => 'field'
+ ,'sql_row' => 'row'
+ ,'sql_params' => 'setparams'
+ ,'sql_update' => 'update'
+ ,'sql_start' => 'start'
+ ,'sql_end' => 'end'
+ ,'sql_use' => 'use'
+ ,'less_av' => 1
+ ,'more_av' => 1
+ ,'repl_step' => 'OSTX'
+ ,'alt_cmd_prefix' => 'processedsqlcommand'
+);
+
+#####
+# Some globals
+#
+{
+ my @dir_list = split /\//, $0;
+ pop @dir_list;
+ $main::my_location = join '/', @dir_list;
+}
+
+# Check config
+# Used for loops, should not start with $main::configuration{'cmd_prefix'} !!
+if ($main::configuration{'alt_cmd_prefix'} =~ /^$main::configuration{'cmd_prefix'}/) {
+ die "Configuration item 'alt_cmd_prefix' cannot start with $main::configuration{'cmd_prefix'}";
+}
+
+$main::myself = $ENV{'_'};
+while ($main::myself =~ /\//) { $main::myself = $'; }
+
+$main::version = '2.0';
+$main::rdate = 'Jan 12, 2016';
+
+&parse_options;
+&get_filenames;
+
+if (!$main::multidoc && -e "$main::path$main::outputfile") {
+ die ("outputfile $main::path$main::outputfile already exists\n")
+ unless (defined $main::options{'f'});
+}
+
+if (defined $main::configurationfile) {
+ open (CF, "<$main::configurationfile");
+ while ($main::line = <CF>) {
+ next if ($main::line =~ /^\s*#/);
+ next if ($main::line =~ /^\s*$/);
+ chomp $main::line;
+ my ($ck, $cv) = split /=/, $main::line;
+ $ck =~ s/\s//g;
+ $cv =~ s/\s//g;
+ if ($cv ne '') {
+ $main::configuration{$ck} = $cv;
+ }
+ }
+ close CF;
+}
+
+if (defined $main::replacefile) {
+ my $repl_cnt = '000';
+ @main::repl_order = ();
+ open (RF, "<$main::replacefile");
+ while ($main::line = <RF>) {
+ next if ($main::line =~ /^\s*$main::configuration{'rfile_comment'}/);
+ chomp $main::line;
+ $main::line =~ s/\t+/\t/;
+ my ($rk, $rv) = split /\t/, $main::line;
+ if ($rk ne '') {
+ push @main::repl_order, $rk;
+ $main::repl_key{$rk} = "$main::configuration{'repl_step'}$repl_cnt";
+ $main::repl_val{"$main::configuration{'repl_step'}$repl_cnt"} = $rv;
+ $repl_cnt++;
+ }
+ }
+ close RF;
+}
+
+# Start processing
+do {
+ &process_file;
+ $main::restart = 0;
+ if ($main::sql_statements == 0) {
+ unlink ("$main::path$main::outputfile");
+ print "no sql statements found in $main::path$main::inputfile\n";
+ $main::multidoc = 0; # Problem in the input, useless to continue
+ } else {
+ print "$main::sql_statements queries executed - TeX file $main::path$main::outputfile written\n"
+ unless ($main::multidoc && ($main::multidoc_cnt == 1));
+ }
+} while ($main::multidoc); # Set to false when done
+
+$main::db_handle->disconnect() if ($main::db_opened);
+exit (0);
+
+#
+# And that's about it.
+#####
diff --git a/support/SQLTeX/SQLTeX.tex b/support/SQLTeX/SQLTeX.tex
new file mode 100644
index 0000000000..4d17cad262
--- /dev/null
+++ b/support/SQLTeX/SQLTeX.tex
@@ -0,0 +1,798 @@
+\documentclass{article}
+\newcommand{\bs}{\ensuremath{\backslash}}
+\newcommand{\vs}{\vspace{3mm}}
+\usepackage{makeidx}
+\usepackage[pdftex
+ ,pagebackref=true
+ ,colorlinks=true
+ ,linkcolor=blue
+ ,unicode]{hyperref}
+\begin{document}
+\title{SQL\TeX\\v2.0}
+\date{Januari 12, 2016}
+\author{Oscar van Eijk}
+\maketitle
+\hrulefill
+\tableofcontents
+\hrulefill
+
+\section{Introduction}
+
+SQL\TeX\ is a preprocessor to enable the use of SQL statements in \LaTeX. It is a perl script that reads
+an input file containing the SQL commands, and writes a \LaTeX\ file that can be processed with your
+\LaTeX\ package.
+
+The SQL commands will be replaced by their values. It's possible to select a single field for substitution
+substitution in your \LaTeX\ document, or to be used as input in another SQL command.
+
+When an SQL command returns multiple fields and or rows, the values can only be used for substitution
+in the document.
+
+\subsection{Known limitations}
+
+\begin{itemize}
+\item The \LaTeX\ \texttt{\bs includeonly} directive is ignored; all documents included with \texttt{\bs include} will be parsed and written to the output file.
+\item Currently, only 9 command- line parameters (1-9), and 10 variables (0-9) can be used in SQL statements.
+\item Replace files can hold only 1,000 items.
+\item In multidocument mode, only one parameter can be retrieved.
+\end{itemize}
+
+\section{Installing SQL\TeX}
+
+Before installing SQL\TeX, you need to have it. The latest version can always be found at
+\textsf{http://freeware.oveas.com/sqltex}.
+The download consists of this do\-cumentation, an installation script for Unix
+(\texttt{install}), and the Perl script \texttt{SQLTeX}, and a replace- file (\texttt{SQLTeX\_r.dat}) for manual installation
+on non- unix platforms\footnote{on Unix, this file will be generated by the install script}.
+
+\vs
+
+On a Unix system, make sure the file \texttt{install} is executable by issueing
+the command:\\
+\texttt{bash\$ chmod +x install}\\
+then execute it with:\\
+\texttt{bash\$ ./install}
+
+The script will ask in which directory SQL\TeX\ should be installed. If you are
+logged in as `root', the default will be \texttt{/usr/local/bin}, otherwise the
+current directory.\\
+Make sure the directory where SQL\TeX\ is installed is in your path.
+
+\vs
+
+For other operating systems, there is no install script, you will have to install
+it manually.
+
+On \textsc{OpenVMS} it would be something like:\\
+\texttt{\$ COPY SQLTEX.PL SYS\$SYSTEM:\\
+\$ COPY SQLTEX.CFG SYS\$SYSTEM:\\
+\$ COPY SQLTEX\_R.DAT SYS\$SYSTEM:\\
+\$ SET FILE/PROTECTION=(W:R) SYS\$SYSTEM:SQLTEX*.*}\\
+However, on \textsc{OpenVMS} you also need to define the command \texttt{SQLTEX} by setting a symbol,
+either in the \texttt{LOGIN.COM} for all users who need to execute this script, or in some group-- or
+system wide login procedure, with the command: \\
+\texttt{\$ SQLTEX :== "PERL SYS\$SYSTEM:SQLTEX.PL"}
+
+\subsection{Configuration}\label{config}
+
+The location where SQL\TeX\ is installed also holds the configuration file \texttt{SQLTeX.cfg}.
+Multiple configuration files can be created, the command line option \texttt{-c} can be used to
+select the requested configuration.
+
+\vs
+
+\noindent\hspace{-3mm}\textit{\underline{Note:}} If a 1.x version of SQL\TeX\ is installed on your system,
+make sure you saved the configuration section, which was inline in older versions.
+
+\vs
+
+Some values can be overwritten using command line options (see section~\ref{cmdline}). When the command line options are omitted, the values from the requested configuration file will be used.
+
+\begin{description}
+
+\item[dbdriver] Database driver. The default is \texttt{mysql}.
+Other supported databases are \texttt{Pg}, \texttt{Sybase}, \texttt{Oracle},
+\texttt{Ingres}, \texttt{mSQL} and \texttt{PostgreSQL}, but also others might
+work without modification. \\
+If your database driver is not support, look for the function
+\texttt{db\_connect} to add support (and please notify me :)
+
+\item[texex] The default file extension for \LaTeX\ file. When SQL\TeX\ is called, the first
+parameter should be the name of the input file. If this filename has no extension,
+SQL\TeX\ looks for one with the default extension.
+
+\item[stx] An output file can be given explicitly using the `\texttt{-o}' option. When omitted,
+SQL\TeX\ composes an output file name using this string.\\
+E.g, if your input file is called \texttt{db-doc.tex}, SQL\TeX\ will produce an
+outputfile with the name \texttt{db-doc\_stx.tex}.
+
+\item[rfile\_comment] The comment-sign used in replace files. If this is empty, comments are not allowed in
+the replace files.
+
+\item[rfile\_regexploc] This must be part of the value \texttt{rfile\_regexp} below.
+
+\item[rfile\_regexp] Explains how a regular expression is identified in the replace files (see section~\ref{regexp}).
+
+\item[cmd\_prefix]\label{prefix} SQL\TeX\ looks for SQL commands in the input file. Commands are specified in the
+same way all \LaTeX\ commands are specified: a backslash (\bs) followed by the
+name of the command.\\
+All SQL\TeX\ commands start with the same string. By default, this is the string
+\texttt{\textbf{sql}}. When user commands are defined that start with the same
+string, this can be changed here to prevent conflicts.
+
+\item[sql\_open] This string is appended to the \texttt{cmd\_prefix}x to
+get the complete SQL\TeX\ command for opening a database.\\
+With the default configuration this command is ``\texttt{\bs sqldb}''.
+
+\item[sql\_field] This string is appended to the \texttt{cmd\_prefix} to
+get the complete SQL\TeX\ command to read a single field from the database.\\
+With the default configuration this command is ``\texttt{\bs sqlfield}''.
+
+\item[sql\_row] This string is appended to the \texttt{cmd\_prefix} to
+get the complete SQL\TeX\ command to read one or more rows from the database.\\
+With the default configuration this command is ``\texttt{\bs sqlrow}''.
+
+\item[sql\_params] This string is appended to the \texttt{cmd\_prefix} to get the complete SQL\TeX\ command to retrieve a list if fields that will be used as parameters (\texttt{\$PAR1}, see section~\ref{params}) in the multidocument environment (see section~\ref{multidoc}).\\
+With the default configuration this command is ``\texttt{\bs sqlparams}''.
+
+\item[sql\_update] This string is appended to the \texttt{cmd\_prefix}
+to get the complete SQL\TeX\ command to update one or more rows in the database.\\
+With the default configuration this command is ``\texttt{\bs sqlupdate}''.
+
+\item[sql\_start] This string is appended to the \texttt{cmd\_prefix} to get the complete SQL\TeX\ command start a section that will be repeated for every row from an array (see section~\ref{loops}).\\
+With the default configuration this command is ``\texttt{\bs sqlstart}''.
+
+\item[sql\_use] This string is appended to the \texttt{cmd\_prefix} to get the complete SQL\TeX\ command use a named variable from the array that is currently being processed in a loop context (see section~\ref{loops}).\\
+With the default configuration this command is ``\texttt{\bs sqluse}''.
+
+\item[sql\_end] This string is appended to the \texttt{cmd\_prefix} to get the complete SQL\TeX\ command to end a loop context (see section~\ref{loops}).\\
+With the default configuration this command is ``\texttt{\bs sqlend}''.
+
+\item[less\_av \& more\_av] These settings are used to determine how the \textsl{help} output should be displayed. If the command `\texttt{less}' is available on the current system, the output will be parsed through this program. Otherwise the output will be parsed through the program `\texttt{more}' if availeble. Both programs are usually available on Unix system (\texttt{more} is standard on most Unix systems), but ports for other
+operating systems are available as well.\\
+Set the values to ``0'' for the program(s) that is (are) not available, or if you don't want to use it.\\
+If none of these programs is available, the \textsl{help} output is plain echoed to the display.
+
+\item[repl\_step] Replacing strings (see section~\ref{replfiles} below) is done two steps, to prevent values from being replaced twice.
+This setting---followed by a three-digit integer - ``000'' to ``999''---is used in the first step and replaces values from the first column.
+In the second step, values from the second column replace the temporary value. \\
+If the first column in the replace file contains a character sequence that occurs in this temporary value, or if query results might contain the full string followed by three digits, this value might need to be changed in something unique.
+
+\item[alt\_cmd\_prefix] In loop context, this setting is used internally to differentiate between sql statements to process immediately and sql statements on stack.\\
+Normally, this setting should never change, but if the value for \texttt{cmd\_prefix} has been changed and a conflict is found, the message ``\texttt{Configuration item 'alt\_cmd\_prefix' cannot start with \textit{<conflicting value>}}'' indicates this setting should change as well.
+
+\end{description}
+
+\subsection{Create replace files}\label{replfiles}
+
+Replace files can be used to substitute values in the output of your SQL commands with a different value. This is especially usefull when the database
+contains characters that are special characters in \LaTeX, like the percent sign (`\%'), underscore (`\_') etc.
+
+When SQL\TeX\ is installed, it comes with a standard file---\texttt{SQLTeX\_r.dat}---which is located in the same directory where SQLTeX is installed,
+with the following replacements:
+
+\vspace{3mm}
+
+\noindent\begin{verbatim}
+$ \$
+_ \_
+% \%
+& \&
+< \texttt{<}
+> \texttt{>}
+{ \{
+} \}
+# \#
+~ \~{}
+\ \ensuremath{\backslash}
+\end{verbatim}
+
+\vspace{3mm}
+
+These are all single character replacements, but you can add your own replacements that consist of a single character or a character sequence (or even regular expressions, see section~\ref{regexp}).\\
+To do so, enter a new line with the character(string) that should be replaced, followed by one or more \texttt{TAB}-character(s) (\textit{not} blanks!) and the character(string) it should be replaced with.
+
+If the first non-blank character is a semicolon (`;'), the line is considered a comment line\footnote{ in the default configuration. See the description for \texttt{rfile\_comment} in section~\ref{config} to change of disable comment lines.}. Blank lines are ignored.
+
+\vspace{3mm}
+
+The contents of the file are case sensitive, so of you add the line: \\
+\verb+LaTeX \LaTeX\+ \\
+the word ``LaTeX'' will be changed, but ``latex'' is untouched.
+
+\vspace{3mm}
+
+Different replace files can be created. To select a different replace file for a certain SQL\TeX\ source, use the commandline option
+`\texttt{-r \textit{filename}}'. To disable the use of replace files, use `\texttt{-rn}'.
+
+\subsubsection{Regular expressions}\label{regexp}
+
+The replace file can include regular expressions, which are recognized by a pattern given in the configuration setting \texttt{rfile\_regexp}. A part of the pattern, configurable as \texttt{rfile\_regexploc}, will be the actual regular expression.
+
+\vs
+
+By default, \texttt{rfile\_regexploc} is ``\texttt{...}'' and \texttt{rfile\_regexp} is ``\texttt{re(...)}''. If the sequence of three dots can appear anywhere else in the replace file, \texttt{rfile\_regexploc} can be changed to any other sequence of characters, e.g. ``\texttt{regexpHere}''.\\
+This also requires \texttt{rfile\_regexp} to be changed. Its new value has to be ``\texttt{re(regexpHere)}''
+
+\vs
+
+Both in the default configuration and with the modification example given above, the key for regular expressions is \texttt{re(<\textit{regular expression}>)}, e.g.:\\
+\hspace{3mm}\verb+re(<p\.*?>) \paragraph*{}+ \\
+will replace all HTML \texttt{<}p\texttt{>} variants (\texttt{<}p style='font-size: normal'\texttt{>}, \texttt{<}p align='center'\texttt{>} etc)
+
+\vs
+
+An example replacement file using regular expressions to handle HTML codes could look like this:
+
+\noindent\begin{verbatim}
+&amp; \&
+<strong> \textbf{
+</strong> }
+<em> \textit{
+</em> }
+re(<br.*?/?>) \\
+re(<p.*?>) \paragraph*{}
+</p> \\[0pt]
+<sup> $^{
+</sup> }$
+re(<span.*?>) \textsl{
+</span> }
+re(<h1.*?>) \section{
+re(<h2.*?>) \subsection{
+re(<h3.*?>) \subsubsection{
+re(</h\d>) }
+\end{verbatim}
+
+\section{Write your SQL\TeX\ file}
+
+For SQL\TeX, you write your \LaTeX\ document just as you're used to. SQL\TeX\ provides you with
+some extra commands that you can include in your file.\\
+The basic format\footnote{in this document, in all examples will be asumed the default values in the
+configuration section as described in section~\ref{config}, have not been changed} of an SQL\TeX\ command is: \\
+\texttt{\bs sql\emph{cmd}[options]\{SQL statement\}}
+
+\vs
+
+All SQL\TeX\ commands can be specified anywhere in a line, and can span multiple lines.
+When SQL\TeX\ executes, the commands are read, executed, and their results---if they return
+any---are written to the output:
+
+\vs
+
+\begin{minipage}[t]{0.5\textwidth}\textsl{Input file:}\\\texttt{\footnotesize{\bs documentclass[article] \\
+\bs pagestyle\{empty\} \\
+\bs sqldb[oscar]\{mydb\} \\
+\bs begin\{document\} \\
+}}\end{minipage}\hfill\begin{minipage}[t]{0.5\textwidth}\textsl{Output file:}\\\texttt{\footnotesize{\bs documentclass[article] \\
+\bs pagestyle\{empty\} \\
+ \\
+\bs begin\{document\} \\
+}}\end{minipage}
+
+\vs
+
+Above you see the SQL\TeX\ command \texttt{\bs sqldb} was removed. Only the command was removed, not
+the \textsl{newline} character at the end of the line, so an empty line will be printed instead.
+The example below shows the output is an SQL\TeX\ command was found on a line with other \LaTeX\
+directives:
+
+\vs
+
+\begin{minipage}[t]{0.5\textwidth}\textsl{Input file:}\\\texttt{\footnotesize{\bs documentclass[article] \\
+\bs pagestyle\{empty\}\bs sqldb[oscar]\{mydb\} \\
+\bs begin\{document\} \\
+\hrulefill}}\end{minipage}\hfill\begin{minipage}[t]{0.5\textwidth}\textsl{Output file:}\\\texttt{\footnotesize{\bs documentclass[article] \\
+\bs pagestyle\{empty\} \\
+\bs begin\{document\} \\
+}}\end{minipage}
+
+\vs
+
+In these examples the SQL\TeX\ commands did not return a value. When commands actually read from
+the database, the returned value is written instead:
+
+\vs
+
+\begin{minipage}[t]{0.5\textwidth}\textsl{Input file:}\\\texttt{\footnotesize{This invoice has \bs sqlfield\{SELECT COUNT(*) FROM INVOICE\_LINE \\
+WHERE INVOICE\_NR = 12345\} lines.\\
+\hrulefill}}\end{minipage}\hfill\begin{minipage}[t]{0.5\textwidth}\textsl{Output file:}\\\texttt{\footnotesize{This invoice has 4 lines \\
+}}\end{minipage}
+
+\subsection{SQL statements}\label{sqlstatements}
+
+This document assumes the reader is familiar with SQL commands. This section only tells something about
+implementing them in SQL\TeX\ files, especially with the use of command parameters and variables.
+Details about the SQL\TeX\ commands will be described in the next sections.
+
+\vs
+
+Let's look at a simple example. Suppose we want to retreive all header information from the database
+for a specific invoice. The SQL statement could look something like this: \\
+\texttt{SELECT $\ast$ FROM INVOICE WHERE INVOICE\_NR = 12345;}\\
+To implement this statement in an SQL\TeX\ file, the \texttt{\bs sqlrow} command should be used (see
+section~\ref{sqlrow}):
+
+First, it is important to know that SQL statements should \textit{not} contain the ending semicolon (;) in
+any of the SQL\TeX\ commands. The command in SQL\TeX\ would be:\\
+\texttt{\bs sqlrow\{SELECT $\ast$ FROM INVOICE WHERE INVOICE\_NR = 12345\}}
+
+Next, SQL\TeX\ would be useless if you have to change your input file every time you want to generate
+the same document for another invoice.
+
+\vs
+
+Therefore, you parameters or variables can be used in your SQL statement. Parameters are given at the command
+line (see section~\ref{params}), variables can be defined using the \texttt{\bs sqlfield} command as
+described in section~\ref{vars}.
+
+Given the example above, the invoice number can be passed as a parameter by rewriting the command as: \\
+\texttt{\bs sqlrow\{SELECT $\ast$ FROM INVOICE WHERE INVOICE\_NR = \$PAR1\}} \\
+or as as variable with the code line: \\
+\texttt{\bs sqlrow\{SELECT $\ast$ FROM INVOICE WHERE INVOICE\_NR = \$VAR0\}}
+
+Note you have to know what datatype is expected by your database. In the example here the datatype is
+\textsc{integer}. If the field ``\textsc{invoice\_nr}'' contains a \textsc{varchar} type, the
+\texttt{\$PAR}amater or \texttt{\$VAR}iable should be enclosed by quotes: \\
+\texttt{\bs sqlrow\{SELECT $\ast$ FROM INVOICE WHERE INVOICE\_NR = '\$PAR1'\}}
+
+\subsection{Opening the database}
+
+Before any information can be read from a database, this database should be opened.
+This is done with the \texttt{\textbf{\bs sqldb}} command.
+\texttt{\bs sqldb} requires the name of the dabatase. Optionally, a username and password can be given. When
+omitted, SQL\TeX\ assumes no username and password is required to connect to the database (the user that
+executes SQL\TeX\ should have access to the specified database). \\
+The format of the command is:\\
+\texttt{\bs sqldb[username,password]\{database\}}
+
+The command can be used anywhere in your input file, but should occur before the first command that tries to
+read data from the database.
+
+\subsection{Reading a single field}\label{sqlfield}
+
+When a single field of information is to be read from the database, the command \texttt{\textbf{\bs sqlfield}}
+is used. By default, the command in the inputfile is replaced by its result in the outputfile.\\
+The SQL command is enclosed by curly braces. Square brackets can optionally be used to enter some extra options.
+Currently, the only supported option is \texttt{setvar} (see section~\ref{vars}).
+
+The full syntax or the \texttt{\bs sqlfield} command is:\\
+\texttt{\bs sqlrow[\textit{options}]\{SELECT \textit{fieldname} FROM \textit{tablename} WHERE \textit{your where-clause}\}} \\
+By default, the SQL\TeX\ command is replaced with the value returned by the SQL query. This behaviour
+can be changed with options.
+
+
+\subsubsection{Define variables}\label{vars}
+
+The \texttt{\bs sqlfield} can also be used to set a variable. The value returned by the SQL query is not
+displayed in this case. Instead, a variable is created which can be used in any other SQL query later in
+the document (see also section~\ref{sqlstatements}).
+
+Therefore, the option \texttt{\textbf{[setvar=\textit{n}]}} is used, where \textit{n} is an integer between
+0 and 9.
+
+\vs
+
+Suppose you have an invoice in \LaTeX. SQL\TeX\ is executed to retrieve the invoice header information
+from the database for a specific customer. Next, the invoice lines are read from the database.
+
+You could pass the invoice number as a paramater to SQL\TeX\ for use in your queries, but that could
+change every month. It is easier to :\\
+\begin{itemize}
+\item pass the customer number as a parameter,
+\item retrieve the current date (asuming that is the invoice date as stored in
+the database by another program), and store it in a variable: \\
+\texttt{\bs sqlfield[setvar=0]\{SELECT DATE\_FORMAT(NOW(), "\%Y-\%m-\%d")\}} \\
+This creates a variable that can be used as \texttt{\$VAR0},
+\item retrieve the invoice number using the customer number (a command line parameter,
+see also section~\ref{params}) and the variable containing the invoice date.
+Store this invoice number in \texttt{\$VAR1}: \\
+\texttt{\bs sqlfield[setvar=1]\{SELECT INVOICE\_NR FROM INVOICES \\
+WHERE CUST\_NR = '\$PAR1' AND INVOICE\_DATE = '\$VAR0'\}}
+\item use \texttt{\$VAR1} to retrieve all invoice information.
+\end{itemize}
+
+\vs
+
+The SQL queries used here do not display any output in your \LaTeX document.
+
+
+\subsection{Reading rows of data}\label{sqlrow}
+
+When an SQL query returns more information than one single field, the SQL\TeX\
+command \texttt{\textbf{\bs sqlrow}} should be used. As with the \texttt{\bs sqlfield},
+command, SQL\TeX\ replaces the command with the values it returns, but \texttt{\bs sqlrow}
+accepts different options for formating the output.
+
+\vs
+
+By default, fields are separated by a comma and a blank (`\texttt{,~}'), and rows by
+a newline character (`\texttt{\bs\bs}'). To change this, the options ``\texttt{fldsep}''
+and ``\texttt{rowsep}'' can be used.
+
+e.g. In a \texttt{tabular} enviroment the fields should be seperated by an amphesand (\texttt{\&}),
+perhaps a line should seperate the rows of information. (\texttt{\bs\bs~\bs hline}).
+To do this, the options can be used with \texttt{\bs sqlrow} as shown here: \\
+\texttt{\bs sqlrow[fldsep=\&,rowsep=\bs\bs~\bs hline]\{SELECT I.LINE\_NR, A.ARTICLE\_NR,
+A.PRICE, I.AMOUNT, (A.PRICE * I.AMOUNT) FROM ARTICLE A, INVOICE\_LINE I WHERE I.INVOICE\_NR = \$VAR1
+AND I.ARTICLE\_NR = A.ARTICLE\_NR\}}
+
+\vs
+
+This will produce an output like: \\
+\texttt{1 \& 9712 \& 12 \& 1 \& 12 \bs\bs~\bs hline \\
+2 \& 4768 \& 9.75 \& 3 \& 29.25 \bs\bs~\bs hline \\
+3 \& 4363 \& 1.95 \& 10 \& 19.5 \bs\bs~\bs hline \\
+4 \& 8375 \& 12.5 \& 2 \& 25 \bs\bs~\bs hline}
+
+\subsubsection{Output rows on seperate lines}
+
+Some \LaTeX\ packages require input on a seperate line. If this output is to be
+read from a database, this can be set with the \texttt{rowsep} option using the
+fixed text ``\texttt{NEWLINE}''.
+
+\subsubsection{Store data in an array}
+
+
+The \texttt{\bs sqlrow} command can also be used to store the data in an array. The value returned by the SQL query is not displayed in this case. Instead, an array is created which can be used later the document in a loop context (see section~\ref{loops}).
+
+Therefore, the option \texttt{\textbf{[setarr=\textit{n}]}} is used, where \textit{n} is an integer between
+0 and 9.
+
+\subsection{Loop context}\label{loops}
+
+In a loop context, an array if filled with data from the database using \texttt{\bs sqlrow}.\\
+Later in the document, the data can be used in a textblock that will be written to the outputfile once for every record retrieved.
+
+\vs
+
+The textblock is between the \texttt{\bs sqlstart\{\textit{n}\}} and \texttt{\bs sqlend\{\textit{n}\}} commands, where \textit{n} is the sequence number of the array to use\footnote{ in \texttt{\bs sqlend}, the sequence number is ignored, but required by syntax.}.
+
+Multiple textblocks can occur in the document, but they can \textit{not} be nested!
+
+\vs
+
+In the example below, data for unpaid invoices is stored in an array identified with sequence number 0:
+
+\texttt{\bs sqlrow[setarr=0]\{SELECT I.INVOICE\_NR AS nr\\
+\hspace*{15mm}, I.DUE\_DATE AS date\\
+\hspace*{15mm}, I.TOTAL AS amount\\
+\hspace*{15mm}, C.NAME AS customer\\
+\hspace*{15mm}FROM INVOICES I\\
+\hspace*{15mm}LEFT OUTER JOIN CUSTOMERS C\\
+\hspace*{20mm}ON C.CUST\_NR = I.CUST\_NR\\
+\hspace*{15mm}WHERE I.PAY\_DATE = NULL\}}
+
+\vs
+
+To use this data, a textblock must start with: \texttt{\bs sqlstart\{0\}}\\
+Between this command and the first occurrence of \texttt{\bs sqlend\{\}}, an unlimited amount\footnote{ limited by your computer's memory only} of \LaTeX\ text can be. Within this text, every occurence of \texttt{\bs sqluse\{<\textit{field name}>\}} will be replaced with the matching field from the current row, e.g.:
+
+\noindent\begin{verbatim}
+\sqlstart{0}
+\begin{flushright}
+Regarding: invoicenumber \sqluse{nr}
+\end{flushright}
+
+Dear \sqluse{customer},
+
+On \today, the invoice with number \sqluse{nr}, payable before
+\sqluse{date}, was not yet received by us.
+
+We kindly request you to pay the amount of \texteuro\sqluse{amount}
+as soon as possible.
+
+\newpage
+\sqlend{}
+\end{verbatim}
+
+
+\subsection{Output multiple documents}\label{multidoc}
+
+A single input file can be created to generate more output files. This option
+retrieves the first parameter (see section~\ref{params}) from the database
+(ignoring any parameters that where given on the command line!).
+
+\vs
+
+The input document must contain the command \texttt{\bs sqlsetparams} (in the
+default configuration) without any options. The query that follows can return an
+unlimited number of rows all containing exactly 1 field: \\
+\texttt{\bs sqlsetparams\{SELECT INVOICE\_NR FROM INVOICES WHERE PAY\_DATE = NULL\}}
+
+\vs
+
+By processing this command, SQL\TeX\ builds a list with all values retrieved and
+processes the input file again for each value.\\
+In those runs, the queries are executed as described in the previous sections,
+using the value as a parameter:\\
+\texttt{\bs sqlrow\{SELECT * FROM INVOICES WHERE INVOICE\_NR = \$PAR1\}}
+
+\vs
+
+To enable the multidocument mode, the command line switch \texttt{-m} or \texttt{-M} must be
+given and no parameters are allowed. The switches \texttt{-m} and \texttt{-M} cannot be used together.\\
+Without the \texttt{-m} or \texttt{-M} switch, a parameter can be given and a single output
+document will be created, ignoring the \texttt{\bs sqlsetparams} command.
+
+\vs
+
+With the \texttt{-m} switch, output filenames will be numbered \texttt{\emph{filename}\_1.tex} to \texttt{\emph{filename}\_\emph{n}.tex}.\\
+With the \texttt{-M} switch, output filenames will be numbered \texttt{\emph{filename}\_\emph{parameter}.tex}, where \emph{parameter} is the value taken from the
+database (\texttt{invoice\_nr} in the example above). Note the parameter will not be formatted to be filename-friendly!\\
+
+\subsection{Update database records}
+
+Since version 1.5, SQL\TeX\ supports database updates as well: \\
+\texttt{\bs sqlupdate\{UPDATE INVOICES SET REMINDERS = REMINDERS + 1,
+LAST\_REMINDER = NOW() INVOICE\_NR = \$VAR1\}}
+
+\vs
+
+This command accepts no options.
+
+\section{Process your SQL\TeX\ file}
+
+To process you SQL\TeX\ file and create a \LaTeX\ file with all information read from
+the database, call SQL\TeX\ with the parameter(s) and (optional) command\-line options as
+described here:
+
+\subsection{Parameters}\label{params}
+
+SQL\TeX\ accepts more than one parameter. The first parameter is required; this should
+be the input file, pointing to your \LaTeX\ document containing the SQL\TeX\ commands.
+
+By default, SQL\TeX\ looks for a file with extension `\texttt{.tex}'.
+
+\vs
+
+All other parameters are used by the queries, if required. If an SQL query contains the
+string \texttt{\$PAR\textit{n}}\footnote{where \textit{n} is a number between 1 and 9. Note
+parameter `0' cannot be used, since that contains the filename!}, it is replaced by that parameter
+(see also section~\ref{sqlstatements}).
+
+\subsection{Command line options}\label{cmdline}
+
+SQL\TeX\ accepts the followint command- line options:
+
+\begin{description}
+\item[-c \textit{file}] SQL\TeX\ configuration file. Default is \texttt{SQLTeX.cfg}
+in the same location where SQL\TeX\ is installed.
+
+\item[-e \textit{string}] add \textit{string} to the output filename:
+\texttt{input.tex} will be \texttt{input\textit{string}.tex}. This overwrites
+the configuration setting \texttt{stx} \\
+In \textit{string}, the values between curly braces \{\} will be substituted:
+\begin{description}
+\item[P\textit{n}] parameter \textit{n}
+\item[M] current monthname (\textit{Mon})
+\item[W] current weekday (\textit{Wdy})
+\item[D] current date (\textit{yyyymmdd})
+\item[DT] current date and time (\textit{yyyymmddhhmmss})
+\item[T] current time (\textit{hhmmss})
+\end{description}
+e.g., the command `\texttt{SQLTeX -e \_\{P1\}\_\{W\} my\_file code}'
+will read `\texttt{my\_file.tex}' and write `\texttt{myfile\_code\_Tue.tex}'
+The same command, but with option \texttt{-E} would create the
+outputfile \texttt{myfile.\_code\_Tuesday}
+By default (without \texttt{-e} or \texttt{-E}) the outputfile
+\texttt{myfile\_stx.tex} would have been written.
+The options \texttt{-E} and \texttt{-e} cannot be used together or with \texttt{-o}.
+
+\item[-E \textit{string}] replace input file extension in outputfile:
+\texttt{input.tex} will be \texttt{input.\textit{string}} \\
+For further notes, see option \texttt{-e} above.
+
+\item[-f] force overwrite of existing files. By default, SQL\TeX\ exists with a
+warning message it the outputfile already exists.
+
+\item[-h] print this help message and exit.
+
+\item[-m] Multidocument mode; create one document for each parameter that is retrieved
+from the database in the input document (see section~\ref{multidoc}). This option cannot be used with \texttt{-o}.
+
+\item[-M] Same as -m, but with the parameter in the filename instead of a serial number (see section~\ref{multidoc}).
+
+\item[-N] \texttt{NULL} return values allowed. By default SQL\TeX\ exits if a
+query returns an empty set.
+
+\item[-o \textit{file}] specify an output file. Cannot be used with \texttt{-e} or \texttt{-E}.
+
+\item[-p \textit{prefix}] prefix used in the SQL\TeX\ file. Default is \texttt{sql} (see also section~\ref{config}
+on page~\pageref{prefix}. This overwrites the configurarion setting \texttt{cmd\_prefix}.
+
+\item[-P] prompt for database password. This overwrites the password in the
+input file.
+
+\item[-q] run in quiet mode.
+
+\item[-r \textit{replace}] Specify a file that contains the replace characters (see section~\ref{replfiles}). This is
+a list with two \texttt{TAB}- seperated fields per lione. The first field holds a string that will be replaced in the SQL output
+
+\item[-rn] Do not use a replace file. \texttt{-rn} and \texttt{-r \textit{file}} are handled on the same order in which they appear
+on the commandline and overwrite each other.
+
+\item[-s \textit{server}] SQL server to connect to. Default is \texttt{localhost}.
+
+\item[-U \textit{user}] database username. This overwrites the username in the
+input file.
+
+\item[-V] print version number and exit.
+\end{description}
+
+
+\section{SQL\TeX\ errors and warnings}
+
+\noindent\textbf{\texttt{no input file specified}}
+
+\vspace{1mm}
+
+\noindent SQL\TeX\ was called without any parameters.\\
+\textit{Action:} Specify at least one parameter at the commandline. This parameter should be
+the name of your input file.
+
+\vs
+
+\noindent\textbf{\texttt{File \textit{input filename} does not exist}}
+
+\vspace{1mm}
+
+\noindent The input file does not exist.\\
+\textit{Action:} Make sure the first parameter points to the input file.
+
+\vs
+
+\noindent\textbf{\texttt{outputfile \textit{output filename} already exists}}
+
+\vspace{1mm}
+
+\noindent The outputfile cannot be created because it already exists.\\
+\textit{Action:} Specify another output filename with command line option \texttt{-e},
+\texttt{-E} or \texttt{-o}, or force an overwrite with option \texttt{-f} (see also section\ref{cmdline}).
+
+\vs
+
+\noindent\textbf{\texttt{no database opened at line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent A query starts at line \textit{line nr}, but at that point no database was opened yet. \\
+\textit{Action:} Add an \texttt{\bs sqldb} command prior to the first query statement.
+
+\vs
+
+\noindent\textbf{\texttt{insufficient parameters to substitute variable on line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent The query starting at line \textit{line nr} uses a parameter in a \textsc{where}- clause with
+\texttt{\$PAR\textit{n}}, where \textit{n} is a number bigger than the number of parameters
+passed to SQL\TeX\. \\
+\textit{Action:} Specify all required parameters at the command line.
+
+\vs
+
+\noindent\textbf{\texttt{trying to substitute with non existing on line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent The query starting at line \textit{line nr} requires a variable \texttt{\$VAR\textit{n}} in its
+\textsc{where}- clause, where \textit{n} points to a variable that has not (yet) been set. \\
+\textit{Action:} Change the number or set the variable prior to this statement.
+
+\vs
+
+\noindent\textbf{\texttt{trying to overwrite an existing variable on line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent At line \textit{line nr}, a \texttt{\bs sqlfield} query tries to set a variable \textit{n}
+using the option \texttt{[setvar=\textit{n}]}, but \texttt{\$VAR\textit{n}} already
+exists at that point. \\
+\textit{Action:} Change the number.
+
+\vs
+
+\noindent\textbf{\texttt{no result set found on line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent The query starting at line \textit{line nr} returned a \texttt{NULL} value. If the
+option \texttt{-N} was specified at the commandline, this is just a warning message.
+Otherwise, SQL\TeX\ exits. \\
+\textit{Action:} None.
+
+\vs
+
+\noindent\textbf{\texttt{result set too big on line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent The query starting at line \textit{line nr}, called with \texttt{\bs sqlfield} returned more than one field. \\
+\textit{Action:} Change your query or use \texttt{\bs sqlrow} instead.
+
+\vs
+
+\noindent\textbf{\texttt{no parameters for multidocument found on line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent SQL\TeX\ is executed in multidocument mode, but the statement on line
+\textit{line nr} did not provide any parameters for the documents. \\
+\textit{Action:} Check your query.
+
+\vs
+
+\noindent\textbf{\texttt{too many fields returned in multidocument mode on \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent In multidocument mode, the lis of parameters retrieved on line
+\textit{line nr} returned more than one fiels per row. \\
+\textit{Action:} Check your query.
+
+\vs
+
+\noindent\textbf{\texttt{start using a non-existing array on line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent An \texttt{\bs sqlstart} command occurs, but refers to a non-existing array. \\
+\textit{Action:} Check the sequence number of the array filled with \texttt{\bs sqlrow[setarr=\textit{n}]} and retrieved with \texttt{\bs sqlstart\{\textit{n}\}} in your input file.
+
+\vs
+
+\noindent\textbf{\texttt{\bs sqluse command encountered outside loop context on line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent Data from array is used, but the current input file position is not in the context where this data is available.\\
+\textit{Action:} Check the presence and positions of the \texttt{\bs sqlstart} and \texttt{\bs sqlend} commands in your input file.
+
+\vs
+
+\noindent\textbf{\texttt{unrecognized command on line \textit{line nr}}}
+
+\vspace{1mm}
+
+\noindent At line \textit{line nr}, a command was found that starts with ``\texttt{\bs sql}'',
+but this command was not recognized by SQL\TeX\. \\
+\textit{Action:} Check for typos. If the command is a user- defined command, it will
+conflict with default SQL\TeX\ commands. Change the SQL\TeX\ command prefix (see section~\ref{config}).
+
+\vs
+
+\noindent\textbf{\texttt{no sql statements found in \textit{input filename}}}
+
+\vspace{1mm}
+
+\noindent SQL\TeX\ did not find any valid SQL\TeX\ commands. \\
+\textit{Action:} Check your input file.
+
+
+\section{Copyright and disclaimer}
+
+\noindent\hrulefill \\
+The SQL\TeX\ project is available from GitHub: https://github.com/oveas/sqltex\\
+The latest stable release is always available at http://oveas.com/freeware/overige/sqltex\\
+For bugs, questions and comments, please use the issue tracker available at https://github.com/oveas/sqltex/issues
+
+\vspace{3mm}
+
+\noindent Copyright\copyright\ 2001-2016 - Oscar van Eijk, Oveas Functionality Provider
+
+\noindent\hrulefill \\
+
+\noindent This software is subject to the terms of the LaTeX Project Public License;
+see http://www.ctan.org/tex-archive/help/Catalogue/licenses.lppl.html.
+
+\section{History}
+
+\begin{description}
+\item[v1.3] \textit{released: Mar 16, 2001}\\First public release
+\item[v1.4] \textit{released: May 2, 2002}\\Implemented replace files
+\item[v1.4.1] \textit{released: Feb 15, 2005}\\Fix: removed leading whitespaces added to database results befure replace
+\item[v1.5] \textit{released: Nov 23, 2007}\\Support for multiple databases\\Implemented database updates (\texttt{sqlupdate})\\Implemented multiple output documents (option \texttt{-m})
+\item[v2.0] \textit{released: Jan 12, 2016}\\Fix: Oracle support using ORASID\\Fix: Ensure replacements are handled in the same order as they appear in the replacements file\\Separate configuration file(s)\\Added the options \texttt{-c} and \texttt{-M}\\Support for regular expressions in replace files\\Implemented support for the \LaTeX\ \texttt{\bs input} and \texttt{\bs include} directives\\Implemented loop context\\Skip commentlines\\Project moved from local CVS to GitHub
+\end{description}
+
+\end{document}
diff --git a/support/SQLTeX/SQLTeX_r.dat b/support/SQLTeX/SQLTeX_r.dat
new file mode 100644
index 0000000000..c4f56bda08
--- /dev/null
+++ b/support/SQLTeX/SQLTeX_r.dat
@@ -0,0 +1,29 @@
+; This file contains all characters or character sequences that
+; will be be replaced by SQLTeX when the occur in the response
+; of an SQL query.
+; It is mainly used for escaping the (La)TeX special characters,
+; but any value can be added here.
+; The first column is the character (sequence) that will be replaced.
+; The second column is the value to replace col 1 with.
+; Columns are sepated with one or more tab- characters.
+;
+; Note all values are case sensitive; if you add the line:
+; LaTeX \LaTeX\
+; the word "latex" will be untouched, but "LaTeX" will be replaced.
+;
+; To replace using regular expressions, use 're(<regular expression>)' as key (or any other
+; regexp indicator if that has been changed in the config file), e.g.
+; re(<p\.*?>) \paragraph*{}
+; will replace all HTML <p> variants (<p style='font-size: normal'>, <p align='center'> etc)
+;
+$ \$
+_ \_
+% \%
+& \&
+< \texttt{<}
+> \texttt{>}
+{ \{
+} \}
+# \#
+~ \~{}
+\ \ensuremath{\backslash}
diff --git a/support/SQLTeX/install b/support/SQLTeX/install
new file mode 100755
index 0000000000..8361a3f215
--- /dev/null
+++ b/support/SQLTeX/install
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+SRCF="SQLTeX.pl"
+TMPF="SQLTeX.tmp"
+SQLT="SQLTeX"
+RFIL="SQLTeX_r.dat"
+CFIL="SQLTeX.cfg"
+TAB="\011"
+
+PI=`which perl` || PI=""
+
+## Is Perl installed ?
+if test -z "$PI"
+then
+ echo "Perl is either not installed on this system, or not included in your path"
+ echo "Please check and correct this error - you need Perl to use SQLTeX"
+ exit
+fi
+
+## Does the source file exist ?
+if ! test -f $SRCF
+then
+ echo "Error - the file $SRCF does not exist in the current directory"
+ exit
+fi
+
+## Where should SQLTeX be installed ?
+CUSR=`whoami`
+if test $CUSR = "root"
+then
+ DDIR="/usr/local/bin"
+else
+ DDIR=`pwd`
+fi
+while test -z "$IDIR"
+do
+ echo -n "Where should SQLTeX be installed [$DDIR] ? "
+ read IDIR
+ if test -z "$IDIR"
+ then
+ IDIR="$DDIR"
+ fi
+ if ! test -d $IDIR
+ then
+ echo "$IDIR does not exist or is not a directory"
+ IDIR=""
+ fi
+done
+
+echo "#!$PI -w" > $TMPF
+echo "" >> $TMPF
+cat $SRCF >> $TMPF
+chmod +x $TMPF
+mv $TMPF $IDIR/$SQLT
+
+## Replacement file
+if ! test -e $IDIR/$RFIL
+then
+ mv $RFIL $IDIR/$RFIL
+fi
+
+## Configuration file
+if ! test -e $IDIR/$CFIL
+then
+ mv $CFIL $IDIR/$CFIL
+fi
+
+echo "Installation complete---type $SQLT -h for help"
+