diff --git a/include/date.cpp b/include/date.cpp index e7a930482..e99a90153 100755 --- a/include/date.cpp +++ b/include/date.cpp @@ -4,41 +4,41 @@ #define __DATE_CPP #include - #include +#include #include #include #define DAYBIAS 36525L #define NULLDATE -99999L -#include +/////////////////////////////////////////////////////////// +// Utility functions +/////////////////////////////////////////////////////////// // @doc EXTERNAL HIDDEN TDate __tmp_date; -HIDDEN char __date_tmp_string[64]; +HIDDEN char __date_tmp_string[128]; TDate::TDate(const TDate &d) : _val(d._val) -{ - memcpy(_format, "1444-", 5); -} +{} TDate::TDate(long l) : _val(l) { if (_val == TODAY) { - char s[10]; + char s[16]; cgetdata(&_val, s); } - memcpy(_format, "1444-", 5); } TDate::TDate(const char* s) { _val = NULLDATE; - if (!isdate(s)) return; + if (!isdate(s)) + return; if (strlen(s) == 10) { @@ -74,20 +74,17 @@ TDate::TDate(const char* s) _val = makedata(day, month, year) + off; } else _val = cpackdata((char*)s); - - memcpy(_format, "1444-", 5); } TDate::TDate(int day, int month, int year) { if (day == TODAY) { - char s[10]; + char s[16]; cgetdata(&_val, s); } else - if ((day == 0) || (month == 0) || (year == 0)) _val = NULLDATE; - else + if (day && month && year) { long off = 0L; @@ -101,44 +98,13 @@ TDate::TDate(int day, int month, int year) _val = makedata(day, month, year) + off; if (!ok()) _val = NULLDATE; } - memcpy(_format, "1444-", 5); + else + _val = NULLDATE; } -// @mfunc Permette di stabilire il criterio di formattazione delle date -void TDate::set_format( - const char* f) // @parm Stringa di 5 caratteri che indica il formato della data - - // @comm Ogni carattere del parametro

permette di settare un tipo di formattazione - // della data: - // 1° carattere - FORMATO. Puo' assumere i seguenti valori: - // 1 = giorno-mese-anno - // 2 = mese-anno-giorno - // 3 = anno-giorno-mese - // 4 = solo anno - // 5 = solo mese - // 6 = solo giorno - // 7 = mese-anno - // 2° carattere - Formato GIORNO. Puo assumere i seguenti valori: - // 2 = formato normale (es. 4) - // 4 = formato con 0 (es. 04) - // 5 = lettere (es. quattro) - // 6 = giorno della settimana - // 3° carattere - Formato MESE. Puo assumere i seguenti valori: - // 2 = formato normale (es. 4) - // 4 = formato con 0 (es. 04) - // 5 = lettere (es. quattro) - // 7 = trimestre - // 4° carattere - Formato ANNO. Puo' assumere i seguenti valori: - // 2 = breve (es. 95) - // 4 = lungo (es. 1995) - // 5° carattere - Carattere SEPARATORE. Puo' essere un carattere o lo spazio -{ - memcpy(_format, f, 5); -} - int TDate::last_day(int month, int year) // parse_filastrok( - // "trenta giorni case novembre + // "trenta giorni ha novembre // con april, giugno e settembre // son ventotto case uno // per default ce n'ha trentuno"); @@ -175,18 +141,18 @@ bool TDate::is_end_month() int TDate::wday() const { // day of week (1=lunedi) - // DDJ algorithm (4/1995) + // DDJ algorithm (4/1995) Della serie: "non e' colpa mia se funziona". int m = month(); int d = day(); int y = year(); - if (m <= 2) + if (m <= 2) // Gennaio e Febbraio sono gli ultimi mesi dell'anno scorso { y --; m += 12; } - return ((d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400) % 7) + 1; + return ((d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400) % 7) + 1; // Pure magic } void TDate::set_day(int n) { _val = makedata(n, month(), year()); } @@ -214,7 +180,6 @@ void TDate::print_on(ostream& out) const void TDate::read_from(istream& in) { char s[256]; - in >> s; if (isdate(s)) _val = cpackdata(s); else _val = NULLDATE; @@ -232,162 +197,104 @@ char* TDate::string( TDate_order ord) const // @parm Ordine con la quale visualizzare la data // (vedi ; default gma_date) { - if (!ok()) return ""; - - int yeardgts = (int)yearf; + if (!ok() || *this == botime) + return ""; - if (yearf == def || dayf != def || monthf != def || ord > amg_date) + if (yearf == ANSI) + { + yearf = full; + ord = amg_date; + } + + TString df(2), yf(4), mf(2); + bool letterflag = FALSE; + + // format day + if (dayf == letters) { - // nonstandard: use new format - // yearf == def significa usa il formato standard specificato - TString dfm(32); - - if (yearf == def) - { - yearf = (TDate_mgafmt)(_format[3] - '0'); - ord = (TDate_order)(_format[0] - '0'); - sep = _format[4]; - } - if (dayf == def) dayf = (TDate_mgafmt)(_format[1] - '0'); - if (monthf== def) monthf = (TDate_mgafmt)(_format[2] - '0'); - - TString df(2), yf(4), mf(2); - - bool letterflag = FALSE; - - // format each one - if (dayf == letters) - { - real ddd(day()); - letterflag = TRUE; - df = ddd.string("LETTERE"); - } - else if (dayf == weekday) - { - letterflag = TRUE; - df = format("%s %d", itow(wday()), day()); - } - else df = format(dayf == brief ? "%d" : "%02d", day()); - - if (yearf == letters) - { - real ddd(year()); - letterflag = TRUE; - yf = ddd.string("LETTERE"); - } - else if (yearf == brief && year() < 2000) - yf = format("%d", year() - 1900); + const real ddd(day()); + df = ddd.string("LETTERE"); + letterflag = TRUE; + } + else if (dayf == weekday) + { + df = format("%s %d", itow(wday()), day()); + letterflag = TRUE; + } + else + df = format(dayf == brief ? "%d" : "%02d", day()); + + // format year + if (yearf == letters) + { + const real ddd(year()); + yf = ddd.string("LETTERE"); + letterflag = TRUE; + } + else + if (yearf == brief) + yf.format("%02d", year() % 100); else - yf = format("%d", year()); - - if (monthf == letters) - { - letterflag = TRUE; - mf = itom(month()); - } - else if (monthf == quarter) - { - if (ord < m_date) ord = ma_date; - mf = format("%do trimestre", (month() / 3) + 1); - } - else - mf = format(monthf == brief ? "%d" : "%02d", month()); - - if (letterflag || sep == 'S') sep = ' '; - - // build date string - // single field - dfm = ""; - - switch (ord) - { - case gma_date: - dfm << df << sep << mf << sep << yf; - break; - case mga_date: - dfm << mf << sep << df << sep << yf; - break; - case amg_date: - dfm << yf << sep << mf << sep << df; - break; - case a_date: - dfm << yf; - break; - case m_date: - dfm << mf; - break; - case g_date: - dfm << df; - break; - case ma_date: - dfm << mf << sep << yf; - break; - } - strcpy(__date_tmp_string, (const char*)dfm); + yf.format("%04d", year()); + + // format month + if (monthf == letters) + { + letterflag = TRUE; + mf = itom(month()); + } + else if (monthf == quarter) + { + if (ord < m_date) ord = ma_date; + mf = format("%do trimestre", (month() / 3) + 1); } else - { - long wv = _val; - int cnt = wv >= DAYBIAS ? 2000 : 1900; - - while (wv < 0) - { - cnt -= 100; - wv += DAYBIAS; - } - ceditdata(wv, __date_tmp_string); - if (strcmp(__date_tmp_string, " - - ") == 0) return ""; - if (sep != '-') - for (char* s = __date_tmp_string; *s; s++) - if (*s == '-') *s = sep; - if (yeardgts > 2) - { - char s[8]; - int year = cnt + atoi(__date_tmp_string + 6); - - if (yeardgts == 3) sprintf(s, "%03d", year % 1000); - else sprintf(s, "%04d", year); - __date_tmp_string[6] = '\0'; - strcat(__date_tmp_string, s); - - if (ord == amg_date) - { - char* d = __date_tmp_string; - const char g[3] = { d[0], d[1], '\0' }; - const char m[3] = { d[3], d[4], '\0' }; - sprintf(d, "%s%c%s%c%s", &d[6], sep, m, sep, g); - } - else if (ord == mga_date) - { - char* d = __date_tmp_string; - char c = d[0]; d[0] = d[3]; d[3] = c; - c = d[1]; d[1] = d[4]; d[4] = c; - } - } - else - if (yeardgts == ANSI) - { - char* s = __date_tmp_string; s[2] = '\0'; s[5] = '\0'; - const int day = atoi(s); - const int month = atoi(s + 3); - const int year = atoi(s + 6); - - sprintf(__date_tmp_string, "%04d%02d%02d", year, month, day); - } + mf = format(monthf == brief ? "%d" : "%02d", month()); + + if ((letterflag && sep == '-') || sep == 'S') + sep = ' '; + + // build date string + + TFixed_string dfm(__date_tmp_string, 128); + dfm.cut(0); + + switch (ord) + { + case mga_date: + dfm << mf << sep << df << sep << yf; + break; + case amg_date: + dfm << yf << sep << mf << sep << df; + break; + case a_date: + dfm << yf; + break; + case m_date: + dfm << mf; + break; + case g_date: + dfm << df; + break; + case ma_date: + dfm << mf << sep << yf; + break; + default: + dfm << df << sep << mf << sep << yf; + break; } + return __date_tmp_string; } int TDate::day() const - { return ::day(_val); } int TDate::month() const - { return ::month(_val); } @@ -508,6 +415,78 @@ const TDate& fnc_max( else return b; } +/////////////////////////////////////////////////////////// +// TFormatted_date +/////////////////////////////////////////////////////////// + +TFormatted_date::TFormatted_date(int day, int month, int year, const char* form) +: TDate(day, month, year) +{ + set_format(form); +} + +TFormatted_date::TFormatted_date(const TDate& d, const char* form) +: TDate(d) +{ + set_format(form); +} + +TFormatted_date::TFormatted_date(const TFormatted_date& d) +: TDate(d) +{ + set_format(d._format); +} + +// @mfunc Permette di stabilire il criterio di formattazione delle date + +void TFormatted_date::set_format( + const char* f) // @parm Stringa di 5 caratteri che indica il formato della data + + // @comm Ogni carattere del parametro

