/* * Copyright (c) 1991,1993 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Systems * Engineering Group at Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header: /cvsroot/nsnam/nam-1/trace.cc,v 1.69 2002/05/03 01:16:39 buchheim Exp $ (LBL) */ #include #include #include #include #ifdef WIN32 #include #include #else #include #include #endif #include #include #include "trace.h" #include "state.h" #include "packet.h" #include "address.h" #include "nam_stream.h" extern double time_atof(const char*); class TraceClass : public TclClass { public: TraceClass() : TclClass("Trace") {} TclObject* create(int argc, const char*const* argv); } trace_class; TclObject* TraceClass::create(int argc, const char*const* argv) { if (argc != 6) return (0); /* * Open the trace file for reading and read its first line * to be able to determine needed values: trace start time, * trace duration, etc. */ Trace* tr = new Trace(argv[4], argv[5]); if (!tr->valid()) { delete tr; tr = NULL; } return (tr); } //---------------------------------------------------------------------- // Trace::Trace(const char *fname, const char *animator) // - Create a new tracefile parser and event handler for // file "fname" and connect it to the animator object //---------------------------------------------------------------------- Trace::Trace(const char *fname, const char *animator) : handlers_(0), nam_(0), skipahead_mode_(0), count_(0) { last_event_time_ = 0.0; // Connect to nam animator nam_ = (NetworkAnimator *)TclObject::lookup(animator); strncpy(fileName_, fname, sizeof(fileName_)-1); fileName_[sizeof(fileName_)-1] = 0; nam_stream_ = NamStream::open(fileName_); if (!nam_stream_->is_ok()) { delete nam_stream_; nam_stream_ = NULL; perror("nam: fdopen"); // exit(1); return; // tr->valid() will check this } findLastLine(); /* * Go to the beginning of the file, read the first line and * save its contents. */ off_t pos = nam_stream_->seek(0, SEEK_SET); assert(pos == 0); /* * Minimum time on the nam time slider is the time of the first * trace event. */ mintime_ = nextTime(); now_ = mintime_; State::instance()->setTimes(mintime_, maxtime_); // Initialize ParseTable parse_table_ = new ParseTable(&pending_); } //---------------------------------------------------------------------- // Trace::~Trace() //---------------------------------------------------------------------- Trace::~Trace() { delete parse_table_; } //---------------------------------------------------------------------- //---------------------------------------------------------------------- int Trace::valid() { return (nam_stream_ && nam_stream_->is_ok()); } //---------------------------------------------------------------------- //---------------------------------------------------------------------- int Trace::ReadEvent(double now, TraceEvent& e) { /* * If specified time is after the next event's time, read * the next line and return 1. Otherwise, just return 0. */ if (direction_ == FORWARDS) { if ((pending_.time != TIME_EOF) && (pending_.time < now)) { e = pending_; scan(); return (1); } } else { /*going backwards!*/ /* * two occasions: 1) pending_.time > now, * 2) pending_.time = -1, which means go to the end of file */ if ((pending_.time > now) || (pending_.time == TIME_EOF)) { e = pending_; scan(); if (pending_.time == TIME_EOF) pending_.time = TIME_BOF; return (1); } } return (0); } //--------------------------------------------------------------------- // int // Trace::nextLine() // // - This needs to be cleaned up and it may effect other parts of // the file parsing code. It is not very efficient with the amount // of seeking going on. //--------------------------------------------------------------------- int Trace::nextLine() { char * position; if (direction_ == FORWARDS) { // moving forward through the trace file // We need to read in one line at a time nam_stream_->gets(pending_.image, sizeof(pending_.image)); ++lineno_; if (nam_stream_->eof()) { Tcl& tcl = Tcl::instance(); tcl.evalf("%s stopmaxtime %f", nam()->name(), pending_.time); return 0; } } else { // moving backwards through the trace file position = nam_stream_->rgets(pending_.image, sizeof(pending_.image)); lineno_--; if (position == NULL ) { fprintf(stderr, "nam file reading error.\n"); return -1; // signal reading error } if (nam_stream_->tell() == 0) { // Beginning of file reached so we need to stop return -1; } } return(nam_stream_->tell()); } //--------------------------------------------------------------------- // void // Trace::scan() // - scan for the next valid nam event line in file // - Once everything becomes stable you can to get rid of all the // data type specific scan functions //--------------------------------------------------------------------- void Trace::scan() { char * time; /* * Read the next line in the trace file and store its contents * depending on line type. */ while (1) { TraceEvent & p = pending_; time = p.image; p.offset = nextLine(); if (p.offset <= 0) { // We reached the beginning of the file pending_.time = TIME_EOF; // Reset the last event time tracker last_event_time_ = 0.0; //fprintf(stderr, "EOF Reached.\n"); return; } // ----------------------------------------------- // This -t * line skipping is a hack to // enable the wireless code to work properly. // All the -t * lines are parsed in tcl files // before the animation starts and reparsing them // seems to screw up the wireless stuff. // ------------------------------------------------ // Skip over -t * lines while (*time != '\0') { // Find the -t flag if (*time == '-') { time++; if (*time == 't') { // Eat the whitespace time++; while (*time == ' ' || *time == '\t') { time++; } // We should be pointing to the // -t flag value now if (*time == '*') { break; } } } else { time++; } } if (*time == '*') { // Notify user if their tracefile has initialization events that // are mixed in with animation events switch (direction_) { case FORWARDS: // last_event_time_ is initialized to 0.0 since events cannot happen before this time. if (last_event_time_ != 0.0) { fprintf(stderr, "Warning: Initialization event is mixed in with animation events.\n"); fprintf(stderr, "%s", p.image); fprintf(stderr, "The above event should occur before all -t