/* SHSQL.C 

*/
#define VERSION_STRING "shsql 1.28\n"

#include <ctype.h>
#include "tdhkit.h"
#include "shsql.h"

extern int getpid(), unlink();
extern int GL_make_unique_string();

int
main( argc, argv )
int argc;
char **argv;
{
int i, j, stat, nfields, ix;
char *names[80];
char *fields[80];
int headermode, html, xml, rowcount, omitnull, tagvalue, echo, tersemsg, niceout, omitfinaldelim;
char nullrep[20];
char delim_char;
char tok1[MAXPATH], tok2[MAXPATH], tok3[MAXPATH];
char buf[256];
char errcombuf[512];
char tmpfilename[256];
char commandbuf[MAXSQLCOMMANDLEN];
FILE *tfp;
int maxoutlen;    /* maximum length of ANY field */
int maxfieldlen;  
int footprint;
int showund[MAXITEMS], nsu;  /* underscore conversion, field by field */
int xlen[MAXITEMS], nxlen;		 /* max lengths, field by field */
int arglen;

TDH_errprog( "shsql" );

/* check command line args.. */
if( argc < 2 ) { fprintf( stderr, "usage: shsql options sqlcommand\n" ); exit( 1 ); }
headermode = 0;
html = xml = rowcount = 0;
omitnull = tagvalue = 0;
tersemsg = 0;
echo = 0;
niceout = 0;
strcpy( nullrep, "null" );
delim_char = '\t';
omitfinaldelim = 0;
maxoutlen = DATAMAXLEN;
footprint = 0;
nsu = 0;
for( i = 0; i < MAXITEMS; i++ ) showund[i] = 0;
nxlen = 0;
for( i = 0; i < MAXITEMS; i++ ) xlen[i] = 0;
for( i = 1; i < argc; i++ ) {
	if( stricmp( argv[i], "-h" )==0 ) headermode = 1;
	else if( stricmp( argv[i], "-n" )==0 ) { niceout = 1; headermode = 1; }
	else if( strcmp( argv[i], "-nat" )==0 ) { delim_char = BLANK; strcpy( nullrep, TDH_dbnull ); }
	else if( strcmp( argv[i], "-html" )==0 ) { html = 1; strcpy( nullrep, "&nbsp;" ); }
	else if( strcmp( argv[i], "-xml" )==0 ) xml = 1;
	else if( strcmp( argv[i], "-tagvalue" )==0 ) tagvalue = 1;
	else if( strcmp( argv[i], "-omitnull" )==0 ) omitnull = 1;
	else if( strcmp( argv[i], "-omitfinaldelim" )==0 ) omitfinaldelim = 1;
	else if( strcmp( argv[i], "-rowcount" )==0 ) rowcount = 1;
	else if( strcmp( argv[i], "-debug" )==0 ) SHSQL_debug = 1;
	else if( strcmp( argv[i], "-debug2" )==0 ) SHSQL_debug = 2;
	else if( strcmp( argv[i], "-noindex" )==0 ) SHSQL_suppressix = 1;
	else if( strcmp( argv[i], "-errstdout" )==0 ) TDH_errmode( "stdout" );
	else if( strcmp( argv[i], "-nolog" )==0 ) SHSQL_translog = 0;
	else if( strcmp( argv[i], "-ver" )==0 ) {
		printf( "%s", VERSION_STRING );
		exit( 0 );
		}
	else if( strcmp( argv[i], "-echo" )==0 ) echo = 1;
	else if( strcmp( argv[i], "-terse" )==0 ) tersemsg = 1;
	else if( strcmp( argv[i], "-footprint" )==0 ) footprint = 1;
	else if( strcmp( argv[i], "-delim" )==0 ) {
		i++;
		if( i < argc ) {
			if( strcmp( argv[i], "space" )==0 ) delim_char = BLANK;
			else if( strcmp( argv[i], "tab" )==0 ) delim_char = '\t';
			else delim_char = argv[i][0];
			}
		}
	else if( strcmp( argv[i], "-nullrep" )==0 ) {
		i++;
		if( i < argc ) strncpy( nullrep, argv[i], 18 );
		}
	else if( strcmp( argv[i], "-id" )==0 ) {
		i++;
		if( i < argc ) TDH_setvar( "_IDENTITY", argv[i] );
		}
	else if( strcmp( argv[i], "-ttprefix" )==0 ) {
		i++;
		if( i < argc ) strcpy( SHSQL_tmptblpfx, argv[i] );
		}
	else if( strcmp( argv[i], "-l" )==0 ) {
		i++;
		if( i < argc ) maxoutlen = atoi( argv[i] );
		if( maxoutlen < 2 ) maxoutlen = DATAMAXLEN;
		}
	else if( strcmp( argv[i], "-und" )==0 ) {
		i++;
		if( i < argc ) {
			arglen = strlen( argv[i] );
			for( j = 0, ix = 0; j < arglen; j++ ) {
				GL_getchunk( buf, argv[i], &ix, "," );
				j = atoi(buf)-1;
				if( j >= 0 ) showund[j] = 1;
				nsu++;
				}
			}
		}
	else if( strcmp( argv[i], "-xlen" )==0 ) {
		i++;
		if( i < argc ) {
			arglen = strlen( argv[i] );
			for( j = 0, ix = 0; j < arglen; j++ ) {
				GL_getseg( buf, argv[i], &ix, "," );
				xlen[j] = atoi(buf);
				nxlen++;
				}
			}
		}
	else if( argv[i][0] == '-' ) fprintf( stderr, "shsql warning: unrecognized option %s ignored\n", argv[i] );
	else break;
	}
if( i == argc ) { fprintf( stderr, "shsql error: sql command expected\n" ); exit( 1 ); }
strcpy( commandbuf, argv[i] );

if( tersemsg ) strcpy( errcombuf, "" );
else sprintf( errcombuf, "(command: %s)", commandbuf );

if( footprint ) { sprintf( buf, "ps -p %d -o vsz -o rss >&2", getpid() ); system( buf ); }

if( echo ) { printf( "%s\n\n", commandbuf ); fflush( stdout ); }

/* intercept and execute CREATE DATABASE (no config file dependency) */
sscanf( commandbuf, "%s %s %s", tok1, tok2, tok3 );
if( stricmp( tok1, "create" )==0  && stricmp( tok2, "database" )==0 ) {
	sprintf( buf, "shsql_create database %s", tok3 );
	system( buf );
	exit( 0 );
	}


/* get config file.. */
stat = SHSQL_allconfig();
if( stat != 0 ) { fprintf( stderr, "shsql: error %d on attempt to read config file\n", stat ); exit( 1 ); }

/* submit the SQL command.. */
stat = SHSQL_sql( 0, commandbuf );
if( stat == 7 ) { fprintf( stderr, "shsql: record is locked and currently unavailable for update %s\n", errcombuf ); exit( 1 ); }
else if( stat != 0 ) { fprintf( stderr, "shsql: error %d %s\n", stat, errcombuf ); exit( 1 ); }


if( niceout ) {  /* open a tmp file to capture results.. */
	char uniqtag[20];
	if( xml || html || rowcount ) { 
		fprintf( stderr, "shsql: warning, ignoring incompatible options\n" );
		xml = html = rowcount = tagvalue = 0;
		}
	GL_make_unique_string( uniqtag, 0 );
	sprintf( tmpfilename, "%s/nice%s", TDH_tmpdir, uniqtag );
	tfp = fopen( tmpfilename, "w" );
	if( tfp == NULL ) { fprintf( stderr, "cannot open tmp file %s to write", tmpfilename ); exit( 1 ); }
	}
else tfp = stdout;

if( headermode || xml || tagvalue ) {
	/* fetch the result field names and print them.. */
	stat = SHSQL_getnames( 0, names, &nfields );
	if( html ) {
		printf( "<tr bgcolor=FFFFEC>\n" );
		for( i = 0; i < nfields; i++ ) printf( "<td>%s</td>", names[i] );
		printf( "</tr>\n" );
		}
	else if( !xml && !tagvalue ) {
		for( i = 0; i < nfields; i++ ) {
			fprintf( tfp, "%s", names[i] );
			if( omitfinaldelim && i == (nfields-1));
			else fprintf( tfp, "%c", delim_char );
			}
		if( !omitfinaldelim ) fprintf( tfp, "\n" );
		}
	}

if( xml ) printf( "<database_retrieval>\n" );

/* fetch the result rows and print them.. */
while( 1 ) {

	stat = SHSQL_getrow( 0, fields, &nfields );
	if( stat == 1 ) break; /* no more rows */
	else if( stat == 7 ) { 
		fprintf( stderr, "shsql: record is locked and currently unavailable for update %s\n", errcombuf ); 
		continue; 
		}
	else if( stat > 1 ) { 
		fprintf( stderr, "shsql: error %d on SQL row retrieval %s\n", stat, errcombuf ); 
		exit( 1 ); 
		}

	for( i = 0; i < nfields; i++ ) if( strcmp( fields[i], TDH_dbnull )==0 ) fields[i] = nullrep;

	if( html ) {
		printf( "<tr bgcolor=FFFFFF>\n" );
		for( i = 0; i < nfields; i++ ) printf( "<td>%s</td>", fields[i] );
		printf( "</tr>\n" );
		}
	else if( xml ) {
		printf( "\t<row>\n" );
		for( i = 0; i < nfields; i++ ) {
			if( omitnull && ( strcmp( fields[i], TDH_dbnull )==0 || fields[i] == nullrep )) continue;
			printf( "\t\t<%s>%s</%s>\n", names[i], fields[i], names[i] );
			}
		printf( "\t</row>\n" );
		}
	else if( tagvalue ) {
		for( i = 0; i < nfields; i++ ) {
			if( omitnull && ( strcmp( fields[i], TDH_dbnull )==0 || fields[i] == nullrep )) continue;
			printf( "%s: %s\n", names[i], fields[i] );
			}
		printf( "\n" );
		}
	else if( !rowcount ) {
		for( i = 0; i < nfields; i++ ) {
			if( nxlen > i && xlen[i] > 0 ) maxfieldlen = xlen[i];
			else maxfieldlen = maxoutlen;
			if( showund[i] || delim_char == BLANK ) {  /* convert embedded space chars to underscore.. */
				for( j = 0; fields[i][j] != '\0' && j < maxfieldlen; j++ ) {
					if( isspace( (int) fields[i][j] )) fprintf( tfp, "_" );
					else fprintf( tfp, "%c", fields[i][j] );
					}
				}
			else for( j = 0; fields[i][j] != '\0' && j < maxfieldlen; j++ ) fprintf( tfp, "%c", fields[i][j] );

			if( omitfinaldelim && i == (nfields-1));
			else fprintf( tfp, "%c", delim_char );
			}
		if( !omitfinaldelim ) fprintf( tfp, "\n" );
		fflush( tfp );
		}
	}

if( xml ) printf( "</database_retrieval>\n" );

if( niceout ) {
	fclose( tfp );
	if( SHSQL_bin[0] != '\0' ) sprintf( buf, "%s/tabo -t -l %s", SHSQL_bin, tmpfilename );
	else sprintf( buf, "tabo -t -l %s", tmpfilename );
	system( buf );
	unlink( tmpfilename );
	}

if( footprint ) { sprintf( buf, "ps -p %d -o vsz -o rss >&2", getpid() ); system( buf ); }

/* get row count */
if( rowcount ) exit( SHSQL_getnrows( 0 ) );

exit( 0 );
}
