2004-05-07 10:25:51 +00:00
# include "../xvaga/incstr.h"
2005-02-17 18:13:12 +00:00
# include <applicat.h>
2008-10-07 09:02:41 +00:00
# include <codeb.h>
2010-03-02 11:23:20 +00:00
# include <colors.h>
# include <dongle.h>
2005-02-17 18:13:12 +00:00
# include <modaut.h>
2004-05-07 10:25:51 +00:00
# include <progind.h>
# include <recset.h>
# include <relation.h>
# include <utility.h>
# include <xml.h>
# include <statbar.h>
///////////////////////////////////////////////////////////
// Utility
///////////////////////////////////////////////////////////
static bool is_numeric ( const char * str )
{
2008-06-11 11:19:53 +00:00
if ( str = = NULL | | * str = = ' \0 ' | | ( * str = = ' 0 ' & & isdigit ( str [ 1 ] ) ) )
2004-05-07 10:25:51 +00:00
return false ; // Se comincia per zero va preservato!
if ( * str = = ' - ' )
{
str + + ;
if ( * str < = ' ' )
return false ;
}
while ( * str )
{
2008-04-08 12:55:06 +00:00
if ( strchr ( " 0123456789., " , * str ) = = NULL )
2004-05-07 10:25:51 +00:00
return false ;
str + + ;
}
return true ;
}
2008-04-04 16:04:15 +00:00
static void num_reformat ( TString & val )
{
xvt_str_number_format ( val . get_buffer ( ) , val . size ( ) ) ;
const int comma = val . find ( ' , ' ) ;
const int point = val . find ( ' . ' ) ;
if ( comma > = 0 & & comma < point )
val . strip ( " , " ) ; else
if ( point > = 0 & & point < comma )
val . strip ( " . " ) ;
}
2004-05-07 10:25:51 +00:00
///////////////////////////////////////////////////////////
// TRecordset
///////////////////////////////////////////////////////////
const TString & TRecordset : : query_text ( ) const
{
return EMPTY_STRING ;
}
const TToken_string & TRecordset : : sheet_head ( ) const
{
TToken_string head ;
TToken_string tablefield ( 32 , ' . ' ) ;
2008-06-11 11:19:53 +00:00
const unsigned int cols = columns ( ) ;
for ( unsigned int c = 0 ; c < cols ; c + + )
2004-05-07 10:25:51 +00:00
{
const TRecordset_column_info & ci = column_info ( c ) ;
tablefield = ci . _name ;
int maxlen = 0 ;
FOR_EACH_TOKEN ( tablefield , tok )
{
if ( maxlen = = 0 )
head . add ( tok ) ;
else
head < < ' \n ' < < tok ;
const int len = strlen ( tok ) ;
if ( len > maxlen )
maxlen = len ;
}
head < < ' @ ' < < max ( ci . _width , maxlen ) ;
2009-10-22 10:03:55 +00:00
switch ( ci . _type )
{
case _boolfld : head < < ' C ' ; break ;
case _wordfld :
case _intfld :
case _longfld :
case _realfld : head < < ' R ' ; break ;
default : break ;
}
2004-05-07 10:25:51 +00:00
}
// Creo la stringa temporanea solo ora, altrimenti puo' essere sovrascritta!
TToken_string & h = get_tmp_string ( ) ;
h = head ;
return h ;
}
2010-03-02 11:23:20 +00:00
2004-05-07 10:25:51 +00:00
bool TRecordset : : save_as_html ( const char * path )
{
ofstream out ( path ) ;
2011-06-01 14:19:19 +00:00
if ( out . fail ( ) )
return false ;
TProgind pi ( items ( ) , TR ( " Esportazione in corso... " ) , true , true ) ;
2004-05-07 10:25:51 +00:00
out < < " <html> " < < endl ;
2010-03-02 11:23:20 +00:00
save_html_head ( out , main_app ( ) . title ( ) ) ;
2004-05-07 10:25:51 +00:00
out < < " <body> " < < endl ;
2011-06-21 14:59:49 +00:00
/* More annoyng than useful
2006-04-13 17:56:02 +00:00
TString qry ; parsed_text ( qry ) ;
2010-03-02 11:23:20 +00:00
if ( qry . full ( ) )
{
for ( int i = qry . find ( ' \n ' ) ; i > 0 ; i = qry . find ( ' \n ' , i + 1 ) )
qry . insert ( " <br/> " , i + 1 ) ;
out < < " <p><b> " < < qry < < " </b></p> " < < endl ;
2011-06-21 14:59:49 +00:00
} */
2006-04-13 17:56:02 +00:00
2010-03-02 11:23:20 +00:00
out < < " <table border= \" 1 \" > " ;
out < < " <caption> " < < main_app ( ) . title ( ) < < " </caption> " < < endl ;
2008-06-11 11:19:53 +00:00
const unsigned int cols = columns ( ) ;
2010-11-03 23:09:49 +00:00
TAttributes attr ;
if ( cols > 0 )
2004-05-07 10:25:51 +00:00
{
2010-03-02 11:23:20 +00:00
out < < " <thead> " < < endl ;
2008-06-11 11:19:53 +00:00
for ( unsigned int c = 0 ; c < cols ; c + + )
2004-05-07 10:25:51 +00:00
{
2008-06-11 11:19:53 +00:00
const TRecordset_column_info & ci = column_info ( c ) ;
2010-03-03 10:42:46 +00:00
out < < " <col " ;
switch ( ci . _type )
{
case _intfld :
case _longfld :
case _realfld : out < < " align= \" right \" " ; break ;
case _boolfld : out < < " align= \" center \" " ; break ;
2011-06-21 14:59:49 +00:00
default : out < < " style= \" mso-number-format: \\ @ \" " ; break ; // Stringa!
2010-03-03 10:42:46 +00:00
}
out < < " /> " < < endl ;
2010-03-02 11:23:20 +00:00
}
2010-03-03 10:42:46 +00:00
TXmlItem tr ; tr . SetTag ( " tr " ) ;
tr . SetColorAttr ( " bgcolor " , BTN_BACK_COLOR ) ;
tr . Write ( out , 2 ) ;
out < < endl ;
2010-03-02 11:23:20 +00:00
for ( unsigned int c = 0 ; c < cols ; c + + )
{
const TRecordset_column_info & ci = column_info ( c ) ;
TToken_string header ( ci . _name , ' \n ' ) ;
2008-06-11 11:19:53 +00:00
TString str ;
FOR_EACH_TOKEN ( header , tok )
{
if ( str . not_empty ( ) )
str < < " <br/> " ;
str < < tok ;
}
2010-11-03 23:09:49 +00:00
if ( get_attr ( c , attr , true ) )
2011-03-14 11:34:20 +00:00
out < < " <th style= \" color : # " < < format ( " %06x " , attr . get_foreground ( ) & 0xFFFFFF )
< < " ; background-color : # " < < format ( " %06x " , attr . get_background ( ) & 0xFFFFFF ) < < " \" > " ;
2010-11-03 23:09:49 +00:00
else
out < < " <th> " ;
out < < str < < " </th> " < < endl ;
2004-05-07 10:25:51 +00:00
}
2010-03-02 11:23:20 +00:00
out < < " </tr> " < < endl ;
2008-06-11 11:19:53 +00:00
out < < " </thead> " < < endl ;
2004-05-07 10:25:51 +00:00
}
2010-03-02 11:23:20 +00:00
out < < " <tbody> " < < endl ;
2004-05-07 10:25:51 +00:00
TString val ;
2007-03-06 16:37:44 +00:00
for ( bool ok = move_first ( ) ; ok ; ok = move_next ( ) )
2004-05-07 10:25:51 +00:00
{
2007-03-06 16:37:44 +00:00
if ( ! pi . addstatus ( 1 ) )
2004-05-07 10:25:51 +00:00
break ;
2010-03-03 10:42:46 +00:00
2010-03-02 11:23:20 +00:00
out < < " <tr> " < < endl ;
2008-06-11 11:19:53 +00:00
for ( unsigned int c = 0 ; c < cols ; c + + )
2004-05-07 10:25:51 +00:00
{
const TRecordset_column_info & ci = column_info ( c ) ;
2010-11-03 00:58:07 +00:00
if ( get_attr ( c , attr ) )
2011-03-14 11:34:20 +00:00
out < < " <td style= \" color : # " < < format ( " %06x " , attr . get_foreground ( ) & 0xFFFFFF )
< < " ; background-color : # " < < format ( " %06x " , attr . get_background ( ) & 0xFFFFFF ) < < " \" > " ;
2010-11-03 00:58:07 +00:00
else
2010-03-02 11:23:20 +00:00
out < < " <td> " ;
2010-03-03 10:42:46 +00:00
switch ( ci . _type )
2010-03-02 11:23:20 +00:00
{
2010-03-03 10:42:46 +00:00
case _intfld :
case _longfld :
{
2011-03-14 11:34:20 +00:00
const TVariant & var = get ( c ) ;
const long r = var . as_int ( ) ;
2010-03-02 11:23:20 +00:00
val . cut ( 0 ) ;
2010-03-03 10:42:46 +00:00
if ( r ! = 0 )
val < < r ;
2010-11-03 00:58:07 +00:00
else
2011-03-14 11:34:20 +00:00
var . as_string ( val ) ;
2010-03-03 10:42:46 +00:00
}
break ;
case _realfld :
{
2010-11-03 00:58:07 +00:00
get ( c ) . as_string ( val ) ;
2011-03-15 09:12:23 +00:00
if ( val . full ( ) & & real : : is_real ( val ) )
2010-11-03 00:58:07 +00:00
{
const real r ( val ) ;
2011-03-15 09:12:23 +00:00
if ( r . is_zero ( ) ) //elimina gli '0' dalle celle vuote in excel, rendendo leggibile il file excel
val . cut ( 0 ) ;
else
val = r . stringe ( ) ;
2010-11-03 00:58:07 +00:00
}
2010-03-03 10:42:46 +00:00
}
break ;
default :
get ( c ) . as_string ( val ) ;
break ;
2010-03-02 11:23:20 +00:00
}
if ( val . full ( ) )
2004-05-07 10:25:51 +00:00
{
val . rtrim ( ) ;
out < < val ;
}
2010-03-02 11:23:20 +00:00
out < < " </td> " < < endl ;
2004-05-07 10:25:51 +00:00
}
2010-03-02 11:23:20 +00:00
out < < " </tr> " < < endl ;
2004-05-07 10:25:51 +00:00
}
2010-03-02 11:23:20 +00:00
out < < " </tbody> " < < endl ;
2004-05-07 10:25:51 +00:00
out < < " </table> " < < endl ;
out < < " </body> " < < endl ;
out < < " </html> " < < endl ;
return ! pi . iscancelled ( ) ;
}
bool TRecordset : : save_as_text ( const char * path )
{
2011-06-01 14:19:19 +00:00
ofstream out ( path ) ;
if ( out . fail ( ) )
return false ;
2004-05-07 10:25:51 +00:00
TProgind pi ( items ( ) , TR ( " Esportazione in corso... " ) , true , true ) ;
TString val ;
2010-08-24 17:53:24 +00:00
const char sep = text_separator ( ) ;
const bool as400 = ( sep = = ' ' ) ;
2008-06-11 11:19:53 +00:00
const unsigned int cols = columns ( ) ;
2007-03-06 16:37:44 +00:00
for ( bool ok = move_first ( ) ; ok ; ok = move_next ( ) )
2004-05-07 10:25:51 +00:00
{
2008-06-11 11:19:53 +00:00
for ( unsigned int c = 0 ; ; c + + )
2004-05-07 10:25:51 +00:00
{
2008-06-11 11:19:53 +00:00
const TVariant & var = get ( c ) ;
if ( var . is_null ( ) & & c > = cols )
break ;
2010-08-24 17:53:24 +00:00
if ( c > 0 & & ! as400 )
out < < sep ;
if ( as400 )
{
2007-03-06 16:37:44 +00:00
var . as_string ( val ) ;
2010-08-24 17:53:24 +00:00
if ( var . type ( ) = = _realfld | | ( cols = = 0 & & is_numeric ( val ) ) )
{
num_reformat ( val ) ;
val . lpad ( column_info ( c ) . _width ) ;
}
else
val . rpad ( column_info ( c ) . _width ) ;
out < < val ;
}
else
{
if ( ! var . is_empty ( ) )
{
var . as_string ( val ) ;
val . rtrim ( ) ;
if ( val . find ( ' \n ' ) > = 0 | | val . find ( ' \t ' ) > = 0 )
out < < unesc ( val ) ; // Evitiamo doppi separatori di campo e record
else
{
if ( var . type ( ) = = _realfld | | ( cols = = 0 & & is_numeric ( val ) ) )
num_reformat ( val ) ;
out < < val ;
}
}
2004-05-07 10:25:51 +00:00
}
}
out < < endl ;
2007-03-06 16:37:44 +00:00
if ( ! pi . addstatus ( 1 ) )
2004-05-07 10:25:51 +00:00
break ;
}
return ! pi . iscancelled ( ) ;
}
bool TRecordset : : save_as_campo ( const char * path )
{
ofstream out ( path ) ;
2011-06-01 14:19:19 +00:00
if ( out . fail ( ) )
return false ;
2004-05-07 10:25:51 +00:00
2011-06-01 14:19:19 +00:00
TProgind pi ( items ( ) , TR ( " Esportazione in corso... " ) , true , true ) ;
2004-05-07 10:25:51 +00:00
out < < " [Head] " < < endl ;
out < < " Version=0 " ;
2008-06-11 11:19:53 +00:00
const unsigned int cols = columns ( ) ;
for ( unsigned int c = 0 ; c < cols ; c + + )
2004-05-07 10:25:51 +00:00
{
const TRecordset_column_info & ci = column_info ( c ) ;
if ( ( c % 8 ) = = 0 )
out < < endl < < " Fields= " ;
else
out < < ' | ' ;
out < < ci . _name ;
}
out < < endl < < endl < < " [Data] " < < endl ;
TString val ;
2007-03-06 16:37:44 +00:00
for ( bool ok = move_first ( ) ; ok ; ok = move_next ( ) )
2004-05-07 10:25:51 +00:00
{
2008-06-11 11:19:53 +00:00
for ( unsigned int c = 0 ; ; c + + )
2004-05-07 10:25:51 +00:00
{
2008-06-11 11:19:53 +00:00
const TVariant & var = get ( c ) ;
if ( var . is_null ( ) & & c > = cols )
break ;
2004-05-07 10:25:51 +00:00
if ( c > 0 )
out < < ' | ' ;
2007-03-06 16:37:44 +00:00
if ( ! var . is_empty ( ) )
2004-05-07 10:25:51 +00:00
{
2007-03-06 16:37:44 +00:00
var . as_string ( val ) ;
if ( var . type ( ) = = _alfafld )
{
val . rtrim ( ) ;
val . replace ( ' | ' , SAFE_PIPE_CHR ) ; // Evitiamo doppi separatori di campo
if ( val . find ( ' \n ' ) > = 0 ) // Evitiamo doppi separatori di record
out < < unesc ( val ) ;
else
out < < val ;
}
else
out < < val ;
2004-05-07 10:25:51 +00:00
}
}
out < < endl ;
2007-03-06 16:37:44 +00:00
if ( ! pi . addstatus ( 1 ) )
2004-05-07 10:25:51 +00:00
break ;
}
return ! pi . iscancelled ( ) ;
}
2007-03-07 13:49:11 +00:00
bool TRecordset : : save_as_dbf ( const char * table , int mode )
{
char volume [ _MAX_DRIVE ] ;
char dirname [ _MAX_PATH ] ;
char name [ _MAX_FNAME ] ;
char ext [ _MAX_EXT ] ;
xvt_fsys_parse_pathname ( table , volume , dirname , name , ext , NULL ) ;
const int logicnum = table2logic ( name ) ;
if ( mode = = 0x0 )
mode = 0x1 ;
if ( mode & 0x4 )
{
if ( logicnum > = LF_USER & & * dirname = = ' \0 ' )
{
TSystemisamfile isam ( logicnum ) ;
if ( isam . zap ( ) ! = NOERR )
return error_box ( TR ( " Impossibile cancellare il file '%s' " ) , table ) ;
}
else
{
TFilename n ;
n = volume ; n . add ( dirname ) ; n . add ( name ) ; n . ext ( " * " ) ;
TString_array files ; list_files ( n , files ) ;
FOR_EACH_ARRAY_ROW ( files , f , row )
2008-05-15 14:59:21 +00:00
xvt_fsys_remove_file ( * row ) ;
2007-03-07 13:49:11 +00:00
}
mode = 0x1 ;
}
TLocalisamfile * pisam = NULL ;
if ( logicnum > = LF_USER )
{
if ( * dirname )
pisam = new TIsamtempfile ( logicnum , table ) ;
else
pisam = new TLocalisamfile ( logicnum ) ;
}
if ( pisam = = NULL )
return error_box ( " Impossibile creare il file %s " , table ) ;
TLocalisamfile & isam = * pisam ;
TProgind pi ( items ( ) , TR ( " Esportazione in corso... " ) ) ;
TRectype & rec = isam . curr ( ) ;
TString_array names ;
int valid = 0 ;
for ( unsigned int j = 0 ; j < columns ( ) ; j + + )
{
const TVariant & var = get ( j ) ;
const TString & name = column_info ( j ) . _name ;
if ( rec . exist ( name ) )
{
names . add ( name ) ;
valid + + ;
}
else
names . add ( EMPTY_STRING ) ;
}
bool ok = true ;
for ( bool go = move_first ( ) ; go ; go = move_next ( ) )
{
pi . addstatus ( 1 ) ;
rec . zero ( ) ;
FOR_EACH_ARRAY_ROW ( names , j , name ) if ( name - > not_empty ( ) )
rec . put ( * name , get ( j ) . as_string ( ) ) ;
int err = NOERR ;
bool to_be_written = true ;
// Devo solo aggiornare parte dei campi?
if ( ( mode & 0x2 ) & & valid < rec . items ( ) )
{
err = isam . read ( _isequal , _lock ) ;
if ( err ! = NOERR )
rec . zero ( ) ;
FOR_EACH_ARRAY_ROW ( names , j , name ) if ( name - > not_empty ( ) )
rec . put ( * name , get ( j ) . as_string ( ) ) ;
if ( err = = NOERR )
to_be_written = isam . rewrite ( ) ! = NOERR ;
}
if ( to_be_written )
{
err = ( mode & 0x1 ) ? isam . write ( ) : isam . rewrite ( ) ;
if ( err ! = NOERR & & ( mode & 0x3 ) ! = 0 )
err = ( mode & 0x1 ) ? isam . rewrite ( ) : isam . write ( ) ;
}
if ( err ! = NOERR )
{
ok = error_box ( FR ( " Errore %d durante la scrittura del record %s " ) , err , rec . build_key ( ) ) ;
break ;
}
}
return ok ;
}
2005-12-29 12:46:33 +00:00
bool TRecordset : : save_as ( const char * path , TRecordsetExportFormat fmt , int mode )
2004-05-07 10:25:51 +00:00
{
if ( fmt = = fmt_unknown )
{
TString ext ;
xvt_fsys_parse_pathname ( path , NULL , NULL , NULL , ext . get_buffer ( ) , NULL ) ;
ext . lower ( ) ;
2010-03-03 10:42:46 +00:00
if ( ext = = " htm " | | ext = = " html " | | ext = = " xml " | | ext = = " xls " )
fmt = fmt_html ;
2010-08-24 17:53:24 +00:00
else
if ( ext = = " dbf " )
fmt = fmt_dbf ;
else
if ( ext = = " csv " )
fmt = fmt_csv ;
2004-05-07 10:25:51 +00:00
}
bool ok = false ;
switch ( fmt )
{
2010-08-24 17:53:24 +00:00
case fmt_html : ok = save_as_html ( path ) ; break ;
case fmt_campo : ok = save_as_campo ( path ) ; break ;
case fmt_dbf : ok = save_as_dbf ( path , mode ) ; break ;
case fmt_as400 : ok = save_as_as400 ( path ) ; break ;
case fmt_csv : ok = save_as_csv ( path ) ; break ;
default : ok = save_as_text ( path ) ; break ;
2004-05-07 10:25:51 +00:00
}
return ok ;
}
int TRecordset : : find_column ( const char * column_name ) const
{
2004-06-07 09:09:47 +00:00
int i ;
for ( i = columns ( ) - 1 ; i > = 0 ; i - - )
2004-05-07 10:25:51 +00:00
{
const TRecordset_column_info & info = column_info ( i ) ;
if ( info . _name = = column_name )
break ;
}
return i ;
}
2005-08-22 15:59:05 +00:00
TVariant & TRecordset : : get_tmp_var ( ) const
{
static TArray _page ; // Variants to be returned by get
static int _next_var = 0 ; // Index of next variant to be returned
if ( _next_var > = 32 )
_next_var = 0 ;
TVariant * var = ( TVariant * ) _page . objptr ( _next_var ) ;
if ( var = = NULL )
{
var = new TVariant ;
_page . add ( var , _next_var ) ;
}
_next_var + + ;
return * var ;
}
2004-05-07 10:25:51 +00:00
const TVariant & TRecordset : : get ( const char * column_name ) const
{
if ( * column_name = = ' # ' )
2004-05-27 16:00:36 +00:00
return get_var ( column_name ) ;
2004-05-07 10:25:51 +00:00
2006-12-29 14:16:28 +00:00
char * colon = ( char * ) strchr ( column_name , ' : ' ) ; //antica porcata
2004-05-07 10:25:51 +00:00
if ( colon ! = NULL )
{
* colon = ' \0 ' ;
const int i = find_column ( column_name ) ;
* colon = ' : ' ;
if ( i > = 0 )
{
const TString & str = get ( i ) . as_string ( ) ;
TString subfield ; subfield < < ( colon + 1 ) < < ' = ' ;
int s = str . find ( subfield ) ;
if ( s = = 0 | | ( s > 0 & & str [ s - 1 ] < ' ' ) )
{
s + = subfield . len ( ) ;
const int e = str . find ( ' \n ' , s ) ;
2007-03-06 16:37:44 +00:00
TVariant & var = get_tmp_var ( ) ;
2004-05-07 10:25:51 +00:00
var . set ( str . sub ( s , e ) ) ;
return var ;
}
}
}
else
{
const int i = find_column ( column_name ) ;
if ( i > = 0 )
return get ( i ) ;
}
return NULL_VARIANT ;
}
const TVariant & TRecordset : : get_var ( const char * name ) const
{
2008-03-20 17:11:59 +00:00
const TVariant * var = ( const TVariant * ) _var . objptr ( name ) ;
// Non so che variabile sia: provo con quelle di sistema
if ( var = = NULL & & * name = = ' # ' )
{
const TFixed_string n ( name ) ;
2005-03-17 18:21:37 +00:00
// Se mi accorgo che posso e voglio accedere ad un campo del recordset padre
2008-03-20 17:11:59 +00:00
if ( _parentset ! = NULL & & n . starts_with ( " #PARENT. " ) )
var = & _parentset - > get ( name + 8 ) ; // Attenzione! E' giusto usare get() e non get_var()
else
2005-05-16 23:44:23 +00:00
{
2008-03-20 17:11:59 +00:00
if ( n . starts_with ( " #RECORD. " ) )
{
const TFixed_string fn ( name + 8 ) ;
TVariant & v = get_tmp_var ( ) ;
if ( fn = = " NUMBER " )
v . set ( current_row ( ) + 1 ) ; else
if ( fn = = " LAST " )
v . set ( items ( ) ) ;
var = & v ;
}
}
2005-05-16 23:44:23 +00:00
}
2004-05-07 10:25:51 +00:00
return var ! = NULL ? * var : NULL_VARIANT ;
}
bool TRecordset : : set_var ( const char * name , const TVariant & var , bool create )
{
bool ok = false ;
TVariant * old = ( TVariant * ) _var . objptr ( name ) ;
if ( old ! = NULL )
{
* old = var ;
ok = true ;
}
else
{
if ( create )
{
2008-03-20 17:11:59 +00:00
const TFixed_string n ( name ) ;
if ( n . starts_with ( " #PARENT. " ) | | n . starts_with ( " #RECORD. " ) )
{
// Aggiungo solo il nome alla lista: niente valore!
_varnames . add ( name ) ;
}
else
{
2004-05-07 10:25:51 +00:00
_var . add ( name , var ) ;
_varnames . add ( name ) ;
2008-03-20 17:11:59 +00:00
}
2004-05-07 10:25:51 +00:00
ok = true ;
}
}
2005-02-17 18:13:12 +00:00
if ( ok )
requery ( ) ;
2004-05-07 10:25:51 +00:00
return ok ;
}
bool is_var_separator ( char c )
{
if ( isspace ( c ) )
return true ;
2007-03-06 16:37:44 +00:00
return strchr ( " <=>+-*/(,. " , c ) ! = NULL ;
2004-05-07 10:25:51 +00:00
}
// Cerca le variabili nel testo SQL:
// Una variabile comincia per # ed e' composta da soli caratteri alfanumerici.
// Prima del simbolo # e dopo il nome della variabile deve esserci un separatore o blank
void TRecordset : : find_and_reset_vars ( )
{
_var . destroy ( ) ;
_varnames . destroy ( ) ;
const TString & sql = query_text ( ) ;
int diesis = sql . find ( ' # ' ) ; // cerco il primo #
for ( ; diesis > 0 ; diesis = sql . find ( ' # ' , diesis + 1 ) ) // Cerco tutti i #
{
if ( is_var_separator ( sql [ diesis - 1 ] ) ) // Controllo che ci sia un separatore prima del #
{
int i = diesis + 1 ;
2006-07-11 13:10:51 +00:00
for ( ; sql [ i ] & & ( isalnum ( sql [ i ] ) | | strchr ( " @_.# " , sql [ i ] ) ! = NULL ) ; i + + ) ;
2004-05-07 10:25:51 +00:00
if ( i > diesis + 1 )
{
const TString & name = sql . sub ( diesis , i ) ;
set_var ( name , NULL_VARIANT , true ) ;
2007-09-17 15:33:04 +00:00
diesis = i ; //ricomincia a cercare variabili dopo la fine della variabile corrente;senza questa istruzione non possono funzionare cose tip #PARENT.#PARENT.33.CAMPO
2004-05-07 10:25:51 +00:00
}
}
}
}
void TRecordset : : parsed_text ( TString & sql ) const
{
sql = query_text ( ) ;
2005-05-16 23:44:23 +00:00
const bool is_isam = sql . starts_with ( " US " ) ;
const bool is_sql = ! is_isam ;
const char * apici = is_isam ? " \" " : " ' " ;
2007-03-07 13:49:11 +00:00
const bool vars = ( ( TRecordset * ) this ) - > ask_variables ( false ) ;
2004-05-07 10:25:51 +00:00
if ( vars ) // Se ci sono variabili faccio le sostituzioni
{
const TString_array & names = variables ( ) ;
2004-05-27 16:00:36 +00:00
TString s ;
2004-05-07 10:25:51 +00:00
FOR_EACH_ARRAY_ROW ( names , i , name ) // Scandisco tutte le variabili
{
TVariant var = get_var ( * name ) ;
int pos = sql . find ( * name ) ;
for ( ; pos > 0 ; pos = sql . find ( * name , pos + 1 ) )
{
const TString & after = sql . mid ( pos + name - > len ( ) ) ;
sql . cut ( pos ) ;
2004-05-27 16:00:36 +00:00
if ( var . type ( ) = = _datefld )
2011-01-17 14:06:40 +00:00
{
if ( var . is_empty ( ) )
s . cut ( 0 ) < < * apici < < * apici ;
else
s . format ( " %ld " , var . as_date ( ) . date2ansi ( ) ) ;
}
2004-05-27 16:00:36 +00:00
else
2004-05-28 13:48:41 +00:00
{
2004-05-27 16:00:36 +00:00
s = var . as_string ( ) ;
2005-05-16 23:44:23 +00:00
if ( is_sql ) // Raddoppia gli apici in SQL
2004-05-28 13:48:41 +00:00
{
2005-05-16 23:44:23 +00:00
for ( int i = 0 ; s [ i ] ; i + + )
{
if ( s [ i ] = = ' \' ' )
s . insert ( " ' " , i + + ) ;
}
2004-05-28 13:48:41 +00:00
}
}
2005-05-16 23:44:23 +00:00
if ( ( var . is_string ( ) & & s [ 0 ] ! = * apici & & sql . right ( 1 ) ! = apici ) | | var . is_null ( ) )
2004-05-07 10:25:51 +00:00
{
2005-05-16 23:44:23 +00:00
s . insert ( apici ) ;
s < < apici ;
2004-05-07 10:25:51 +00:00
}
sql < < s < < after ;
}
}
}
}
bool ask_variable ( const char * name , TVariant & var )
{
2004-07-28 13:22:26 +00:00
TMask m ( TR ( " Richiesta variabile " ) , 1 , 52 , 4 ) ;
2004-05-07 10:25:51 +00:00
m . add_static ( - 1 , 0 , name , 1 , 0 ) ;
m . add_string ( 101 , 0 , " " , 1 , 1 , 80 , " " , 50 ) ;
m . add_button ( DLG_OK , 0 , " " , - 12 , - 1 , 10 , 2 ) ;
m . add_button ( DLG_CANCEL , 0 , " " , - 22 , - 1 , 10 , 2 ) ;
m . set ( 101 , var . as_string ( ) ) ;
const bool ok = m . run ( ) = = K_ENTER ;
if ( ok )
{
const TString & str = m . get ( 101 ) ;
if ( is_numeric ( str ) )
var = real ( str ) ;
else
var = str ;
}
return ok ;
}
bool TRecordset : : ask_variables ( bool all )
{
const bool ok = variables ( ) . items ( ) > 0 ;
if ( ok ) // Se ci sono variabili faccio le sostituzioni
{
FOR_EACH_ARRAY_ROW ( _varnames , i , name )
{
TVariant var = get_var ( * name ) ;
if ( var . is_null ( ) | | all )
{
ask_variable ( * name , var ) ;
if ( var . is_null ( ) )
var . set ( " " ) ; // Mi serve assolutamente un valore!
set_var ( * name , var ) ;
}
}
}
return ok ;
}
2008-10-07 09:02:41 +00:00
const TString & TRecordset : : driver_version ( ) const
{ return EMPTY_STRING ; }
2010-08-24 17:53:24 +00:00
TRecordset : : TRecordset ( ) : _parentset ( NULL ) , _text_separator ( ' \t ' )
2005-02-17 18:13:12 +00:00
{ }
2004-05-07 10:25:51 +00:00
///////////////////////////////////////////////////////////
// Utility
///////////////////////////////////////////////////////////
2005-02-17 18:13:12 +00:00
static void sort_files ( TString_array & files )
2004-05-07 10:25:51 +00:00
{
2005-02-17 18:13:12 +00:00
TFilename path ;
// Trasforma i path completi in nomi senza estensione
FOR_EACH_ARRAY_ROW ( files , i , row )
{
path = * row ;
path = path . name ( ) ;
path . ext ( " " ) ;
2005-06-07 14:19:42 +00:00
path . lower ( ) ;
2005-02-17 18:13:12 +00:00
* row = path ;
}
files . sort ( ) ; // Ordina alfabeticamente
2004-05-07 10:25:51 +00:00
2005-02-17 18:13:12 +00:00
// Rimuove i files doppi proveninenti da Campo e Custom
for ( int j = files . last ( ) ; j > 0 ; j - - )
{
if ( files . row ( j ) = = files . row ( j - 1 ) )
files . destroy ( j ) ;
}
2009-03-06 12:11:03 +00:00
files . pack ( ) ;
2005-02-17 18:13:12 +00:00
}
2004-05-07 10:25:51 +00:00
2005-06-07 14:19:42 +00:00
static bool get_xml_attr ( const TString & line , const char * attr , TString & value )
{
TString80 str ; str < < ' ' < < attr < < " = \" " ;
const int pos = line . find ( str ) ;
if ( pos > = 0 )
{
const int apicia = line . find ( ' " ' , pos ) + 1 ;
const int apicic = line . find ( ' " ' , apicia ) ;
if ( apicic > apicia )
{
value = line . sub ( apicia , apicic ) ;
return true ;
}
}
2005-06-15 11:07:27 +00:00
value . cut ( 0 ) ;
2005-06-07 14:19:42 +00:00
return false ;
}
static bool get_xml_child ( const TString & line , const char * tag , TString & value )
2005-02-17 18:13:12 +00:00
{
2005-06-07 14:19:42 +00:00
TString80 str ; str < < ' < ' < < tag < < ' > ' ;
const int pos = line . find ( str ) ;
if ( pos > = 0 )
{
const int apicia = line . find ( ' > ' , pos ) + 1 ;
const int apicic = line . find ( ' < ' , apicia ) ;
if ( apicic > apicia )
{
value = line . sub ( apicia , apicic ) ;
return true ;
}
}
2005-06-15 11:07:27 +00:00
value . cut ( 0 ) ;
2005-06-07 14:19:42 +00:00
return false ;
}
2005-06-29 09:50:17 +00:00
bool list_custom_files ( const char * ext , const char * classe , TString_array & files )
2005-06-07 14:19:42 +00:00
{
TString_array lista ;
TFilename path ;
2008-03-21 09:37:21 +00:00
TWait_cursor hourglass ;
TFilename name = path . name ( ) ;
const bool wild = ( name . find ( ' * ' ) > = 0 ) | | ( name . find ( ' ? ' ) > = 0 ) ;
2005-02-17 18:13:12 +00:00
2008-03-21 09:37:21 +00:00
if ( ! wild )
name = " * " ;
2008-03-20 17:11:59 +00:00
2008-03-21 09:37:21 +00:00
// Leggo i files in custom
if ( main_app ( ) . has_module ( RSAUT ) )
{
TFilename custom = firm2dir ( - 1 ) ;
custom . add ( " custom " ) ;
if ( ! custom . exist ( ) )
xvt_fsys_mkdir ( custom ) ;
2006-04-13 17:56:02 +00:00
2008-03-21 09:37:21 +00:00
path = custom ;
path . add ( name ) ;
path . ext ( ext ) ;
}
2005-06-07 14:19:42 +00:00
list_files ( path , lista ) ;
2008-03-21 09:37:21 +00:00
path = name ; path . ext ( ext ) ; // Leggo i files in campo
list_files ( path , lista ) ;
sort_files ( lista ) ; // Ordino i files e rimuovo i doppioni
2006-04-13 17:56:02 +00:00
2005-06-29 09:50:17 +00:00
TString8 acqua ;
2005-06-07 14:19:42 +00:00
TString stringona , desc ;
2004-05-07 10:25:51 +00:00
2005-06-07 14:19:42 +00:00
FOR_EACH_ARRAY_ROW ( lista , i , row )
2004-05-07 10:25:51 +00:00
{
2005-02-17 18:13:12 +00:00
path = * row ; path . ext ( ext ) ;
2005-06-07 14:19:42 +00:00
bool ok = path . custom_path ( ) ;
if ( ok )
{
TScanner scan ( path ) ;
stringona . cut ( 0 ) ;
2008-04-08 12:55:06 +00:00
for ( int i = 0 ; i < 4 & & scan . good ( ) ; i + + ) // Leggo solo le prime righe
2005-06-07 14:19:42 +00:00
stringona < < scan . line ( ) ;
2005-06-21 11:47:01 +00:00
2005-06-29 09:50:17 +00:00
get_xml_attr ( stringona , " class " , acqua ) ;
if ( classe & & * classe )
ok = acqua = = classe ;
2008-04-08 12:55:06 +00:00
2007-09-18 10:38:15 +00:00
if ( ok )
2005-02-17 18:13:12 +00:00
{
2005-06-21 11:47:01 +00:00
get_xml_child ( stringona , " description " , desc ) ;
2005-02-17 18:13:12 +00:00
TToken_string * riga = new TToken_string ;
riga - > add ( * row ) ;
2005-06-29 09:50:17 +00:00
riga - > add ( acqua ) ;
2008-04-08 12:55:06 +00:00
riga - > add ( desc ) ;
riga - > add ( path . find ( " custom " ) > 0 ? " X " : " " ) ;
2005-06-07 14:19:42 +00:00
files . add ( riga ) ;
2005-02-17 18:13:12 +00:00
}
2004-05-07 10:25:51 +00:00
}
}
2005-06-07 14:19:42 +00:00
return ! files . empty ( ) ;
}
2007-09-18 10:38:15 +00:00
bool select_custom_file ( TFilename & path , const char * ext , const char * classe )
2005-06-07 14:19:42 +00:00
{
2009-03-06 12:11:03 +00:00
TArray_sheet sheet ( - 1 , - 1 , 78 , 20 , TR ( " Selezione " ) , HR ( " Nome@16|Classe@8|Descrizione@50|Custom " ) ) ;
2005-06-07 14:19:42 +00:00
TString_array & files = sheet . rows_array ( ) ;
2008-04-08 12:55:06 +00:00
TFilename first = path . name ( ) ; first . ext ( " " ) ; // Riga su cui posizionarsi
2007-09-18 10:38:15 +00:00
bool ok = list_custom_files ( ext , classe , files ) ;
2006-04-13 17:56:02 +00:00
2004-05-07 10:25:51 +00:00
if ( ok )
{
2008-04-08 12:55:06 +00:00
if ( first . full ( ) ) // Cerco la prima riga da selezionare se possibile
2005-08-22 15:59:05 +00:00
{
2008-04-08 12:55:06 +00:00
FOR_EACH_ARRAY_ROW ( files , i , row )
{
if ( first . compare ( row - > get ( 0 ) , - 1 , true ) = = 0 ) // Ho trovato la selezione corrente
{
sheet . select ( i ) ;
break ;
}
}
2005-08-22 15:59:05 +00:00
}
2005-06-07 14:19:42 +00:00
ok = sheet . run ( ) = = K_ENTER ;
if ( ok )
{
path = sheet . row ( - 1 ) . get ( 0 ) ;
path . ext ( ext ) ;
ok = path . custom_path ( ) ;
}
2004-05-07 10:25:51 +00:00
}
2005-06-07 14:19:42 +00:00
2004-05-07 10:25:51 +00:00
return ok ;
}
///////////////////////////////////////////////////////////
// TCursor_parser
///////////////////////////////////////////////////////////
class TCursor_parser
{
istream & _instr ;
TArray & _column ;
TString _pushed ;
TString _token ;
TRelation * _relation ;
TCursor * _cursor ;
protected :
const TString & pop ( ) ;
2005-05-16 23:44:23 +00:00
const TString & line ( ) ;
2004-05-07 10:25:51 +00:00
void push ( ) ;
void add_column_info ( const char * table , const TRectype & rec ) ;
void parse_sortexpr ( TToken_string & se ) ;
void parse_filter ( TToken_string & filter ) ;
2005-05-16 23:44:23 +00:00
void parse_select ( TToken_string & filter ) ;
2004-05-07 10:25:51 +00:00
void parse_region ( TRectype & rec ) ;
void parse_join_param ( TRelation * rel , const TString & j , int to ) ;
void parse_join ( ) ;
void parse_sortedjoin ( ) ;
public :
TRelation * get_relation ( ) { return _relation ; }
TCursor * get_cursor ( ) { return _cursor ; }
TCursor_parser ( istream & instr , TArray & column ) ;
} ;
const TString & TCursor_parser : : pop ( )
{
if ( _pushed . not_empty ( ) )
{
_token = _pushed ;
_pushed . cut ( 0 ) ;
}
else
{
2006-12-29 14:16:28 +00:00
_token . cut ( 0 ) ;
2004-06-07 09:09:47 +00:00
eatwhite ( _instr ) ;
2005-06-01 11:20:06 +00:00
char instring = ' \0 ' ;
2006-12-29 14:16:28 +00:00
while ( _instr )
2004-05-07 10:25:51 +00:00
{
2005-06-01 11:20:06 +00:00
char c ;
2004-05-07 10:25:51 +00:00
_instr . get ( c ) ;
2005-06-01 11:20:06 +00:00
if ( c = = EOF )
break ;
if ( instring > ' ' ) // Sono dentro ad una stringa
{
if ( c = = ' \n ' )
break ;
if ( c = = instring )
instring = ' \0 ' ;
_token < < c ;
}
else
{
if ( c = = ' " ' | | c = = ' \' ' )
{
instring = c ;
_token < < c ;
}
else
{
if ( isspace ( c ) )
break ;
_token < < c ;
}
}
2004-05-07 10:25:51 +00:00
}
}
return _token ;
}
2005-05-16 23:44:23 +00:00
const TString & TCursor_parser : : line ( )
{
if ( _pushed . not_empty ( ) )
return pop ( ) ;
char * buff = _token . get_buffer ( 256 ) ;
_instr . getline ( buff , _token . size ( ) ) ;
return _token ;
}
2004-05-07 10:25:51 +00:00
void TCursor_parser : : push ( )
{
CHECK ( _pushed . empty ( ) , " Repushing? " ) ;
_pushed = _token ;
}
void TCursor_parser : : add_column_info ( const char * table , const TRectype & rec )
{
for ( int i = 0 ; i < rec . items ( ) ; i + + )
{
TRecordset_column_info * info = new TRecordset_column_info ;
const char * name = rec . fieldname ( i ) ;
info - > _name < < table < < ' . ' < < name ;
info - > _type = rec . type ( name ) ;
switch ( info - > _type )
{
case _datefld : info - > _width = 10 ; break ;
case _memofld : info - > _width = 50 ; break ;
default : info - > _width = rec . length ( name ) ; break ;
}
_column . add ( info ) ;
}
}
void TCursor_parser : : parse_sortexpr ( TToken_string & se )
{
const char sep = se . separator ( ) ;
se . separator ( ' ' ) ;
_instr . getline ( se . get_buffer ( ) , se . size ( ) ) ;
2005-09-23 15:57:29 +00:00
se . strip_double_spaces ( ) ;
2004-05-07 10:25:51 +00:00
se . replace ( ' ' , sep ) ;
se . separator ( sep ) ;
2005-05-16 23:44:23 +00:00
// Trasforma i nomi dei files in numeri se necessario
if ( se . find ( ' . ' ) > 0 )
{
TToken_string fld ( 16 , ' . ' ) ;
TString16 name ;
for ( int i = 0 ; se . get ( i , fld ) ; i + + )
{
if ( ! isdigit ( fld [ 0 ] ) & & fld . find ( ' . ' ) > 0 )
{
fld . get ( 0 , name ) ;
const int num = : : table2logic ( name ) ;
if ( num ! = 0 )
{
fld . add ( num , 0 ) ;
se . add ( fld , i ) ;
}
}
}
}
2004-05-07 10:25:51 +00:00
}
void TCursor_parser : : parse_filter ( TToken_string & filter )
{
const TString & str = pop ( ) ;
while ( str . find ( ' = ' ) > 0 )
{
filter . add ( str ) ;
pop ( ) ;
}
push ( ) ;
}
2005-05-16 23:44:23 +00:00
void TCursor_parser : : parse_select ( TToken_string & filter )
{
filter = line ( ) ;
filter . trim ( ) ;
}
2004-05-07 10:25:51 +00:00
void TCursor_parser : : parse_region ( TRectype & rec )
{
TString16 field ;
2005-05-16 23:44:23 +00:00
TString80 value ;
2004-05-07 10:25:51 +00:00
while ( true )
{
const TString & ass = pop ( ) ;
const int equal = ass . find ( ' = ' ) ;
if ( equal > 0 )
{
field = ass . left ( equal ) ;
value = ass . mid ( equal + 1 ) ;
2008-10-08 10:23:29 +00:00
value . trim ( ) ;
2004-05-07 10:25:51 +00:00
if ( value [ 0 ] = = ' " ' | | value [ 0 ] = = ' \' ' )
{
value . rtrim ( 1 ) ;
value . ltrim ( 1 ) ;
}
rec . put ( field , value ) ;
}
else
break ;
}
push ( ) ;
}
void TCursor_parser : : parse_join_param ( TRelation * rel , const TString & j , int to )
{
int key = 1 ;
const TString & tok = pop ( ) ;
if ( tok . starts_with ( " KE " ) )
{
pop ( ) ;
key = atoi ( tok ) ;
}
else
push ( ) ;
int alias = 0 ;
pop ( ) ;
if ( tok . starts_with ( " AL " ) )
{
pop ( ) ;
alias = atoi ( tok ) ;
}
else
push ( ) ;
TToken_string exp ( 80 ) ;
pop ( ) ;
if ( tok = = " INTO " )
{
parse_filter ( exp ) ;
}
if ( exp . empty ( ) )
yesnofatal_box ( " JOIN senza espressioni INTO " ) ;
const int logicnum = table2logic ( j ) ;
2008-08-06 10:30:33 +00:00
switch ( logicnum )
{
case LF_TABGEN :
case LF_TABCOM :
case LF_TAB :
case LF_TABMOD :
rel - > add ( j , exp , key , to , alias ) ; // join table
break ;
default :
2004-05-07 10:25:51 +00:00
rel - > add ( logicnum , exp , key , to , alias ) ; // join file
2008-08-06 10:30:33 +00:00
break ;
}
2004-05-07 10:25:51 +00:00
TString16 tabname ;
if ( alias > 0 )
tabname < < alias < < ' @ ' ;
else
tabname = j ;
const TRectype & rec = rel - > curr ( logicnum ) ;
add_column_info ( tabname , rec ) ;
}
void TCursor_parser : : parse_join ( )
{
const TString j = pop ( ) ; // File or table
int to = 0 ;
const TString & tok = pop ( ) ;
if ( tok = = " TO " ) // TO keyword
{
pop ( ) ;
to = table2logic ( tok ) ;
}
else
push ( ) ;
parse_join_param ( _relation , j , to ) ;
}
void TCursor_parser : : parse_sortedjoin ( )
{
TToken_string filter , sortexp ;
const TString j = pop ( ) ; // File or table
const TString & tok = pop ( ) ;
if ( tok = = " BY " )
parse_sortexpr ( sortexp ) ;
else
push ( ) ;
pop ( ) ;
if ( tok . starts_with ( " FI " ) | | tok . starts_with ( " SE " ) )
{
2005-05-16 23:44:23 +00:00
parse_select ( filter ) ;
2004-05-07 10:25:51 +00:00
}
else
push ( ) ;
TRelation * sortrel = new TRelation ( table2logic ( j ) ) ;
while ( true )
{
pop ( ) ;
if ( tok . empty ( ) | | tok . starts_with ( " JO " ) )
{
break ;
}
if ( tok . starts_with ( " US " ) ) // USING keyword
{
const TString subj = pop ( ) ; // File or table
parse_join_param ( sortrel , subj , table2logic ( j ) ) ;
}
}
int to = 0 ;
pop ( ) ;
if ( tok = = " TO " ) // TO keyword
{
pop ( ) ;
to = table2logic ( tok ) ;
}
else
push ( ) ;
int key = 1 ;
pop ( ) ;
if ( tok . starts_with ( " KE " ) )
{
pop ( ) ;
key = atoi ( tok ) ;
}
else
push ( ) ;
int alias = 0 ;
pop ( ) ;
if ( tok . starts_with ( " AL " ) )
{
pop ( ) ;
alias = atoi ( tok ) ;
}
else
push ( ) ;
TToken_string exp ( 80 ) ;
if ( pop ( ) = = " INTO " )
{
pop ( ) ;
while ( tok . find ( ' = ' ) > 0 )
{
exp . add ( tok ) ;
pop ( ) ;
}
}
push ( ) ;
TSortedfile * sf = new TSortedfile ( atoi ( j ) , sortrel , sortexp , filter , key ) ;
_relation - > add ( ( TLocalisamfile * ) sf , exp , key , to , alias , false ) ; // join table
TString16 tabname = j ;
if ( alias > 0 )
tabname . cut ( 0 ) < < alias < < ' @ ' ;
add_column_info ( tabname , sf - > curr ( ) ) ;
}
TCursor_parser : : TCursor_parser ( istream & instr , TArray & col )
: _instr ( instr ) , _column ( col ) , _relation ( NULL ) , _cursor ( NULL )
{
_column . destroy ( ) ;
const TString & tok = pop ( ) ;
if ( ! tok . starts_with ( " US " ) )
push ( ) ;
pop ( ) ;
if ( tok . blank ( ) )
return ;
2009-04-07 13:53:49 +00:00
TString table ( tok ) ; table . upper ( ) ;
if ( table . ends_with ( " .DBF " ) )
{
TFilename dbf = table ;
2009-04-17 14:13:47 +00:00
if ( table [ 0 ] = = ' $ ' | | table [ 0 ] = = ' % ' )
2009-04-07 13:53:49 +00:00
{
2009-04-17 14:13:47 +00:00
if ( table [ 0 ] = = ' % ' )
dbf = firm2dir ( 0 ) ;
else
dbf = firm2dir ( prefix ( ) . get_codditta ( ) ) ;
dbf . add ( table . mid ( 1 ) ) ;
}
else
{
if ( dbf . is_relative_path ( ) )
2009-04-07 13:53:49 +00:00
{
2009-04-17 14:13:47 +00:00
if ( ! dbf . custom_path ( ) )
{
dbf . tempdir ( ) ;
dbf . add ( table ) ;
}
2009-04-07 13:53:49 +00:00
}
}
dbf . lower ( ) ;
TExternisamfile * eif = new TExternisamfile ( dbf , true ) ;
_relation = new TRelation ( eif ) ;
}
2004-06-17 09:18:30 +00:00
else
2009-04-07 13:53:49 +00:00
{
int logicnum = table2logic ( tok ) ;
if ( logicnum = = LF_MAG & & tok = = " MAG " ) // Faccio prevalere la tabella MAG sul file MAG
logicnum = LF_TAB ;
if ( logicnum = = LF_TAB | | logicnum = = LF_TABCOM | | logicnum = = LF_TABMOD )
_relation = new TRelation ( tok ) ;
else
_relation = new TRelation ( logicnum ) ;
}
2008-03-20 17:11:59 +00:00
pop ( ) ;
add_column_info ( table , _relation - > curr ( ) ) ;
2004-05-07 10:25:51 +00:00
int key = 1 ; // key number
if ( tok . starts_with ( " KE " ) )
{
pop ( ) ;
key = atoi ( tok ) ;
}
else
push ( ) ;
2005-02-17 18:13:12 +00:00
pop ( ) ;
TToken_string filter ;
if ( tok . starts_with ( " FI " ) | | tok . starts_with ( " SE " ) )
2005-05-16 23:44:23 +00:00
parse_select ( filter ) ;
2005-02-17 18:13:12 +00:00
else
push ( ) ;
2004-05-07 10:25:51 +00:00
pop ( ) ;
if ( tok . starts_with ( " BY " ) ) // "sort BY": user-defined sort
{
TToken_string ordexpr ( 256 ) ;
parse_sortexpr ( ordexpr ) ;
2005-02-17 18:13:12 +00:00
_cursor = new TSorted_cursor ( _relation , ordexpr , " " , key ) ;
2004-05-07 10:25:51 +00:00
}
else
push ( ) ;
if ( _cursor = = NULL )
_cursor = new TCursor ( _relation , " " , key ) ;
2008-10-08 10:23:29 +00:00
_relation - > lfile ( ) . zero ( ) ; // Azzera correttamente tabelle normali e di modulo!
2004-06-09 09:54:56 +00:00
TRectype rec_start ( _relation - > curr ( ) ) ;
2004-06-08 10:05:24 +00:00
TRectype rec_stop ( rec_start ) ;
2004-05-07 10:25:51 +00:00
2008-03-20 17:11:59 +00:00
TString_array fields ;
pop ( ) ;
while ( tok . starts_with ( " DI " ) )
{
pop ( ) ;
pop ( ) ;
TString field ;
if ( tok . find ( " . " ) < 0 )
field < < table < < " . " ;
field < < tok ;
fields . add ( field ) ;
pop ( ) ;
}
push ( ) ;
2004-05-07 10:25:51 +00:00
while ( true )
{
pop ( ) ;
2004-06-08 10:05:24 +00:00
if ( tok . starts_with ( " FR " ) )
parse_region ( rec_start ) ; else
if ( tok . starts_with ( " TO " ) )
parse_region ( rec_stop ) ; else
2004-05-07 10:25:51 +00:00
if ( tok . starts_with ( " JO " ) )
parse_join ( ) ; else
if ( tok . starts_with ( " SO " ) )
parse_sortedjoin ( ) ;
else
break ;
}
push ( ) ;
2004-06-08 10:05:24 +00:00
if ( ! rec_start . empty ( ) | | ! rec_stop . empty ( ) )
2005-06-01 11:20:06 +00:00
_cursor - > setregion ( rec_start , rec_stop ) ;
2005-02-17 18:13:12 +00:00
if ( ! filter . empty ( ) )
_cursor - > setfilter ( filter ) ;
2008-03-20 17:11:59 +00:00
if ( fields . items ( ) > 0 )
{
FOR_EACH_ARRAY_ITEM_BACK ( _column , i , obj )
{
TRecordset_column_info * info = ( TRecordset_column_info * ) obj ;
if ( fields . find ( info - > _name ) = = - 1 )
_column . destroy ( i , true ) ;
}
}
2004-05-07 10:25:51 +00:00
if ( _relation - > items ( ) = = 0 ) // Non ci sono anche tabelle collegate
{
FOR_EACH_ARRAY_ITEM ( _column , i , obj )
{
TRecordset_column_info * info = ( TRecordset_column_info * ) obj ;
const int arrow = info - > _name . find ( ' . ' ) ;
if ( arrow > 0 )
info - > _name = info - > _name . mid ( arrow + 1 ) ;
}
}
}
///////////////////////////////////////////////////////////
// TISAM_recordset
///////////////////////////////////////////////////////////
2006-12-13 16:22:33 +00:00
const TVariant & TISAM_recordset : : get_field ( int logic , const char * fldname ) const
2004-05-07 10:25:51 +00:00
{
2005-03-03 15:42:04 +00:00
const int idx = relation ( ) - > log2ind ( logic ) ;
if ( idx < 0 )
return NULL_VARIANT ;
2004-05-07 10:25:51 +00:00
TString80 name = fldname ;
TString16 subfield ;
int from = 1 , to = 0 ;
const int open_bracket = name . find ( ' [ ' ) ;
if ( open_bracket > 0 )
{
2008-04-08 12:55:06 +00:00
TToken_string range ( name . mid ( open_bracket + 1 ) , ' , ' ) ;
from = range . get_int ( ) ;
to = range . get_int ( ) ;
2004-05-07 10:25:51 +00:00
name . cut ( open_bracket ) ;
}
const int colon = name . find ( ' : ' ) ;
2006-07-11 13:10:51 +00:00
2004-05-07 10:25:51 +00:00
if ( colon > 0 )
{
subfield = name . mid ( colon + 1 ) ;
name . cut ( colon ) ;
}
2005-03-03 15:42:04 +00:00
const TRectype & rec = relation ( ) - > file ( idx ) . curr ( ) ;
2004-05-07 10:25:51 +00:00
const TFieldtypes ft = rec . type ( name ) ;
if ( ft = = _nullfld )
{
2009-10-22 10:03:55 +00:00
switch ( logic ) // Proviamo la magia dei campi virtuali
2004-05-07 10:25:51 +00:00
{
2009-10-22 10:03:55 +00:00
case LF_DOC : subfield = name ; name = " G1 " ; break ;
case LF_RIGHEDOC : subfield = name ; name = " RG1 " ; break ;
default : return NULL_VARIANT ;
2004-05-07 10:25:51 +00:00
}
}
TVariant & var = get_tmp_var ( ) ;
switch ( ft )
{
2009-10-22 10:03:55 +00:00
case _boolfld : var . set ( rec . get_bool ( name ) ) ; break ;
2004-05-07 10:25:51 +00:00
case _datefld : var . set ( rec . get_date ( name ) ) ; break ;
case _realfld : var . set ( rec . get_real ( name ) ) ; break ;
case _intfld :
case _longfld :
case _wordfld : var . set ( rec . get_long ( name ) ) ; break ;
2009-10-22 10:03:55 +00:00
case _intzerofld : // Non usare il convertitore degll interi
case _longzerofld : // in modo da preservare gli zeri iniziali
default : var . set ( rec . get ( name ) ) ; break ;
2004-05-07 10:25:51 +00:00
}
if ( subfield . not_empty ( ) )
{
subfield < < ' = ' ;
const TString & str = var . as_string ( ) ;
int s = str . find ( subfield ) ;
if ( s = = 0 | | ( s > 0 & & str [ s - 1 ] < ' ' ) )
{
s + = subfield . len ( ) ;
const int e = str . find ( ' \n ' , s ) ;
var . set ( str . sub ( s , e ) ) ;
}
2009-10-26 16:35:51 +00:00
else
var . set_null ( ) ;
2004-05-07 10:25:51 +00:00
}
2009-10-26 16:35:51 +00:00
if ( to > = from & & ! var . is_empty ( ) )
2004-05-07 10:25:51 +00:00
var . set ( var . as_string ( ) . sub ( from - 1 , to ) ) ;
return var ;
}
const TVariant & TISAM_recordset : : get ( size_t c ) const
{
const TRecordset_column_info * info = ( const TRecordset_column_info * ) _column . objptr ( c ) ;
if ( info ! = NULL )
{
int logic = 0 ;
const char * field = info - > _name ;
const int dot = info - > _name . find ( ' . ' ) ;
if ( dot > 0 )
{
logic = table2logic ( info - > _name . left ( dot ) ) ;
field + = dot + 1 ;
}
2006-12-13 16:22:33 +00:00
return get_field ( logic , field ) ;
2004-05-07 10:25:51 +00:00
}
return NULL_VARIANT ;
}
const TVariant & TISAM_recordset : : get ( const char * name ) const
{
2004-05-27 16:00:36 +00:00
if ( * name = = ' # ' )
return get_var ( name ) ;
2004-05-07 10:25:51 +00:00
const TFixed_string fldname ( name ) ;
int table_end = fldname . find ( ' . ' ) ;
int field_start = table_end + 1 ;
if ( table_end < 0 )
{
table_end = fldname . find ( ' - ' ) ;
if ( table_end > 0 )
field_start = table_end + 2 ;
}
int logic = 0 ;
const char * field = name ;
if ( table_end > 0 )
{
2004-06-08 13:14:06 +00:00
const TString & table = fldname . left ( table_end ) ;
logic = table2logic ( table ) ;
2004-05-07 10:25:51 +00:00
field + = field_start ;
}
2006-12-13 16:22:33 +00:00
return get_field ( logic , field ) ;
2004-05-07 10:25:51 +00:00
}
const TRecordset_column_info & TISAM_recordset : : column_info ( size_t i ) const
{
return ( const TRecordset_column_info & ) _column [ i ] ;
}
2004-05-18 13:47:49 +00:00
TCursor * TISAM_recordset : : cursor ( ) const
2004-05-07 10:25:51 +00:00
{
2007-03-06 16:37:44 +00:00
if ( _cursor = = NULL & & _use . full ( ) )
2004-05-07 10:25:51 +00:00
{
TString use ; parsed_text ( use ) ;
TPerformance_profiler prof ( " ISAM query " ) ;
TISAM_recordset * my = ( TISAM_recordset * ) this ;
2004-06-07 09:09:47 +00:00
# ifdef LINUX
string s ( use . get_buffer ( ) ) ;
istringstream instr ( s ) ;
# else
2006-12-29 14:16:28 +00:00
istrstream instr ( use . get_buffer ( ) , use . len ( ) + 1 ) ; //"barata" x aggiungere il carattere finale
2004-06-07 09:09:47 +00:00
# endif
2004-05-07 10:25:51 +00:00
TCursor_parser parser ( instr , my - > _column ) ;
my - > _relation = parser . get_relation ( ) ;
my - > _cursor = parser . get_cursor ( ) ;
if ( _cursor ! = NULL )
{
2005-06-07 14:19:42 +00:00
set_custom_filter ( * _cursor ) ;
2005-03-03 15:42:04 +00:00
const TRecnotype items = _cursor - > items ( ) ;
2006-07-11 13:10:51 +00:00
2004-05-07 10:25:51 +00:00
_cursor - > freeze ( ) ;
2005-03-03 15:42:04 +00:00
if ( items > 0 )
* _cursor = 0L ;
2004-05-07 10:25:51 +00:00
}
}
2004-05-18 13:47:49 +00:00
return _cursor ;
}
TRelation * TISAM_recordset : : relation ( ) const
{
cursor ( ) ;
return _relation ;
}
TRecnotype TISAM_recordset : : current_row ( ) const
{
TCursor * c = cursor ( ) ;
return c ! = NULL ? c - > pos ( ) : - 1 ;
}
TRecnotype TISAM_recordset : : items ( ) const
{
TCursor * c = cursor ( ) ;
2005-09-23 15:57:29 +00:00
return c ! = NULL ? c - > items ( ) : 0 ;
2004-05-07 10:25:51 +00:00
}
unsigned int TISAM_recordset : : columns ( ) const
{
2004-05-18 13:47:49 +00:00
cursor ( ) ;
2004-05-07 10:25:51 +00:00
return _column . items ( ) ;
}
bool TISAM_recordset : : move_to ( TRecnotype pos )
{
2004-05-18 13:47:49 +00:00
TCursor * c = cursor ( ) ;
2006-04-13 17:56:02 +00:00
bool ok = c ! = NULL & & pos > = 0 ;
2004-05-07 10:25:51 +00:00
if ( ok )
{
2004-05-18 13:47:49 +00:00
* c = pos ;
2006-12-13 16:22:33 +00:00
ok = pos > = 0 & & pos < c - > items ( ) ;
2004-05-07 10:25:51 +00:00
}
return ok ;
}
void TISAM_recordset : : reset ( )
{
_column . destroy ( ) ;
2007-03-06 16:37:44 +00:00
requery ( ) ;
2004-05-07 10:25:51 +00:00
}
2005-02-17 18:13:12 +00:00
void TISAM_recordset : : requery ( )
2004-05-28 13:48:41 +00:00
{
2005-02-17 18:13:12 +00:00
if ( _cursor ! = NULL )
{
delete _cursor ;
_cursor = NULL ;
}
2007-03-06 16:37:44 +00:00
if ( _relation ! = NULL )
{
delete _relation ;
_relation = NULL ;
}
2004-05-28 13:48:41 +00:00
}
2004-05-07 10:25:51 +00:00
void TISAM_recordset : : set ( const char * use )
{
reset ( ) ;
_use = use ;
find_and_reset_vars ( ) ;
}
2008-10-07 09:02:41 +00:00
const TString & TISAM_recordset : : driver_version ( ) const
{
TString & tmp = get_tmp_string ( 20 ) ;
DB_version ( tmp . get_buffer ( ) , tmp . size ( ) ) ;
return tmp ;
}
2004-05-07 10:25:51 +00:00
TISAM_recordset : : TISAM_recordset ( const char * use )
: _relation ( NULL ) , _cursor ( NULL )
{
set ( use ) ;
}
TISAM_recordset : : ~ TISAM_recordset ( )
{
2007-03-06 16:37:44 +00:00
requery ( ) ;
2004-05-07 10:25:51 +00:00
}
///////////////////////////////////////////////////////////
// TRecordset_sheet
///////////////////////////////////////////////////////////
void TRecordset_sheet : : get_row ( long r , TToken_string & row )
{
row . separator ( ' \t ' ) ;
row . cut ( 0 ) ;
if ( _query . move_to ( r ) )
{
TString str ;
2009-10-20 15:22:22 +00:00
unsigned int cols = _query . sheet_head ( ) . items ( ) ;
if ( cols = = 0 )
cols = _query . columns ( ) ;
for ( unsigned int c = 0 ; c < cols ; c + + )
2004-05-07 10:25:51 +00:00
{
_query . get ( c ) . as_string ( str ) ;
row . add ( str ) ;
}
}
}
long TRecordset_sheet : : get_items ( ) const
{
return _query . items ( ) ;
}
2007-03-06 14:41:36 +00:00
TRecordset_sheet : : TRecordset_sheet ( TRecordset & query , const char * title , byte buttons )
2011-09-22 15:24:04 +00:00
: TSheet ( - 1 , - 1 , - 2 , - 5 , title , query . sheet_head ( ) , buttons , 1 ) , _query ( query )
2004-05-07 10:25:51 +00:00
{
2007-03-06 14:41:36 +00:00
}