1 /*
2  * sqsh_init.c - Initialize/cleanup global variable
3  *
4  * Copyright (C) 1995, 1996 by Scott C. Gray
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, write to the Free Software
18  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  * You may contact the author :
21  *   e-mail:  gray@voicenet.com
22  *            grays@xtend-tech.com
23  *            gray@xenotropic.com
24  */
25 #include <stdio.h>
26 #include "sqsh_config.h"
27 #include "sqsh_error.h"
28 #include "sqsh_global.h"
29 #include "sqsh_expand.h"
30 #include "sqsh_cmd.h"
31 #include "sqsh_env.h"
32 #include "sqsh_readline.h"
33 #include "sqsh_stdin.h"
34 #include "sqsh_init.h"
35 #include "config.h"
36 #if defined(HAVE_LOCALE_H)
37 #include <locale.h>
38 #endif
39 /*
40  * The following defines the tables which are used to inialize the
41  * variable global variables.
42  */
43 #define SQSH_INIT
44 #include "cmd.h"
45 #include "var.h"
46 #include "alias.h"
47 #undef SQSH_INIT
48 
49 /*-- Current Version --*/
50 #if !defined(lint) && !defined(__LINT__)
51 static char RCS_Id[] = "$Id: sqsh_init.c,v 1.9 2013/12/03 09:22:23 mwesdorp Exp $" ;
USE(RCS_Id)52 USE(RCS_Id)
53 #endif /* !defined(lint) */
54 
55 /*
56  * sqsh_init():
57  *
58  * Initializes all global variables for the first time. This function
59  * should be pretty much the first thing called. True is returned
60  * upon success, False is returned otherwise.
61  *
62  * Note: Careful attention should be payed to sqsh_fork.c and how it
63  * interacts with these variables.
64  */
65 int sqsh_init()
66 {
67 	int        i ;
68 	char      *histsize ;
69 	varbuf_t  *expand_buf ;
70 
71 
72 	/*
73 	 * sqsh-2.3 : Initialize locale to the default of C.
74 	 */
75 #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
76 	setlocale ( LC_ALL, "C" );
77 #endif
78 
79 	/*
80 	 * g_connection: This variable is initiazed to NULL.  It is the responsibility
81 	 *           of a user function to actually perform the connection to
82 	 *           set it.  This allows sqsh to be started without actually
83 	 *           connecting to the database.
84 	 */
85 	g_context    = NULL ;
86 	g_connection = NULL ;
87 
88 	/*
89 	 * g_sqlbuf: This variable contains the working SQL buffer being typed
90 	 *           into by the user.  It is initialized to an empty buffer.
91 	 */
92 	if( (g_sqlbuf = varbuf_create( 1024 )) == NULL ) {
93 		sqsh_set_error( sqsh_get_error(), "varbuf_create: %s", sqsh_get_errstr());
94 		return False ;
95 	}
96 
97 	/*
98 	 * g_cmdset: The set of commands that may be executed by a user or
99 	 *           internally.
100 	 */
101 	if( (g_cmdset = cmdset_create()) == NULL ) {
102 		sqsh_set_error( sqsh_get_error(), "cmdset_create: %s", sqsh_get_errstr());
103 		return False ;
104 	}
105 
106 	/*
107 	 * g_funcset: The set of commands that may be executed by a user or
108 	 *           internally.
109 	 */
110 	if ((g_funcset = funcset_create()) == NULL)
111 	{
112 		sqsh_set_error( sqsh_get_error(),
113 			"cmdset_create: %s", sqsh_get_errstr());
114 		return False;
115 	}
116 
117 	/*
118 	 * Now, populate the g_cmdset with the set of commands defined in
119 	 * cmd.h.
120 	 */
121 	for( i = 0; i < (sizeof(sg_cmd_entry) / sizeof(cmd_entry_t)); i++ ) {
122 
123 		if( cmdset_add( g_cmdset,
124 							 sg_cmd_entry[i].ce_name,
125 							 sg_cmd_entry[i].ce_func ) == False ) {
126 			sqsh_set_error( sqsh_get_error(), "cmdset_add: %s",
127 								 sqsh_get_errstr() ) ;
128 			return False ;
129 		}
130 
131 	}
132 
133 	/*
134 	 * Initialize our table of aliases
135 	 */
136 	if( (g_alias = alias_create()) == NULL ) {
137 		sqsh_set_error(sqsh_get_error(), "alias_create: %s", sqsh_get_errstr()) ;
138 		return False ;
139 	}
140 
141 	for( i = 0; i < (sizeof(sg_alias_entry) / sizeof(alias_entry_t)); i++ ) {
142 		if( alias_add( g_alias,
143 		               sg_alias_entry[i].ae_name,
144 		               sg_alias_entry[i].ae_body ) == False ) {
145 			sqsh_set_error( sqsh_get_error(), "alias_add: %s: %s",
146 			                sg_alias_entry[i].ae_name,
147 			                sqsh_get_errstr() ) ;
148 			return False ;
149 		}
150 	}
151 
152 	/*
153 	 * g_buf:    Where named buffers are stored.
154 	 */
155 	if( (g_buf = env_create( 47 )) == NULL ) {
156 		sqsh_set_error( sqsh_get_error(), "env_create: %s", sqsh_get_errstr() ) ;
157 		return False ;
158 	}
159 
160 	/*
161 	 * g_internal_env: This is the internal environment information that
162 	 *           is not settable by a user, but is queryable.
163 	 *
164 	 */
165 	if( (g_internal_env = env_create(47)) == NULL ) {
166 		sqsh_set_error( sqsh_get_error(), "env_create: %s", sqsh_get_errstr() ) ;
167 		return False ;
168 	}
169 
170 	/*
171 	 * g_env:    This is the environment for the process.  Here we simply
172 	 *           create the environment and initialize it with the default
173 	 *           values, these may then be overridden by the users .sqshrc
174 	 */
175 	if( (g_env = env_create( 47 )) == NULL ) {
176 		sqsh_set_error( sqsh_get_error(), "env_create: %s", sqsh_get_errstr() ) ;
177 		return False ;
178 	}
179 
180 	/*
181 	 * The following buffer is used to expand the values of the variables
182 	 * prior to setting them within the environment.  It is destroyed when
183 	 * we are done with this process.
184 	 */
185  	if( (expand_buf = varbuf_create( 64 )) == NULL ) {
186 		sqsh_set_error(sqsh_get_error(), "varbuf_create: %s", sqsh_get_errstr());
187 		return False ;
188  	}
189 
190 	/*
191 	 * Now, using the array defined in var.h, populate the global
192 	 * environment.
193 	 */
194 	for( i = 0; i < (sizeof(sg_var_entry) / sizeof(var_entry_t)); i++ ) {
195 
196 		if( sg_var_entry[i].ve_value != NULL ) {
197 			/*
198 			 * Expand the value of the variable prior to sticking it in the
199 			 * environment.  This, more-or-less, emulates the behaviour as
200 			 * if you had typed it in from the command line.
201 			 */
202 			if( sqsh_expand( sg_var_entry[i].ve_value, expand_buf,
203 			                 EXP_STRIPESC ) == False ){
204 				sqsh_set_error( sqsh_get_error(), "%s: %s",
205 									 sg_var_entry[i].ve_value, sqsh_get_errstr());
206 				return False ;
207 			}
208 
209 			if( env_set_valid(
210 					g_env,                     /* Global environment */
211 					sg_var_entry[i].ve_name,   /* Name of variable */
212 					varbuf_getstr(expand_buf), /* Default value */
213 					sg_var_entry[i].ve_set,    /* Settor function */
214 					sg_var_entry[i].ve_get ) == False ) {
215 				sqsh_set_error( sqsh_get_error(), "env_set_valid: %s",
216 									 sqsh_get_errstr() ) ;
217 				return False ;
218 			}
219 		} else {  /* NULL value */
220 			if( env_set_valid(
221 					g_env,                     /* Global environment */
222 					sg_var_entry[i].ve_name,   /* Name of variable */
223 					NULL,                      /* NULL value */
224 					sg_var_entry[i].ve_set,    /* Settor function */
225 					sg_var_entry[i].ve_get ) == False ) {
226 				sqsh_set_error( sqsh_get_error(), "env_set_valid: %s",
227 									 sqsh_get_errstr() ) ;
228 				return False ;
229 			}
230 		}
231 	}
232 
233 	/*-- Don't need it any more --*/
234 	varbuf_destroy( expand_buf ) ;
235 
236 	/*
237 	 * sqsh-2.2.0 - Initialize variable keyword_refresh in the
238 	 * g_internal_env to prevent misses in subsequent variable lookups.
239 	 */
240 	env_set( g_internal_env, "keyword_refresh", "0" );
241 
242 	/*
243 	 * Allocate our global set of sub-processes.
244 	 */
245 	if( (g_jobset = jobset_create( 47 )) == NULL ) {
246 		sqsh_set_error( sqsh_get_error(), "jobset_create: %s",
247 							 sqsh_get_errstr() ) ;
248 	 	return False ;
249 	}
250 
251 	/*
252 	 * Since the global environment set has been created and initialized
253 	 * we can retrieve any variables that may affect the size of other
254 	 * data structures...such as the history.
255 	 */
256 	env_get( g_env, "histsize", &histsize ) ;
257 	if( histsize == NULL || (i = atoi( histsize )) == 0 )
258 		i = 10 ;
259 
260 	if( (g_history = history_create( i )) == NULL ) {
261 		sqsh_set_error( sqsh_get_error(), "history_create: %s",
262 							 sqsh_get_errstr() ) ;
263 	 	return False ;
264 	}
265 
266 	sqsh_set_error( SQSH_E_NONE, NULL ) ;
267 	return True ;
268 }
269 
sqsh_exit(exit_status)270 void sqsh_exit( exit_status )
271 	int  exit_status ;
272 {
273 	char      *history;
274 	char      *histsave;
275 	char      *term_title;
276 	varbuf_t  *exp_buf;
277 
278 	/*
279 	 * If the history has been created, and it contains items, and $history
280 	 * has been defined, then we write the history out to a file.
281 	 */
282 	if (g_history != NULL)
283 	{
284 		if (g_env != NULL)
285 		{
286 			env_get( g_env, "history", &history );
287 			env_get( g_env, "histsave", &histsave );
288 		}
289 		else
290 		{
291 			history = NULL;
292 			histsave = NULL;
293 		}
294 
295 		if (g_interactive && (histsave == NULL || *histsave == '1') &&
296 		    history != NULL && history_get_nitems( g_history ) > 0)
297 		{
298 			exp_buf = varbuf_create( 512 );
299 
300 			if (exp_buf == NULL)
301 			{
302 				fprintf( stderr, "sqsh_exit: %s\n", sqsh_get_errstr() );
303 			}
304 			else
305 			{
306 				if (sqsh_expand( history, exp_buf, 0 ) == False)
307 				{
308 					fprintf( stderr, "sqsh_exit: Error expanding $history: %s\n",
309 						sqsh_get_errstr() );
310 				}
311 				else
312 				{
313 					history_save( g_history, varbuf_getstr(exp_buf) );
314 				}
315 
316 				varbuf_destroy( exp_buf );
317 			}
318 		}
319 
320 		history_destroy( g_history );
321 		g_history = NULL;
322 	}
323 
324 	/*
325 	 * Clean up readline.
326 	 */
327 	if ( g_interactive )
328 		sqsh_readline_exit();
329 
330 	if( g_connection != NULL )
331 	{
332 		if (ct_close( g_connection, CS_UNUSED) != CS_SUCCEED)
333 		    ct_close( g_connection, CS_FORCE_CLOSE );
334 		ct_con_drop( g_connection );
335 		g_connection = NULL;
336 	}
337 
338 	if (g_context != NULL)
339 	{
340 		if (ct_exit( g_context, CS_UNUSED ) != CS_SUCCEED)
341 		    ct_exit( g_context, CS_FORCE_EXIT );
342 
343 		/*
344 		 * If sqsh is aborting, maybe because of losing a database connection
345 		 * and the callback handler requests sqsh_exit(254), then do not drop
346 		 * the g_context structure, as it will generate an error:
347 		 * CS-Library error:
348 		 *    severity(1) layer(2) origin(1) number(31)
349 		 *    cs_ctx_drop: cslib user api layer: external error:
350 		 *    The context structure cannot be dropped because the application
351 		 *    has not exited from ct.
352 		 * This is due to the fact that the callback handler did not return
353 		 * to CS/CT-Library.
354 		 */
355 		if (exit_status != 254)
356 			cs_ctx_drop( g_context );
357 		g_context = NULL;
358 	}
359 
360 	if( g_buf != NULL ) {
361 		env_destroy( g_buf ) ;
362 		g_buf = NULL;
363 	}
364 
365 	if ( g_internal_env != NULL ) {
366 		env_destroy( g_internal_env ) ;
367 		g_internal_env = NULL;
368 	}
369 
370 	/*
371 	 * sqsh-2.1.7 - Reset term_title.
372 	 */
373 	if (g_env != NULL && g_interactive)
374 	{
375 		env_get( g_env, "term_title", &term_title );
376 		if (term_title != NULL && *term_title != '\0')
377 		    fprintf (stdout, "%c]0;%c", '\033', '\007' );
378 	}
379 
380 	/*
381 	 * sqsh-2.5 - Close file $p2fname
382 	 */
383 	if (g_p2f_fp != NULL) {
384 		fclose (g_p2f_fp);
385 		g_p2f_fp = NULL;
386 	}
387 
388 	if( g_env != NULL ) {
389 		env_destroy( g_env ) ;
390 		g_env = NULL;
391 	}
392 
393 	if( g_sqlbuf != NULL ) {
394 		varbuf_destroy( g_sqlbuf ) ;
395 		g_sqlbuf = NULL;
396 	}
397 
398 	if( g_cmdset != NULL ) {
399 		cmdset_destroy( g_cmdset ) ;
400 		g_cmdset = NULL;
401 	}
402 
403 	if( g_funcset != NULL ) {
404 		funcset_destroy( g_funcset ) ;
405 		g_funcset = NULL;
406 	}
407 
408 	if( g_jobset != NULL ) {
409 		jobset_destroy( g_jobset ) ;
410 		g_jobset = NULL;
411 	}
412 
413 	exit (exit_status) ;
414 }
415 
416 
417