diff options
author | Norbert Preining <norbert@preining.info> | 2022-02-05 03:00:59 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2022-02-05 03:00:59 +0000 |
commit | 08ccf305ee79ab8e5ba9d1a8f3d22e74dccedd80 (patch) | |
tree | 814254dfa55b15022a4361ba4e12cccdcdac1f2a /support/SQLTeX/src | |
parent | b7a48c5e229d2c195b6a32bfd73a1036a31f2df3 (diff) |
CTAN sync 202202050300
Diffstat (limited to 'support/SQLTeX/src')
-rw-r--r-- | support/SQLTeX/src/Makefile.am | 20 | ||||
-rw-r--r-- | support/SQLTeX/src/Makefile.in | 369 | ||||
-rw-r--r-- | support/SQLTeX/src/SQLTeX.cfg | 59 | ||||
-rw-r--r-- | support/SQLTeX/src/SQLTeX.pl | 1152 | ||||
-rw-r--r-- | support/SQLTeX/src/SQLTeX_r.dat | 29 |
5 files changed, 1629 insertions, 0 deletions
diff --git a/support/SQLTeX/src/Makefile.am b/support/SQLTeX/src/Makefile.am new file mode 100644 index 0000000000..b8194eeba5 --- /dev/null +++ b/support/SQLTeX/src/Makefile.am @@ -0,0 +1,20 @@ +# Automake makefile for the SQLTeX code and configfiles + +.PHONY: distdir +DATAFILES = SQLTeX_r.dat SQLTeX.cfg +DISTFILES = Makefile.am Makefile.in SQLTeX.pl ${DATAFILES} + +PL=$(shell which perl) + +all : SQLTeX + +distdir : ${DISTFILES} + cp $(DISTFILES) $(distdir) + +SQLTeX: SQLTeX.pl + cat $^ | sed -e 's#{PERLDIR}#!$(PL)#;s#{SYSCONFDIR}#$(sysconfdir)#' > $@ + @chmod +x $@ + +install : SQLTeX ${DATAFILES} + @cp $< $(bindir) + @cp $(DATAFILES) $(sysconfdir) diff --git a/support/SQLTeX/src/Makefile.in b/support/SQLTeX/src/Makefile.in new file mode 100644 index 0000000000..234100000c --- /dev/null +++ b/support/SQLTeX/src/Makefile.in @@ -0,0 +1,369 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Automake makefile for the SQLTeX code and configfiles +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_prog_perl_modules.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +am__leading_dot = @am__leading_dot@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +DATAFILES = SQLTeX_r.dat SQLTeX.cfg +DISTFILES = Makefile.am Makefile.in SQLTeX.pl ${DATAFILES} +PL = $(shell which perl) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic cscopelist-am \ + ctags-am distclean distclean-generic distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +.PHONY: distdir + +all : SQLTeX + +distdir : ${DISTFILES} + cp $(DISTFILES) $(distdir) + +SQLTeX: SQLTeX.pl + cat $^ | sed -e 's#{PERLDIR}#!$(PL)#;s#{SYSCONFDIR}#$(sysconfdir)#' > $@ + @chmod +x $@ + +install : SQLTeX ${DATAFILES} + @cp $< $(bindir) + @cp $(DATAFILES) $(sysconfdir) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/SQLTeX/src/SQLTeX.cfg b/support/SQLTeX/src/SQLTeX.cfg new file mode 100644 index 0000000000..0ba20c4ff5 --- /dev/null +++ b/support/SQLTeX/src/SQLTeX.cfg @@ -0,0 +1,59 @@ +# 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 + +# When no output file is specified or output file without (relative) path is given, an output file +# is generated in the current directory. +# By setting 'def_out_is_in' to True (1), the output file is generated in the same directory +# where the input file resides (this was the behaviour up until v2.0). +# Refer to the documentation for more info. +# +def_out_is_in = 0 + +# 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. +# +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/src/SQLTeX.pl b/support/SQLTeX/src/SQLTeX.pl new file mode 100644 index 0000000000..e44daede41 --- /dev/null +++ b/support/SQLTeX/src/SQLTeX.pl @@ -0,0 +1,1152 @@ +#{PERLDIR} + +################################################################################ +# +# 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-2022, 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 +# v2.1 Jan 21, 2022 +# Refer to the documentation for changes per release +# +# TODO: +# ===== +# Code is getting messy - too many globals: rewrite required +# +################################################################################ +# +use strict; +use DBI; +use Getopt::Long; +use Term::ReadKey; +Getopt::Long::Configure ("bundling"); +use feature 'state'; + +##### +# Check if we're running on linux +# +sub is_linux { + return ($^O eq "linux"); +} + +##### +# Check if we're running on windows +# +sub is_windows { + return ($^O eq "MSWin32"); +} + +##### +# Find out if any command-line options have been given +# Parse them using 'Getopt' +# +sub parse_options { + + $main::NULLallowed = 0; + + if (!GetOptions('help|h|?' => \$main::options{'h'} + , 'configfile|c=s' => \$main::options{'c'} + , 'replacementfile|r=s' => \$main::options{'r'} + , 'no-replacementfile|R' => \$main::options{'R'} + , 'output|o=s' => \$main::options{'o'} + , 'filename-extend|e=s' => \$main::options{'e'} + , 'file-extension|E=s' => \$main::options{'E'} + , 'sqlserver|s=s' => \$main::options{'s'} + , 'username|U=s' => \$main::options{'U'} + , 'password|P:s' => \$main::options{'P'} + , 'null-allowed|N' => \$main::options{'N'} + , 'version|V' => \$main::options{'V'} + , 'force|f' => \$main::options{'f'} + , 'quiet|q' => \$main::options{'q'} + , 'multidoc-numbered|m' => \$main::options{'m'} + , 'multidoc-named|M' => \$main::options{'M'} + , 'prefix|p=s' => \$main::options{'p'} + , 'use-local-config|l' => \$main::options{'l'} + , 'updates|u' => \$main::options{'u'} + )) { + print "usage: $main::myself [options] <file[.$main::configuration{'texex'}]> [parameter...]\n" + . " type \"$main::myself --help\" for help\n"; + 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); + + $optcheck = 0; + $optcheck++ if (defined $main::options{'r'}); + $optcheck++ if (defined $main::options{'R'}); + die ("options \"-r\" and \"-R\" 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#' + } + } + + if (defined $main::options{'l'} && !&is_linux) { + warn "Option \"-l\" is ignored on $^O"; + delete $main::options{'l'}; + } +} + +##### +# Print the Usage: line on errors and after the '-h' switch +# +sub short_help ($) { + my $onerror = shift; + my $helptext = "usage: $main::myself [options] <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 .= " --configfile <file>\n"; + $helptext .= " -c <file>\n"; + $helptext .= " SQLTeX configuration file.\n"; + $helptext .= " Default is \'$main::config_location/SQLTeX.cfg\'.\n"; + $helptext .= " --file-extension <string>\n"; + $helptext .= " -E <string>\n"; + $helptext .= " replace input file extension in outputfile:\n"; + $helptext .= " \'input.tex\' will be \'input.string\'\n"; + $helptext .= " For further notes, see option \'--filename-extend\' below\n"; + $helptext .= " --null-allowed\n"; + $helptext .= " -N\n"; + $helptext .= " NULL return values allowed. By default SQLTeX exits if a\n"; + $helptext .= " query returns an empty set\n"; + $helptext .= " --password [password]\n"; + $helptext .= " -P [password]\n"; + $helptext .= " database password. The value is optional; if omitted, SQLTeX will prompt for\n"; + $helptext .= " a password. This overwrites the password in the input file.\n"; + $helptext .= " --username <user>\n"; + $helptext .= " -U <user>\n"; + $helptext .= " database username\n"; + $helptext .= " --version\n"; + $helptext .= " -V\n"; + $helptext .= " print version number and exit\n"; + $helptext .= " --filename-extend <string>\n"; + $helptext .= " -e <string>\n"; + $helptext .= " 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 --filename-extend _{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 \--file-extension\' would create the\n"; + $helptext .= " outputfile \'myfile._code_Tue\'\n"; + $helptext .= " By default the outputfile \'myfile_stx.tex\' would have been written.\n"; + $helptext .= " The options \'--file-extension\' and \'--filename-extend\' cannot be used\n"; + $helptext .= " together or with \'--output\'.\n"; + $helptext .= " --force\n"; + $helptext .= " -f\n"; + $helptext .= " force overwrite of existing files\n"; + $helptext .= " --help\n"; + $helptext .= " -h\n"; + $helptext .= " print this help message and exit\n"; + $helptext .= " --multidoc-numbered\n"; + $helptext .= " -m\n"; + $helptext .= " Multidocument mode; create one document for each parameter that is retrieved\n"; + $helptext .= " from the database in the input document (see documentation)\n"; + $helptext .= " This option cannot be used with \'--output\'.\n"; + $helptext .= " --multidoc-named\n"; + $helptext .= " -M\n"; + $helptext .= " Same as -m, but with the parameter in the filename i.s.o. a serial number\n"; + $helptext .= " --output <file>\n"; + $helptext .= " -o <file>\n"; + $helptext .= " specify an output file. Cannot be used with \'--file-extension\',\n"; + $helptext .= " \'--filename-extend\' or the \'--multidoc\' options.\n"; + $helptext .= " --prefix <prefix>\n"; + $helptext .= " -p <prefix>\n"; + $helptext .= " prefix used in the SQLTeX file. Default is \'sql\'\n"; + $helptext .= " (e.g. \\sqldb[user]{database}), but this can be overwritten if it conflicts\n"; + $helptext .= " with other user-defined commands.\n"; + $helptext .= " --quiet\n"; + $helptext .= " -q\n"; + $helptext .= " run in quiet mode\n"; + $helptext .= " --replacementfile <file>\n"; + $helptext .= " -r <file>\n"; + $helptext .= " specify a file that contains replace characters. This is a list with two tab- seperated\n"; + $helptext .= " fields per line. The first field holds a string that will be replaced in the SQL output\n"; + $helptext .= " by the second string.\n"; + $helptext .= " By default the file \'$main::config_location/SQLTeX_r.dat\' is used.\n"; + $helptext .= " --no-replacementfile\n"; + $helptext .= " -R\n"; + $helptext .= " do not use a replace file. \'--replacementfile\' \'--no-replacementfile\' are handled\n"; + $helptext .= " in the same order as they appear on the command line.\n"; + $helptext .= " For backwards compatibility, -rn is also still supported.\n"; + + if (&is_linux) { + $helptext .= " --use-local-config\n"; + $helptext .= " -l\n"; + $helptext .= " use $main::my_location as default location for the config- and replacement files\n"; + $helptext .= " in stead of $main::config_location.\n"; + } + + $helptext .= " --sqlserver <server>\n"; + $helptext .= " -s <server>\n"; + $helptext .= " SQL server to connect to. Default is \'localhost\'\n"; + $helptext .= " --updates\n"; + $helptext .= " -u\n"; + $helptext .= " 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"; + + 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) = @_; + + my $pwd = ""; + + print "Password for $usr\@$srv : "; + + ReadMode(4); + while(ord(my $keyStroke = ReadKey(0)) != 10) { + if(ord($keyStroke) == 127 || ord($keyStroke) == 8) { # DEL/Backspace + chop($pwd); + print "\b \b"; + } elsif(ord($keyStroke) >= 32) { # Skip control characters + $pwd = $pwd . $keyStroke; + print '*'; + } + } + ReadMode(0); + + return $pwd; +} + +##### +# If we have to prompt for a user. Get it and return it to the caller +# +sub get_username ($) { + my $srv = shift; + + print "Username at $srv : "; + + my $usr = <STDIN>; + chomp $usr; + return $usr; +} + + +####### +# 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); +} + +##### +# Find the configuration files +# +sub get_configfiles { + if (defined $main::options{'c'}) { + $main::configurationfile = $main::options{'c'}; + } else { + $main::configurationfile = $main::config_location + . ($main::config_location eq '' ? '' : '/') + . '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::config_location + . ($main::config_location eq '' ? '' : '/') + . 'SQLTeX_r.dat' + unless (defined $main::options{'R'}); + } + if (defined $main::replacefile && !-e $main::replacefile) { + warn ("replace file $main::replacefile does not exist\n") unless ($main::replacefile eq "n"); + undef $main::replacefile; + } + + return; +} + +##### +# 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"; + } + if ($main::configuration{'def_out_is_in'}) { + $main::outputfile = $main::path . $main::outputfile; + } + } else { + $main::outputfile = $main::options{'o'}; + if ($main::configuration{'def_out_is_in'} && !($main::outputfile =~ /\//)) { + $main::outputfile = $main::path . $main::outputfile; + } + } + + return; +} + +####### +# Connect to the database +# +sub db_connect($$) { + my ($up, $db) = @_; + state $data_source; + state $gotInput = 0; + + $main::line =~ s/(\[.*?\])?\{$db\}//; + + state $un = ''; + state $pw = ''; + state $hn = ''; + + if (!$gotInput) { + 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'}); + $un = &get_username($main::options{'s'} || 'localhost') if ($un eq '?'); + + my $promptForPwd = 0; + if (defined $main::options{'P'}) { + if ($main::options{'P'} eq '') { + $promptForPwd = 1; + } else { + $pw = $main::options{'P'} + } + } + if ($pw eq '?') { + $promptForPwd = 1; + } + $pw = &get_password ($un, $main::options{'s'} || 'localhost') if ($promptForPwd); + $gotInput = 1; + + $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); # TODO Proper errorhandling + return; +} + +##### +# 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{$'}; + $main::fldsep =~ s/NEWLINE/\n/; +# if ($main::fldsep eq 'NEWLINE') { +# $main::fldsep = "\n"; +# } + } + if ($opt =~ /^rowsep=/i) { + $main::rowsep = qq{$'}; + $main::rowsep =~ s/NEWLINE/\n/; +# 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::multidoc); # TODO Proper errorhandling + @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); # TODO Proper errorhandling + } + + $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); # TODO Proper errorhandling + } elsif ($#result > 0) { + &just_died (5); # TODO Proper errorhandling + } else { + &print_message ("Found 1 value: \"$result[0]\""); + if ($main::setvar) { + &just_died (7) if (defined $main::var[$main::var_no] && !$main::multidoc); # TODO Proper errorhandling + $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]); # TODO Proper errorhandling + 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/\\//; + $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 TODO Proper errorhandling + push @return_values, @values; + } + $stat_handle->finish (); + + if ($#return_values < 0) { + &just_died (8); # TODO Proper errorhandling + } + + $rc = $#return_values + 1; + &print_message ("Multidocument parameters found; $rc documents will be created: handle document $main::multidoc_cnt"); + + return (@return_values); +} + + +##### +# Perform an update. +# +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. +# FIXME We need some decent errorhandling +# +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::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])); # TODO Proper errorhandling + $statement =~ s/\$VAR$varno/$main::var[$varno]/g; + } + &just_died (3) if ($statement =~ /\$PAR/ && ($main::multidoc_cnt > 0) && $main::multidoc); # TODO Proper errorhandling + $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); # TODO Proper errorhandling + + 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); # TODO Proper errorhandling + $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); # TODO Proper errorhandling + } + + return 0; +} + +sub read_input($$$$) { + my ($input_file, $output_handle, $multidoc_par) = @_; + + $main::fcount++; + $main::lcount[$main::fcount] = 0; + + if (!-e $input_file) { + die "input file $input_file not found"; + } + print_message("Processing file $input_file..."); + open (my $fileIn, "<$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::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, can be overwritten with SQLTeX.cfg +# +%main::configuration = ( + 'dbdriver' => 'mysql' + ,'oracle_sid' => 'ORASID' + ,'texex' => 'tex' + ,'stx' => '_stx' + ,'def_out_is_in' => 0 + ,'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' + ,'repl_step' => 'OSTX' + ,'alt_cmd_prefix' => 'processedsqlcommand' +); + +##### +# Some globals +# +{ + my @dir_list = split /\//, $0; + pop @dir_list; + $main::my_location = join '/', @dir_list; + + if (&is_linux) { + $main::config_location = '{SYSCONFDIR}'; + } else { + $main::config_location = $main::my_location; + } +} + +# 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 = $0; + +$main::version = '2.1'; +$main::rdate = 'Jan 21, 2022'; + +&parse_options; +if (defined $main::options{'l'}) { + $main::config_location = $main::my_location; +} + +&get_configfiles; + +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; +} + +&get_filenames; + +if (!$main::multidoc && -e "$main::outputfile") { + die ("outputfile $main::outputfile already exists\n") + unless (defined $main::options{'f'}); +} + +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::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::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/src/SQLTeX_r.dat b/support/SQLTeX/src/SQLTeX_r.dat new file mode 100644 index 0000000000..c4f56bda08 --- /dev/null +++ b/support/SQLTeX/src/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} |