668 lines
16 KiB
C++
Executable File
668 lines
16 KiB
C++
Executable File
#include "stdafx.h"
|
|
|
|
#include <fstream.h>
|
|
#include <io.h>
|
|
|
|
#include "columnst.h"
|
|
#include "sesa.h"
|
|
|
|
static CDatabase _db;
|
|
static CString _strWorkDir;
|
|
|
|
#ifndef WIN32
|
|
#define S4DLL
|
|
#include <d4all.h>
|
|
|
|
static CODE4 _codebase;
|
|
static DATA4 *_dbdata;
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// SESA field info
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class SESA_Field : public CObject
|
|
{
|
|
CString m_strName;
|
|
int m_nType;
|
|
|
|
CString m_strValue;
|
|
CTime m_tValue;
|
|
double m_dValue;
|
|
float m_fValue;
|
|
BOOL m_bValue;
|
|
|
|
public:
|
|
const CString& Name() const { return m_strName; }
|
|
int Type() const { return m_nType; }
|
|
|
|
CString& StrValue() { return m_strValue; }
|
|
CTime& TimeValue() { return m_tValue; }
|
|
double& DoubleValue() { return m_dValue; }
|
|
float& FloatValue() { return m_fValue; }
|
|
BOOL& BoolValue() { return m_bValue; }
|
|
|
|
SESA_Field(LPCSTR strName, int nType);
|
|
virtual ~SESA_Field() { }
|
|
};
|
|
|
|
SESA_Field::SESA_Field(LPCSTR strName, int nType)
|
|
: m_strName(strName), m_nType(nType), m_bValue(FALSE), m_dValue(0.0)
|
|
{ }
|
|
|
|
class SESA_FieldList : public CObject
|
|
{
|
|
CObList m_List;
|
|
|
|
public:
|
|
void Add(const CString& strField, int nType);
|
|
POSITION GetHeadPosition() const;
|
|
SESA_Field& GetNext(POSITION& rPosition);
|
|
SESA_Field& Find(const CString& strField);
|
|
void RemoveAll();
|
|
|
|
int GetCount() const { return m_List.GetCount(); }
|
|
|
|
virtual ~SESA_FieldList();
|
|
};
|
|
|
|
void SESA_FieldList::Add(const CString& strName, int nType)
|
|
{
|
|
SESA_Field* pField = new SESA_Field(strName, nType);
|
|
m_List.AddTail(pField);
|
|
}
|
|
|
|
POSITION SESA_FieldList::GetHeadPosition() const
|
|
{
|
|
return m_List.GetHeadPosition();
|
|
}
|
|
|
|
SESA_Field& SESA_FieldList::GetNext(POSITION& rPosition)
|
|
{
|
|
SESA_Field* pField = (SESA_Field*)m_List.GetNext(rPosition);
|
|
ASSERT(pField);
|
|
return *pField;
|
|
}
|
|
|
|
SESA_Field& SESA_FieldList::Find(const CString& strName)
|
|
{
|
|
for (POSITION pos = GetHeadPosition(); pos;)
|
|
{
|
|
SESA_Field& fld = GetNext(pos);
|
|
if (fld.Name() == strName)
|
|
return fld;
|
|
}
|
|
return SESA_Field("", 0);
|
|
}
|
|
|
|
void SESA_FieldList::RemoveAll()
|
|
{
|
|
while (!m_List.IsEmpty())
|
|
{
|
|
CObject* pField = m_List.RemoveHead();
|
|
delete pField;
|
|
}
|
|
}
|
|
|
|
SESA_FieldList::~SESA_FieldList()
|
|
{
|
|
RemoveAll();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Sesa recordset
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class SESA_Recordset : public CRecordset
|
|
{
|
|
// DECLARE_DYNAMIC(SESA_Recordset)
|
|
SESA_FieldList m_FieldList;
|
|
CStringList m_DumpList;
|
|
|
|
protected:
|
|
virtual CString GetDefaultConnect();
|
|
virtual CString GetDefaultSQL();
|
|
virtual void DoFieldExchange(CFieldExchange* pFX);
|
|
|
|
public:
|
|
BOOL Open(LPCSTR strTable);
|
|
|
|
void DumpHeader(ostream& out);
|
|
void ReadDumpList(const CString& strFile);
|
|
void DumpFields(ostream& out);
|
|
|
|
SESA_Recordset(CDatabase* pDatabase);
|
|
virtual ~SESA_Recordset() { }
|
|
};
|
|
|
|
//IMPLEMENT_DYNAMIC(SESA_Recordset, CRecordset)
|
|
|
|
CString SESA_Recordset::GetDefaultConnect()
|
|
{
|
|
return "ODBC;"; // Copied from CATALOG sample application
|
|
}
|
|
|
|
CString SESA_Recordset::GetDefaultSQL()
|
|
{
|
|
ASSERT(FALSE); // Copied from CATALOG sample application
|
|
return "!";
|
|
}
|
|
|
|
BOOL SESA_Recordset::Open(LPCSTR strTable)
|
|
{
|
|
CColumns Cols(&_db);
|
|
Cols.m_strTableNameParam = strTable;
|
|
BOOL ok = Cols.Open(CRecordset::forwardOnly, NULL, CRecordset::readOnly);
|
|
if (ok)
|
|
{
|
|
while (!Cols.IsEOF())
|
|
{
|
|
m_FieldList.Add(Cols.m_strColumnName, Cols.m_nDataType);
|
|
Cols.MoveNext();
|
|
}
|
|
RETCODE nRetCode;
|
|
AFX_SQL_SYNC(::SQLFreeStmt(Cols.m_hstmt, SQL_CLOSE));
|
|
|
|
m_nFields = m_FieldList.GetCount();
|
|
}
|
|
|
|
if (ok)
|
|
{
|
|
ok = CRecordset::Open(CRecordset::forwardOnly, strTable, CRecordset::readOnly);
|
|
if (!ok)
|
|
{
|
|
CString msg;
|
|
msg = "Impossibile aprire la tabella ";
|
|
msg += strTable;
|
|
AfxMessageBox(msg, MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
void SESA_Recordset::DoFieldExchange(CFieldExchange* pFX)
|
|
{
|
|
pFX->SetFieldType(CFieldExchange::outputColumn);
|
|
BOOL bLoad= pFX->m_nOperation == CFieldExchange::Fixup;
|
|
|
|
int nField = 1;
|
|
for (POSITION pos = m_FieldList.GetHeadPosition(); pos; nField++)
|
|
{
|
|
SESA_Field& fld = m_FieldList.GetNext(pos);
|
|
CString& val = fld.StrValue();
|
|
switch(fld.Type())
|
|
{
|
|
case SQL_BIT:
|
|
{
|
|
BOOL& b = fld.BoolValue();
|
|
RFX_Bool(pFX, fld.Name(), b);
|
|
if (bLoad)
|
|
{
|
|
if (b == FALSE ||
|
|
#ifdef WIN32
|
|
IsFieldNull(&b))
|
|
#else
|
|
IsFieldFlagNull(nField, CFieldExchange::outputColumn))
|
|
#endif
|
|
val.Empty();
|
|
else
|
|
val = "X";
|
|
}
|
|
}
|
|
break;
|
|
case SQL_CHAR:
|
|
case SQL_NUMERIC:
|
|
RFX_Text(pFX, fld.Name(), val);
|
|
break;
|
|
case SQL_DATE:
|
|
{
|
|
CTime& t = fld.TimeValue();
|
|
RFX_Date(pFX, fld.Name(), t);
|
|
if (bLoad)
|
|
{
|
|
TIMESTAMP_STRUCT* pts = (TIMESTAMP_STRUCT*)m_pvFieldProxy[nField];
|
|
if (pts->year == 0)
|
|
val.Empty();
|
|
else
|
|
{
|
|
char* buf = val.GetBuffer(16);
|
|
sprintf(buf, "%02d-%02d-%04d", pts->day, pts->month, pts->year);
|
|
val.ReleaseBuffer();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SQL_REAL:
|
|
{
|
|
float& d = fld.FloatValue();
|
|
RFX_Single(pFX, fld.Name(), d);
|
|
if (bLoad)
|
|
{
|
|
if (d == 0.0 ||
|
|
#ifdef WIN32
|
|
IsFieldNull(&d))
|
|
#else
|
|
IsFieldFlagNull(nField, CFieldExchange::outputColumn))
|
|
#endif
|
|
{
|
|
val.Empty();
|
|
}
|
|
else
|
|
{
|
|
char* buf = val.GetBuffer(32);
|
|
sprintf(buf, "%.12g", d);
|
|
val.ReleaseBuffer();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SQL_FLOAT:
|
|
case SQL_DOUBLE:
|
|
{
|
|
double& d = fld.DoubleValue();
|
|
RFX_Double(pFX, fld.Name(), d);
|
|
if (bLoad)
|
|
{
|
|
if (d == 0.0 ||
|
|
#ifdef WIN32
|
|
IsFieldNull(&d))
|
|
#else
|
|
IsFieldFlagNull(nField, CFieldExchange::outputColumn))
|
|
#endif
|
|
{
|
|
val.Empty();
|
|
}
|
|
else
|
|
{
|
|
char* buf = val.GetBuffer(32);
|
|
sprintf(buf, "%.12lg", d);
|
|
val.ReleaseBuffer();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SESA_Recordset::DumpHeader(ostream& out)
|
|
{
|
|
out << "[MAIN]" << endl
|
|
<< "TYPEFIELD=-1" << endl
|
|
<< "DECSEP=." << endl
|
|
<< "FIELDSEP=|" << endl
|
|
<< endl;
|
|
|
|
out << "[RECORD]" << endl;
|
|
int num = 0;
|
|
for (POSITION pos = m_FieldList.GetHeadPosition(); pos; num++)
|
|
{
|
|
const SESA_Field& fld = m_FieldList.GetNext(pos);
|
|
out << "NAME(" << num << ") = " << fld.Name() << endl
|
|
<< endl;
|
|
}
|
|
}
|
|
|
|
void SESA_Recordset::ReadDumpList(const CString& strFile)
|
|
{
|
|
char szField[16];
|
|
char szName[16];
|
|
char szFile[32];
|
|
|
|
// Mette .\ davanti al nome per cercare nella directory corrente,
|
|
// altrimenti lo cerca nella directory di Windows
|
|
sprintf(szFile, ".\\%s", strFile);
|
|
|
|
for (int num = 0; ; num++)
|
|
{
|
|
sprintf(szField, "NAME(%d)", num);
|
|
GetPrivateProfileString("RECORD", szField, "", szName, sizeof(szName), szFile);
|
|
if (*szName)
|
|
m_DumpList.AddTail(szName);
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SESA_Recordset::DumpFields(ostream& out)
|
|
{
|
|
if (m_DumpList.IsEmpty())
|
|
{
|
|
int num = 0;
|
|
for (POSITION pos = m_FieldList.GetHeadPosition(); pos; num++)
|
|
{
|
|
SESA_Field& fld = m_FieldList.GetNext(pos);
|
|
if (num) out << '|';
|
|
out << fld.StrValue();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int num = 0;
|
|
for (POSITION npos = m_DumpList.GetHeadPosition(); npos; num++)
|
|
{
|
|
CString& strName = m_DumpList.GetNext(npos);
|
|
SESA_Field& fld = m_FieldList.Find(strName);
|
|
if (num) out << '|';
|
|
out << fld.StrValue();
|
|
}
|
|
}
|
|
|
|
out << endl;
|
|
}
|
|
|
|
|
|
SESA_Recordset::SESA_Recordset(CDatabase* pDatabase)
|
|
: CRecordset(pDatabase)
|
|
{ }
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// SESA functions
|
|
///////////////////////////////////////////////////////////
|
|
|
|
inline BOOL is_space(char c) { return c >= '\t' && c <= ' '; }
|
|
|
|
static BOOL UpdateODBCIni(LPCSTR szEntry, LPCSTR szDefault, BOOL bForce = FALSE)
|
|
{
|
|
BOOL bWrite = bForce;
|
|
|
|
if (!bForce)
|
|
{
|
|
char szBuffer[80];
|
|
::GetPrivateProfileString("SIGLAPP", szEntry, "", szBuffer, sizeof(szBuffer), "odbc.ini");
|
|
bWrite = *szBuffer == '\0';
|
|
}
|
|
|
|
if (bWrite)
|
|
::WritePrivateProfileString("SIGLAPP", szEntry, szDefault, "odbc.ini");
|
|
|
|
return bWrite;
|
|
}
|
|
|
|
BOOL SESA_OpenDatabase(const char* lpszDSN, const char* lpszConnect)
|
|
{
|
|
if (lpszDSN == NULL || *lpszDSN == '\0')
|
|
lpszDSN = "SIGLAPP";
|
|
if (lpszConnect == NULL || *lpszConnect == '\0')
|
|
lpszConnect = "ODBC;"; //UID=sa;PWD=";
|
|
|
|
BOOL ok;
|
|
TRY
|
|
{
|
|
// DataSrc Excl ReadOnly ConnectString
|
|
ok = _db.Open(lpszDSN, FALSE, TRUE, lpszConnect);
|
|
if (ok)
|
|
_db.m_bStripTrailingSpaces = TRUE;
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
ok = FALSE;
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
if (!ok)
|
|
{
|
|
CString msg;
|
|
msg = "Impossibile connettersi al database ";
|
|
msg += lpszDSN;
|
|
msg += " usando ";
|
|
msg += lpszConnect;
|
|
AfxMessageBox(msg, MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
BOOL SESA_CloseDatabase()
|
|
{
|
|
if (_db.IsOpen())
|
|
_db.Close();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL SESA_DumpTableODBC(const char* lpszTableName)
|
|
{
|
|
const BOOL bWasOpen = _db.IsOpen();
|
|
if (!bWasOpen)
|
|
{
|
|
BOOL bOk = SESA_OpenDatabase();
|
|
if (!bOk)
|
|
return FALSE;
|
|
}
|
|
|
|
SESA_Recordset rs(&_db);
|
|
BOOL ok = rs.Open(lpszTableName);
|
|
if (ok)
|
|
{
|
|
CString strName = _strWorkDir;
|
|
strName += lpszTableName;
|
|
strName += ".ini";
|
|
|
|
if (access(strName, 0x00) == 0)
|
|
{
|
|
rs.ReadDumpList(strName);
|
|
}
|
|
else
|
|
{
|
|
ofstream out(strName);
|
|
rs.DumpHeader(out);
|
|
}
|
|
|
|
strName = _strWorkDir;
|
|
strName += lpszTableName;
|
|
strName += ".txt";
|
|
ofstream out(strName);
|
|
while (!rs.IsEOF())
|
|
{
|
|
rs.DumpFields(out);
|
|
rs.MoveNext();
|
|
}
|
|
|
|
RETCODE nRetCode;
|
|
AFX_SQL_SYNC(::SQLFreeStmt(rs.m_hstmt, SQL_CLOSE));
|
|
}
|
|
else
|
|
{
|
|
CString msg;
|
|
msg = "Impossibile aprire la tabella ";
|
|
msg += lpszTableName;
|
|
AfxMessageBox(msg, MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
|
|
if (!bWasOpen)
|
|
SESA_CloseDatabase();
|
|
|
|
return ok;
|
|
}
|
|
|
|
BOOL SESA_DumpTableCODEBASE(const char* SIGLAPP, const char* lpszTableName)
|
|
{
|
|
BOOL ok = TRUE;
|
|
#ifndef WIN32
|
|
CString filename;
|
|
CString msg;
|
|
|
|
d4init(&_codebase);
|
|
_dbdata = NULL;
|
|
_codebase.read_lock=0;
|
|
_codebase.default_unique_error=e4unique;
|
|
_codebase.safety=0;
|
|
_codebase.lock_attempts=1;
|
|
u4ncpy(_codebase.date_format,"CCYYMMDD",sizeof(_codebase.date_format));
|
|
|
|
filename = SIGLAPP;
|
|
if (filename.Right(1) != "\\" && filename.Right(1) != "/")
|
|
filename += "\\";
|
|
filename += lpszTableName;
|
|
_codebase.error_code=0;
|
|
_dbdata=d4open(&_codebase,(char*)(const char*)filename);
|
|
if (_dbdata != NULL)
|
|
{
|
|
CString strName = _strWorkDir;
|
|
CString fld_name,fld_val;
|
|
CStringArray field_list;
|
|
strName += lpszTableName;
|
|
strName += ".ini";
|
|
|
|
if (access(strName, 0x00) == 0)
|
|
{
|
|
// Legge la lista dei campi dal .ini se esiste gia'
|
|
|
|
char szField[16];
|
|
char szName[16];
|
|
char szFile[32];
|
|
|
|
// Mette .\ davanti al nome per cercare nella directory corrente,
|
|
// altrimenti lo cerca nella directory di Windows
|
|
sprintf(szFile, ".\\%s", strName);
|
|
|
|
for (int num = 0; ; num++)
|
|
{
|
|
sprintf(szField, "NAME(%d)", num);
|
|
GetPrivateProfileString("RECORD", szField, "", szName, sizeof(szName), szFile);
|
|
if (*szName)
|
|
field_list.Add(szName);
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Scarica il tracciato dei campi
|
|
ofstream out(strName);
|
|
out << "[MAIN]" << endl
|
|
<< "TYPEFIELD=-1" << endl
|
|
<< "DECSEP=." << endl
|
|
<< "FIELDSEP=|" << endl
|
|
<< endl;
|
|
|
|
out << "[RECORD]" << endl;
|
|
FIELD4INFO *field_info = d4field_info(_dbdata);
|
|
if (field_info != NULL)
|
|
{
|
|
const int num_fields = d4num_fields(_dbdata);
|
|
for (int num=0; num < num_fields; num++)
|
|
{
|
|
out << "NAME(" << num << ") = " << field_info[num].name << endl
|
|
<< endl;
|
|
field_list.Add(field_info[num].name);
|
|
}
|
|
u4free(field_info);
|
|
}
|
|
else
|
|
{
|
|
msg = "Impossibile reperire informazioni sulla testata del file";
|
|
AfxMessageBox(msg, MB_OK | MB_ICONEXCLAMATION);
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
|
|
if (ok)
|
|
{
|
|
strName = _strWorkDir;
|
|
strName += lpszTableName;
|
|
strName += ".txt";
|
|
ofstream out(strName);
|
|
d4top(_dbdata); // No tag is required
|
|
while (!d4eof(_dbdata) && ok)
|
|
{
|
|
if (!d4deleted(_dbdata)) // Dump only undeleted records
|
|
{
|
|
const int items = field_list.GetSize();
|
|
for (int num = 0; num < items && ok; num++)
|
|
{
|
|
fld_name = field_list.GetAt(num);
|
|
if (num)
|
|
out << '|';
|
|
FIELD4* fldfld = d4field(_dbdata,(char*)(const char*)fld_name);
|
|
if (fldfld != NULL)
|
|
{
|
|
fld_val = f4str(fldfld);
|
|
char * v = fld_val.GetBuffer(80);
|
|
// Trims leading & trailing spaces
|
|
{
|
|
char* last = v;
|
|
|
|
// Salta spazi iniziali
|
|
for (const char* s = v; *s && is_space(*s); s++);
|
|
|
|
// Copia stringa
|
|
for(char* c = v; *s; s++)
|
|
{
|
|
*c++ = *s;
|
|
if (!is_space(*s)) last = c;
|
|
}
|
|
// Elimina spazi finali
|
|
*last = '\0';
|
|
}
|
|
out << v;
|
|
fld_val.ReleaseBuffer();
|
|
}
|
|
else
|
|
{
|
|
msg = "Impossibile reperire il campo ";
|
|
msg += fld_val;
|
|
AfxMessageBox(msg, MB_OK | MB_ICONEXCLAMATION);
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
out << endl;
|
|
}
|
|
d4skip(_dbdata,1L); // Skip next
|
|
}
|
|
}
|
|
|
|
d4close(_dbdata);
|
|
}
|
|
else
|
|
{
|
|
msg = "Impossibile aprire il file ";
|
|
msg += filename;
|
|
AfxMessageBox(msg, MB_OK | MB_ICONEXCLAMATION);
|
|
ok = FALSE;
|
|
}
|
|
|
|
d4init_undo(&_codebase);
|
|
|
|
#endif
|
|
return ok;
|
|
}
|
|
|
|
BOOL SESA_DumpTable(const char* lpszTableName)
|
|
{
|
|
char szBuffer[80];
|
|
::GetPrivateProfileString("SIGLAPP",
|
|
#ifndef WIN32
|
|
"Driver",
|
|
#else
|
|
"Driver32",
|
|
#endif
|
|
"", szBuffer, sizeof(szBuffer), "odbc.ini");
|
|
|
|
if (*szBuffer == '\0' || !SESA_DumpTableODBC(lpszTableName))
|
|
{
|
|
const char *SIGLAPP = getenv("SPPROOT");
|
|
if (SIGLAPP)
|
|
return SESA_DumpTableCODEBASE(SIGLAPP, lpszTableName);
|
|
else
|
|
{
|
|
AfxMessageBox("Impossibile trovare la variabile d'ambiente SPPROOT", MB_OK | MB_ICONEXCLAMATION);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL SESA_WorkDir(const char* strDir)
|
|
{
|
|
_strWorkDir = strDir;
|
|
_strWorkDir = _strWorkDir.SpanExcluding(" ");
|
|
const char& last = _strWorkDir[_strWorkDir.GetLength()-1];
|
|
if (last != '\\' && last != '/')
|
|
_strWorkDir += "\\";
|
|
return !_strWorkDir.IsEmpty();
|
|
}
|