summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormwesdorp <mwesdorp>2013-04-25 14:09:47 +0000
committermwesdorp <mwesdorp>2013-04-25 14:09:47 +0000
commited5fdf742a5039576bc581a335fa9494a760000c (patch)
tree7f56ad436e424aebc16167a65e81e84a8096c798 /src
parent4b49cc67ac8d7654b88ded70baa0109d8d162cde (diff)
sqsh-2.2.0 new features and bugfixes
Diffstat (limited to 'src')
-rw-r--r--src/cmd_connect.c325
-rw-r--r--src/cmd_input.c242
-rw-r--r--src/cmd_reconnect.c14
-rw-r--r--src/sqsh_debug.h1
-rw-r--r--src/sqsh_env.c97
-rw-r--r--src/sqsh_env.h3
-rw-r--r--src/sqsh_expand.c43
-rw-r--r--src/sqsh_history.c9
-rw-r--r--src/sqsh_init.c13
-rw-r--r--src/sqsh_main.c48
-rw-r--r--src/var.h10
-rw-r--r--src/var_debug.c3
12 files changed, 510 insertions, 298 deletions
diff --git a/src/cmd_connect.c b/src/cmd_connect.c
index 2820e7d..8cc7888 100644
--- a/src/cmd_connect.c
+++ b/src/cmd_connect.c
@@ -24,8 +24,10 @@
*/
#include <stdio.h>
#include <ctype.h>
+#include <setjmp.h>
#include <ctpublic.h>
#include "sqsh_config.h"
+#include "sqsh_debug.h"
#include "sqsh_error.h"
#include "sqsh_global.h"
#include "sqsh_getopt.h"
@@ -40,7 +42,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: cmd_connect.c,v 1.28 2013/04/18 11:54:43 mwesdorp Exp $";
+static char RCS_Id[] = "$Id: cmd_connect.c,v 1.29 2013/04/25 14:09:47 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -109,7 +111,9 @@ static CS_RETCODE ShowNetAuthCredExp _ANSI_ARGS((CS_CONNECTION *,
;
/* sqsh-2.2.0 - Signal handler to respond to SIGINT during cmd_connect */
-static void connect_signal ( int, void *);
+static JMP_BUF sg_jmp_buf;
+static int sg_interrupted;
+static void connect_run_sigint ( int, void *);
/*
* cmd_connect:
@@ -186,6 +190,9 @@ int cmd_connect( argc, argv )
CS_INT SybTimeOut;
CS_BOOL NetAuthRequired;
varbuf_t *exp_buf = NULL;
+ /* sqsh-2.2.0 - New variables */
+ char *debug_tds_logdata;
+ char *debug_tds_capture;
#if defined(CTLIB_SIGPOLL_BUG) && defined(F_SETOWN)
int ctlib_fd;
@@ -257,14 +264,15 @@ int cmd_connect( argc, argv )
}
break ;
case 'N' : /* sqsh-2.1.5 */
- if (env_put( g_env, "appname", sqsh_optarg, ENV_F_TRAN ) == False)
- {
+ if (env_put( g_env, "appname", sqsh_optarg, ENV_F_TRAN ) == False)
+ {
fprintf( stderr, "\\connect: -N: %s\n", sqsh_get_errstr() );
- have_error = True;
- }
+ have_error = True;
+ }
break;
case 'P' :
- if (g_password_set == True && g_password != NULL) strcpy( orig_password, g_password );
+ if (g_password_set == True && g_password != NULL)
+ strcpy( orig_password, g_password );
password_changed = True;
if (env_put( g_env, "password", sqsh_optarg, ENV_F_TRAN ) == False)
@@ -405,12 +413,15 @@ int cmd_connect( argc, argv )
sqsh_exit( 255 );
}
- /*
- * sqsh-2.2.0 - Install a signal handler to catch SIGINT during cmd_connect.
- * The current signals are saved first and restored at the end of cmd_connect.
- */
+ /*
+ * sqsh-2.2.0 - Install a signal handler to catch SIGINT during cmd_connect.
+ * The current signals are saved first and restored at the end of cmd_connect.
+ */
sig_save();
- sig_install( SIGINT, connect_signal, (void *) NULL, 0);
+ sig_install( SIGINT, connect_run_sigint, (void *) NULL, 0);
+ sg_interrupted = False;
+ if (SETJMP( sg_jmp_buf ) != 0)
+ goto connect_fail;
/*
* If the $session variable is set and the path that it contains
@@ -617,19 +628,19 @@ int cmd_connect( argc, argv )
goto connect_fail;
if (ct_callback( g_context, /* Context */
- (CS_CONNECTION*)NULL, /* Connection */
- CS_SET, /* Action */
- CS_CLIENTMSG_CB, /* Type */
- (CS_VOID*)syb_client_cb /* Callback Pointer */
- ) != CS_SUCCEED)
+ (CS_CONNECTION*)NULL, /* Connection */
+ CS_SET, /* Action */
+ CS_CLIENTMSG_CB, /* Type */
+ (CS_VOID*)syb_client_cb /* Callback Pointer */
+ ) != CS_SUCCEED)
goto connect_fail;
if (ct_callback( g_context, /* Context */
- (CS_CONNECTION*)NULL, /* Connection */
- CS_SET, /* Action */
- CS_SERVERMSG_CB, /* Type */
- (CS_VOID*)syb_server_cb /* Callback Pointer */
- ) != CS_SUCCEED)
+ (CS_CONNECTION*)NULL, /* Connection */
+ CS_SET, /* Action */
+ CS_SERVERMSG_CB, /* Type */
+ (CS_VOID*)syb_server_cb /* Callback Pointer */
+ ) != CS_SUCCEED)
goto connect_fail;
/*
@@ -639,12 +650,12 @@ int cmd_connect( argc, argv )
#if !defined(_WINDOZE_)
netio_type = CS_SYNC_IO;
if (ct_config( g_context, /* Context */
- CS_SET, /* Action */
- CS_NETIO, /* Property */
- (CS_VOID*)&netio_type, /* Buffer */
- CS_UNUSED, /* Buffer Length */
- NULL /* Output Length */
- ) != CS_SUCCEED)
+ CS_SET, /* Action */
+ CS_NETIO, /* Property */
+ (CS_VOID*)&netio_type, /* Buffer */
+ CS_UNUSED, /* Buffer Length */
+ NULL /* Output Length */
+ ) != CS_SUCCEED)
goto connect_fail;
#endif
@@ -705,7 +716,7 @@ int cmd_connect( argc, argv )
(CS_VOID*)cp, /* Buffer */
CS_NULLTERM, /* Buffer Length */
NULL /* Output Length */
- ) != CS_SUCCEED)
+ ) != CS_SUCCEED)
goto connect_fail;
}
else
@@ -826,12 +837,12 @@ int cmd_connect( argc, argv )
if (hostname != NULL && *hostname != '\0')
{
if (ct_con_props( g_connection, /* Connection */
- CS_SET, /* Action */
- CS_HOSTNAME, /* Property */
- (CS_VOID*)hostname, /* Buffer */
- CS_NULLTERM, /* Buffer Length */
- (CS_INT*)NULL /* Output Length */
- ) != CS_SUCCEED)
+ CS_SET, /* Action */
+ CS_HOSTNAME, /* Property */
+ (CS_VOID*)hostname, /* Buffer */
+ CS_NULLTERM, /* Buffer Length */
+ (CS_INT*)NULL /* Output Length */
+ ) != CS_SUCCEED)
goto connect_fail;
}
@@ -840,12 +851,12 @@ int cmd_connect( argc, argv )
{
i = atoi(packet_size);
if (ct_con_props( g_connection, /* Connection */
- CS_SET, /* Action */
- CS_PACKETSIZE, /* Property */
- (CS_VOID*)&i, /* Buffer */
- CS_UNUSED, /* Buffer Length */
- (CS_INT*)NULL /* Output Length */
- ) != CS_SUCCEED)
+ CS_SET, /* Action */
+ CS_PACKETSIZE, /* Property */
+ (CS_VOID*)&i, /* Buffer */
+ CS_UNUSED, /* Buffer Length */
+ (CS_INT*)NULL /* Output Length */
+ ) != CS_SUCCEED)
goto connect_fail;
}
@@ -854,12 +865,12 @@ int cmd_connect( argc, argv )
{
i = CS_TRUE;
if (ct_con_props( g_connection, /* Connection */
- CS_SET, /* Action */
- CS_SEC_ENCRYPTION, /* Property */
- (CS_VOID*)&i, /* Buffer */
- CS_UNUSED, /* Buffer Length */
- (CS_INT*)NULL /* Output Length */
- ) != CS_SUCCEED)
+ CS_SET, /* Action */
+ CS_SEC_ENCRYPTION, /* Property */
+ (CS_VOID*)&i, /* Buffer */
+ CS_UNUSED, /* Buffer Length */
+ (CS_INT*)NULL /* Output Length */
+ ) != CS_SUCCEED)
goto connect_fail;
#if defined (CS_SEC_EXTENDED_ENCRYPTION)
@@ -868,13 +879,13 @@ int cmd_connect( argc, argv )
* connect to ASE servers with 'net password encryption reqd'
* configured to 2 (RSA).
*/
- if (ct_con_props( g_connection, /* Connection */
- CS_SET, /* Action */
- CS_SEC_EXTENDED_ENCRYPTION, /* Property */
- (CS_VOID*)&i, /* Buffer */
- CS_UNUSED, /* Buffer Length */
- (CS_INT*)NULL /* Output Length */
- ) != CS_SUCCEED)
+ if (ct_con_props( g_connection, /* Connection */
+ CS_SET, /* Action */
+ CS_SEC_EXTENDED_ENCRYPTION, /* Property */
+ (CS_VOID*)&i, /* Buffer */
+ CS_UNUSED, /* Buffer Length */
+ (CS_INT*)NULL /* Output Length */
+ ) != CS_SUCCEED)
goto connect_fail;
#endif
@@ -891,50 +902,50 @@ int cmd_connect( argc, argv )
/*-- Initialize --*/
if (cs_locale( g_context, /* Context */
CS_SET, /* Action */
- locale, /* Locale Structure */
+ locale, /* Locale Structure */
CS_LC_ALL, /* Property */
- (CS_CHAR*)NULL, /* Buffer */
+ (CS_CHAR*)NULL, /* Buffer */
CS_UNUSED, /* Buffer Length */
(CS_INT*)NULL /* Output Length */
- ) != CS_SUCCEED)
+ ) != CS_SUCCEED)
goto connect_fail;
/*-- Language --*/
if( language != NULL && *language != '\0' )
{
- if (cs_locale( g_context, /* Context */
- CS_SET, /* Action */
- locale, /* Locale Structure */
- CS_SYB_LANG, /* Property */
- (CS_CHAR*)language, /* Buffer */
- CS_NULLTERM, /* Buffer Length */
- (CS_INT*)NULL /* Output Length */
- ) != CS_SUCCEED)
+ if (cs_locale( g_context, /* Context */
+ CS_SET, /* Action */
+ locale, /* Locale Structure */
+ CS_SYB_LANG, /* Property */
+ (CS_CHAR*)language, /* Buffer */
+ CS_NULLTERM, /* Buffer Length */
+ (CS_INT*)NULL /* Output Length */
+ ) != CS_SUCCEED)
goto connect_fail;
}
/*-- Character Set --*/
- if (charset != NULL && *charset != '\0') /* sqsh-2.1.6 sanity check */
+ if (charset != NULL && *charset != '\0') /* sqsh-2.1.6 sanity check */
{
- if (cs_locale( g_context, /* Context */
- CS_SET, /* Action */
- locale, /* Locale Structure */
- CS_SYB_CHARSET, /* Property */
- (CS_CHAR*)charset, /* Buffer */
- CS_NULLTERM, /* Buffer Length */
- (CS_INT*)NULL /* Output Length */
- ) != CS_SUCCEED)
+ if (cs_locale( g_context, /* Context */
+ CS_SET, /* Action */
+ locale, /* Locale Structure */
+ CS_SYB_CHARSET, /* Property */
+ (CS_CHAR*)charset, /* Buffer */
+ CS_NULLTERM, /* Buffer Length */
+ (CS_INT*)NULL /* Output Length */
+ ) != CS_SUCCEED)
goto connect_fail;
}
/*-- Locale Property --*/
- if (ct_con_props( g_connection, /* Connection */
- CS_SET, /* Action */
- CS_LOC_PROP, /* Property */
- (CS_VOID*)locale, /* Buffer */
- CS_UNUSED, /* Buffer Length */
- (CS_INT*)NULL /* Output Length */
- ) != CS_SUCCEED)
+ if (ct_con_props( g_connection, /* Connection */
+ CS_SET, /* Action */
+ CS_LOC_PROP, /* Property */
+ (CS_VOID*)locale, /* Buffer */
+ CS_UNUSED, /* Buffer Length */
+ (CS_INT*)NULL /* Output Length */
+ ) != CS_SUCCEED)
goto connect_fail;
/* Handle case where server is defined as host:port */
@@ -956,6 +967,97 @@ int cmd_connect( argc, argv )
}
#endif
+#if defined (DEBUG) && defined (CS_SET_DBG_FILE) && defined (CS_SET_PROTOCOL_FILE)
+ /*
+ * sqsh-2.2.0 - Setup TDS debugging using a logdata file and or a capture file
+ * for tracing TDS packets.
+ */
+ if ( sqsh_debug_show (DEBUG_TDS) )
+ {
+ /*
+ * Note, this requires the CT-lib development libraries to be linked/loaded with sqsh.
+ */
+ env_get (g_env, "debug_tds_logdata", &debug_tds_logdata);
+ if (debug_tds_logdata != NULL && *debug_tds_logdata != '\0')
+ {
+ if (sqsh_expand( debug_tds_logdata, exp_buf, 0 ) != False)
+ {
+ cp = varbuf_getstr( exp_buf );
+ if (ct_debug ( g_context, /* Context */
+ NULL, /* Connection */
+ CS_SET_DBG_FILE, /* Action */
+ CS_UNUSED, /* Flag */
+ cp, /* Buffer value */
+ strlen(cp) /* Buffer length */
+ ) != CS_SUCCEED)
+ fprintf (stderr, "\\connect: ct_debug - Unable to set CS_SET_DBG_FILE to %s\n", cp);
+ else
+ {
+ fprintf (stdout, "\\connect: ct_debug - Successfully set CS_SET_DBG_FILE to %s\n", cp);
+ if (ct_debug ( g_context, /* Context */
+ g_connection, /* Connection */
+ CS_SET_FLAG, /* Action */
+ CS_DBG_ALL, /* Flag */
+ NULL, /* Buffer value */
+ CS_UNUSED /* Buffer length */
+ ) != CS_SUCCEED)
+ fprintf (stderr, "\\connect: ct_debug - Unable to set flag CS_DBG_ALL\n");
+ else
+ fprintf (stdout, "\\connect: ct_debug - Flag CS_DBG_ALL successfully set\n");
+ }
+ }
+ else
+ {
+ fprintf( stderr, "sqsh: Error expanding $debug_tds_logdata: %s\n", sqsh_get_errstr() );
+ }
+ }
+
+ /*
+ * For protocol tracing regular CT-lib libraries will do.
+ * The created trace file can be decoded using Ribo.
+ */
+ env_get (g_env, "debug_tds_capture", &debug_tds_capture);
+ if (debug_tds_capture != NULL && *debug_tds_capture != '\0')
+ {
+ if (sqsh_expand( debug_tds_capture, exp_buf, 0 ) != False)
+ {
+ cp = varbuf_getstr( exp_buf );
+ if (ct_debug ( NULL, /* Context */
+ g_connection, /* Connection */
+ CS_SET_PROTOCOL_FILE, /* Action */
+ CS_UNUSED, /* Flag */
+ cp, /* Buffer value */
+ strlen(cp) /* Buffer length */
+ ) != CS_SUCCEED)
+ fprintf (stderr, "\\connect: ct_debug - Unable to set CS_SET_PROTOCOL_FILE to %s\n", cp);
+ else
+ {
+ fprintf (stdout, "\\connect: ct_debug - Successfully set CS_SET_PROTOCOL_FILE to %s\n", cp);
+ if (ct_debug ( NULL, /* Context */
+ g_connection, /* Connection */
+ CS_SET_FLAG, /* Action */
+ CS_DBG_PROTOCOL, /* Flag */
+ NULL, /* Buffer value */
+ CS_UNUSED /* Buffer length */
+ ) != CS_SUCCEED)
+ fprintf (stderr, "\\connect: ct_debug - Unable to set falg CS_DBG_PROTOCOL\n");
+ else
+ fprintf (stdout, "\\connect: ct_debug - Flag CS_DBG_PROTOCOL successfully set\n");
+ }
+ }
+ else
+ {
+ fprintf( stderr, "sqsh: Error expanding $debug_tds_capture: %s\n", sqsh_get_errstr() );
+ }
+ }
+ }
+#elif defined (DEBUG)
+ if ( sqsh_debug_show (DEBUG_TDS) )
+ {
+ fprintf( stderr, "\\connect: ct_debug - TDS debugging is not supported in this version of CT-lib\n" );
+ }
+#endif
+
/*
* We sit in a loop and attempt to connect while we are getting
* "Login failed" messages.
@@ -1026,12 +1128,12 @@ int cmd_connect( argc, argv )
* that CT-Lib uses a file descriptor as its communication mechanism.
*/
if (ct_con_props( g_connection, /* Connection */
- CS_GET, /* Action */
- CS_ENDPOINT, /* Property */
- (CS_VOID*)&ctlib_fd, /* Buffer */
- CS_UNUSED, /* Buffer Length */
- (CS_INT*)NULL /* Output Length */
- ) != CS_SUCCEED)
+ CS_GET, /* Action */
+ CS_ENDPOINT, /* Property */
+ (CS_VOID*)&ctlib_fd, /* Buffer */
+ CS_UNUSED, /* Buffer Length */
+ (CS_INT*)NULL /* Output Length */
+ ) != CS_SUCCEED)
{
fprintf( stderr, "\\connect: WARNING: Unable to fetch CT-Lib file\n" );
fprintf( stderr, "\\connect: descriptor to work around SIGPOLL bug.\n" );
@@ -1071,7 +1173,8 @@ int cmd_connect( argc, argv )
CS_TDS_VERSION, /* Property */
(CS_VOID*)&version, /* Buffer */
CS_UNUSED, /* Buffer Length */
- (CS_INT*)NULL ) == CS_SUCCEED)
+ (CS_INT*)NULL
+ ) == CS_SUCCEED)
{
switch (version) {
case CS_TDS_40:
@@ -1196,16 +1299,16 @@ connect_fail:
}
/*-- Clean up the connection if established --*/
- if (g_connection != NULL)
+ if (g_connection != NULL && sg_interrupted == False)
{
-
/*-- Find out if the we are connected or not --*/
if (ct_con_props( g_connection, /* Connection */
CS_GET, /* Action */
CS_CON_STATUS, /* Property */
(CS_VOID*)&con_status, /* Buffer */
CS_UNUSED, /* Buffer Length */
- (CS_INT*)NULL ) != CS_SUCCEED)
+ (CS_INT*)NULL
+ ) != CS_SUCCEED)
{
DBG(sqsh_debug(DEBUG_ERROR, "connect: Unable to get con status.\n");)
con_status = CS_CONSTAT_CONNECTED;
@@ -1228,20 +1331,22 @@ connect_fail:
ct_con_drop( g_connection );
}
- if (locale != NULL)
+ if (sg_interrupted == False)
{
- DBG(sqsh_debug(DEBUG_ERROR, "connect: Dropping locale\n");)
- cs_loc_drop( g_context, locale );
- }
+ if (locale != NULL)
+ {
+ DBG(sqsh_debug(DEBUG_ERROR, "connect: Dropping locale\n");)
+ cs_loc_drop( g_context, locale );
+ }
- if (g_context != NULL)
- {
- DBG(sqsh_debug(DEBUG_ERROR, "connect: Dropping context\n");)
- if (ct_exit( g_context, CS_UNUSED ) != CS_SUCCEED)
- ct_exit( g_context, CS_FORCE_EXIT );
- cs_ctx_drop( g_context );
+ if (g_context != NULL)
+ {
+ DBG(sqsh_debug(DEBUG_ERROR, "connect: Dropping context\n");)
+ if (ct_exit( g_context, CS_UNUSED ) != CS_SUCCEED)
+ ct_exit( g_context, CS_FORCE_EXIT );
+ cs_ctx_drop( g_context );
+ }
}
-
g_connection = NULL;
g_context = NULL;
return_code = CMD_FAIL;
@@ -1594,13 +1699,15 @@ static CS_RETCODE syb_client_cb ( ctx, con, msg )
if (sg_login == False)
{
env_get( g_env, "DSQUERY", &server ) ;
- /*
+#if defined(CS_TDS_50)
if (CS_SEVERITY(msg->msgnumber) >= CS_SV_COMM_FAIL ||
ctx == NULL || con == NULL)
- */
+#else
+ /* Then we use freetds which uses enum instead of defines */
if ((CS_SEVERITY(msg->msgnumber) >= CS_SV_COMM_FAIL &&
CS_SEVERITY(msg->msgnumber) <= CS_SV_FATAL) ||
ctx == NULL || con == NULL)
+#endif
{
fprintf (stderr, "%s: Aborting on severity %d\n", server, (int) CS_SEVERITY(msg->msgnumber) );
sqsh_exit(254);
@@ -1939,14 +2046,16 @@ ShowNetAuthCredExp (conn, cmdname)
#endif
}
+
/*
- * connect_signal():
+ * connect_run_sigint():
*
* This function is called whenever a SIGINT signal is received while processing cmd_connect.
- * Its only real job is to abort the connection attempt and leave sqsh.
+ * Its only real job is to return to the point where the SETJMP function was executed.
*/
-static void connect_signal (int sig, void *user_data )
+static void connect_run_sigint (int sig, void *user_data )
{
- sqsh_exit (254);
+ sg_interrupted = True;
+ LONGJMP (sg_jmp_buf, 1);
}
diff --git a/src/cmd_input.c b/src/cmd_input.c
index 7685bbf..2a9172c 100644
--- a/src/cmd_input.c
+++ b/src/cmd_input.c
@@ -52,7 +52,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: cmd_input.c,v 1.7 2012/03/29 16:25:46 mwesdorp Exp $";
+static char RCS_Id[] = "$Id: cmd_input.c,v 1.8 2013/04/25 14:09:47 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -74,8 +74,8 @@ static int DynKeywordLoad _ANSI_ARGS(( void )); /* sqsh-2.1.8 - Feature d
/*
- * sg_jmp_buf: The following buffer is used to contain the location
- * to which this module will return upon receipt of a
+ * sg_jmp_buf: The following buffer is used to contain the location
+ * to which this module will return upon receipt of a
* SIGINT. It is only used while waiting on input from the
* user.
*/
@@ -122,7 +122,6 @@ int cmd_input()
int exit_status ; /* Exit status of sub-command */
JMP_BUF old_jmp_buf ; /* Store the previous jmp_buf */
int is_cmd ; /* True if the current line is cmd */
- int no_hist ; /* True if hist should not be updt. */
job_id_t job_id ; /* Id of job launched or completed */
char *defer_file ; /* Name of file holding user output */
struct stat stat_buf ; /* Check for defer file's existence */
@@ -134,6 +133,11 @@ int cmd_input()
int cur_lineno;
int interactive;
+ /*
+ * sqsh-2.2.0 - Extension on semicolon_hack
+ */
+ char *semicolon_hack2 ; /* Value of $semicolon_hack2 */
+ char *str_remainder = NULL; /* Remainder of input string after ; */
/*
* Variables that need to be restored before turning to the
@@ -245,7 +249,7 @@ int cmd_input()
*/
env_get( g_env, "keyword_dynamic", &keyword_dynamic );
env_get( g_internal_env, "keyword_refresh", &keyword_refresh );
- if (interactive &&
+ if (interactive &&
keyword_refresh != NULL && *keyword_refresh != '0' &&
keyword_dynamic != NULL && *keyword_dynamic != '0')
{
@@ -254,37 +258,50 @@ int cmd_input()
}
#endif
- no_hist = False; /* Save history for this buffer */
-
/*
- * Clear out the buffer that will be used to place input read
- * from the user.
+ * sqsh-2.2.0 - Semicolon_hack2. If str_remainder is not NULL
+ * then we have a leftover from the previous loop were a ;
+ * has been processed. So this part of the input should be
+ * processed next. The else branch executes the pre-sqsh-2.2.0
+ * code path.
*/
- varbuf_clear( read_buf );
+ if (str_remainder != NULL)
+ {
+ str = str_remainder;
+ str_remainder = NULL;
+ }
+ else
+ {
+ /*
+ * Clear out the buffer that will be used to place input read
+ * from the user.
+ */
+ varbuf_clear( read_buf );
- /*
- * If an input_file was supplied, or no input string was supplied
- * then call input_read. By default, if input_read gets a NULL
- * input_file, stdin is used.
- */
- ret = input_read( read_buf, interactive );
+ /*
+ * If an input_file was supplied, or no input string was supplied
+ * then call input_read. By default, if input_read gets a NULL
+ * input_file, stdin is used.
+ */
+ ret = input_read( read_buf, interactive );
- if (ret <= 0)
- {
- if (ret == 0)
+ if (ret <= 0)
{
- goto loop_leave;
+ if (ret == 0)
+ {
+ goto loop_leave;
+ }
+ fprintf( stderr, "input: %s\n", sqsh_get_errstr() );
+ goto loop_abort;
}
- fprintf( stderr, "input: %s\n", sqsh_get_errstr() );
- goto loop_abort;
+
+ /*
+ * Pull contents of read_buf out.
+ */
+ str = varbuf_getstr( read_buf );
}
/*
- * Pull contents of read_buf out.
- */
- str = varbuf_getstr( read_buf );
-
- /*
* The first thing we need to determine is if the current
* line contains a sqsh command. This information will be
* used in several places.
@@ -301,7 +318,7 @@ int cmd_input()
* then we pretend it is a buffer recall. So, we turn
* it into a logical call to \buf-append.
*/
- if (is_cmd == False && interactive && *str == '!' &&
+ if (is_cmd == False && interactive && *str == '!' &&
!isspace((int)*(str+1)))
{
@@ -341,50 +358,93 @@ int cmd_input()
* input_strchr(), returns the first ';' in str that will not
* be contained in double quotes when str is appended to
* g_sqlbuf.
+ * sqsh-2.2.0 - If semicolon_hack2 is set, it doesn't matter
+ * if the input line is a command or not. We still want to
+ * process possible semicolons. So that makes the if statement
+ * a bit more complex.
*/
- env_get( g_env, "semicolon_hack", &semicolon_hack );
- if (semicolon_hack != NULL && *semicolon_hack == '1' && !is_cmd &&
- strchr( str, ';') != NULL &&
- (ch = input_strchr( g_sqlbuf, str, ';' )) != NULL)
+ env_get( g_env, "semicolon_hack", &semicolon_hack );
+ env_get( g_env, "semicolon_hack2", &semicolon_hack2 );
+ if ( (strchr( str, ';') != NULL && (ch = input_strchr( g_sqlbuf, str, ';' )) != NULL) &&
+ ((semicolon_hack != NULL && *semicolon_hack == '1' && !is_cmd) ||
+ (semicolon_hack2 != NULL && *semicolon_hack2 == '1'))
+ )
{
/*
- * Copy everything up to the ';' into the current work buffer.
- */
- if (ch - str != 0)
- {
- varbuf_strncat( g_sqlbuf, str, ch - str );
- varbuf_charcat( g_sqlbuf, '\n' );
-
- /*
- * We now have an extra line.
- */
- env_set( g_env, "lineno", "+1" );
- }
-
- /*
* Look up the name of the command that the user wishes
* to use when a semicolon is encountered.
*/
env_get( g_env, "semicolon_cmd", &semicolon_cmd );
-
if (semicolon_cmd == NULL || *semicolon_cmd == '\0')
- {
varbuf_strcpy( sg_buf, "\\go " );
- }
else
- {
varbuf_strcpy( sg_buf, semicolon_cmd );
- varbuf_charcat( sg_buf, ' ' );
- }
/*
- * Now, stick the semicolon command in the front of everything
- * following the semicolon. and turn that into the command
- * line.
+ * sqsh-2.2.0 - The hack is going to be even worse and worse.
+ * If semicolon_hack2 is set, then we treat a ; as a
+ * command or batch separator, execute the portion before
+ * the ; as a SQL buffer, or as a sqsh command. The remainder
+ * of the string after the ; is saved for later use.
*/
- varbuf_strcat( sg_buf, ch + 1 );
+ if (semicolon_hack2 != NULL && *semicolon_hack2 == '1')
+ {
+ /*
+ * replace the ; with end of line
+ */
+ *ch = '\0';
+ /*
+ * save the remainder of the string in str_remainder
+ * or set it to NULL if there is really nothing left
+ */
+ str_remainder = ch + 1;
+ if (*str_remainder == '\n' || *str_remainder == '\0')
+ str_remainder = NULL;
+ /*
+ * Check if we have to deal with a sqsh command or
+ * a SQL statement, at least the last part of it.
+ */
+ if (!is_cmd && jobset_is_cmd( g_jobset, str ) == False)
+ {
+ if (ch - str != 0)
+ {
+ varbuf_strncat( g_sqlbuf, str, ch - str );
+ varbuf_charcat( g_sqlbuf, '\n' );
+ env_set( g_env, "lineno", "+1" );
+ }
+ str = varbuf_getstr( sg_buf );
+ }
+ /* else the current str is a sqsh command */
+ }
+ else
+ {
+ /*
+ * Original pre-sqsh-2.2.0 code path with only
+ * semicolon_hack set to true.
+ */
+ /*
+ * Copy everything up to the ';' into the current work buffer.
+ */
+ if (ch - str != 0)
+ {
+ varbuf_strncat( g_sqlbuf, str, ch - str );
+ varbuf_charcat( g_sqlbuf, '\n' );
+
+ /*
+ * We now have an extra line.
+ */
+ env_set( g_env, "lineno", "+1" );
+ }
- str = varbuf_getstr( sg_buf );
+ /*
+ * Now, stick the semicolon command in the front of everything
+ * following the semicolon. and turn that into the command
+ * line.
+ */
+ varbuf_charcat( sg_buf, ' ' );
+ varbuf_strcat( sg_buf, ch + 1 );
+ str = varbuf_getstr( sg_buf );
+ }
is_cmd = True;
}
@@ -474,7 +534,7 @@ int cmd_input()
* if $interactive is set to 0, then this entry will
* automatically be thrown away.
*/
- if (!no_hist && interactive)
+ if (interactive)
{
history_append( g_history, varbuf_getstr(g_sqlbuf) );
@@ -488,8 +548,8 @@ int cmd_input()
case CMD_CLEARBUF:
/*
- * sqsh-2.1.7 - The same as CMD_RESETBUF but without
- * saving the buffer to the history.
+ * sqsh-2.1.7 - The same as CMD_RESETBUF but without
+ * saving the buffer to the history.
*/
varbuf_clear( g_sqlbuf );
env_set( g_env, "lineno", "=1" ) ; /* Set to 1 */
@@ -530,7 +590,6 @@ int cmd_input()
case CMD_ABORT :
goto loop_abort;
break;
-
default :
sprintf( number, "=%d", cur_lineno );
@@ -546,7 +605,7 @@ int cmd_input()
* jobset_run() returned a non-negative value, so it launched
* a background process. The only thing we need to do it
* let the user know it was launched.
- * sqsh-2.1.7 - Also save and clear the command buffer.
+ * sqsh-2.1.7 - Also save and clear the command buffer.
*/
default :
if (interactive)
@@ -554,14 +613,11 @@ int cmd_input()
job_pid = jobset_get_pid( g_jobset, job_id );
fprintf( stdout, "Job #%d running [%d]\n", (int)job_id,
(int)job_pid );
- if (!no_hist)
- {
- history_append( g_history, varbuf_getstr(g_sqlbuf) );
+ history_append( g_history, varbuf_getstr(g_sqlbuf) );
- /*-- Set histnum to be current history number --*/
- sprintf( number, "%d", history_get_nbr(g_history) );
- env_set( g_env, "histnum", number );
- }
+ /*-- Set histnum to be current history number --*/
+ sprintf( number, "%d", history_get_nbr(g_history) );
+ env_set( g_env, "histnum", number );
varbuf_clear( g_sqlbuf );
env_set( g_env, "lineno", "=1" ) ; /* Set to 1 */
}
@@ -576,7 +632,7 @@ int cmd_input()
* than each time the user hits return.
*/
job_id = 0;
- while(interactive &&
+ while(interactive &&
(job_id = jobset_wait(g_jobset, -1, &exit_status, JOB_NONBLOCK)) > 0)
{
/*
@@ -674,7 +730,7 @@ loop_done :
if (read_buf != NULL)
varbuf_destroy( read_buf );
-
+
/*
* Restore the line number to its previous value.
*/
@@ -692,7 +748,7 @@ loop_done :
varbuf_destroy( g_sqlbuf );
g_sqlbuf = (varbuf_t*)orig_sqlbuf;
}
-
+
/*
* Restore the original signal context, and, just in case
* cmd_loop() has been recursively called, restore the original
@@ -725,7 +781,7 @@ static int input_read( output_buf, interactive )
char *exp_prompt = NULL;
/*
- * If we are in interactive mode then we need to display a
+ * If we are in interactive mode then we need to display a
* prompt to the user.
*/
if (interactive)
@@ -733,7 +789,7 @@ static int input_read( output_buf, interactive )
/*
* If we haven't already allocated a buffer in which to
* expand the prompt then we should do so.
- * sqsh-2.1.6 - expand buffer from 32 to 64 bytes.
+ * sqsh-2.1.6 - expand buffer from 32 to 64 bytes.
*/
if (sg_prompt_buf == NULL)
{
@@ -761,13 +817,13 @@ static int input_read( output_buf, interactive )
if (!is_continued)
{
env_get( g_env, "prompt", &prompt );
- if( prompt == NULL || *prompt == '\0' )
+ if( prompt == NULL || *prompt == '\0' )
prompt = "${lineno}> ";
}
else
{
env_get( g_env, "prompt2", &prompt );
- if( prompt == NULL || *prompt == '\0' )
+ if( prompt == NULL || *prompt == '\0' )
prompt = "--> ";
}
@@ -780,7 +836,7 @@ static int input_read( output_buf, interactive )
fprintf( stderr, "prompt: %s\n", sqsh_get_errstr() );
varbuf_strcpy( sg_prompt_buf, "?> " );
}
-
+
exp_prompt = varbuf_getstr(sg_prompt_buf);
}
else
@@ -898,13 +954,13 @@ static char* input_strchr( varbuf, str, c )
case QUOTE_NONE:
switch (*cptr)
{
- case '\'':
+ case '\'':
quote_type = QUOTE_SINGLE;
break;
- case '\"':
+ case '\"':
quote_type = QUOTE_DOUBLE;
break;
- case '/' :
+ case '/' :
if (*(cptr + 1) == '*')
quote_type = QUOTE_COMMENT;
break;
@@ -922,28 +978,28 @@ static char* input_strchr( varbuf, str, c )
break;
}
break;
-
+
case QUOTE_COMMENT:
if (*cptr == '*' && *(cptr + 1) == '/')
{
quote_type = QUOTE_NONE;
}
break;
-
+
case QUOTE_SINGLE:
if (*cptr == '\'')
{
quote_type = QUOTE_NONE;
}
break;
-
+
case QUOTE_DOUBLE:
if (*cptr == '\"')
{
quote_type = QUOTE_NONE;
}
break;
-
+
default:
break;
}
@@ -960,13 +1016,13 @@ static char* input_strchr( varbuf, str, c )
case QUOTE_NONE:
switch (*cptr)
{
- case '\'':
+ case '\'':
quote_type = QUOTE_SINGLE;
break;
- case '\"':
+ case '\"':
quote_type = QUOTE_DOUBLE;
break;
- case '/' :
+ case '/' :
if (*(cptr + 1) == '*')
quote_type = QUOTE_COMMENT;
break;
@@ -984,28 +1040,28 @@ static char* input_strchr( varbuf, str, c )
break;
}
break;
-
+
case QUOTE_COMMENT:
if (*cptr == '*' && *(cptr + 1) == '/')
{
quote_type = QUOTE_NONE;
}
break;
-
+
case QUOTE_SINGLE:
if (*cptr == '\'')
{
quote_type = QUOTE_NONE;
}
break;
-
+
case QUOTE_DOUBLE:
if (*cptr == '\"')
{
quote_type = QUOTE_NONE;
}
break;
-
+
default:
break;
}
@@ -1076,13 +1132,13 @@ static int DynKeywordLoad ()
keyword_query, /* Buffer */
CS_NULLTERM, /* Buffer Length */
CS_UNUSED /* Options */
- ) != CS_SUCCEED)
+ ) != CS_SUCCEED)
{
ct_cmd_drop( cmd );
DBG(sqsh_debug(DEBUG_ERROR, "DynKeywordLoad: Call to ct_command failed.\n"));
return (CS_FAIL);
}
- if (ct_send( cmd ) != CS_SUCCEED)
+ if (ct_send( cmd ) != CS_SUCCEED)
{
ct_cmd_drop( cmd );
DBG(sqsh_debug(DEBUG_ERROR, "DynKeywordLoad: Call to ct_send failed.\n"));
diff --git a/src/cmd_reconnect.c b/src/cmd_reconnect.c
index 3e0ce2c..7eb4818 100644
--- a/src/cmd_reconnect.c
+++ b/src/cmd_reconnect.c
@@ -30,7 +30,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: cmd_reconnect.c,v 1.2 2013/04/04 10:52:35 mwesdorp Exp $" ;
+static char RCS_Id[] = "$Id: cmd_reconnect.c,v 1.3 2013/04/25 14:09:47 mwesdorp Exp $" ;
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -39,19 +39,27 @@ USE(RCS_Id)
*
* Re-establishes a connection the database, closing the prior
* connection. This allows, essentially, an 'su' for databases.
+ *
+ * sqsh-2.2.0 - Also save the current context and let ct_connect setup
+ * a new context. In case of success we can drop the original context,
+ * otherwise restore the original context.
*/
int cmd_reconnect( argc, argv )
int argc ;
char *argv[] ;
{
CS_CONNECTION *old_connection;
+ CS_CONTEXT *old_context;
old_connection = g_connection;
+ old_context = g_context;
g_connection = NULL;
+ g_context = NULL;
if( cmd_connect( argc, argv ) == CMD_FAIL )
{
g_connection = old_connection ;
+ g_context = old_context ;
return CMD_FAIL ;
}
@@ -59,5 +67,9 @@ int cmd_reconnect( argc, argv )
ct_close( old_connection, CS_FORCE_CLOSE );
ct_con_drop( old_connection );
+ if (ct_exit( old_context, CS_UNUSED ) != CS_SUCCEED)
+ ct_exit( old_context, CS_FORCE_EXIT );
+ cs_ctx_drop( old_context );
+
return CMD_LEAVEBUF ;
}
diff --git a/src/sqsh_debug.h b/src/sqsh_debug.h
index a9861ec..be06006 100644
--- a/src/sqsh_debug.h
+++ b/src/sqsh_debug.h
@@ -40,6 +40,7 @@
#define DEBUG_ERROR (1<<12) /* Debug error handlers */
#define DEBUG_SIG (1<<13) /* Debug signal handlers */
#define DEBUG_HISTORY (1<<14) /* Debug history processing */
+#define DEBUG_TDS (1<<15) /* Debug TDS protocol CS communications */
#define DEBUG_ALL ~(0) /* Turn on all debugging */
#if defined(DEBUG)
diff --git a/src/sqsh_env.c b/src/sqsh_env.c
index 5e0b1d0..33cc8fa 100644
--- a/src/sqsh_env.c
+++ b/src/sqsh_env.c
@@ -29,7 +29,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: sqsh_env.c,v 1.1 2004/04/07 12:35:05 chunkm0nkey Exp $";
+static char RCS_Id[] = "$Id: sqsh_env.c,v 1.2 2013/04/25 14:09:47 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -57,14 +57,14 @@ env_t* env_create( hsize )
if (hsize < 1)
{
sqsh_set_error( SQSH_E_BADPARAM, NULL );
- return False;
+ return NULL;
}
/*-- Attempt to allocate an environment --*/
if ((e = (env_t*)malloc(sizeof(env_t))) == NULL)
{
sqsh_set_error( SQSH_E_NOMEM, NULL );
- return False;
+ return NULL;
}
/*-- Create the hash table --*/
@@ -72,7 +72,7 @@ env_t* env_create( hsize )
{
free( e );
sqsh_set_error( SQSH_E_NOMEM, NULL );
- return False;
+ return NULL;
}
for (i = 0; i < hsize; i++)
@@ -196,12 +196,16 @@ int env_remove( e, var_name, flags )
*/
if (e->env_save != NULL && (flags & ENV_F_TRAN) != 0)
{
+ DBG(sqsh_debug( DEBUG_ENV, "env_remove: Variable '%s' with value '%s' deleted in TRAN\n",
+ v->var_name , v->var_value);)
v->var_sptype = ENV_SP_REMOVE;
v->var_nxt = e->env_save;
e->env_save = v;
}
else
{
+ DBG(sqsh_debug( DEBUG_ENV, "env_remove: Variable '%s' with value '%s' deleted\n",
+ v->var_name , v->var_value);)
var_destroy( v );
}
@@ -297,10 +301,11 @@ int env_put( e, var_name, value, flags )
return False;
}
-
new_v->var_sptype = ENV_SP_CHANGE;
new_v->var_nxt = e->env_save;
e->env_save = new_v;
+ DBG(sqsh_debug( DEBUG_ENV, "env_put: Variable '%s' changed from '%s' to '%s' in TRAN\n",
+ v->var_name , v->var_value, value );)
}
/*
@@ -316,6 +321,22 @@ int env_put( e, var_name, value, flags )
}
else
{
+ if (e->env_save != NULL && (flags & ENV_F_TRAN) != 0)
+ {
+ new_v = var_create( var_name, value );
+
+ if (new_v == NULL)
+ {
+ return False;
+ }
+
+ new_v->var_sptype = ENV_SP_NEW;
+ new_v->var_nxt = e->env_save;
+ e->env_save = new_v;
+ DBG(sqsh_debug( DEBUG_ENV, "env_put: Variable '%s' with value '%s' added in TRAN\n",
+ var_name , value );)
+ }
+
/*
* The variable doesn't exist, so create it and stick it
* into the hash table.
@@ -345,7 +366,7 @@ int env_put( e, var_name, value, flags )
* if a 'get' validation function exists for the variable, then it is called.
* Upon success, 1 is returned with value containing the value of var_name,
* otherwise 0 is returned if the variable doesn't exist, or a -1
- * is retuend if the validation function failed, or some other error condition
+ * is returned if the validation function failed, or some other error condition
* ocurred.
*/
int env_nget( e, var_name, value, n )
@@ -357,6 +378,9 @@ int env_nget( e, var_name, value, n )
var_t *v;
int hval;
char *cptr;
+#if defined(DEBUG)
+ char *dbg_var_name;
+#endif
/*-- Always check your arguments --*/
if (e == NULL || var_name == NULL)
@@ -390,15 +414,19 @@ int env_nget( e, var_name, value, n )
}
#if defined(DEBUG)
+ dbg_var_name = sqsh_strdup (var_name);
+ if (n >= 0)
+ dbg_var_name[n] = '\0';
if (v == NULL)
{
- sqsh_debug( DEBUG_ENV, "env_nget: Miss on %s, checking environment.\n",
- var_name );
+ sqsh_debug( DEBUG_ENV, "env_nget: Miss on variable '%s', checking OS environment\n",
+ dbg_var_name );
}
else
{
- sqsh_debug( DEBUG_ENV, "env_nget: Hit on %s.\n", var_name );
+ sqsh_debug( DEBUG_ENV, "env_nget: Hit on variable '%s'\n", dbg_var_name );
}
+ free (dbg_var_name);
#endif /* DEBUG */
/*
@@ -421,7 +449,7 @@ int env_nget( e, var_name, value, n )
/*
* If we are only interested in part of a string, then
- * we need to need to create a temporary buffer in which
+ * we need to create a temporary buffer in which
* to place the partial string to pass it to getenv.
*/
if (n >= 0)
@@ -505,37 +533,12 @@ int env_nget( e, var_name, value, n )
return 1;
}
-int env_print( e )
- env_t *e;
-{
- int i;
- var_t *v;
-
- if (e == NULL)
- {
- sqsh_set_error( SQSH_E_BADPARAM, NULL );
- return False;
- }
-
- for (i = 0; i < e->env_hsize; i++)
- {
- for (v = e->env_htable[i]; v != NULL; v = v->var_nxt)
- {
- printf("%s = %s\n",
- v->var_name != NULL ? v->var_name : "NULL",
- v->var_value != NULL ? v->var_value : "NULL" );
- }
- }
-
- sqsh_set_error( SQSH_E_NONE, NULL );
- return True;
-}
/*
* env_tran():
*
* Create a transaction "save-point" in the environment. After
- * calling env_tran(), subsequnt calls to env_put() or env_remove()
+ * calling env_tran(), subsequent calls to env_put() or env_remove()
* with a flag of ENV_F_TRAN will cause the resulting change to
* be logged. A call to env_rollback() will restore all logged
* changes to be reversed, and a call to env_commit() ends the
@@ -576,33 +579,34 @@ int env_rollback( e )
var_t *v;
/*
- * Now, blast through our save stack, reseting each variable
+ * Now, blast through our save stack, resetting each variable
* to its original state.
*/
while (e->env_save != NULL &&
e->env_save->var_sptype != ENV_SP_START)
{
v = e->env_save;
- e->env_save = e->env_save->var_nxt;
+ e->env_save = v->var_nxt;
switch (v->var_sptype)
{
case ENV_SP_NEW:
DBG(sqsh_debug( DEBUG_ENV,
- "env_rollback: Removing '%s'\n", v->var_name );)
+ "env_rollback: Removing variable '%s'\n", v->var_name );)
env_remove( e, v->var_name, 0 );
break;
case ENV_SP_CHANGE:
DBG(sqsh_debug( DEBUG_ENV,
- "env_rollback: Restoring '%s' to '%s'\n",
+ "env_rollback: Restoring variable '%s' to '%s'\n",
v->var_name, v->var_value );)
env_put( e, v->var_name, v->var_value, 0 );
break;
case ENV_SP_REMOVE:
DBG(sqsh_debug( DEBUG_ENV,
- "env_rollback: Adding '%s'\n", v->var_name );)
+ "env_rollback: Adding variable '%s' with value '%s'\n",
+ v->var_name, v->var_value );)
env_set_valid( e, v->var_name, v->var_value,
v->var_setf, v->var_getf );
@@ -619,10 +623,10 @@ int env_rollback( e )
if (e->env_save != NULL)
{
v = e->env_save;
- e->env_save = e->env_save->var_nxt;
+ e->env_save = v->var_nxt;
var_destroy( v );
}
- DBG(sqsh_debug( DEBUG_ENV, "env_save: Save-point restored\n" );)
+ DBG(sqsh_debug( DEBUG_ENV, "env_rollback: Save-point rolled-back\n" );)
return True;
}
@@ -646,11 +650,7 @@ int env_commit( e )
e->env_save = v->var_nxt;
var_destroy( v );
}
- else
- {
- e->env_save = NULL;
- }
- DBG(sqsh_debug( DEBUG_ENV, "env_commit: Save-point restored\n" );)
+ DBG(sqsh_debug( DEBUG_ENV, "env_commit: Save-point committed\n" );)
return True;
}
@@ -803,6 +803,7 @@ static var_t* var_create( var_name, value )
v->var_sptype = ENV_SP_NONE;
v->var_setf = NULL;
v->var_getf = NULL;
+ v->var_nxt = NULL;
return v;
}
diff --git a/src/sqsh_env.h b/src/sqsh_env.h
index 8c5e529..d7d934b 100644
--- a/src/sqsh_env.h
+++ b/src/sqsh_env.h
@@ -59,13 +59,12 @@ int env_set_valid _ANSI_ARGS(( env_t*, char*, char*, env_f*, env_f* ));
int env_set _ANSI_ARGS(( env_t*, char*, char* ));
int env_put _ANSI_ARGS(( env_t*, char*, char*, int ));
int env_remove _ANSI_ARGS(( env_t*, char*, int ));
-int env_del _ANSI_ARGS(( env_t*, char* ));
-int env_get _ANSI_ARGS(( env_t*, char*, char** ));
int env_nget _ANSI_ARGS(( env_t*, char*, char**, int ));
int env_tran _ANSI_ARGS(( env_t* ));
int env_commit _ANSI_ARGS(( env_t* ));
int env_rollback _ANSI_ARGS(( env_t* ));
int env_destroy _ANSI_ARGS(( env_t* ));
+/* int env_get _ANSI_ARGS(( env_t*, char*, char** )); */
#define env_get(e,k,v) env_nget(e,k,v,-1)
diff --git a/src/sqsh_expand.c b/src/sqsh_expand.c
index 555ddbb..3da6e5d 100644
--- a/src/sqsh_expand.c
+++ b/src/sqsh_expand.c
@@ -36,7 +36,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: sqsh_expand.c,v 1.6 2013/04/04 10:52:36 mwesdorp Exp $";
+static char RCS_Id[] = "$Id: sqsh_expand.c,v 1.7 2013/04/25 14:09:47 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -722,8 +722,34 @@ static int expand_variable( cpp, str_end, buf, flags )
*cpp = str;
return True;
}
+
+ /*
+ * Check for special cases.
+ * sqsh-2.2.0 - First, $? is the result of last action.
+ */
+ if (*var_name_start == '?' &&
+ (var_name_end - var_name_start) == 1)
+ {
+ env_get( g_internal_env, "?", &var_value );
+ varbuf_strcat( buf, var_value );
+ *cpp = str;
+ return(True);
+ }
+
+ /*
+ * Next, $$ is the current processid.
+ */
+ if (*var_name_start == '$' &&
+ (var_name_end - var_name_start) == 1)
+ {
+ sprintf(nbr, "%d", (int) getpid() );
+ varbuf_strcat( buf, nbr );
+ *cpp = str;
+ return(True);
+ }
+
/*
- * Check for special case. First, $# is the number of arguments.
+ * Next, $# is the number of arguments.
*/
if (*var_name_start == '#' &&
(var_name_end - var_name_start) == 1)
@@ -745,19 +771,6 @@ static int expand_variable( cpp, str_end, buf, flags )
return(True);
}
-
- /*
- * Next, $$ is the current processid.
- */
- if (*var_name_start == '$' &&
- (var_name_end - var_name_start) == 1)
- {
- sprintf(nbr, "%d", (int) getpid() );
- varbuf_strcat( buf, nbr );
- *cpp = str;
- return(True);
- }
-
/*
* Next, $* is the complete list of arguments.
*/
diff --git a/src/sqsh_history.c b/src/sqsh_history.c
index 500abca..2978d1a 100644
--- a/src/sqsh_history.c
+++ b/src/sqsh_history.c
@@ -33,7 +33,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: sqsh_history.c,v 1.8 2013/04/18 11:54:43 mwesdorp Exp $" ;
+static char RCS_Id[] = "$Id: sqsh_history.c,v 1.9 2013/04/25 14:09:47 mwesdorp Exp $" ;
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -414,6 +414,7 @@ int history_del( h, idx )
hb != NULL; hb->hb_nbr = i--, hb = hb->hb_nxt);
break;
}
+ h->h_change = HISTSAVE_FORCE;
hist_auto_save ( h );
return True ;
@@ -528,9 +529,13 @@ int history_save( h, save_file )
/*
* sqsh-2.2.0 - Merge the history file with the buffers in memory.
+ * If h_change is set to HISTSAVE_FORCE then we do not want to
+ * merge, because we may have just removed a bunch of buffers
+ * for example.
*/
env_get (g_env, "histmerge", &histmerge);
- if ( histmerge != NULL && *histmerge == '1')
+ if ( histmerge != NULL && *histmerge == '1' &&
+ h->h_change != HISTSAVE_FORCE)
{
x = history_create (history_get_size(h));
if (history_load (x, save_file) == True)
diff --git a/src/sqsh_init.c b/src/sqsh_init.c
index 55c2d62..0729928 100644
--- a/src/sqsh_init.c
+++ b/src/sqsh_init.c
@@ -44,7 +44,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: sqsh_init.c,v 1.4 2013/04/04 10:52:36 mwesdorp Exp $" ;
+static char RCS_Id[] = "$Id: sqsh_init.c,v 1.5 2013/04/25 14:09:47 mwesdorp Exp $" ;
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -223,6 +223,12 @@ int sqsh_init()
varbuf_destroy( expand_buf ) ;
/*
+ * sqsh-2.2.0 - Initialize variable keyword_refresh in the
+ * g_internal_env to prevent misses in subsequent variable lookups.
+ */
+ env_set( g_internal_env, "keyword_refresh", "0" );
+
+ /*
* Allocate our global set of sub-processes.
*/
if( (g_jobset = jobset_create( 47 )) == NULL ) {
@@ -345,6 +351,11 @@ void sqsh_exit( exit_status )
g_buf = NULL;
}
+ if ( g_internal_env != NULL ) {
+ env_destroy( g_internal_env ) ;
+ g_internal_env = NULL;
+ }
+
/*
* sqsh-2.1.7 - Reset term_title.
*/
diff --git a/src/sqsh_main.c b/src/sqsh_main.c
index 9b6a99b..29601b7 100644
--- a/src/sqsh_main.c
+++ b/src/sqsh_main.c
@@ -42,7 +42,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: sqsh_main.c,v 1.22 2013/04/18 11:54:43 mwesdorp Exp $";
+static char RCS_Id[] = "$Id: sqsh_main.c,v 1.23 2013/04/25 14:09:47 mwesdorp Exp $";
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -162,6 +162,15 @@ main( argc, argv )
varbuf_t *exp_buf;
/*
+ * sqsh-2.2.0 - Variables used by password handling option
+ * moved here.
+ */
+ char buf[MAXPWD];
+ char *p;
+ int fdin, fdout;
+
+
+ /*
* If termios.h defines TIOCGWINSZ, then we need to declare a
* structure in which to retrieve the current window size.
*/
@@ -368,7 +377,6 @@ main( argc, argv )
read_file = True;
show_banner = False;
ret = env_set( g_env, "script", sqsh_optarg );
- ret = env_set( g_internal_env, "0", sqsh_optarg );
break;
case 'I' :
ret = env_set( g_env, "interfaces", sqsh_optarg );
@@ -516,10 +524,6 @@ main( argc, argv )
* to solve a problem with pipes already in use. (Patch-id 2607434)
* The actual pipe file descriptors will now be passed on with the \250 option.
*/
- char buf[MAXPWD];
- char *p;
- int fdin, fdout;
-
memset(buf, 0, MAXPWD);
if (sqsh_optarg != NULL)
strcpy (buf, sqsh_optarg);
@@ -585,7 +589,7 @@ main( argc, argv )
{
if (sqsh_optind > 1)
{
- argv[sqsh_optind-1] = argv[0];
+ env_get (g_env, "script", &(argv[sqsh_optind-1])) ;
}
g_func_args[g_func_nargs].argc = argc - sqsh_optind + 1;
g_func_args[g_func_nargs].argv = &(argv[sqsh_optind-1]);
@@ -1015,7 +1019,6 @@ static void hide_password (argc, argv)
char *argv[];
{
int i, j;
- char **argn;
char buf[32];
int filedes[2];
char nullpwd[2];
@@ -1024,10 +1027,6 @@ static void hide_password (argc, argv)
int status;
- /*
- * sqsh-2.2.0 - Allocate memory for a complete new argument list.
- */
- argn = malloc (sizeof(char*)*argc);
nullpwd[0] = '\n';
nullpwd[1] = '\0';
@@ -1043,7 +1042,7 @@ static void hide_password (argc, argv)
* New password parameter encounterd.
*/
pwd = NULL;
- if (*(argv[i]+2))
+ if (*(argv[i]+2) != '\0')
{
/*
* Password passed on as: "sqsh -SSYBASE -Usa -Pxxxxxx" , or as -P-
@@ -1067,7 +1066,7 @@ static void hide_password (argc, argv)
}
}
else
- argn[j++] = argv[i];
+ argv[j++] = argv[i];
}
/*
@@ -1076,7 +1075,6 @@ static void hide_password (argc, argv)
*/
if (pwd == NULL)
{
- free (argn);
return;
}
@@ -1089,21 +1087,21 @@ static void hide_password (argc, argv)
return;
}
sprintf (buf, "-%c%d/%d", '\250', filedes[0], filedes[1]);
- argn[j++] = buf;
- argn[j] = NULL;
+ argv[j++] = buf;
+ argv[j] = NULL;
- if ((pid = fork()))
+ if ((pid = fork()) != 0)
{
/*
* sqsh-2.2.0 - This code is executed by the parent process.
* Wait for the child process to finish execution before we continue.
*/
- waitpid (pid, &status, 0);
+ (void) waitpid (pid, &status, 0);
/*
- * Re-execute ourselves in the parent process, with the new argn[] list.
+ * Re-execute ourselves in the parent process, with the modified argv[] list.
*/
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
- execvp (argn[0], argn);
+ if (WIFEXITED(status) != 0 && WEXITSTATUS(status) == 0)
+ (void) execvp (argv[0], argv);
/* Not reached */
else
{
@@ -1117,13 +1115,13 @@ static void hide_password (argc, argv)
* The child process writes the password to the pipe, closes the pipe
* and exits.
*/
- if (write (filedes[1], pwd, strlen(pwd)) != strlen(pwd))
+ if ((int) write (filedes[1], pwd, strlen(pwd)) != (int) strlen(pwd))
{
fprintf (stderr, "sqsh: Error: Failed to write password to pipe (filedes=%d)\n", filedes[1]);
sqsh_exit (255);
}
- close (filedes[0]);
- close (filedes[1]);
+ (void) close (filedes[0]);
+ (void) close (filedes[1]);
sqsh_exit (0);
}
}
diff --git a/src/var.h b/src/var.h
index 800cd43..c8d1ce4 100644
--- a/src/var.h
+++ b/src/var.h
@@ -195,9 +195,15 @@ static var_entry_t sg_var_entry[] = {
/* sqsh-2.1.9 - New variables */
{ "datefmt", NULL, var_set_datefmt, var_get_datefmt },
{ "timefmt", NULL, var_set_timefmt, var_get_timefmt },
- /* sqsh-2.2.0 - New variables */
+ /* sqsh-2.2.0 - New or missing variables in global env added */
+ { "autouse", NULL, var_set_nullstr, NULL },
+ { "debug_tds_logdata",NULL, var_set_nullstr, NULL },
+ { "debug_tds_capture",NULL, var_set_nullstr, NULL },
+ { "histmerge", "0", var_set_bool, NULL },
{ "readline_histignore", NULL, var_set_nullstr, NULL },
- { "histmerge", "0", var_set_bool, NULL },
+ { "script", NULL, var_set_nullstr, NULL },
+ { "semicolon_hack2", "0", var_set_bool, NULL },
+ { "tds_version", NULL, var_set_nullstr, NULL },
} ;
#endif /* SQSH_INIT */
diff --git a/src/var_debug.c b/src/var_debug.c
index eabda05..f0a6f10 100644
--- a/src/var_debug.c
+++ b/src/var_debug.c
@@ -32,7 +32,7 @@
/*-- Current Version --*/
#if !defined(lint) && !defined(__LINT__)
-static char RCS_Id[] = "$Id: var_debug.c,v 1.3 2013/04/18 11:54:43 mwesdorp Exp $" ;
+static char RCS_Id[] = "$Id: var_debug.c,v 1.4 2013/04/25 14:09:48 mwesdorp Exp $" ;
USE(RCS_Id)
#endif /* !defined(lint) */
@@ -65,6 +65,7 @@ struct debug_st {
{ "SIG", DEBUG_SIG },
{ "SIGCHLD", DEBUG_SIGCLD },
{ "SIGCLD", DEBUG_SIGCLD },
+ { "TDS", DEBUG_TDS },
} ;
#endif