#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; } static int curr_recno() { return _curr_recno; } 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 { TAssoc_array* m_vars; 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, TAssoc_array* vars = NULL); 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), m_vars(NULL) { } TTextRecord(const TXmlItem& trc) : m_vars(NULL) { SetTrc(trc); } }; void TTextRecord::SetTrc(const TXmlItem& trc, TAssoc_array* vars) { m_vars = vars; 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 { if (m_vars != NULL) { const TString* val = (const TString*)m_vars->objptr(name); if (val != NULL) return *val; } 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) // C'e' qualche variabile o funzione { 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! if (str[0] == '"') // Togli virgolette dalle costanti { str.rtrim(1); str.ltrim(1); } } 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 /////////////////////////////////////////////////////////// enum TExportFormat { fmt_txt, fmt_slk }; class TCasaEditrice : public TAssoc_array { const TXmlItem& m_trc; const TXmlItem* m_pRecOut; TExportFormat m_fmt; TArray _expressions; 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; void Translate(TString& str) const; ofstream& ChooseOutput(const TTextRecord& rec); const TString& evaluate(const TTextRecord& rec, int index) const; void WriteField(ostream& output, int x, int y, const char* val) 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; } void Write(const TTextRecord& rec); TCasaEditrice(const TXmlItem& trc, const char* name); virtual ~TCasaEditrice(); }; void TCasaEditrice::Translate(TString& str) const { int ampersend = str.find("&#"); TString tmp; while (ampersend >= 0) { const int semicolon = str.find(';', ampersend+2); if (semicolon < 0) break; const int k = hex2int(str.sub(ampersend+2, semicolon)); tmp.format("%c", k); tmp.insert(str.left(ampersend)); tmp << str.mid(semicolon+1); str = tmp; ampersend = str.find("&#", ampersend+1); } } void TCasaEditrice::WriteHeader(ostream& output) const { TXmlItem* pOutput = m_trc.FindFirst("Output"); CHECK(pOutput, "NULL output file"); TXmlItem* pHeader = pOutput->FindFirst("Header"); TString strHeader; if (pHeader != NULL) { pHeader->GetEnclosedText(strHeader); if (strHeader.not_empty()) { if (strHeader[0] == '"') { strHeader.rtrim(1); strHeader.ltrim(1); } Translate(strHeader); } } if (strHeader.empty() && m_fmt == fmt_slk) strHeader = "ID;PWXL;N;E\n"; output << strHeader; if (pHeader != NULL && pHeader->GetIntAttr("Auto") != 0) { 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); WriteField(output, i, 0, outfield->GetAttr("Name")); } 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"); TString strFooter; if (pFooter != NULL) { pFooter->GetEnclosedText(strFooter); if (strFooter[0] == '"') { strFooter.rtrim(1); strFooter.ltrim(1); } Translate(strFooter); } if (strFooter.empty() && m_fmt == fmt_slk) strFooter = "E\n"; 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(); } const TString& TCasaEditrice::evaluate(const TTextRecord& rec, int index) const { TExpr_omnia& exp = (TExpr_omnia&)_expressions[index]; return rec.Evaluate(exp); } void TCasaEditrice::WriteField(ostream& output, int x, int y, const char* val) const { switch(m_fmt) { case fmt_slk: output << "C;Y" << (y+1) << ";X" << (x+1) << ";K\"" << val << '"' << endl; break; default: output << FldHead() << val << FldFoot(); break; } } void TCasaEditrice::Write(const TTextRecord& rec) { ofstream& output = ChooseOutput(rec); output << RecHead(); TString expr; for (int i = 0; i < m_pRecOut->GetChildren(); i++) { TXmlItem* outfield = m_pRecOut->GetChild(i); outfield->GetEnclosedText(expr); const TString& val = evaluate(rec, i); WriteField(output, i, TExpr_omnia::curr_recno(), val); } output << RecFoot(); } TCasaEditrice::TCasaEditrice(const TXmlItem& trc, const char* name) : m_trc(trc), m_fmt(fmt_txt), 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); if (m_strExt.compare("slk", -1, true) == 0 || m_strExt.compare("xls", -1, true) == 0) m_fmt = fmt_slk; } 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); m_pRecOut = pOutFile->FindFirst("Record"); CHECK(m_pRecOut, "NULL output record"); if (m_fmt != fmt_slk) { m_strRecHead = m_pRecOut->GetAttr("RecHead"); Translate(m_strRecHead); m_strRecFoot = m_pRecOut->GetAttr("RecFoot"); Translate(m_strRecFoot); m_strFldHead = m_pRecOut->GetAttr("FldHead"); Translate(m_strFldHead); m_strFldFoot = m_pRecOut->GetAttr("FldFoot"); Translate(m_strFldFoot); } TString expr; for (int i = 0; i < m_pRecOut->GetChildren(); i++) { const TXmlItem* outfield = m_pRecOut->GetChild(i); outfield->GetEnclosedText(expr); _expressions.add(new TExpr_omnia(expr)); } } 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; 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; public: int convert(const TFilename& src, const TFilename& trc, const TFilename& dst, TAssoc_array& vars); 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; } int TLettore::convert(const TFilename& src, const TFilename& trc, const TFilename& dst, TAssoc_array& vars) { 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; } TAssoc_array* varibili = (vars.items() > 0) ? &vars : NULL; _curr.SetTrc(_trc, varibili); const int inmode = infile->GetIntAttr("Binary") != 0 ? (ios::in|ios::binary) : ios::in; ifstream input(src, inmode); TCasaEditrice mondadori(_trc, dst); while (_curr.Read(input)) mondadori.Write(_curr); 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(); TAssoc_array vars; TString varname, value; for (const char* t = str.get(); t; t = str.get()) { varname = t; const int equal = varname.find('='); if (equal > 0) { value = varname.mid(equal+1); varname.cut(equal); } else value.cut(0); vars.add(varname, value); } return convert(src, trc, dst, vars); } int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR lpCmdLine, int) { TLettore app; const int err = app.convert(lpCmdLine); return err; }