#include #include #include #include "date.h" #include "expr.h" #include "utility.h" #include "xml.h" class TExpr_omnia : public TExpression { enum { _date2k, _periodlastday, _recno }; static int _curr_recno; protected: virtual int parse_user_func(const char* name, int nparms) const; virtual void evaluate_user_func(int index, int nparms, TEval_stack& stack, TTypeexp type) const; public: static void set_curr_recno(int n) { _curr_recno = n; } TExpr_omnia(const char* exp) { set(exp, _strexpr); } }; int TExpr_omnia::_curr_recno = 0; int TExpr_omnia::parse_user_func(const char* name, int nparms) const { if (strcmp(name, "DATE2K") == 0) return nparms == 1 ? _date2k : -1; if (strcmp(name, "PERIODLASTDAY") == 0) return nparms == 1 ? _periodlastday : -1; if (strcmp(name, "RECNO") == 0) return nparms == 0 ? _recno : -1; return -1; } void TExpr_omnia::evaluate_user_func(int index, int nparms, TEval_stack& stack, TTypeexp type) const { switch (index) { case _date2k: // Acqua Omnia Only { TString& str = stack.peek_string(); TToken_string tok(str, '/'); const int d = tok.get_int(0); const int m = tok.get_int(); int y = tok.get_int(); if (d > 0 && m > 0 && y < 100) { y += 2000; const TDate milleniumbug(d, m, y); str = milleniumbug.string(full, '/'); } } break; case _periodlastday: // Acqua Omnia Only { TString& period = stack.peek_string(); char m1[4], m2[4]; int year = 0; sscanf(period, "%3s-%3s/%d", m1, m2, &year); const TString4 strMonth = m2; for (int month = 12; month > 0; month--) { if (strMonth.compare(itom(month), 3, true) == 0) break; } if (month > 0) { TDate day(1, month, year); day.set_end_month(); period = day.string(full, '/'); } } break; case _recno: stack.push(_curr_recno); break; default: break; } } /////////////////////////////////////////////////////////// // TTextRecord /////////////////////////////////////////////////////////// class TTextRecord : public TString_array { const TXmlItem* m_inrec; const TXmlItem* m_outrec; int m_nLines, m_nColumns; TString m_str; protected: char* GetLineBuffer(int i, int size); const TString& GetFieldValue(const TXmlItem& field) const; const TXmlItem* FindInputField(const TString& name) const; public: void SetTrc(const TXmlItem& trc); bool Read(istream& input); const TString& GetValue(const TString& name) const; const TString& Evaluate(TExpr_omnia& exp) const; TTextRecord() : m_nLines(0), m_nColumns(0) { } TTextRecord(const TXmlItem& trc) { SetTrc(trc); } }; void TTextRecord::SetTrc(const TXmlItem& trc) { const TXmlItem& input = *trc.FindFirst("Input"); m_nLines = input.GetIntAttr("Lines"); if (m_nLines <= 0) m_nLines = 1; m_nColumns = input.GetIntAttr("Columns"); m_inrec = input.FindFirst("Record"); CHECK(m_inrec, "Null input record"); m_outrec = trc.FindFirst("Output")->FindFirst("Record"); CHECK(m_outrec, "Null output record"); } char* TTextRecord::GetLineBuffer(int i, int size) { CHECKD(i >= 0 && i < m_nLines, "Line out of range ", i); CHECKD(size > 0, "Bad record size ", size); TToken_string* str = (TToken_string*)objptr(i); if (str == NULL) { str = new TToken_string(size); add(str, i); } char* buff = str->get_buffer(size); *buff = '\0'; return buff; } bool TTextRecord::Read(istream& input) { bool ok = !input.eof(); if (ok) { if (m_nLines <= 1 && m_nColumns > 0) // Record a lunghezza fissa { char* buff = GetLineBuffer(0, m_nColumns); input.read(buff, m_nColumns); buff[m_nColumns] = '\0'; ok = *buff != '\0'; } else { int size = m_nColumns; if (size <= 0) size = 1024*16; for (int i = 0; i < m_nLines; i++) { char* buff = GetLineBuffer(i, size); input.getline(buff, size); buff[size] = '\0'; } } } return ok; } const TString& TTextRecord::GetFieldValue(const TXmlItem& field) const { int y = field.GetIntAttr("Y" ) - 1; if (y < 0) y = 0; int x = field.GetIntAttr("X" ) - 1; if (x < 0) x = 0; const int l = field.GetIntAttr("Length"); TString& str = (TString&)m_str; str = row(y).mid(x, l); const TString& strTrim = field.GetAttr("Trim"); int nTrim = 2; if (strTrim.not_empty()) nTrim = atoi(strTrim); switch (nTrim) { case 0: break; case 1: str.ltrim(); break; case 2: str.rtrim(); break; default: str.trim(); break; } return str; } const TXmlItem* TTextRecord::FindInputField(const TString& name) const { for (int i = 0; i < m_inrec->GetChildren(); i++) { const TXmlItem* field = m_inrec->GetChild(i); if (field->GetAttr("Name") == name) return field; } return NULL; } const TString& TTextRecord::GetValue(const TString& name) const { const TXmlItem* f = FindInputField(name); if (f != NULL) return GetFieldValue(*f); return name; } const TString& TTextRecord::Evaluate(TExpr_omnia& exp) const { TString& str = (TString&)m_str; const int nv = exp.numvar(); if (nv > 0 || strchr(exp.string(), '(') != NULL) { for (int i = nv-1; i >= 0; i--) { const TString& name = exp.varname(i); const TString& value = GetValue(name); exp.setvar(i, value); } str = exp.as_string(); } else str = exp.string(); // Nessuna variabile = costante! return str; } /////////////////////////////////////////////////////////// // TScrittore /////////////////////////////////////////////////////////// class TScrittore : public TObject { private: ofstream* _out; int _recno; public: ofstream& OutStream() { return *_out; } int inc_recno() { _recno++; return _recno; } int recno() const { return _recno; } TScrittore(const char* name) : _recno(0) { _out = new ofstream(name); } virtual~ TScrittore() { delete _out; } }; /////////////////////////////////////////////////////////// // TCasaEditrice /////////////////////////////////////////////////////////// class TCasaEditrice : public TAssoc_array { const TXmlItem& m_trc; TString m_strPrefix, m_strExt; TExpr_omnia* m_exprSuffix; TString m_strRecHead, m_strRecFoot, m_strFldHead, m_strFldFoot; protected: TScrittore& Scrittore(const char* suffix); void WriteHeader(ostream& output) const; void WriteFooter(ostream& output) const; public: const TString& RecHead() const { return m_strRecHead; } const TString& RecFoot() const { return m_strRecFoot; } const TString& FldHead() const { return m_strFldHead; } const TString& FldFoot() const { return m_strFldFoot; } ofstream& ChooseOutput(const TTextRecord& rec); TCasaEditrice(const TXmlItem& trc, const char* name); virtual ~TCasaEditrice(); }; void TCasaEditrice::WriteHeader(ostream& output) const { TXmlItem* pOutput = m_trc.FindFirst("Output"); CHECK(pOutput, "NULL output file"); TXmlItem* pHeader = pOutput->FindFirst("Header"); if (pHeader != NULL) { TString strHeader; pHeader->GetEnclosedText(strHeader); if (strHeader[0] == '"') { strHeader.rtrim(1); strHeader.ltrim(1); } strHeader = esc(strHeader); output << strHeader; if (pHeader->GetAttr("Auto") == "1") { TXmlItem* pRecOut = pOutput->FindFirst("Record"); CHECK(pRecOut, "NULL output record"); output << m_strRecHead; for (int i = 0; i < pRecOut->GetChildren(); i++) { const TXmlItem* outfield = pRecOut->GetChild(i); output << m_strFldHead; output << outfield->GetAttr("Name"); output << m_strFldFoot; } output << m_strRecFoot; } } } void TCasaEditrice::WriteFooter(ostream& output) const { TXmlItem* pOutput = m_trc.FindFirst("Output"); CHECK(pOutput, "NULL output file"); TXmlItem* pFooter = pOutput->FindFirst("Footer"); if (pFooter != NULL) { TString strFooter; pFooter->GetEnclosedText(strFooter); if (strFooter[0] == '"') { strFooter.rtrim(1); strFooter.ltrim(1); } strFooter = esc(strFooter); output << strFooter; } } TScrittore& TCasaEditrice::Scrittore(const char* suffix) { TScrittore* s = (TScrittore*)objptr(suffix); if (s == NULL) { TFilename n; n << m_strPrefix << suffix; if (m_strExt.not_empty()) n << '.' << m_strExt; s = new TScrittore(n); add(suffix, s); WriteHeader(s->OutStream()); } return *s; } ofstream& TCasaEditrice::ChooseOutput(const TTextRecord& rec) { TString16 strSuffix; if (m_exprSuffix != NULL) strSuffix = rec.Evaluate(*m_exprSuffix); TScrittore& s = Scrittore(strSuffix); TExpr_omnia::set_curr_recno(s.inc_recno()); return s.OutStream(); } TCasaEditrice::TCasaEditrice(const TXmlItem& trc, const char* name) : m_trc(trc), m_exprSuffix(NULL) { const TFilename path(name); const int dot = path.rfind('.'); if (dot >= 0) { m_strPrefix = path.left(dot); m_strExt = path.mid(dot+1); } else { m_strPrefix = path; m_strExt.cut(0); } const TXmlItem* pOutFile = m_trc.FindFirst("Output"); CHECK(pOutFile, "NULL Output tag"); const TString strSuffix = pOutFile->GetAttr("Suffix"); if (strSuffix.not_empty()) m_exprSuffix = new TExpr_omnia(strSuffix); TXmlItem* pRecOut = pOutFile->FindFirst("Record"); CHECK(pRecOut, "NULL output record"); m_strRecHead = esc(pRecOut->GetAttr("RecHead")); m_strRecFoot = esc(pRecOut->GetAttr("RecFoot")); m_strFldHead = esc(pRecOut->GetAttr("FldHead")); m_strFldFoot = esc(pRecOut->GetAttr("FldFoot")); } TCasaEditrice::~TCasaEditrice() { TAssoc_array& myself = *this; FOR_EACH_ASSOC_OBJECT(myself, h, k, o) { TScrittore* s = (TScrittore*)o; WriteFooter(s->OutStream()); } } /////////////////////////////////////////////////////////// // TLettore /////////////////////////////////////////////////////////// class TLettore : public TObject { TXmlItem _trc; TTextRecord _curr; TArray _expressions; protected: bool load_trc(const char* trc); const TString& get_field(const TXmlItem& field) const; const TXmlItem* find_field(const TXmlItem& record, const TString& name) const; const TString& evaluate(int index) const; public: int convert(const TFilename& src, const TFilename& trc, const TFilename& dst); int convert(const char* cmd); }; bool TLettore::load_trc(const char* t) { const TFilename trc = t; bool ok = trc.exist(); if (ok) { ifstream in(trc); ok = _trc.Read(in); } _curr.destroy(); // reset line sizes return ok; } const TString& TLettore::evaluate(int index) const { TExpr_omnia& exp = (TExpr_omnia&)_expressions[index]; return _curr.Evaluate(exp); } int TLettore::convert(const TFilename& src, const TFilename& trc, const TFilename& dst) { if (!src.exist()) { error_box("Non esiste il file di input\n%s", (const char*)src); return 1; } if (!load_trc(trc)) { error_box("Non esiste il tracciato record\n%s", (const char*)trc); return 2; } if (dst.blank()) { error_box("File di output non valido:\n%s", (const char*)dst); return 3; } const TXmlItem* infile = _trc.FindFirst("Input"); const TXmlItem* outfile = _trc.FindFirst("Output"); if (infile == NULL || outfile == NULL) { error_box("Tracciato record non valido:\nNon esiste il tag o "); return 4; } const TXmlItem* recin = infile->FindFirst("Record"); const TXmlItem* recout = outfile->FindFirst("Record"); if (recin == NULL || recout == NULL) { error_box("Tracciato record non valido:\nNon esiste il tag "); return 4; } _curr.SetTrc(_trc); const int inmode = infile->GetIntAttr("Binary") != 0 ? (ios::in|ios::binary) : ios::in; ifstream input(src, inmode); TCasaEditrice mondadori(_trc, dst); TString expr; for (int i = 0; i < recout->GetChildren(); i++) { const TXmlItem* outfield = recout->GetChild(i); outfield->GetEnclosedText(expr); _expressions.add(new TExpr_omnia(expr)); } while (_curr.Read(input)) { ofstream& output = mondadori.ChooseOutput(_curr); output << mondadori.RecHead(); for (int i = 0; i < recout->GetChildren(); i++) { TXmlItem* outfield = recout->GetChild(i); outfield->GetEnclosedText(expr); const TString& val = evaluate(i); output << mondadori.FldHead() << val << mondadori.FldFoot(); } output << mondadori.RecFoot(); } return 0; } int TLettore::convert(const char* cmd) { TToken_string str(cmd, ' '); str.strip_d_spaces(); const TFilename src = str.get(); const TFilename trc = str.get(); const TFilename dst = str.get(); return convert(src, trc, dst); } int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR lpCmdLine, int) { TLettore app; const int err = app.convert(lpCmdLine); return err; }