/* * Copyright (c) 1995, 1996 Gunther Schadow. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "pg_config.h" IDENT("@(#) SegStruc.cc (Gunther Schadow) 12/19/96"); #pragma implementation #include "UniMesIdCode.h" #include "SegTypeCode.h" #include "SegStruc.h" #include "xios.h" #include "Delimiters.h" #include "misc.h" #include "exception.h" #include "logfile.h" #include "Segment.h" #include "ParseTrace.h" #define ITEM(i) ( & ( this ->* itemtab[i].memberp ) ) #ifdef PEDANTIC_SEGSTRUC bool SegStruc::pedantic = TRUE; #else bool SegStruc::pedantic = FALSE; #endif void SegStruc::unset() { int i; for(i=0; iunset(); } Structure::unset(); } bool SegStruc::OK() const { int i; for(i=0; iOK()) return FALSE; return Structure::OK(); } bool SegStruc::commit() { int i; bool isset = FALSE; for(i=0; icommit(); isset = isset1 || isset; if(!isset1 && itemtab[i].required) if(pedantic) ERROR("missing required item %d `%s'", i, itemtab[i].name); else LOGWARNING("missing required item %d `%s'", i, itemtab[i].name); } if(isset) set(); else if(ispresent()) unset(); // enforce a valid state return isset; } void SegStruc::output(ostream& os) const { int i; if(ishl7er(os) || isastmer(os)) { if(ispresent()) { for(i=0; ioutput(os); } } else /* debug output */ { if(ispresent()) { i=0; while(ioutput(os); if(i==noitems) break; os << DSSEPR; } } else os << DSNOPS; os << DSEGRP; } } struct pseudo_stack { const int top_mark = -1; int stack; inline pseudo_stack(int i = top_mark) { stack = i; } inline bool is_empty() const { return stack == top_mark; } inline void push(int i) { if(is_empty()) stack = i; } inline int pop() { int r = stack; stack = top_mark; return r; } }; #ifndef SEGSTRUC_USE_OLD_INPUT const SegTypeCode::Value end_of_message = SegTypeCode::not_present; SegTypeCode::Value peek(istream& is) { SegTypeCode::Value next_seg; /**/ while(TRUE) { if(!is.ipfx(1)) { if(is.eof()) { LOGDEBUG("end of stream"); return end_of_message; } else ERROS("error on input stream"); } next_seg = Segment::peek(is); if(next_seg == SegTypeCode::invalid || /* if undefined segment */ next_seg == SegTypeCode::not_present || next_seg == SegTypeCode::null ) /* or other junk */ { /* issue warning and skip segment */ char tag[4]; is.get(tag, 4); if(is.eof()) { LOGDEBUG("end of stream"); return end_of_message; } else if(tag[0] == '\0') ERROS("error on input stream"); else { record_parse_warning("undefined segment `%s'", tag); LOGWARNING("undefined segment `%s'", tag); match(is, getdel(is, Delimiters::seglevel)); parseTrace.incrSegOfMsg(); // increase actual segment continue; } } else break; } /* probing for end of message */ switch(next_seg) { case SegTypeCode::MSHval: // MSH is start of new message case SegTypeCode::BTSval: // BTS is end of batch return end_of_message; case SegTypeCode::FTSval: // FTS is end of file, but there was no BTS record_parse_warning("BTS missing before FTS"); LOGWARNING("BTS missing before FTS"); return end_of_message; case SegTypeCode::BHSval: // BHS is actually illegal record_parse_warning("BHS within message??"); LOGWARNING("BHS within message??"); return end_of_message; case SegTypeCode::FHSval: // FHS is illegal as well record_parse_warning("FHS within message??"); LOGWARNING("FHS within message??"); return end_of_message; default: return next_seg; } } result SegStruc::input(istream& is) { SegStrucTracer tracer(subclass()); if(!is.ipfx(1)) { if(is.eof()) { LOGDEBUG("end of message"); tracer.reject(); return FAIL; } else ERROS("error on input stream"); } streammarker spos(is.rdbuf()); /* a group might fail, needing to backtrack */ pseudo_stack failed(0); SegTypeCode::Value next_seg; /**/ while(!failed.is_empty()) { pseudo_stack failed_required; bool any_success = FALSE; int i; for(i = failed.pop(), tracer = i; i < noitems; i++, tracer++) { if(failed.is_empty()) // no failed segment --> peek at next one { next_seg = peek(is); LOGDEBUG("next segment is: %s", (const char*)SegTypeCode(next_seg)); if(next_seg == end_of_message) { /* end of message, unset everything else */ for(; i < noitems; i++, tracer++) { ITEM(i)->unset(); if(itemtab[i].required) { if(subclass() == PGObject::group) { unset(); is.rdbuf()->seekmark(spos); tracer.reject(); return FAIL; } else { if(pedantic) { record_parse_error("missing required item" "%d `%s'", i, itemtab[i].name); EPARSE("missing required item %d `%s'", i, itemtab[i].name); } else { record_parse_warning("missing required item" "%d `%s'", i, itemtab[i].name); LOGWARNING("missing required item %d `%s'", i, itemtab[i].name); } } } } /* end of for-loop */ set(); tracer.accept(); return SUCCESS; } } /* if next_segment is available: */ SegTypeCode::Value leader = (SegTypeCode::Value)itemtab[i].leader; LOGDEBUG("trying: %s %s", (const char*)SegTypeCode(itemtab[i].leader), itemtab[i].name); bool hit; if(leader == next_seg) hit = TRUE; /* an item leader matches the current segment */ else if(leader == any_leader) hit = ( ITEM(i)->input(is) == SUCCESS ); else hit = FALSE; if(hit) { if(!failed_required.is_empty()) { /* if we had to skip a required item... */ int f = failed_required.pop(); tracer = f; if(subclass() == PGObject::group) { /*** if we are a goup, we fail */ unset(); is.rdbuf()->seekmark(spos); tracer.reject(); return FAIL; } else /*** whereas non-groups issue a... */ if(pedantic) /* ...parse error */ { record_parse_error("missing required item %d `%s'", f, itemtab[f].name); EPARSE("missing required item %d `%s'", f, itemtab[f].name); } else /* ...warning */ { record_parse_warning("missing required item %d `%s'", f, itemtab[f].name); LOGWARNING("missing required item %d `%s'", f, itemtab[f].name); } tracer = i; // undos `tracer = f;' above } /* read on, skipping the unmatching items */ failed.pop(); if(leader != any_leader) /* any_leader-item was read above */ ITEM(i)->input(is); any_success = TRUE; // tracer++; (if we would count actual places) } else /* i.e. if leading segment could not be matched */ { LOGDEBUG("failed to input %d `%s'", i, itemtab[i].name); ITEM(i)->unset(); /* unset in case we do not come back */ if(itemtab[i].required) failed_required.push(i); failed.push(i); } } /* end of for */ tracer = -1; // we tried every item and we are exhausted now switch(subclass()) { case PGObject::message: if(!failed.is_empty()) { /* remove unexpected segment */ char tag[4]; is.get(tag, 4); record_parse_warning("unexpected segment `%s'", tag); LOGWARNING("unexpected segment `%s'", tag); match(is, getdel(is, Delimiters::seglevel)); parseTrace.incrSegOfMsg(); // increase actual segment } break; case PGObject::group: if(!failed.is_empty()) { /* for pure optional groups: */ if(any_success) /* if there was at least any success */ { set(); tracer.accept(); return SUCCESS; } else { unset(); is.rdbuf()->seekmark(spos); tracer.reject(); return FAIL; } } break; default: FATAL("unhandled subclass %d", subclass()); //internal error } } set(); tracer.accept(); return SUCCESS; } #else /* SEGSTRUC_USE_OLD_INPUT */ result SegStruc::input(istream& is) { if(!is.ipfx(1)) { if(is.eof()) { LOGDEBUG("end of message"); return FAIL; } else ERROS("error on input stream"); } streammarker spos(is.rdbuf()); /* a group might fail, needing to backtrack */ bool eom_seen = FALSE; if(isdebug(is)) FATAL("can't read from debug stream"); int i; for(i=0; iunset(); else if(item->input(is) != SUCCESS) { LOGDEBUG("failed to input %d `%s'", i, itemtab[i].name); if(itemtab[i].required) { if(subclass() == PGObject::group) { unset(); is.rdbuf()->seekmark(spos); return FAIL; } else { if(pedantic) { record_parse_error("missing required item %d `%s'", i, itemtab[i].name); EPARSE("missing required item %d `%s'", i, itemtab[i].name); } else { record_parse_error("missing required item %d `%s'", i, itemtab[i].name); LOGWARNING("missing required item %d `%s'", i, itemtab[i].name); } } } } } set(); return SUCCESS; } #endif /* SEGSTRUC_USE_OLD_INPUT */