[PATCH] VMS-style native command syntax for fisql, freebcp, and defncopy
"Craig A. Berry" <[email protected]>
| Newsgroups | gmane.comp.db.tds.freetds |
|---|---|
| Message-ID | <[email protected]> |
I apologize for the size of the attached patch (almost 1700 lines), but it does something critically important in my environment (which I'll explain below) and has no effect at all on non-VMS platforms. I'd really like to see it checked in and would be glad to do further work to make it acceptable if necessary. If the threatened commit bit turns up, I'm happy to do the grunt work and save James or Freddy the effort of getting this into the repository, but it seemed like it should be mentioned on-list in any case. What does it do? It provides a wrapper around fisql, freebcp, and defncopy so that VMS- style commands on the command line get translated into the Unix-style commands that the utilities expect. For example, instead of: % fisql -Sserver -Uuser -Ppass you say: $ fisql/server_name="server"/user="user"/password="pass" Why? Once upon a time there were Sybase client utilities (not to mention Sybase servers) on VMS. Where I work we have a large number of command procedures (what other OS's call shell scripts) that use those client utilities to push data around among databases, run stored procedures remotely in coordination with various VMS-centric jobs, or extract data for further processing and shipping off to various banks, insurance companies, etc. Over the years the databases changed from Sybase to SQL Server, and then higher versions of SQL Server. In the past year (since we upgrade our VMS hardware every 15 years whether it needs it or not) we replaced ancient Alpha hardware with shiny new Itanium hardware -- but there have never been Sybase clients on Itanium. The only thing that has allowed us to survive all these transitions is FreeTDS. Obviously other things could have been done, but all of those things would have been much more difficult and expensive than coercing the FreeTDS clients into functioning as drop-in replacements for the old Sybase clients. So that's what we did. The patch here is a more complete, less intrusive and cleaned-up version of something we've been running in production for several years. Some details about what's changed and new follow. I *think* I included all of the necessary copyright notices and Makefile.am changes. % lsdiff -s vmscmd.patch ! freetds-0.83.dev.20100522/Makefile.am ! freetds-0.83.dev.20100522/src/apps/defncopy.c ! freetds-0.83.dev.20100522/src/apps/fisql/fisql.c ! freetds-0.83.dev.20100522/src/apps/freebcp.c ! freetds-0.83.dev.20100522/vms/Makefile.am ! freetds-0.83.dev.20100522/vms/config_h.vms ! freetds-0.83.dev.20100522/vms/descrip_mms.template + freetds-0.83.dev.20100522/vms/vargdefs.h + freetds-0.83.dev.20100522/vms/vmsarg_command_bcp.cld + freetds-0.83.dev.20100522/vms/vmsarg_command_defncopy.cld + freetds-0.83.dev.20100522/vms/vmsarg_command_isql.cld + freetds-0.83.dev.20100522/vms/vmsarg_mapping_bcp.c + freetds-0.83.dev.20100522/vms/vmsarg_mapping_defncopy.c + freetds-0.83.dev.20100522/vms/vmsarg_mapping_isql.c + freetds-0.83.dev.20100522/vms/vmsarg_parse.c ________________________________________ Craig A. Berry mailto:[email protected] "... getting out of a sonnet is much more difficult than getting in." Brad Leithauser _______________________________________________ FreeTDS mailing list [email protected] http://lists.ibiblio.org/mailman/listinfo/freetds
vmscmd.patch
(application/octet-stream, 57.5 KB)
diff -purN freetds-0.83.dev.20100522/Makefile.am freetds-0.83.dev.20100522-vmscmd/Makefile.am
--- freetds-0.83.dev.20100522/Makefile.am 2010-01-21 02:34:04.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/Makefile.am 2010-05-25 22:09:12.000000000 -0500
@@ -9,11 +9,22 @@ ACLOCAL_AMFLAGS = -I m4
VMS = vms/config_h.vms \
vms/configure.com \
+ vms/edit.c \
vms/descrip_mms.template \
vms/getpass.c \
vms/libodbc.opt \
+ vms/Makefile.am \
vms/odbc_driver_axp.opt \
- vms/README.vms
+ vms/README.vms \
+ vms/vargdefs.h \
+ vms/vmsarg_command_bcp.cld \
+ vms/vmsarg_command_defncopy.cld \
+ vms/vmsarg_command_isql.cld \
+ vms/vmsarg_mapping_bcp.c \
+ vms/vmsarg_mapping_defncopy.c \
+ vms/vmsarg_mapping_isql.c \
+ vms/vmsarg_parse.c
+
EXTRA_DIST = $(VMS) interfaces PWD.in BUGS \
freetds.conf locales.conf \
diff -purN freetds-0.83.dev.20100522/src/apps/defncopy.c freetds-0.83.dev.20100522-vmscmd/src/apps/defncopy.c
--- freetds-0.83.dev.20100522/src/apps/defncopy.c 2010-01-11 08:03:20.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/src/apps/defncopy.c 2010-05-25 20:19:47.000000000 -0500
@@ -143,6 +143,11 @@ main(int argc, char *argv[])
RETCODE erc;
int i, nrows;
+#ifdef __VMS
+ /* Convert VMS-style arguments to Unix-style */
+ parse_vms_args(&argc, &argv);
+#endif
+
/* Initialize db-lib */
#if _WIN32 && defined(MicrosoftsDbLib)
LPCSTR msg = dbinit();
diff -purN freetds-0.83.dev.20100522/src/apps/fisql/fisql.c freetds-0.83.dev.20100522-vmscmd/src/apps/fisql/fisql.c
--- freetds-0.83.dev.20100522/src/apps/fisql/fisql.c 2010-05-21 10:18:49.000000000 -0500
+++ freetds-0.83.dev.20100522-vmscmd/src/apps/fisql/fisql.c 2010-05-25 20:19:47.000000000 -0500
@@ -268,6 +268,11 @@ main(int argc, char *argv[])
int nby;
char adash;
+#ifdef __VMS
+ /* Convert VMS-style arguments to Unix-style */
+ parse_vms_args(&argc, &argv);
+#endif
+
editor = getenv("EDITOR");
if (!editor) {
editor = getenv("VISUAL");
diff -purN freetds-0.83.dev.20100522/src/apps/freebcp.c freetds-0.83.dev.20100522-vmscmd/src/apps/freebcp.c
--- freetds-0.83.dev.20100522/src/apps/freebcp.c 2010-05-21 09:10:31.000000000 -0500
+++ freetds-0.83.dev.20100522-vmscmd/src/apps/freebcp.c 2010-05-25 20:19:47.000000000 -0500
@@ -74,6 +74,11 @@ main(int argc, char **argv)
DBPROCESS *dbproc;
int ok = FALSE;
+#ifdef __VMS
+ /* Convert VMS-style arguments to Unix-style */
+ parse_vms_args(&argc, &argv);
+#endif
+
memset(¶ms, '\0', sizeof(params));
params.textsize = 4096; /* our default text size is 4K */
diff -purN freetds-0.83.dev.20100522/vms/Makefile.am freetds-0.83.dev.20100522-vmscmd/vms/Makefile.am
--- freetds-0.83.dev.20100522/vms/Makefile.am 2010-05-25 22:18:01.000000000 -0500
+++ freetds-0.83.dev.20100522-vmscmd/vms/Makefile.am 2010-05-25 22:03:47.000000000 -0500
@@ -1,4 +1,8 @@
-EXTRA_DIST = config_h.vms configure.com descrip_mms.template \
- edit.c getpass.c libodbc.opt odbc_driver_axp.opt README.vms
+EXTRA_DIST = config_h.vms configure.com edit.c descrip_mms.template \
+ getpass.c libodbc.opt odbc_driver_axp.opt README.vms \
+ vargdefs.h vmsarg_command_bcp.cld vmsarg_command_defncopy.cld \
+ vmsarg_command_isql.cld vmsarg_mapping_bcp.c \
+ vmsarg_mapping_defncopy.c vmsarg_mapping_isql.c \
+ vmsarg_parse.c
clean:
diff -purN freetds-0.83.dev.20100522/vms/config_h.vms freetds-0.83.dev.20100522-vmscmd/vms/config_h.vms
--- freetds-0.83.dev.20100522/vms/config_h.vms 2009-04-08 20:40:25.000000000 -0500
+++ freetds-0.83.dev.20100522-vmscmd/vms/config_h.vms 2010-05-25 20:19:47.000000000 -0500
@@ -346,4 +346,7 @@ char * readpassphrase(const char *, char
#define HAVE_SQLSETPOSIROW 1
#define TDS_SQLCOLATTRIBUTE_SQLLEN 1
+/* Prototype for routine to convert VMS-style arguments to Unix-style. */
+int parse_vms_args(int *argc, char **argv[]);
+
#endif /* CONFIG_H_LOADED */
diff -purN freetds-0.83.dev.20100522/vms/descrip_mms.template freetds-0.83.dev.20100522-vmscmd/vms/descrip_mms.template
--- freetds-0.83.dev.20100522/vms/descrip_mms.template 2010-05-21 09:02:08.000000000 -0500
+++ freetds-0.83.dev.20100522-vmscmd/vms/descrip_mms.template 2010-05-25 20:19:47.000000000 -0500
@@ -293,10 +293,21 @@ $(TDSODBCSHR) : []libtdsodbc$(OLB)
apps : freebcp$(E) tsql$(E) bsqldb$(E) defncopy$(E) tdspool$(E) fisql$(E)
@ continue
-freebcp$(E) : [.src.apps]freebcp$(OBJ) []libsybdb$(OLB) []libtds$(OLB)
- link$(LINKFLAGS)/exe=$(MMS$TARGET) $(MMS$SOURCE),[]libsybdb$(OLB)/library, []libtds$(OLB)/library
+[]vmsarg_parse$(OBJ) : [.vms]vmsarg_parse.c
+ $(CC) $(CFLAGS)/INCLUDE=([.vms],$(CINCLUDE)) $(CDBGFLAGS) $(MMS$SOURCE)
+
+
+freebcp$(E) : [.src.apps]freebcp$(OBJ) []vmsarg_mapping_bcp$(OBJ) []vmsarg_command_bcp$(OBJ) []vmsarg_parse$(OBJ)
+ link$(LINKFLAGS)/exe=$(MMS$TARGET) $(MMS$SOURCE_LIST),[]libsybdb$(OLB)/library, []libtds$(OLB)/library
+
+[.src.apps]freebcp$(OBJ) : [.src.apps]freebcp.c []libsybdb$(OLB) []libtds$(OLB)
+
+[]vmsarg_mapping_bcp$(OBJ) : [.vms]vmsarg_mapping_bcp.c
+ $(CC) $(CFLAGS)/INCLUDE=([.vms],$(CINCLUDE)) $(CDBGFLAGS) $(MMS$SOURCE)
+
+[]vmsarg_command_bcp$(OBJ) : [.vms]vmsarg_command_bcp.cld
+ SET COMMAND/OBJECT=$(MMS$TARGET) $(MMS$SOURCE)
-[.src.apps]freebcp$(OBJ) : [.src.apps]freebcp.c
tsql$(E) : [.src.apps]tsql$(OBJ) []libsybdb$(OLB) []libtds$(OLB)
link$(LINKFLAGS)/exe=$(MMS$TARGET) $(MMS$SOURCE),[]libsybdb$(OLB)/library, []libtds$(OLB)/library
@@ -305,24 +316,34 @@ tsql$(E) : [.src.apps]tsql$(OBJ) []libsy
@ define/nolog/user_mode readline [.include]
$(CC) $(CFLAGS)/INCLUDE=($(CINCLUDE)) $(MMS$SOURCE)
+
bsqldb$(E) : [.src.apps]bsqldb$(OBJ) []libsybdb$(OLB) []libtds$(OLB)
link$(LINKFLAGS)/exe=$(MMS$TARGET) $(MMS$SOURCE),[]libsybdb$(OLB)/library, []libtds$(OLB)/library
[.src.apps]bsqldb$(OBJ) : [.src.apps]bsqldb.c
-defncopy$(E) : [.src.apps]defncopy$(OBJ) []libsybdb$(OLB) []libtds$(OLB)
- link$(LINKFLAGS)/exe=$(MMS$TARGET) $(MMS$SOURCE),[]libsybdb$(OLB)/library, []libtds$(OLB)/library
-[.src.apps]defncopy$(OBJ) : [.src.apps]defncopy.c
+defncopy$(E) : [.src.apps]defncopy$(OBJ) []vmsarg_mapping_defncopy$(OBJ) []vmsarg_command_defncopy$(OBJ) []vmsarg_parse$(OBJ)
+ link$(LINKFLAGS)/exe=$(MMS$TARGET) $(MMS$SOURCE_LIST),[]libsybdb$(OLB)/library, []libtds$(OLB)/library
+
+[.src.apps]defncopy$(OBJ) : [.src.apps]defncopy.c []libsybdb$(OLB) []libtds$(OLB)
+
+[]vmsarg_mapping_defncopy$(OBJ) : [.vms]vmsarg_mapping_defncopy.c
+ $(CC) $(CFLAGS)/INCLUDE=([.vms],$(CINCLUDE)) $(CDBGFLAGS) $(MMS$SOURCE)
+
+[]vmsarg_command_defncopy$(OBJ) : [.vms]vmsarg_command_defncopy.cld
+ SET COMMAND/OBJECT=$(MMS$TARGET) $(MMS$SOURCE)
+
tdspool$(E) : $(TDSPOOLOBJS) []libtdssrv$(OLB) []libtds$(OLB)
link$(LINKFLAGS)/exe=$(MMS$TARGET) $(TDSPOOLOBJS), []libtdssrv$(OLB)/library, []libtds$(OLB)/library
-fisql$(E) : [.src.apps.fisql]fisql$(OBJ) [.src.apps.fisql]interrupt$(OBJ) [.src.apps.fisql]handlers$(OBJ) [.vms]edit$(OBJ)
- link$(LINKFLAGS)/exe=$(MMS$TARGET) $(MMS$SOURCE_LIST),[]libsybdb$(OLB)/library, []libtds$(OLB)/library
-
-[.src.apps.fisql]fisql$(OBJ) : [.src.apps.fisql]fisql.c
+fisql$(E) : [.src.apps.fisql]fisql$(OBJ) [.src.apps.fisql]interrupt$(OBJ) [.src.apps.fisql]handlers$(OBJ) [.vms]edit$(OBJ) \
+ []vmsarg_mapping_isql$(OBJ) []vmsarg_command_isql$(OBJ) []vmsarg_parse$(OBJ)
+ link$(LINKFLAGS)/exe=$(MMS$TARGET) $(MMS$SOURCE_LIST),[]libsybdb$(OLB)/library, []libtds$(OLB)/library
+
+[.src.apps.fisql]fisql$(OBJ) : [.src.apps.fisql]fisql.c []libsybdb$(OLB) []libtds$(OLB)
@ define/nolog/user_mode readline [.include]
$(CC) $(CFLAGS)/INCLUDE=($(CINCLUDE)) $(MMS$SOURCE)
@@ -330,6 +351,11 @@ fisql$(E) : [.src.apps.fisql]fisql$(OBJ)
[.src.apps.fisql]handlers$(OBJ) : [.src.apps.fisql]handlers.c
+[]vmsarg_mapping_isql$(OBJ) : [.vms]vmsarg_mapping_isql.c
+ $(CC) $(CFLAGS)/INCLUDE=([.vms],$(CINCLUDE)) $(CDBGFLAGS) $(MMS$SOURCE)
+
+[]vmsarg_command_isql$(OBJ) : [.vms]vmsarg_command_isql.cld
+ SET COMMAND/OBJECT=$(MMS$TARGET) $(MMS$SOURCE)
# Run the test suite
diff -purN freetds-0.83.dev.20100522/vms/vargdefs.h freetds-0.83.dev.20100522-vmscmd/vms/vargdefs.h
--- freetds-0.83.dev.20100522/vms/vargdefs.h 1969-12-31 18:00:00.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/vms/vargdefs.h 2010-05-25 20:19:47.000000000 -0500
@@ -0,0 +1,70 @@
+/* FreeTDS - Library of routines accessing Sybase and Microsoft databases
+ * Copyright (C) 2010 Craig A. Berry [email protected]
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+
+/*
+ * Definitions used by the VMSARG parsing and mapping routines.
+ *
+ * Based on VMSARG Version 2.0 by Tom Wade <[email protected]>
+ *
+ * Extensively revised for inclusion in FreeTDS by Craig A. Berry.
+ *
+ * From the VMSARG 2.0 documentation:
+ *
+ * The product is aimed at . . . people who are porting a package from
+ * Unix to VMS. This software is made freely available for inclusion in
+ * such products, whether they are freeware, public domain or commercial.
+ * No licensing is required.
+ */
+
+#if __CRTL_VER >= 70302000 && !defined(__VAX)
+#define QUAL_LENGTH (4000+1)
+#define S_LENGTH (4096+1)
+#else
+#define QUAL_LENGTH (255+1)
+#define S_LENGTH (1024+1)
+#endif
+
+#define MAX_ARGS 255
+
+/* bit fields for arg flags.
+*/
+
+#define VARG_M_AFFIRM 1
+#define VARG_M_NEGATIVE 2
+#define VARG_M_KEYWORDS 4
+#define VARG_M_SEPARATOR 8
+#define VARG_M_DATE 16
+#define VARG_M_APPEND 32
+#define VARG_M_HELP 64
+
+/* bit fields for action flags.
+*/
+
+#define VARGACT_M_UPPER 1
+#define VARGACT_M_LOWER 2
+#define VARGACT_M_SPECIAL 4
+#define VARGACT_M_ESCAPE 8
+#define VARGACT_M_DOUBLE 16
+#define VARGACT_M_IMAGE 32
+#define VARGACT_M_SYMBOL 64
+#define VARGACT_M_COMMAND 128
+#define VARGACT_M_RETURN 256
+#define VARGACT_M_PROTECT 512
+#define VARGACT_M_UNIXARG 1024
+
+#define VARGACT_M_PROTMASK 1+2+4+8+16
diff -purN freetds-0.83.dev.20100522/vms/vmsarg_command_bcp.cld freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_command_bcp.cld
--- freetds-0.83.dev.20100522/vms/vmsarg_command_bcp.cld 1969-12-31 18:00:00.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_command_bcp.cld 2010-05-25 20:19:47.000000000 -0500
@@ -0,0 +1,92 @@
+! FreeTDS - Library of routines accessing Sybase and Microsoft databases
+! Copyright (C) 2010 Craig A. Berry [email protected]
+!
+! This library is free software; you can redistribute it and/or
+! modify it under the terms of the GNU Library General Public
+! License as published by the Free Software Foundation; either
+! version 2 of the License, or (at your option) any later version.
+!
+! This library is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Library General Public License for more details.
+!
+! You should have received a copy of the GNU Library General Public
+! License along with this library; if not, write to the
+! Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+
+! Command definitions for the BCP command.
+
+
+Module VARG_CLD
+
+Define Verb VARG
+ parameter P1, label=TABLE_NAME
+ value (required)
+ parameter P2, label=DIRECTION
+ value (required,type=DIR_KEYS)
+ parameter P3, label=DATA_FILE
+ value (required,type=$file)
+ qualifier MAX_ERRORS
+ value (required,type=$number)
+ qualifier FORMAT_FILE
+ value (required,type=$file)
+ qualifier ERRORFILE
+ value (required,type=$file)
+ qualifier FIRST_ROW
+ value (required,type=$number)
+ qualifier LAST_ROW
+ value (required,type=$number)
+ qualifier BATCH_SIZE
+ value (required,type=$number)
+ qualifier NATIVE_DEFAULT
+ qualifier CHARACTER_DEFAULT
+ qualifier COLUMN_TERMINATOR
+ value (required)
+ qualifier ROW_TERMINATOR
+ value (required)
+ qualifier USERNAME
+ value
+ qualifier PASSWORD
+ value (default="")
+ qualifier SERVER_NAME
+ value (required)
+ qualifier INPUT
+ value (required,type=$file)
+ qualifier OUTPUT
+ value (required,type=$file)
+ qualifier SERVCHARSET
+ value
+ qualifier CLIENTCHARSET
+ value
+ qualifier DISPCHARSET
+ value
+ qualifier FILECHARSET
+ value
+ qualifier LANGUAGE
+ value
+ qualifier FILECHARSET
+ value
+ qualifier TDSPACKETSIZE
+ value (type=$number)
+ qualifier TEXTSIZE
+ value (type=$number)
+ qualifier VERSION, syntax=NOPARAM
+ qualifier HOMEDIR
+ value
+ qualifier ENCRYPT
+ qualifier IDENTITY
+ disallow (NATIVE_DEFAULT and CHARACTER_DEFAULT)
+
+define type DIR_KEYS
+ keyword IN
+ keyword OUT
+
+define syntax NOPARAM
+ parameter P1, label=TABLE_NAME
+ parameter P2, label=DIRECTION
+ value (type=DIR_KEYS)
+ parameter P3, label=DATA_FILE
+ value (type=$file)
+
diff -purN freetds-0.83.dev.20100522/vms/vmsarg_command_defncopy.cld freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_command_defncopy.cld
--- freetds-0.83.dev.20100522/vms/vmsarg_command_defncopy.cld 1969-12-31 18:00:00.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_command_defncopy.cld 2010-05-25 20:19:47.000000000 -0500
@@ -0,0 +1,65 @@
+! FreeTDS - Library of routines accessing Sybase and Microsoft databases
+! Copyright (C) 2010 Craig A. Berry [email protected]
+!
+! This library is free software; you can redistribute it and/or
+! modify it under the terms of the GNU Library General Public
+! License as published by the Free Software Foundation; either
+! version 2 of the License, or (at your option) any later version.
+!
+! This library is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Library General Public License for more details.
+!
+! You should have received a copy of the GNU Library General Public
+! License along with this library; if not, write to the
+! Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+
+! Command definitions for the DEFNCOPY command.
+
+Module VARG_CLD
+
+define verb VARG
+ parameter P1, label=DIRECTION
+ value (required,type=DIR_KEYS)
+ parameter P2, label=FILE_NAME
+ value (required,type=$file)
+ parameter P3, label=DATABASE_NAME
+ value (required)
+ parameter P4, label=OBJECT_NAME
+ value (list)
+ qualifier USERNAME
+ value
+ qualifier PASSWORD
+ value (default="")
+ qualifier SERVER_NAME, label=SERVERNAME
+ value
+ qualifier VERSION, syntax=NOPARAM
+ qualifier INTERFACES, label=INTERFACE
+ value (type=$file)
+ qualifier DISPCHARSET
+ value
+ qualifier LANGUAGE
+ value
+ qualifier SERVCHARSET
+ value
+ qualifier CLIENTCHARSET
+ value
+ qualifier REAL_VERSION
+ qualifier HOMEDIR
+ value
+
+define type DIR_KEYS
+ keyword IN
+ keyword OUT
+
+define syntax NOPARAM
+ parameter P1, label=DIRECTION
+ value (type=DIR_KEYS)
+ parameter P2, label=FILE_NAME
+ value (type=$file)
+ parameter P3, label=DATABASE_NAME
+ parameter P4, label=OBJECT_NAME
+ value (list)
+
diff -purN freetds-0.83.dev.20100522/vms/vmsarg_command_isql.cld freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_command_isql.cld
--- freetds-0.83.dev.20100522/vms/vmsarg_command_isql.cld 1969-12-31 18:00:00.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_command_isql.cld 2010-05-25 20:19:47.000000000 -0500
@@ -0,0 +1,79 @@
+! FreeTDS - Library of routines accessing Sybase and Microsoft databases
+! Copyright (C) 2010 Craig A. Berry [email protected]
+!
+! This library is free software; you can redistribute it and/or
+! modify it under the terms of the GNU Library General Public
+! License as published by the Free Software Foundation; either
+! version 2 of the License, or (at your option) any later version.
+!
+! This library is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+! Library General Public License for more details.
+!
+! You should have received a copy of the GNU Library General Public
+! License along with this library; if not, write to the
+! Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+
+! Command definitions for the ISQL command.
+
+Module VARG_CLD
+
+Define Verb VARG
+ qualifier ECHO
+ qualifier STATISTICS
+ qualifier NOPROMPT
+ qualifier TERMINATOR
+ value
+ qualifier WIDTH
+ value (type=$number)
+ qualifier COLSEPARATOR
+ value
+ qualifier ROWSINPAGE
+ value (type=$number)
+ qualifier TIMEOUT
+ value
+ qualifier ERRORLEVEL
+ value (type=$number)
+ qualifier USERNAME
+ value
+ qualifier PASSWORD
+ value
+ qualifier SERVER_NAME
+ value
+ qualifier INTERFACE
+ value (type=$file)
+ qualifier HOSTNAME
+ value
+ qualifier CLIENTCHARSET
+ value
+ qualifier DISPCHARSET
+ value
+ qualifier INPUT
+ value (type=$file)
+ qualifier OUTPUT
+ value (type=$file)
+ qualifier LANGUAGE
+ value
+ qualifier HOMEDIR
+ value
+ qualifier VERSION
+ qualifier DEBUG
+ qualifier BROWSE
+ qualifier RECORD_FRONT_TO_SERVER
+ value
+ qualifier LOGINTIME
+ value
+ qualifier EDITOR
+ value
+ qualifier TDSPACKETSIZE
+ value (type=$number)
+ qualifier TRACE
+ value
+ qualifier ADDID
+ qualifier LOOK3
+ qualifier ENCRYPT
+ qualifier CHAIN_XACT
+ qualifier FIPS
+define syntax NOPARAM
diff -purN freetds-0.83.dev.20100522/vms/vmsarg_mapping_bcp.c freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_mapping_bcp.c
--- freetds-0.83.dev.20100522/vms/vmsarg_mapping_bcp.c 1969-12-31 18:00:00.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_mapping_bcp.c 2010-05-25 20:19:47.000000000 -0500
@@ -0,0 +1,136 @@
+/* FreeTDS - Library of routines accessing Sybase and Microsoft databases
+ * Copyright (C) 2010 Craig A. Berry [email protected]
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+
+/*
+ * Mapping table for the BCP command.
+ */
+
+int vmsarg_mapping (int *nvargs, char *vms_arg[], char *unix_arg[],
+ char *unix_narg[], char *vms_key[], char *unix_key[],
+ char *separator[], int flags[], char *pattern[],
+ char **outverb, int *action_flags, char **arg_symbol,
+ char **image_name)
+{
+ *nvargs = 26;
+ *action_flags = 1301;
+ vms_arg[1] = "TABLE_NAME";
+ flags[1] = 1;
+ unix_arg[1] = "$";
+
+ vms_arg[2] = "DIRECTION";
+ flags[2] = 1;
+ unix_arg[2] = "$";
+
+ vms_arg[3] = "DATA_FILE";
+ flags[3] = 1;
+ unix_arg[3] = "$";
+
+ vms_arg[4] = "MAX_ERRORS";
+ flags[4] = 1;
+ unix_arg[4] = "-m";
+
+ vms_arg[5] = "FORMAT_FILE";
+ flags[5] = 1;
+ unix_arg[5] = "-f";
+
+ vms_arg[6] = "ERRORFILE";
+ flags[6] = 1;
+ unix_arg[6] = "-e";
+
+ vms_arg[7] = "FIRST_ROW";
+ flags[7] = 1;
+ unix_arg[7] = "-F";
+
+ vms_arg[8] = "LAST_ROW";
+ flags[8] = 1;
+ unix_arg[8] = "-L";
+
+ vms_arg[9] = "BATCH_SIZE";
+ flags[9] = 1;
+ unix_arg[9] = "-b";
+
+ vms_arg[10] = "NATIVE_DEFAULT";
+ flags[10] = 1;
+ unix_arg[10] = "-n";
+
+ vms_arg[11] = "CHARACTER_DEFAULT";
+ flags[11] = 1;
+ unix_arg[11] = "-c";
+
+ vms_arg[12] = "COLUMN_TERMINATOR";
+ flags[12] = 1;
+ unix_arg[12] = "-t";
+
+ vms_arg[13] = "ROW_TERMINATOR";
+ flags[13] = 1;
+ unix_arg[13] = "-r";
+
+ vms_arg[14] = "USERNAME";
+ flags[14] = 1;
+ unix_arg[14] = "-U";
+
+ vms_arg[15] = "PASSWORD";
+ flags[15] = 1;
+ unix_arg[15] = "-P";
+
+ vms_arg[16] = "SERVER_NAME";
+ flags[16] = 1;
+ unix_arg[16] = "-S";
+
+ vms_arg[17] = "INPUT";
+ flags[17] = 1;
+ unix_arg[17] = "-i";
+
+ vms_arg[18] = "OUTPUT";
+ flags[18] = 1;
+ unix_arg[18] = "-o";
+
+ vms_arg[19] = "TDSPACKETSIZE";
+ flags[19] = 1;
+ unix_arg[19] = "-A";
+
+ vms_arg[20] = "TEXTSIZE";
+ flags[20] = 1;
+ unix_arg[20] = "-T";
+
+ vms_arg[21] = "VERSION";
+ flags[21] = 1;
+ unix_arg[21] = "-v";
+
+ vms_arg[22] = "DISPCHARSET";
+ flags[22] = 1;
+ unix_arg[22] = "-a";
+
+ vms_arg[23] = "LANGUAGE";
+ flags[23] = 1;
+ unix_arg[23] = "-z";
+
+ vms_arg[24] = "CLIENTCHARSET";
+ flags[24] = 1;
+ unix_arg[24] = "-J";
+
+ vms_arg[25] = "IDENTITY";
+ flags[25] = 1;
+ unix_arg[25] = "-E";
+
+ vms_arg[26] = "ENCRYPT";
+ flags[26] = 1;
+ unix_arg[26] = "-X";
+
+ return 1;
+}
diff -purN freetds-0.83.dev.20100522/vms/vmsarg_mapping_defncopy.c freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_mapping_defncopy.c
--- freetds-0.83.dev.20100522/vms/vmsarg_mapping_defncopy.c 1969-12-31 18:00:00.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_mapping_defncopy.c 2010-05-25 20:19:47.000000000 -0500
@@ -0,0 +1,80 @@
+/* FreeTDS - Library of routines accessing Sybase and Microsoft databases
+ * Copyright (C) 2010 Craig A. Berry [email protected]
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+
+/*
+ * Mapping table for the DEFNCOPY command.
+ */
+
+int vmsarg_mapping (int *nvargs, char *vms_arg[], char *unix_arg[],
+ char *unix_narg[], char *vms_key[], char *unix_key[],
+ char *separator[], int flags[], char *pattern[],
+ char **outverb, int *action_flags, char **arg_symbol,
+ char **image_name)
+{
+ *nvargs = 12;
+ *action_flags = 1301;
+ vms_arg[1] = "DIRECTION";
+ flags[1] = 1;
+ unix_arg[1] = "$";
+
+ vms_arg[2] = "FILE_NAME";
+ flags[2] = 1;
+ unix_arg[2] = "$";
+
+ vms_arg[3] = "DATABASE_NAME";
+ flags[3] = 1;
+ unix_arg[3] = "$";
+
+ vms_arg[4] = "OBJECT_NAME";
+ flags[4] = 1;
+ unix_arg[4] = "$";
+
+ vms_arg[5] = "USERNAME";
+ flags[5] = 1;
+ unix_arg[5] = "-U";
+
+ vms_arg[6] = "PASSOWRD";
+ flags[6] = 1;
+ unix_arg[6] = "-P";
+
+ vms_arg[7] = "SERVER_NAME";
+ flags[7] = 1;
+ unix_arg[7] = "-S";
+
+ vms_arg[8] = "VERSION";
+ flags[8] = 1;
+ unix_arg[8] = "-v";
+
+ vms_arg[9] = "INTERFACES";
+ flags[9] = 1;
+ unix_arg[9] = "-I";
+
+ vms_arg[10] = "DISPCHARSET";
+ flags[10] = 1;
+ unix_arg[10] = "-a";
+
+ vms_arg[11] = "LANGUAGE";
+ flags[11] = 1;
+ unix_arg[11] = "-z";
+
+ vms_arg[12] = "CLIENTCHARSET";
+ flags[12] = 1;
+ unix_arg[12] = "-J";
+
+ return 1;
+}
diff -purN freetds-0.83.dev.20100522/vms/vmsarg_mapping_isql.c freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_mapping_isql.c
--- freetds-0.83.dev.20100522/vms/vmsarg_mapping_isql.c 1969-12-31 18:00:00.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_mapping_isql.c 2010-05-25 20:19:47.000000000 -0500
@@ -0,0 +1,143 @@
+/* FreeTDS - Library of routines accessing Sybase and Microsoft databases
+ * Copyright (C) 2010 Craig A. Berry [email protected]
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+
+/*
+ * Mapping table for the ISQL command.
+ */
+
+#include <stdlib.h>
+
+int vmsarg_mapping (int *nvargs, char *vms_arg[], char *unix_arg[],
+ char *unix_narg[], char *vms_key[], char *unix_key[],
+ char *separator[], int flags[], char *pattern[],
+ char **outverb, int *action_flags, char **arg_symbol,
+ char **image_name)
+{
+ *nvargs = 26;
+ *action_flags = 1301;
+ vms_arg[1] = "USERNAME";
+ flags[1] = 1;
+ unix_arg[1] = "-U";
+
+ vms_arg[2] = "PASSWORD";
+ flags[2] = 1;
+ unix_arg[2] = "-P";
+
+ vms_arg[3] = "SERVER_NAME";
+ flags[3] = 1;
+ unix_arg[3] = "-S";
+
+ vms_arg[4] = "TIMEOUT";
+ flags[4] = 1;
+ unix_arg[4] = "-t";
+
+ vms_arg[5] = "INPUT";
+ flags[5] = 1;
+ unix_arg[5] = "-i";
+
+ vms_arg[6] = "OUTPUT";
+ flags[6] = 1;
+ unix_arg[6] = "-o";
+
+ vms_arg[7] = "VERSION";
+ flags[7] = 1;
+ unix_arg[7] = "-v";
+
+ vms_arg[8] = "ECHO";
+ flags[8] = 1;
+ unix_arg[8] = "-e";
+
+ vms_arg[9] = "FIPS";
+ flags[9] = 1;
+ unix_arg[9] = "-F";
+
+ vms_arg[10] = "STATISTICS";
+ flags[10] = 1;
+ unix_arg[10] = "-p";
+
+ vms_arg[11] = "NOPROMPT";
+ flags[11] = 1;
+ unix_arg[11] = "-n";
+
+ vms_arg[12] = "ENCRYPT";
+ flags[12] = 1;
+ unix_arg[12] = "-X";
+
+ vms_arg[13] = "CHAIN_XACT";
+ flags[13] = 1;
+ unix_arg[13] = "-Y";
+
+ vms_arg[14] = "DISPCHARSET";
+ flags[14] = 1;
+ unix_arg[14] = "-a";
+
+ vms_arg[15] = "TDSPACKETSIZE";
+ flags[15] = 1;
+ unix_arg[15] = "-A";
+
+ vms_arg[16] = "TERMINATOR";
+ flags[16] = 1;
+ unix_arg[16] = "-c";
+
+ vms_arg[17] = "EDITOR";
+ flags[17] = 1;
+ unix_arg[17] = "-E";
+
+ vms_arg[18] = "ROWSINPAGE";
+ flags[18] = 1;
+ unix_arg[18] = "-h";
+
+ vms_arg[19] = "HOSTNAME";
+ flags[19] = 1;
+ unix_arg[19] = "-H";
+
+ vms_arg[20] = "INTERFACE";
+ flags[20] = 1;
+ unix_arg[20] = "-I";
+
+ vms_arg[21] = "CLIENTCHARSET";
+ flags[21] = 1;
+ unix_arg[21] = "-J";
+
+ vms_arg[22] = "ERRORLEVEL";
+ flags[22] = 1;
+ unix_arg[22] = "-m";
+
+ vms_arg[23] = "LOGINTIME";
+ flags[23] = 1;
+ unix_arg[23] = "-l";
+
+ vms_arg[24] = "COLSEPARATOR";
+ flags[24] = 1;
+ unix_arg[24] = "-s";
+
+ vms_arg[25] = "WIDTH";
+ flags[25] = 1;
+ unix_arg[25] = "-w";
+
+ vms_arg[26] = "LANGUAGE";
+ flags[26] = 1;
+ unix_arg[26] = "-z";
+
+ /* Because vi is not a reasonable default on VMS.
+ */
+ if (setenv("EDITOR", "edit", 0) != 0)
+ return 0;
+
+ return 1;
+}
diff -purN freetds-0.83.dev.20100522/vms/vmsarg_parse.c freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_parse.c
--- freetds-0.83.dev.20100522/vms/vmsarg_parse.c 1969-12-31 18:00:00.000000000 -0600
+++ freetds-0.83.dev.20100522-vmscmd/vms/vmsarg_parse.c 2010-05-25 20:19:47.000000000 -0500
@@ -0,0 +1,814 @@
+/* FreeTDS - Library of routines accessing Sybase and Microsoft databases
+ * Copyright (C) 2010 Craig A. Berry [email protected]
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+
+/*
+ * Program to Parse VMS style arguments. The calling program passes
+ * argc, argv into this routine, and we translate the VMS qualifiers into
+ * Unix style arguments according to a user specified translation table.
+ * It then puts these into a new argv and returns that address to the
+ * caller. The calling program then happily proceeds with the Unix style
+ * qualifiers that it was written to deal with.
+ *
+ * Based on VMSARG Version 2.0 by Tom Wade <[email protected]>
+ *
+ * Extensively revised for inclusion in FreeTDS by Craig A. Berry.
+ *
+ * From the VMSARG 2.0 documentation:
+ *
+ * The product is aimed at . . . people who are porting a package from
+ * Unix to VMS. This software is made freely available for inclusion in
+ * such products, whether they are freeware, public domain or commercial.
+ * No licensing is required.
+ */
+
+
+#include "vargdefs.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <climsgdef.h>
+#include <descrip.h>
+#include <libdef.h>
+#include <ssdef.h>
+
+#include <cli$routines.h>
+#include <lbr$routines.h>
+#include <lib$routines.h>
+#include <starlet.h>
+
+/* Increment arg counter and crash out if we have too many
+*/
+
+#define Increment(x) x = x + 1;\
+ if (x > MAX_ARGS) sys$exit(SS$_OVRMAXARG);
+
+/* Declare internal static routines
+*/
+
+static int varg_get_index(), varg_set_index(), varg_convert_date(), varg_do_help();
+static int varg_protect_string(), varg_set_symbol(), varg_do_command();
+static int varg_do_exit();
+
+parse_vms_args(int *argc, char **argv[])
+{
+ static char command[S_LENGTH], value_template[S_LENGTH];
+ static char qual_template[S_LENGTH];
+ char verb[] = "VARG ";
+ char *vms_arg[MAX_ARGS];
+ char *unix_arg[MAX_ARGS];
+ char *unix_narg[MAX_ARGS];
+ char *vms_key[MAX_ARGS];
+ char *unix_key[MAX_ARGS];
+ char *separator[MAX_ARGS];
+ char *pattern[MAX_ARGS];
+ char *outverb, *arg_symbol, *image_name;
+ char foreign_image[S_LENGTH];
+ int flags[MAX_ARGS], action_flags;
+ int nvargs, u_length, l_element, index;
+ char arg_string[S_LENGTH], arg_element[S_LENGTH];
+ static char value[S_LENGTH];
+ char *special_chars;
+ char default_special[] = "!@#^&()=+\'\"/?,";
+ $DESCRIPTOR(command_desc, command);
+ $DESCRIPTOR(qual_desc, "");
+ $DESCRIPTOR(value_desc, value);
+ int i, length, status, i_length, arg_count, q_length;
+ static char command_args[S_LENGTH];
+ $DESCRIPTOR(command_arg_desc, command_args);
+ extern VARG_CLD;
+ static char *newargv[MAX_ARGS];
+ int affirm_flag, negative_flag, keywords_flag, separator_flag;
+ int date_flag, append_flag, present, more_flag, multivalue, help_flag;
+ int vmsarg_mapping();
+
+ /* Get the VMS -> Unix mapping definitions from the routine generated
+ by the GEN_MAPPING utility.
+ */
+
+ vmsarg_mapping(&nvargs, vms_arg, unix_arg, unix_narg, vms_key, unix_key,
+ separator, flags, pattern, &outverb, &action_flags,
+ &arg_symbol, &image_name );
+
+ /* Get the original command line from the foreign command utility.
+ */
+
+ length = 0; /* RTL only writes word */
+ lib$get_foreign(&command_arg_desc, 0, &length);
+ command_args[length] = 0; /* add NULL terminator */
+
+ /* Check to see if any of the exising arguments start with a "-"
+ character. if so, assume he's already using Unix style arguments so
+ we don't have to do anything. Only do this if the Unix_Arg bit is
+ set in the action flags.
+ */
+
+ if ((action_flags & VARGACT_M_UNIXARG)) {
+ for (i = 1; i <= *argc - 1; i++)
+ if ((*argv) [i][0] == '-') {
+ /* He's using Unix style args. */
+ if ((action_flags & VARGACT_M_RETURN)) {
+ return 1; /* back out quietly */
+ } else {
+ status = varg_do_exit(action_flags, arg_symbol, command_args,
+ image_name, outverb);
+ sys$exit(status); /* exit with DCL stuff done */
+ }
+ }
+ }
+
+ /* Catenate verb and arguments into the command string for DCL
+ to parse.
+ */
+
+ strcpy(command, verb);
+ strcat(command, command_args);
+ command_desc.dsc$w_length = strlen(verb) + strlen(command_args);
+
+ /* Pass it to the DCL parser for its approval.
+ */
+
+ status = cli$dcl_parse(&command_desc, &VARG_CLD);
+ if ((status & 1) != 1) sys$exit (status);
+
+ /* Now that DCL is happy, we go through all the defined VMS qualifiers
+ and parameters to check if they are present or defaulted.
+ */
+
+ arg_count = 0; /* so far so good */
+
+ for (i = 1; i <= nvargs; i++) {
+
+ /* Set The various flags for this qualifier.
+ */
+
+ affirm_flag = (VARG_M_AFFIRM & flags[i]) != 0;
+ negative_flag = (VARG_M_NEGATIVE & flags[i]) != 0;
+ keywords_flag = (VARG_M_KEYWORDS & flags[i]) != 0;
+ separator_flag = (VARG_M_SEPARATOR & flags[i]) != 0;
+ date_flag = (VARG_M_DATE & flags[i]) != 0;
+ append_flag = (VARG_M_APPEND & flags[i]) != 0;
+ help_flag = (VARG_M_HELP & flags[i]) != 0;
+
+ /* Check if the qualifier or parameter is present
+ */
+
+ qual_desc.dsc$w_length = strlen(vms_arg[i]);
+ qual_desc.dsc$a_pointer = vms_arg[i];
+ present = cli$present(&qual_desc) & 1;
+
+ /* if the qualifier is present, and there is a positive translation,
+ then replace the VMS qualifier by its Unix equivalent. Note that
+ if the Unix equivalent starts with a '$', then it is a parameter and
+ we omit the qualifier name, only putting in the value.
+ */
+
+ qual_template[0] = 0; /* zero string initially */
+
+ if (present && affirm_flag) {
+ if (unix_arg[i][0] != '$') strcpy(qual_template, unix_arg[i]);
+ }
+
+ if (!(present & 1) && negative_flag) /* NOT present AND
+ negative_flag */
+ {
+ strcpy(qual_template, unix_narg[i]);
+ }
+
+ /* Get the first value (if any). We may have to catenate this with the
+ qualifier keyword, or build up multiple values in a single argv
+ element.
+ */
+
+ if (present) {
+ value_desc.dsc$w_length = QUAL_LENGTH;
+ status = cli$get_value(&qual_desc, &value_desc, &length);
+ if ((status & 1) != 1) length = 0;
+ value[length] = 0; /* NULL terminator */
+ more_flag = status == CLI$_COMMA;
+ } else {
+ length = 0;
+ }
+
+ /* if the /APPEND qualifier was used, then the qualifier and its value
+ are in the same argv element.
+ */
+
+ if (append_flag) {
+ strcpy(value_template, qual_template);
+ } else {
+ /* Allocate a fresh argv element and load the Unix keyword into it.
+ */
+ q_length = strlen(qual_template);
+
+ if (q_length != 0) {
+ Increment(arg_count);
+ newargv[arg_count] = malloc(q_length + 1);
+ if (newargv[arg_count] == NULL) sys$exit(LIB$_INSVIRMEM);
+ strcpy(newargv[arg_count], qual_template);
+ }
+ }
+
+ multivalue = more_flag;
+
+ /* Get all the various values and either append them with appropriate
+ separators to the current template, or load them in successive argv
+ elements.
+ */
+
+ while (affirm_flag && (length != 0)) {
+
+ /* if a keyword list is involved, get the corresponding field from the
+ Unix equivalent.
+ */
+
+ if (keywords_flag) {
+ index = varg_get_index(value, vms_key[i]);
+ varg_set_index(value, unix_key[i], index);
+ }
+
+ /* if the /DATE qualifier was present, we interpret the value as a
+ VMS date/time specification, and convert it to the equivalent Unix
+ type string.
+ */
+
+ if (date_flag) varg_convert_date(value, pattern[i]);
+
+ /* Add the current value to the template so far. Add a separator
+ character if we need one.
+ */
+
+ strcat(value_template, value);
+
+ if (separator_flag) {
+ if (more_flag)
+ strcat(value_template, separator[i]);
+ } else {
+
+ /* Each value should have its own argv element.
+ */
+
+ Increment(arg_count);
+ newargv[arg_count] = malloc(strlen(value_template) + 1);
+ if (newargv[arg_count] == NULL) sys$exit(LIB$_INSVIRMEM);
+ strcpy(newargv[arg_count], value_template);
+ value_template[0] = 0;
+ }
+
+ /* Get the next value from the DCL parser.
+ */
+
+ value_desc.dsc$w_length = QUAL_LENGTH; /* reset string */
+ status = cli$get_value(&qual_desc, &value_desc, &length);
+ if ((status & 1) != 1) length = 0;
+ value[length] = 0;
+ more_flag = status == CLI$_COMMA;
+ }
+
+ /* All the values are in for this qualifier - if there were being stacked
+ up then load them all into an argv element.
+ */
+
+ if (separator_flag & multivalue) {
+ Increment(arg_count);
+ newargv[arg_count] = malloc(strlen(value_template) + 1);
+ if (newargv[arg_count] == NULL) sys$exit(LIB$_INSVIRMEM);
+ strcpy(newargv[arg_count], value_template);
+ value_template[0] = 0;
+ }
+
+ /* Check to see if this is a HELP directive. if so, then the help
+ library name is stored in pattern[i] and the initial help string
+ in unix_arg[i]
+ */
+
+ if ((present &1) && help_flag) {
+ varg_do_help(pattern[i], unix_arg[i]);
+ }
+
+ /* And around for the next qualifier.
+ */
+
+ }
+
+ /* We've built the argument vector. Now lets find out what we're
+ supposed to do with it.
+ */
+
+ if ((action_flags & VARGACT_M_RETURN)) {
+
+ /* We should return the result to the caller. Set the corresponding argc
+ & argv variables in the caller to point at these. Make sure the new
+ argv contains the same [0] element as the old one (program name).
+ */
+
+ *argc = arg_count + 1;
+ newargv[0] = (*argv)[0];
+ *argv = newargv;
+ return 1;
+ }
+
+ /* We must convert the argv elements into an arg string.
+ */
+
+ arg_string[0] = 0;
+ special_chars = default_special;
+
+ for (i = 1; i <= arg_count; i++) {
+ varg_protect_string(newargv[i], arg_element, action_flags,
+ special_chars);
+ strcat(arg_string, arg_element);
+ if (i != arg_count) strcat(arg_string, " ");
+ }
+
+ status = varg_do_exit(action_flags, arg_symbol, arg_string, image_name, outverb);
+
+ /* if we got this far then exit to DCL.
+ */
+
+ sys$exit(status);
+}
+
+/*****************************************************************************|
+| Routine to scan the string 'string' to see if it matches any of |
+| the fields in 'keywords' (fields delimited by "|" characters). if |
+| so, return the field number (1=first). if it doesn't match, return |
+| 0. |
+\*****************************************************************************/
+
+static int varg_get_index(char *string, char *keywords)
+{
+ int i;
+ char temp[S_LENGTH];
+ char *field;
+
+ i = 0;
+ strcpy(temp, keywords); /* don't muck up caller's string. */
+
+ /* Get successive fields using STRTOK function and compare.
+ */
+
+ field = strtok(temp, "|");
+
+ while (field != NULL) {
+ i = i + 1;
+ if (strcmp(field, string) == 0) return i;
+ field = strtok(NULL, "|");
+ }
+
+ return 0;
+}
+
+/*****************************************************************************|
+| Routine to return the 'index' numbered field of 'keywords' in |
+| 'string'. Keywords are delimited by "|" characters. if 'index' |
+| is 0 do nothing. |
+\*****************************************************************************/
+
+static int varg_set_index(char *string, char *keywords, int index)
+{
+ int i;
+ char temp[S_LENGTH];
+ char *field;
+
+ if (index == 0) return 1;
+ strcpy(temp, keywords); /* don't screw up caller's string. */
+ field = strtok(temp, "|");
+
+ for (i = 1; i <= index - 1; i++) {
+ field = strtok(NULL, "|");
+ }
+
+ strcpy(string, field);
+ return 1;
+}
+
+/*****************************************************************************|
+| Invoke a help dialog with the user using the supplied help library |
+| and initial help command. |
+\*****************************************************************************/
+
+static int varg_do_help(char *help_library, char *help_command)
+{
+ $DESCRIPTOR(lib_desc, "");
+ $DESCRIPTOR(command_desc, "");
+ int status;
+
+ lib_desc.dsc$w_length = strlen(help_library);
+ lib_desc.dsc$a_pointer = help_library;
+ command_desc.dsc$w_length = strlen(help_command);
+ command_desc.dsc$a_pointer = help_command;
+
+ status = lbr$output_help(&lib$put_output, 0, &command_desc, &lib_desc, 0,
+ &lib$get_input);
+ return status;
+}
+
+/*****************************************************************************|
+| Routine to create a DCL symbol called 'symbol' with value 'value'. |
+\*****************************************************************************/
+
+static int varg_set_symbol(char *symbol, char *value)
+{
+ $DESCRIPTOR(symbol_desc, "");
+ $DESCRIPTOR(value_desc, "");
+ int status;
+
+ symbol_desc.dsc$w_length = strlen(symbol);
+ symbol_desc.dsc$a_pointer = symbol;
+ value_desc.dsc$w_length = strlen(value);
+ value_desc.dsc$a_pointer = value;
+ status = lib$set_symbol(&symbol_desc, &value_desc);
+ return status;
+}
+
+/*****************************************************************************|
+| Routine to exit the program and pass 'command' to DCL for execution. |
+\*****************************************************************************/
+
+static int varg_do_command(char *command)
+{
+ $DESCRIPTOR(command_desc, "");
+ int status;
+
+ command_desc.dsc$w_length = strlen(command);
+ command_desc.dsc$a_pointer = command;
+ status = lib$do_command(&command_desc);
+ return status;
+}
+
+/*****************************************************************************|
+| Routine to rebuild 'date_string' converting from a VMS standard |
+| date/time specifier to the Unix format specified in 'pattern'. |
+| |
+\*****************************************************************************/
+
+static int varg_convert_date(char *date_string, char *pattern)
+{
+ char date_text[30];
+ int bin_time[2], flags, length, status, i, from, to;
+ char year_4[5], year_2[4], month_name[4];
+ char month_2[2], month_1[2], date_2[3], date_1[2];
+ char hour_2[3], hour_1[2], minute[3], second[3];
+ char *months[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ $DESCRIPTOR(date_desc, "");
+ static int context;
+
+
+ /* First convert the date string into internal VMS format
+ */
+
+ date_desc.dsc$w_length = strlen(date_string);
+ date_desc.dsc$a_pointer = date_string;
+ context = 0;
+ flags = 0X7F;
+ status = lib$convert_date_string(&date_desc, &bin_time, &context, &flags);
+ if ((status & 1) != 1) return status;
+
+ /* Now convert it back to string form. This ensures that delta times
+ and keywords like TODAY get translated into a consistent format.
+ */
+
+ date_desc.dsc$w_length = 30;
+ /* date_desc.dsc$a_pointer = &date_text;*/
+ date_desc.dsc$a_pointer = date_text;
+ length = 0;
+ status = sys$asctim(&length, &date_desc, &bin_time, 0);
+ if ((status & 1) != 1) return status;
+
+ date_text[length] = 0; /* add NULL terminator */
+ date_string[0] = 0; /* start with empty string */
+
+ /* Break the date/time string up into the constituent fields. Fields
+ such as date have two instances - one with leading zero and one without
+ e.g. "05" and "5".
+ */
+
+ if (date_text[0] == ' ') {
+ date_2[0] = '0';
+ date_2[1] = date_text[1];
+ date_2[2] = 0;
+ date_1[0] = date_text[1];
+ date_1[1] = 0;
+ } else {
+ date_2[0] = date_text[0];
+ date_2[1] = date_text[1];
+ date_2[2] = 0;
+ strcpy(date_1, date_2);
+ }
+
+ /* Extract the month name and lowercase the 2nd and 3rd characters.
+ */
+
+ month_name[0] = date_text [3];
+ month_name[1] = tolower(date_text [4]);
+ month_name[2] = tolower(date_text [5]);
+ month_name[3] = 0;
+
+ /* Calculate the month number by looking up the month name in a
+ character array.
+ */
+
+ for (i = 1; i <= 12; i++) {
+ if (strcmp(month_name, months[i]) == 0) {
+ sprintf(month_2, "%02d", i);
+ sprintf(month_1, "%d", i);
+ break;
+ }
+ }
+
+ /* Extract the year field (both 4 digit and 2 digit forms).
+ */
+
+ year_2[0] = date_text[9];
+ year_2[1] = date_text[10];
+ year_2[3] = 0;
+
+ for (i = 0; i <= 3; i++) {
+ year_4[i] = date_text[i+7];
+ }
+
+ year_4[4] = 0;
+
+ /* Extract hour field.
+ */
+
+ hour_2[0] = date_text[12];
+ hour_2[1] = date_text[13];
+ hour_2[2] = 0;
+
+ if (date_text[12] == '0') {
+ hour_1[0] = date_text[13];
+ hour_1[1] = 0;
+ } else strcpy(hour_1, hour_2);
+
+ /* Lastly copy the minutes and seconds.
+ */
+
+ for (i = 0; i <= 1; i++) {
+ minute[i] = date_text[i+15];
+ second[i] = date_text[i+18];
+ }
+
+ minute[2] = 0;
+ second[2] = 0;
+
+ /* Now start building up the output string by copying characters from
+ 'pattern' to 'date_string' substituting the various fields when we
+ encounter an escape pair.
+ */
+
+ from = 0;
+ to = 0;
+
+ while (pattern[from] != 0) {
+ if (pattern[from] == '$') {
+ switch (pattern[from+1]) {
+ case 'Y':
+ strcat(date_string, year_4);
+ to = to + 4;
+ break;
+
+ case 'y':
+ strcat(date_string, year_2);
+ to = to + 2;
+ break;
+
+ case 'M':
+ strcat(date_string, month_name);
+ to = to + 3;
+ break;
+
+ case 'N':
+ strcat(date_string, month_2);
+ to = to + 2;
+ break;
+
+ case 'n':
+ strcat(date_string, month_1);
+ to = to + strlen(month_1);
+ break;
+
+ case 'D':
+ strcat(date_string, date_2);
+ to = to + 2;
+ break;
+
+ case 'd':
+ strcat(date_string, date_1);
+ to = to + strlen(date_1);
+ break;
+
+ case 'H':
+ strcat(date_string, hour_2);
+ to = to + 2;
+ break;
+
+ case 'h':
+ strcat(date_string, hour_1);
+ to = to + strlen(hour_1);
+ break;
+
+ case 'm':
+ strcat(date_string, minute);
+ to = to + 2;
+ break;
+
+ case 'S':
+ case 's':
+ strcat(date_string, second);
+ to = to + 2;
+ break;
+
+ case '$':
+ date_string[to] = '$';
+ date_string[to+1] = 0;
+ to = to + 1;
+ break;
+ }
+
+ from = from + 2;
+ } else {
+ date_string[to] = pattern[from];
+ date_string[to+1] = 0;
+ from = from + 1;
+ to = to + 1;
+ }
+ }
+}
+
+/*****************************************************************************|
+| Routine to decide if a string requires to be enclosed in quotation |
+| marks, and if so, put them in. The various bits in 'flags' tells |
+| us what characters require protecting. 'Quote' contains the actual |
+| quote character (which may require doubling or escaping with "\" |
+| if it occurs in the string). 'Special' contains a list of characters |
+| which require protecting. |
+\*****************************************************************************/
+
+static int varg_protect_string(char *instring, char *outstring,
+ int flags, char *special)
+{
+ int protection_needed, quote_present;
+ int length, i, j, special_length;
+ char ch, quote = '\"';
+ char quote_string[1];
+
+ quote_string[0] = quote;
+ quote_string[1] = 0;
+ length = strlen(instring);
+ special_length = strlen(special);
+ protection_needed = 0;
+ quote_present = 0;
+
+ /* Check to see if we actually need the quotes.
+ */
+
+ if ((flags & VARGACT_M_PROTMASK) != 0) {
+ for (i = 0; i <= length-1; i++) {
+ ch = instring[i];
+
+ if ((flags & VARGACT_M_UPPER) && isupper (ch)) {
+ protection_needed = 1;
+ continue;
+ }
+
+ if ((flags & VARGACT_M_LOWER) && islower (ch)) {
+ protection_needed = 1;
+ continue;
+ }
+
+ if ((flags & VARGACT_M_SPECIAL)) {
+ for (j = 0; j <= special_length-1; j++) {
+ if (ch == special[j]) {
+ protection_needed = 1;
+ continue;
+ }
+ }
+
+ if (protection_needed) continue;
+ }
+
+ if (((flags & VARGACT_M_ESCAPE) ||
+ (flags & VARGACT_M_DOUBLE)) &&
+ ch == quote) {
+ protection_needed = 1;
+ quote_present = 1;
+ continue;
+ }
+ }
+ }
+
+ /* if protection is not needed, just copy the input string to the
+ output string.
+ */
+
+ if (!protection_needed) {
+ strcpy(outstring, instring);
+ return 1;
+ }
+
+ /* Protection is needed. if no quotes are present, then we simply
+ enclose the string in quote marks, otherwise we have to step through
+ the string.
+ */
+
+ if (quote_present) {
+ outstring[0] = quote;
+ j = 1;
+
+ for (i = 0; i <= length-1; i++) {
+ ch = instring[i];
+
+ if (ch == quote) {
+ if ((flags & VARGACT_M_ESCAPE)) {
+ outstring[j] = '\\';
+ j = j + 1;
+ }
+
+ if ((flags & VARGACT_M_DOUBLE)) {
+ outstring[j] = quote;
+ j = j + 1;
+ }
+ }
+
+ outstring[j] = ch;
+ j = j + 1;
+ }
+
+ outstring[j] = 0;
+ } else { /* just append the output string + quote */
+ outstring[0] = 0;
+ strcat(outstring, quote_string);
+ strcat(outstring, instring);
+ strcat(outstring, quote_string);
+ }
+
+ return 1;
+}
+
+/*****************************************************************************|
+| Routine to define any DCL symbols that are required, and if the |
+| appropriate flag bit is set, exit to DCL using a LIB$DO_COMMAND call |
+| which will activate the real application image. |
+\*****************************************************************************/
+
+static int varg_do_exit(int flags, char *arg_symbol,
+ char *arg_string, char *image_name, char *verb)
+{
+ char *foreign_image;
+ char *command;
+ int status;
+
+ /* Should we set up a symbol containing this arg string ?
+ */
+
+ if ((flags & VARGACT_M_SYMBOL))
+ varg_set_symbol(arg_symbol, arg_string);
+
+ /* Should we define an image name in the verb symbol ?
+ */
+
+ if ((flags & VARGACT_M_IMAGE)) {
+ foreign_image = malloc(strlen(image_name) + 2);
+ if (foreign_image == NULL) return LIB$_INSVIRMEM;
+ strcpy(foreign_image, "$");
+ strcat(foreign_image, image_name);
+ varg_set_symbol(verb, foreign_image);
+ }
+
+ /* Should we exit the program and and activate another image or
+ command procedure ?
+ */
+
+ if ((flags & VARGACT_M_COMMAND)) {
+ command = malloc(strlen(verb) + strlen(arg_string) + 2);
+ if (command == NULL) return LIB$_INSVIRMEM;
+ strcpy(command, verb);
+ strcat(command, " ");
+ strcat(command, arg_string);
+ status = varg_do_command(command);
+ return status;
+ }
+
+ return 1;
+}