permette di settare un tipo di formattazione + // della data: + // 1° carattere - FORMATO. Puo' assumere i seguenti valori: + // 1 = giorno-mese-anno + // 2 = mese-anno-giorno + // 3 = anno-giorno-mese + // 4 = solo anno + // 5 = solo mese + // 6 = solo giorno + // 7 = mese-anno + // 2° carattere - Formato GIORNO. Puo assumere i seguenti valori: + // 2 = formato normale (es. 4) + // 4 = formato con 0 (es. 04) + // 5 = lettere (es. quattro) + // 6 = giorno della settimana + // 3° carattere - Formato MESE. Puo assumere i seguenti valori: + // 2 = formato normale (es. 4) + // 4 = formato con 0 (es. 04) + // 5 = lettere (es. quattro) + // 7 = trimestre + // 4° carattere - Formato ANNO. Puo' assumere i seguenti valori: + // 2 = breve (es. 95) + // 4 = lungo (es. 1995) + // 5° carattere - Carattere SEPARATORE. Puo' essere un carattere o lo spazio + +{ + CHECKS(memchr(f, 0, 5) == NULL, "Bad date format ", f); + memcpy(_format, f, 5); +} + +const char* TFormatted_date::string() const +{ + TDate_mgafmt yearf = (TDate_mgafmt)(_format[3] - '0'); + char sep = _format[4]; + TDate_mgafmt dayf = (TDate_mgafmt)(_format[1] - '0'); + TDate_mgafmt monthf = (TDate_mgafmt)(_format[2] - '0'); + TDate_order ord = (TDate_order)(_format[0] - '0'); + + return TDate::string(yearf, sep, dayf, monthf, ord); +} + + +/////////////////////////////////////////////////////////// +// Utility functions +/////////////////////////////////////////////////////////// // @func Converte un numero da 1 a 12 nel corrispondente mese const char* itom( @@ -538,3 +517,4 @@ const char* itow( "Sabato", "Domenica" }; return nomi[(d-1) % 7]; } + diff --git a/include/date.h b/include/date.h index 480419aaf..c20e16208 100755 --- a/include/date.h +++ b/include/date.h @@ -35,12 +35,10 @@ enum TDate_mgafmt { // @base public | TObject class TDate : public TObject { - // @access Private Member - // @cmember Valore data in formato packed long _val; - // @cmember Formato per tutti i pezzettini - byte _format[5]; + +protected: // @cmember Controlla se una data e' minore di un'altra friend bool operator <(const TDate& a, const TDate& b); @@ -58,7 +56,8 @@ class TDate : public TObject // @access Public Member public: // @cmember Ritorna la data in formato di stringa (anche in formato ANSI) - char* string(TDate_mgafmt year=def,char sep='-',TDate_mgafmt day=def,TDate_mgafmt month=def,TDate_order ord=gma_date) const ; + char* string(TDate_mgafmt year = full, char sep = '-', TDate_mgafmt day = full, + TDate_mgafmt month = full, TDate_order ord = gma_date) const ; // @cmember Ritorna il giorno int day() const ; @@ -140,12 +139,28 @@ public: TDate(int day = 0, int month = 0, int year = 0); }; +class TFormatted_date : public TDate +{ + // @cmember Formato per tutti i pezzettini + char _format[5]; + +public: + void set_format(const char* f); + const char* string() const; + + TFormatted_date& operator =(const char* s) { TDate::operator =(s); return *this; } + TFormatted_date& operator =(const TDate& d) { TDate::operator =(d); return *this; } + TFormatted_date& operator =(const TFormatted_date& d) { TDate::operator =(d); set_format(d._format); return *this; } + + TFormatted_date(int day = 0, int month = 0, int year = 0, const char* f = "1444-"); + TFormatted_date(const TDate& d, const char* f = "1444-"); + TFormatted_date(const TFormatted_date& d); +}; + TDate& operator +(const TDate& a, long nday) ; TDate& operator +(const long nday, const TDate& b) ; TDate& operator -(const TDate& a, long nday) ; - - // @func inline bool | operator | Controlla se una data e' minore di un'altra // // @rdesc Ritorna i seguenti valori @@ -200,6 +215,7 @@ inline bool operator ==( const TDate& a, // @parm Prima data da confrontare const TDate& b) // @parm Secondo data da confrontare { return a._val == b._val;} + // @func inline bool | operator != | Controlla se 2 date sono diverse // // @rdesc Ritorna i seguenti valori diff --git a/include/form.cpp b/include/form.cpp index 648fe30f1..17ec0e617 100755 --- a/include/form.cpp +++ b/include/form.cpp @@ -11,14 +11,65 @@ #include "../ba/ba2100.h" -static TForm* _form = NULL; +/////////////////////////////////////////////////////////// +// Utility functions +/////////////////////////////////////////////////////////// -static TForm& form() +// Current form (edit, print) +HIDDEN TForm* _cur_form = NULL; + +HIDDEN TForm& form() { - CHECK(_form, "Can't print NULL form"); - return *_form; + CHECK(_cur_form, "Can't print NULL form"); + return *_cur_form; } +// Translate char to pagetype +HIDDEN pagetype char2page(char c) +{ + pagetype pt; + switch(c) + { + case '1': + case 'E': + pt = even_page; break; + case '2': + case 'F': + pt = first_page; break; + case '3': + case 'L': + pt = last_page; break; + default: + pt = odd_page; break; + } + return pt; +} + + +// Handler of F_BUT_FILE field on mask +HIDDEN bool but_file_handler(TMask_field& f, KEY k) +{ + if (k == K_SPACE) + { + TRelation_description* r = form().reldef(); + if (r != NULL && r->choose_file()) + f.mask().set(f.dlg()-1, r->file_desc()); + } + return TRUE; +} + +// Handler of F_BUT_FIELD field on mask +HIDDEN bool but_field_handler(TMask_field& f, KEY k) +{ + if (k == K_SPACE) + { + TRelation_description* r = form().reldef(); + if (r != NULL && r->choose_field()) + f.mask().set(f.dlg()-1, r->field_desc()); + } + return TRUE; +} + /////////////////////////////////////////////////////////// // TForm_flags /////////////////////////////////////////////////////////// @@ -28,7 +79,7 @@ struct TForm_flags : public TObject bool automagic : 1; bool enabled : 1; bool shown : 1; - + protected: void print_on(ostream& out) const; @@ -100,6 +151,98 @@ void TForm_flags::read_from(const TMask& m) automagic = m.get_bool(F_AUTOMAGIC); } +/////////////////////////////////////////////////////////// +// TForm_permissions +/////////////////////////////////////////////////////////// + +struct TForm_permissions : public TObject +{ + bool coord : 1; + bool enable : 1; + bool show : 1; + bool field : 1; + bool remove : 1; + +protected: + void print_on(ostream& out) const; + +public: + TForm_permissions(); + + void print_on(TMask& m); + void read_from(const TMask& m); + bool update(const char* s); +}; + +TForm_permissions::TForm_permissions() +{ + coord = enable = show = field = TRUE; + remove = FALSE; +} + +// Read from string +// Certified 100% +bool TForm_permissions::update(const char* s) +{ + CHECK(s, "NULL permission string"); + for (; *s; s++) switch(toupper(*s)) + { + case 'C': + coord = TRUE; break; + case 'E': + enable = TRUE; break; + case 'F': + field = TRUE; break; + case 'R': + remove = TRUE; break; + case 'S': + show = TRUE; break; + default : + error_box("Unknown form permission '%c'", *s); break; + } + return TRUE; +} + + +// Print on stream +// Certified 100% +void TForm_permissions::print_on(ostream& out) const +{ + TString16 s; + + if (coord) s << 'C'; + if (enable) s << 'E'; + if (field) s << 'F'; + if (show) s << 'S'; + if (remove) s << 'R'; + + if (s != "CEFS") + out << " PERMISSIONS \"" << s << '"' << endl; +} + +// Set mask fields +// Certified 100% +void TForm_permissions::print_on(TMask& m) +{ + m.set(F_PERM_COORD, coord ? "X" : " "); + m.set(F_PERM_ENABLE, enable ? "X" : " "); + m.set(F_PERM_SHOW, show ? "X" : " "); + m.set(F_PERM_FIELD, field ? "X" : " "); + m.set(F_PERM_REMOVE, remove ? "X" : " "); +} + + +// Get mask fields +// Certified 100% +void TForm_permissions::read_from(const TMask& m) +{ + coord = m.get_bool(F_PERM_COORD); + enable = m.get_bool(F_PERM_ENABLE); + show = m.get_bool(F_PERM_SHOW); + field = m.get_bool(F_PERM_FIELD); + remove = m.get_bool(F_PERM_REMOVE); +} + /////////////////////////////////////////////////////////// // TForm_item @@ -109,14 +252,15 @@ class TForm_item : public TObject { TPrint_section* _section; TForm_flags _flag; + TForm_permissions _perm; TBit_array _group; TString_array _message; protected: - int _x, _y, _width, _height; + short _id, _x, _y, _width, _height; TString _prompt; TString _desc; - TString16 _permissions; + bool _base; // as written in base form, or modified -> file virtual void print_on(ostream& out) const; virtual void print_body(ostream& out) const; @@ -142,17 +286,13 @@ protected: public: // permissions - // X : coordinate modificabili; - // F : field modificabile - // E : enable/disable concessi - // H : hide/show concessi - // C : compulsory (non si puo' cancellare nemmeno se il form lo consente - bool has_coord_permission() const { return _permissions.find('X') != -1; } - bool has_field_permission() const { return _permissions.find('F') != -1; } - bool has_enable_permission() const { return _permissions.find('E') != -1; } - bool has_hide_permission() const { return _permissions.find('H') != -1; } - bool has_remove_permission() const { return _permissions.find('C') == -1; } - + bool has_coord_permission() const { return _perm.coord; } + bool has_field_permission() const { return _perm.field; } + bool has_enable_permission() const { return _perm.enable; } + bool has_show_permission() const { return _perm.show; } + bool has_remove_permission() const { return _perm.remove; } + + short id() const { return _id; } virtual int width() const { return _width; } virtual int height() const { return _height; } @@ -172,7 +312,7 @@ public: const TString& key() const { return _desc; } void print_on(TToken_string& row) const; - virtual void show(bool on = TRUE) { _flag.shown = on; } // TBI + virtual void show(bool on = TRUE) { _flag.shown = on; } void hide() { show(FALSE); } virtual void enable(bool on = TRUE); void disable() { enable(FALSE); } @@ -183,21 +323,27 @@ public: TForm_item::TForm_item(TPrint_section* section) -: _section(section), _x(-1), _y(-1), _width(0), _height(0), _permissions("XFEH") +: _section(section), _x(-1), _y(-1), _width(0), _height(0) {} bool TForm_item::parse_head(TScanner& scanner) -{ +{ + _id = scanner.integer(); + + if (_id == 0) // Temporary + _id = _section->fields()+1; + _width = scanner.integer(); - if (_width) _height = scanner.integer(); + if (_width > 0) + _height = scanner.integer(); return TRUE; } void TForm_item::print_on(ostream& out) const { - out << class_name(); + out << class_name() << ' ' << id(); if (_width > 0) { out << ' ' << _width; @@ -223,15 +369,14 @@ void TForm_item::print_body(ostream& out) const out << " GROUP " << _group << "\n"; out << _flag; + out << _perm; if (_message.items() == 1) { - const TToken_string& m = (TToken_string&)_message[0]; + const TToken_string& m = _message.row(0); if (!m.empty_items()) out << " MESSAGE " << m << endl; } - - out << " PERMISSIONS \"" << _permissions << "\"\n"; } @@ -245,15 +390,12 @@ bool TForm_item::parse_item(TScanner& scanner) return TRUE; } - if (scanner.key() == "PE") - { - _permissions = scanner.string(); - return TRUE; - } - if (scanner.key() == "FL") return _flag.update(scanner.string()); + if (scanner.key() == "PE") + return _perm.update(scanner.string()); + if (scanner.key() == "ME") { TFixed_string m(scanner.line()); @@ -398,14 +540,34 @@ bool TForm_item::do_message(int num) else { const TString16 cmd(msg.get()); // Get command - const word id = msg.get_int(); // Get destination group + const TString16 id = msg.get(); // Get destination - // Send the message to all fields with the given group - for (word i = 0; i < section().fields(); i++) + if (id.right(1) == "@") { - TForm_item& des = section().field(i); - if (des.in_group(id)) + const word group = atoi(id); + // Send the message to all fields with the given group + for (word i = 0; i < section().fields(); i++) + { + TForm_item& des = section().field(i); + if (des.in_group(group)) + send_message(cmd, des); + } + } + else + { + if (isdigit(id[0])) // Field in the same section + { + TForm_item& des = section().find_field(atoi(id)); send_message(cmd, des); + } + else + { + const pagetype pt = (id[1] == '-') ? section().page_type() : char2page(id[1]); + const int freccia = id.find("->"); + CHECK(freccia > 0, "Non trovo la freccia in un campo di stampa"); + TForm_item& des = section().form().find_field(id[0], pt, atoi(id.mid(freccia+2))); + send_message(cmd, des); + } } } } @@ -424,6 +586,7 @@ bool TForm_item::update() void TForm_item::print_on(TToken_string& row) const { row = class_name(); + row.add(id()); row.add(_y); row.add(_x); @@ -436,6 +599,7 @@ void TForm_item::print_on(TToken_string& row) const void TForm_item::print_on(TMask& m) { m.set(F_CLASS, class_name()); + m.set(F_ID, id()); m.set(F_KEY, key()); m.set(F_X, _x); m.set(F_Y, _y); @@ -449,6 +613,7 @@ void TForm_item::print_on(TMask& m) } _flag.print_on(m); + _perm.print_on(m); for (int g = 1; g <= 24; g++) m.set(F_GROUP+g, _group[g] ? "X" : " "); @@ -462,7 +627,9 @@ void TForm_item::read_from(const TMask& m) _prompt = m.get(F_PROMPT); _width = atoi(m.get(F_WIDTH)); _height = atoi(m.get(F_HEIGHT)); + _flag.read_from(m); + _perm.read_from(m); _group.reset(); for (int g = 1; g <= 24; g++) @@ -472,75 +639,29 @@ void TForm_item::read_from(const TMask& m) bool TForm_item::edit(TMask& m) { - m.reset(); - - if (m.insert_mode()) - m.enable(F_CLASS); - else print_on(m); + m.enable(F_CLASS, m.insert_mode()); + + m.reset(); + if (!m.insert_mode()) + print_on(m); // handle permissions - if (!has_field_permission()) - { - m.disable(F_BUT_FILE); - m.disable(F_BUT_FIELD); - } + m.enable(F_BUT_FILE1, has_field_permission()); + m.enable(F_BUT_FIELD1, has_field_permission()); + m.enable(F_BUT_FILE2, has_field_permission()); + m.enable(F_BUT_FIELD2, has_field_permission()); - if (!has_coord_permission()) - { - m.disable(F_X); - m.disable(F_Y); - m.disable(F_WIDTH); - m.disable(F_HEIGHT); - } + m.enable(F_X, has_coord_permission()); + m.enable(F_Y, has_coord_permission()); + m.enable(F_WIDTH, has_coord_permission()); + m.enable(F_HEIGHT, has_coord_permission()); - if (!has_hide_permission()) - m.disable(F_HIDDEN); + m.enable(F_HIDDEN, has_show_permission()); + m.enable(F_DISABLED, has_enable_permission()); - if (!has_enable_permission()) - m.disable(F_DISABLED); + const bool dirty = m.run() == K_ENTER && m.dirty(); + if (dirty) read_from(m); - bool dirty = FALSE; // (m.run() == K_ENTER) && m.dirty(); - - for(KEY k = 0; k != K_ENTER && k != K_ESC; k = m.run()) - { - switch(k) - { - case K_ENTER: - dirty = (bool)m.dirty(); - break; - case K_ESC: - break; - case F_BUT_FILE: - // TBI - if (form().reldef() != NULL && form().reldef()->choose_file()) - { - m.set(F_FILE, form().reldef()->file_desc()); - } - break; - case F_BUT_FIELD: - // TBI - if (form().reldef() != NULL && form().reldef()->choose_field()) - { - m.set(F_FIELD, form().reldef()->field_desc()); - } - break; - } - } - - if (m.insert_mode()) - m.disable(F_CLASS); - else if (dirty) - read_from(m); - - m.enable(F_Y); - m.enable(F_X); - m.enable(F_WIDTH); - m.enable(F_HEIGHT); - m.enable(F_HIDDEN); - m.enable(F_DISABLED); - m.enable(F_FILE); - m.enable(F_FIELD); - return dirty; } @@ -583,7 +704,7 @@ public: TForm_subsection::TForm_subsection(TPrint_section* s, const char* nm) : -TForm_item(s), _ssec(&(s->form())), _name(nm) +TForm_item(s), _ssec(&(s->form()), s->page_type()), _name(nm) {} @@ -626,9 +747,9 @@ void TForm_subsection::print_on(ostream& out) const } +// ??? int TForm_subsection::width() const { - int w = 0; for (word i = 0; i < _ssec.fields(); i++) if (_ssec.field(i).width() > w) @@ -636,6 +757,7 @@ int TForm_subsection::width() const return w; } +// ??? int TForm_subsection::height() const { int h = 0; @@ -644,12 +766,14 @@ int TForm_subsection::height() const return h; } +// ??? void TForm_subsection::show(bool on) { for (unsigned int i = 0; i < _ssec.fields(); i++) _ssec.field(i).show(on); } +// ??? void TForm_subsection::enable(bool on) { for (unsigned int i = 0; i < _ssec.fields(); i++) @@ -695,7 +819,8 @@ bool TForm_string::parse_item(TScanner& scanner) if (scanner.key() == "FI") { TFieldref* fr = new TFieldref(scanner.line(), 0); - _field.add(fr); + _field.add(fr); + // TBI set field return TRUE; } @@ -720,11 +845,11 @@ void TForm_string::print_body(ostream& out) const void TForm_string::print_on(TMask& m) { TForm_item::print_on(m); - for (int i = 0; i < 2; i++) if (i < _field.items()) + for (int i = 0; i < _field.items(); i++) { TString80 f; f << field(i); - m.set(i == 0 ? F_FIELD : F_FIELD2, f); + m.set(i == 0 ? F_FIELDREF1 : F_FIELDREF2, f); } m.set(F_PICTURE, _picture); @@ -737,7 +862,7 @@ void TForm_string::read_from(const TMask& m) for (int i = 0; i < 2; i++) { - const TString& f = m.get(i == 0 ? F_FIELD : F_FIELD2); + const TString& f = m.get(i == 0 ? F_FIELDREF1 : F_FIELDREF2); if (f.not_empty()) _field.add(new TFieldref(f, 0), i); else @@ -814,11 +939,14 @@ bool TForm_string::update() class TForm_number : public TForm_string { -protected: +protected: // TForm_string virtual const char* class_name() const { return "NUMERO"; } virtual bool parse_head(TScanner& scanner); virtual bool update(); + virtual int height() const { return 0; } + +protected: int decimals() const { return _height; } public: @@ -828,9 +956,10 @@ public: bool TForm_number::parse_head(TScanner& scanner) -{ - _width = 0; - _height = scanner.integer(); +{ + TForm_item::parse_head(scanner); + _height = _width; // Decimals + _width = 0; return TRUE; } @@ -855,8 +984,7 @@ bool TForm_number::update() class TForm_date : public TForm_string { - - TString _format; + TString16 _format; protected: virtual const char* class_name() const { return "DATA"; } @@ -868,7 +996,7 @@ protected: virtual void print_on(TMask& m); virtual void read_from(const TMask& m); - static bool dateformat_handler(TMask_field& f, KEY k); + static bool dateformat_handler(TMask_field& f, KEY k); public: @@ -892,8 +1020,8 @@ bool TForm_date::read() void TForm_date::print_body(ostream& out) const { - out << " FORMAT \"" << _format << "\"\n"; TForm_string::print_body(out); + out << " FORMAT \"" << _format << "\"\n"; } bool TForm_date::parse_item(TScanner& scanner) @@ -908,20 +1036,20 @@ bool TForm_date::parse_item(TScanner& scanner) bool TForm_date::set(const char* s) { - const TDate d(s); - TForm_string::set(d.string((width() == 8) ? brief : full)); - return TRUE; + const TDate da(s); + return set(da); } -bool TForm_date::set(const TDate& d) +bool TForm_date::set(const TDate& da) { - TForm_string::set(d.string((width() == 8) ? brief : full)); + TFormatted_date d(da); d.set_format(_format); + TForm_string::set(d.string()); return TRUE; } void TForm_date::print_on(TMask& m) { - TDate d(TODAY); d.set_format(_format); + const TFormatted_date d(TODAY, 0, 0, _format); m.set(F_DEXAMPLE, d.string()); m.set(F_DFORMAT, _format.mid(0,1)); @@ -958,26 +1086,20 @@ bool TForm_date::edit(TMask& m) bool TForm_date::dateformat_handler(TMask_field& f, KEY k) { - if (k != K_SPACE) - return TRUE; - - TMask_field& df = f.mask().field(F_DFORMAT); - TMask_field& dd = f.mask().field(F_DDAY); - TMask_field& dm = f.mask().field(F_DMONTH); - TMask_field& dy = f.mask().field(F_DYEAR); - TMask_field& ds = f.mask().field(F_DSEP); - - char fmt[5]; TDate ex(TODAY); - - fmt[0] = (df.get())[0]; - fmt[1] = (dd.get())[0]; - fmt[2] = (dm.get())[0]; - fmt[3] = (dy.get())[0]; - fmt[4] = (ds.get())[0]; - - ex.set_format(fmt); - f.mask().set(F_DEXAMPLE, ex.string()); - + if (k == K_SPACE) + { + TMask& m = f.mask(); + + char fmt[5]; + fmt[0] = m.get(F_DFORMAT)[0]; + fmt[1] = m.get(F_DDAY)[0]; + fmt[2] = m.get(F_DMONTH)[0]; + fmt[3] = m.get(F_DYEAR)[0]; + fmt[4] = m.get(F_DSEP)[0]; + + const TFormatted_date ex(TODAY, 0, 0, fmt); + f.mask().set(F_DEXAMPLE, ex.string()); + } return TRUE; } @@ -1122,7 +1244,6 @@ class TForm_group : public TForm_item { protected: virtual const char* class_name() const { return "GRUPPO"; } - virtual bool parse_head(TScanner&) { return TRUE; } virtual bool update() { return TRUE; } public: @@ -1137,7 +1258,8 @@ public: TMask* TPrint_section::_msk = NULL; -TPrint_section::TPrint_section(TForm* f) : _height(0), _x(0), _y(0), _form(f) +TPrint_section::TPrint_section(TForm* f, pagetype pt) +: _height(0), _x(0), _y(0), _form(f), _page_type(pt) {} TPrint_section::~TPrint_section() @@ -1179,7 +1301,7 @@ void TPrint_section::offset(int& x, int& y) const TForm_item* TPrint_section::parse_item(const TString& s) { if (s == "SE") - return new TForm_subsection(this); // TBI + return new TForm_subsection(this); if (s == "ST") return new TForm_string(this); if (s == "NU") @@ -1191,7 +1313,7 @@ TForm_item* TPrint_section::parse_item(const TString& s) if (s == "GR") return new TForm_group(this); - error_box("Campo di stampa non ammesso per la sezione di stampa: %s", (const char*)s); + yesnofatal_box("Campo di stampa non ammesso per la sezione di stampa: %s", (const char*)s); return NULL; } @@ -1245,7 +1367,9 @@ bool TPrint_section::update() bool TPrint_section::edit(const char* title, bool all) -{ +{ + _cur_form = _form; + TMask m("ba2100s"); m.set_caption(title); @@ -1266,12 +1390,10 @@ bool TPrint_section::edit(const char* title, bool all) } word flags = 0x08; - if (form().has_add_permission()) flags |= 0x02; if (form().has_remove_permission()) flags |= 0x04; - TArray_sheet a(-1, -1, 0, 0, title, "Tipo@8|Riga@R|Col.@R|Gr.@R|Descrizione@40", - flags); + TArray_sheet a(-1, -1, 0, 0, title, "Tipo@8|ID@4|Riga@R|Col.@R|Gr.@R|Descrizione@40", flags); for (word i = 0; i < fields(); i++) { @@ -1288,7 +1410,10 @@ bool TPrint_section::edit(const char* title, bool all) if (_msk == NULL && (k == K_ENTER || k == K_INS)) { _msk = new TMask("ba2100f"); - // if (!all) _msk->disable(-7); + _msk->set_handler(F_BUT_FILE1, but_file_handler); + _msk->set_handler(F_BUT_FIELD1, but_field_handler); + _msk->set_handler(F_BUT_FILE2, but_file_handler); + _msk->set_handler(F_BUT_FIELD2, but_field_handler); } TForm_string dummy(this); @@ -1340,12 +1465,35 @@ bool TPrint_section::edit(const char* title, bool all) } void TPrint_section::print_on(ostream& out) const -{ +{ + out << ' '; + switch (page_type()) + { + case even_page: + out << "EVEN"; break; + case first_page: + out << "FIRST"; break; + case last_page: + out << "LAST"; break; + default: + out << "ODD"; break; + } out << ' ' << _height << ' ' << _x << ' ' << _y << endl << endl; for(word i = 0; i < fields(); i++) out << field(i); } +TForm_item& TPrint_section::find_field(short id) const +{ + for(word i = 0; i < fields(); i++) + { + TForm_item& f = field(i); + if (f.id() == id) return f; + } + yesnofatal_box("Can't find item whit id %d", id); + return field(0); +} + /////////////////////////////////////////////////////////// // TGraphic_section /////////////////////////////////////////////////////////// @@ -1361,7 +1509,7 @@ protected: public: void append(const char* s) { _back << s; } - TGraphic_section(TForm* f) : TPrint_section(f) {} + TGraphic_section(TForm* f, pagetype pt) : TPrint_section(f, pt) {} virtual ~TGraphic_section() {} }; @@ -1545,16 +1693,16 @@ bool TForm::parse_permissions(TScanner& scanner) TString16 s; scanner.popkey(); // eat BEGIN - memset(_permissions, 'X', 8); - _permissions[8] = '\0'; // solo per leggerlo col debuggerator + strcpy(_permissions, "XXXX"); while ((s = scanner.pop()) != "END") { - if (s == "ADD") _permissions[0] = 'A'; - else if (s == "REMOVE") _permissions[1] = 'R'; - else if (s == "MODIFY") _permissions[2] = 'M'; - else if (s == "RELATION") _permissions[3] = 'L'; - else return FALSE; + if (s == "ADD") _permissions[0] = 'A'; else + if (s == "REMOVE") _permissions[1] = 'R'; else + if (s == "MODIFY") _permissions[2] = 'M'; else + if (s == "RELATION") _permissions[3] = 'L'; + else + return yesnofatal_box("Bad form permission: %s", (const char*)s); } return TRUE; @@ -1597,13 +1745,19 @@ TPrint_section* TForm::exist(char s, pagetype t, bool create) TPrint_section* sec = (TPrint_section*)a->objptr(t); if (sec == NULL && create) { - sec = (s == 'G') ? new TGraphic_section(this) : new TPrint_section(this); + sec = (s == 'G') ? new TGraphic_section(this, t) : new TPrint_section(this, t); a->add(sec, t); } return sec; } +TForm_item& TForm::find_field(char s, pagetype t, short id) const +{ + const TPrint_section* ps = ((TForm*)this)->exist(s, t); + CHECKD(ps, "Can't find section for field %d", id); + return ps->find_field(id); +} TPrint_section& TForm::section(char s, word p) { @@ -1720,7 +1874,7 @@ long TForm::records() const bool TForm::print(long from, long to) { - _form = this; // Setta il form corrente + _cur_form = this; TPrinter& pr = printer(); // Setta handlers pr.setheaderhandler(header_handler); @@ -1767,10 +1921,9 @@ bool TForm::print(long from, long to) if (!was_open) pr.close(); - _form = NULL; // resetta handlers pr.setheaderhandler(NULL); pr.setfooterhandler(NULL); - + return ok; } @@ -1793,7 +1946,7 @@ void TForm::print_section(ostream& out, char s) const default : name = "BODY"; break; } - out << "SECTION " << name << ' ' << int(t); + out << "SECTION " << name; out << *sec; out << "END\n" << endl; } @@ -1812,12 +1965,12 @@ void TForm::print_on(ostream& out) const out << "PERMISSIONS\nBEGIN\n"; - if (has_add_permission()) out << " ADD" << endl; - if (has_remove_permission()) out << " REMOVE" << endl; - if (has_modify_permission()) out << " MODIFY" << endl; - if (has_relation_permission()) out << " RELATION" << endl; + if (has_add_permission()) out << " ADD\n"; + if (has_remove_permission()) out << " REMOVE\n"; + if (has_modify_permission()) out << " MODIFY\n"; + if (has_relation_permission()) out << " RELATION\n"; - out << "END\n"; + out << "END\n" << endl; print_section(out, 'G'); print_section(out, 'H'); @@ -1850,11 +2003,42 @@ word TForm::height() } -TForm::TForm(const char* name, bool is_base) -: _name(name), _relation(NULL), _cursor(NULL), _reldef(NULL), _isbase(is_base) +bool TForm::read_profile() +{ + return TRUE; +} + +bool TForm::write_profile() { + return TRUE; +} + +TForm::TForm(const char* name, const char* code) +: _name(name), _relation(NULL), _cursor(NULL), _reldef(NULL), + _forms(LF_FORMS), _prof(LF_PROF), _isbase(code == NULL), _isnew(FALSE) +{ main_app().begin_wait(); - + + if (!_isbase) + { + // extract base form name + _code = code; + _forms.zero(); + _forms.put("BASE", _name); + _forms.put("CODF", _code); + _isnew = _forms.read() != NOERR; + if (_isnew) + { + // create new form + _forms.put("BASE", _name); + _forms.put("CODF", _code); + _forms.put("DESC", "Generated automatically"); + _forms.write(); + } + else _desc = _forms.get("DESC"); + } + + // read base form _name.ext("frm"); TScanner scanner(_name); @@ -1882,8 +2066,8 @@ TForm::TForm(const char* name, bool is_base) { if (scanner.popkey() != "SE") // SECTION or END break; - const char sec = scanner.popkey()[0]; // Section name (GR, HE, BO, FO) - const pagetype p = (pagetype)scanner.integer(); // Section type (odd, even, first, last) + const char sec = scanner.popkey()[0]; // Section name (GRAPH, HEAD, BODY, FOOT) + const pagetype p = char2page(scanner.popkey()[0]); // Section type (odd, even, first, last) TPrint_section* ps = exist(sec, p, TRUE); // Create section ok = ps->parse(scanner); // Parse section } @@ -1891,7 +2075,10 @@ TForm::TForm(const char* name, bool is_base) if (!has_add_permission()) { // TBI lascia solo la descrizione dei campi gia' utilizzati - } + } + + if (!_isbase) + read_profile(); // read from LF_PROF file main_app().end_wait(); } diff --git a/include/form.h b/include/form.h index 6dff54b16..508e93ecf 100755 --- a/include/form.h +++ b/include/form.h @@ -13,6 +13,10 @@ class TMask; #endif +#ifndef __ISAM_H +#include +#endif + #ifndef __RELATION_H class TRelation; class TRelation_description; @@ -28,11 +32,13 @@ class TPrint_section : public TArray { static TMask* _msk; - word _height; // Altezza della sezione - int _x, _y; // Offset di stampa + word _height; // Altezza della sezione + int _x, _y; // Offset di stampa - TForm* _form; // Form cui appartiene alla sezione - TArray _item; // Lista dei campi da stampare + TForm* _form; // Form cui appartiene alla sezione + pagetype _page_type; // Tipo della pagina + + TArray _item; // Lista dei campi da stampare const TPrint_section& copy(const TPrint_section& ps); @@ -46,6 +52,8 @@ public: TForm& form() const { return *_form; } TForm_item& field(int n) const { return (TForm_item&)_item[n]; } + TForm_item& find_field(short id) const; + word fields() const { return _item.items(); } word height() const { return _height; } int offset_x() const { return _x; } @@ -59,9 +67,10 @@ public: bool parse(TScanner& scanner); bool edit(const char* title, bool all); + pagetype page_type() const { return _page_type; } const TPrint_section& operator=(const TPrint_section& ps) { return copy(ps); } - TPrint_section(TForm* parent); + TPrint_section(TForm* parent, pagetype pt); TPrint_section(const TPrint_section& ps) { copy(ps); } virtual ~TPrint_section(); }; @@ -71,21 +80,28 @@ class TForm : public TObject { friend class TForm_editor; - TFilename _name; // Profile name + TFilename _name; // Profile name + TString16 _code; // Profile code + + TLocalisamfile _forms; // forms names file + TLocalisamfile _prof; // profile definition file - TRelation* _relation; // Can be NULL - TCursor* _cursor; // Can be NULL + TRelation* _relation; // Can be NULL + TCursor* _cursor; // Can be NULL TRelation_description* _reldef; // pure - TArray _head; // Headers - TArray _body; // Bodies - TArray _foot; // Footers - TArray _back; // Graphic background + TArray _head; // Headers + TArray _body; // Bodies + TArray _foot; // Footers + TArray _back; // Graphic background - char _permissions[9]; // user permissions - bool _lastpage; // I am about to print the last page - bool _isbase; // base form (.frm file) + char _permissions[9]; // user permissions + bool _lastpage; // I am about to print the last page? + bool _isnew; // new form + bool _isbase; // base form (.frm file) + TString _desc; // form description + TPrint_section* exist(char s, pagetype t, bool create = FALSE); // Can be NULL static void header_handler(TPrinter& p); @@ -94,7 +110,7 @@ class TForm : public TObject protected: // H = Header, B = Body, F = Footer, R = Relation TPrint_section& section(char s = 'B', word page = 1); - word height(); // Height of first page + word height(); // Height of first page void print_section(ostream& out, char s) const; virtual void print_on(ostream& out) const; @@ -104,7 +120,10 @@ protected: bool parse_join(TScanner&); bool parse_permissions(TScanner&); bool parse_descfield(TScanner&); - + + bool read_profile(); + bool write_profile(); + word page(const TPrinter& p) const; virtual long records() const; @@ -129,8 +148,12 @@ public: TCursor* cursor() const { return _cursor; } virtual const char* validate(const char* cur, TToken_string& val); - - TForm(const char* form, bool base = FALSE); + + TForm_item& find_field(char sec, pagetype pag, short id) const; + + // if code == NULL it's a base form + // otherwise it's integrated by a file definition + TForm(const char* form, const char* code = NULL); virtual ~TForm(); }; diff --git a/include/relapp.cpp b/include/relapp.cpp index 145f59826..936f5bd5d 100755 --- a/include/relapp.cpp +++ b/include/relapp.cpp @@ -1,4 +1,4 @@ -// $Id: relapp.cpp,v 1.56 1995-05-10 16:12:51 guy Exp $ +// $Id: relapp.cpp,v 1.57 1995-05-18 14:17:56 guy Exp $ #include #include #include @@ -348,17 +348,18 @@ bool TRelation_application::autonum(TMask* m, bool rec) void TRelation_application::query_mode(bool pre_ins) { - TMask* old = _mask; - - const bool changing = changing_mask(MODE_QUERY) || old == NULL; + TMask* old = _mask; + const bool was_open = old != NULL && old->is_open(); + const bool changing = changing_mask(MODE_QUERY); - if (changing && old != NULL) + if (changing && was_open) old->close_modal(); _mask = get_mask(MODE_QUERY); if (changing) { - if (old) _mask->open_modal(); + if (was_open) + _mask->open_modal(); if (_maskeys) delete _maskeys; _maskeys = new TKey_array(_mask); set_limits(); @@ -393,7 +394,7 @@ void TRelation_application::insert_mode() } const bool changing = changing_mask(MODE_INS); - TFilename workname; workname.temp("msk$$"); + TFilename workname; workname.temp("msk"); if (changing) { _mask->set_workfile(workname); @@ -439,11 +440,8 @@ bool TRelation_application::modify_mode() } const bool changing = changing_mask(MODE_MOD); - if (changing) - { _mask->close_modal(); - } _mask = get_mask(MODE_MOD); diff --git a/include/relation.cpp b/include/relation.cpp index 90f28da46..649f3e87d 100755 --- a/include/relation.cpp +++ b/include/relation.cpp @@ -1,4 +1,4 @@ -// $Id: relation.cpp,v 1.40 1995-05-09 09:12:24 villa Exp $ +// $Id: relation.cpp,v 1.41 1995-05-18 14:17:58 guy Exp $ // relation.cpp // fv 12/8/93 // relation class for isam files @@ -1530,7 +1530,9 @@ int TRecord_array::remove() return rewrite(); } +/////////////////////////////////////////////////////////// // TRelation_description +/////////////////////////////////////////////////////////// void TRelation_description::read_rel() { @@ -1539,19 +1541,22 @@ void TRelation_description::read_rel() // scan files and build description arrays _rel->print_on(_files); + TString tn; + for (int i = 0; i < _files.items(); i++) { TToken_string& tt = (TToken_string&)_files[i]; - TString descfname(36); - descfname << DESCDIR << "/d"; + TFilename descfname; descfname << DESCDIR << "/d"; - TString tn(tt.get(0)); + tn = tt.get(0); if (tn[0] == '%' || tn[0] == '$') descfname << tn.mid(1); - else descfname << tn; + else + descfname << tn; descfname << ".des"; - if ((which_file = atoi(tn)) == 0) + which_file = atoi(tn); + if (which_file == 0) which_file = TTable::name2log(tn); if (fexist(descfname)) @@ -1567,11 +1572,10 @@ void TRelation_description::read_rel() { ttmp = trec.fielddef(f); TString16 name = ttmp.get(0); - TString80 dfld; if (!name.blank()) { - dfld = conf.get(name); + TString80 dfld(conf.get(name)); if (!dfld.blank() && dfld[0] != '#') { ttmp.add(dfld,4); @@ -1581,7 +1585,8 @@ void TRelation_description::read_rel() } } } - if (rdesc->items() > 0) _fields.add(rdesc); + if (rdesc->items() > 0) + _fields.add(rdesc); else { _files.destroy(i); @@ -1596,13 +1601,14 @@ void TRelation_description::read_rel() bool TRelation_description::choose_file (int file) { - TArray_sheet sht(-1,-1,0,0,"Selezione archivio", "Descrizione archivio@70"); + TArray_sheet sht(-1,-1,0,0,"Selezione archivio", "Codice|Descrizione archivio@70"); TToken_string tt(80); for (int i = 0; i < _files.items(); i++) { TToken_string& tf = _files.row(i); - tt = tf.get(1); tt.cut(70); + tt = tf.get(0); + tt.add(tf.get()); sht.add(tt); } if (sht.run() == K_ENTER) diff --git a/include/text.cpp b/include/text.cpp index f0c7bc95d..0c01eaee2 100755 --- a/include/text.cpp +++ b/include/text.cpp @@ -455,8 +455,7 @@ bool TTextfile::append (const char *l) { if (_interactive) { - TString *ll = new TString (l); - _page.add (ll, _lines - _page_start - 1l); + _page.add (new TString(l), int(_lines - _page_start - 1)); _page_end++; int len = 0;