#include "stdafx.h" #include #include #include "columnst.h" #include "sesa.h" static CDatabase _db; static CString _strWorkDir; #ifndef WIN32 #define S4DLL #include 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(); }