/*--------------------------------------------------------------------------
| Copyright (c) 2003 Quest Technical Solutions Inc.
Rev. 1.00 - 04/24/03 6:52PM

+--------------------------------------------------------------------------*/

#ifdef _MSC_VER
#define strncmpi(a1,a2,a3)(_strnicmp((a1),(a2),(a3)))
#endif

#ifdef __cplusplus
extern "C"
{
#else
#define CMD_LINE_VER
#endif

#define VER "1.01"

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
#include <time.h>

#include "QtTypDef.h"
#include "PbcPdu.h"
#include "postfix.h"


// definitions

typedef struct tag_KEY_WORD
{
    char    keyWord[33];
    BYTE    keyType;
    DWORD   keyVal;
} KEY_WORD;
#define KEY_CONSTANT    0x01


KEY_WORD KeyWord[] =
{
    "STSOK"     , KEY_CONSTANT   , PBC_STS_OK           ,
    "STSSTP"    , KEY_CONSTANT   , PBC_STS_STP_ERR      ,
    "STSPAR"    , KEY_CONSTANT   , PBC_STS_PAR_ERR      ,
    "STSSD"     , KEY_CONSTANT   , PBC_STS_SD_ERR       ,
    "STSRPT"    , KEY_CONSTANT   , PBC_STS_RPT_ERR      ,
    "STSUND"    , KEY_CONSTANT   , PBC_STS_UND_ERR      ,
    "STSOVR"    , KEY_CONSTANT   , PBC_STS_OVR_ERR      ,
    "STSCHK"    , KEY_CONSTANT   , PBC_STS_FCS_ERR      ,
    "STSED"     , KEY_CONSTANT   , PBC_STS_ED_ERR       ,
    "SD1"       , KEY_CONSTANT   , PBC_SD_SD1           ,
    "SD2"       , KEY_CONSTANT   , PBC_SD_SD2           ,
    "SD3"       , KEY_CONSTANT   , PBC_SD_SD3           ,
    "SD4"       , KEY_CONSTANT   , PBC_SD_SD4           ,
    "SC"        , KEY_CONSTANT   , PBC_SD_SC            ,
    "ED"        , KEY_CONSTANT   , PBC_ED               ,
    "SAPEXT"    , KEY_CONSTANT   , 0x80                 ,
    "TYPMSK"    , KEY_CONSTANT   , 0xcf                 ,
    "MTM1"      , KEY_CONSTANT   , 0x40                 ,
    "MTM2"      , KEY_CONSTANT   , 0xc0                 ,
    "MSRD"      , KEY_CONSTANT   , 0x41                 ,
    "MSDN"      , KEY_CONSTANT   , 0x42                 ,
    "SDAL"      , KEY_CONSTANT   , 0x43                 ,
    "SDNL"      , KEY_CONSTANT   , 0x44                 ,
    "SDAH"      , KEY_CONSTANT   , 0x45                 ,
    "SDNH"      , KEY_CONSTANT   , 0x46                 ,
    "RDD"       , KEY_CONSTANT   , 0x47                 ,
    "GSRD"      , KEY_CONSTANT   , 0x48                 ,
    "RFDL"      , KEY_CONSTANT   , 0x49                 ,
    "MDLY"      , KEY_CONSTANT   , 0x4a                 ,
    "MKEP"      , KEY_CONSTANT   , 0x4b                 ,
    "SRDL"      , KEY_CONSTANT   , 0x4c                 ,
    "SRDH"      , KEY_CONSTANT   , 0x4d                 ,
    "RIR "      , KEY_CONSTANT   , 0x4e                 ,
    "RLSR"      , KEY_CONSTANT   , 0x4f                 ,
    "OK"        , KEY_CONSTANT   , 0x00                 ,
    "UE"        , KEY_CONSTANT   , 0x01                 ,
    "RR"        , KEY_CONSTANT   , 0x02                 ,
    "RS"        , KEY_CONSTANT   , 0x03                 ,
    "DL"        , KEY_CONSTANT   , 0x08                 ,
    "NR"        , KEY_CONSTANT   , 0x09                 ,
    "DH"        , KEY_CONSTANT   , 0x0a                 ,
    "RD"        , KEY_CONSTANT   , 0x0c                 ,
    "RDH"       , KEY_CONSTANT   , 0x0d                 ,

    "STS"       , STS_CHAR       , 0                    ,
    "LEN"       , LEN_CHAR       , 0                    ,
    "SD"        , SD_CHAR        , 0                    ,

    "DA"        , NODE_CHAR      , 0                    ,
    "SA"        , NODE_CHAR      , 1                    ,
    "FC"        , FC_CHAR        , 0                    ,
    "DSAP"      , DSAP_CHAR      , 0                    ,
    "SSAP"      , SSAP_CHAR      , 0                    ,

    "DataByte"  , DATA_BYTE_CHAR , 0                    ,
    "DataWord"  , DATA_WORD_CHAR , 0                    ,
    "CmdArg"    , CMD_ARG_CHAR   , 0                    ,
    "GapTme"    , GAP_CHAR       , 0                    ,
};

static bool ShowFileOfs;
static bool NoRef;
static bool NoDelim;
static bool NoDst;
static bool NoSrc;
static bool NoFc;
static bool NoDstSap;
static bool NoSrcSap;
static bool NoData;
static bool DataSgn;
static bool DataUns;
static bool Data16;
static bool NoBad;
static bool DetailSts;
static bool ShowFcbTyp;
static bool ShowFcs;
static bool Selective;
static char TmeAbsFmt[20];
static char TmeGapFmt[20];
static char TmeDeltaFmt[20];
static BYTE    GrphGapWdth;
static __int64 GrphGapMax;
static BYTE    GrphDeltaWdth;
static __int64 GrphDeltaMax;

DWORD CmdArg[4];

static char OptFileName[500];
static char    EquBuf[4096];
static char ErrStr[500];

static __int64 TmeDiv;
static __int64 TmeMult;
static uchr    BaudMul;
static PBC_CAPTFILE_HDR CptHdr;

static char   InFileNameBase[500];
static DWORD  Hour;
static DWORD  Min;
static DWORD  NumMin;

static __int64 AbsTme;
static __int64 DeltaTime;
static __int64 GapTime;

static bool    FirstDelta;

static bool    FirstFrame;

static __int64 LastRawTme=0;
static __int64 LastDspTme=0;
static BYTE    LastLen=0;

static BYTE    GapGraphWidth=20;

static DWORD  RefNum;
static BYTE   FrmDataLen;
static BYTE   FrameSts;
static BYTE   FrameSd;
static BYTE * pFrmNode;
static BYTE * pFrmFc;
static BYTE * pFrmDSap;
static BYTE * pFrmSSap;
static BYTE * pFrmData;

char   InFileName[80];
FILE * InFp=0;
FILE * OutFp=0;

#ifdef CMD_LINE_VER
DWORD  InFileLen;
DWORD  Progress, ProgressLast;
#endif

char * ParseExpresion (FILE * fp );
bool   LookUpEquate (char * pStr, BYTE * Type, DWORD *Arg );


char * ReadOptionFile ();
char * ParseOptArg (char * pArgStr);

void   ProcTimeStamp  (__int64 RawTme, BYTE Len);
void   CalcTimeFactors (void);
void   PrintTimeStamp ();
void   PrintTime (__int64 Time64, char * pFmt);
void   PrintGraph (BYTE Wdth, __int64 Tme, __int64 Max);
void   PrintFrame (BYTE * pBuf, BYTE Len);
void   PrintLunit (BYTE * pBuf, BYTE Len);
void   PrintDstSrc(BYTE Dst, BYTE Src);
void   PrintDstSapSrcSap (BYTE Dst, BYTE Src, BYTE DstSap, BYTE SrcSap);
void   PrintFC    (BYTE   FrmCtl);
void   PrintFrameData (BYTE * pBuf, BYTE Len);
void   PrintRaw   (BYTE * pBuf, BYTE Len);

char * SyncToCapture ();
char * ReadFrame (__int64 * pRawTme, BYTE * pBuf, BYTE * pLen);
char * PbcFileFread (BYTE * pBuf, size_t RqLen);
char * GetNextFile ();
void   CloseFiles();
void   SkipToToken (char ** ppStr);
void   SkipPastToken (char ** ppStr);
char * ParseTime (char ** ppStr, __int64 * pVal);
char * ParseNum  (char ** ppStr, long * pVal);

char * PbcDumpText(char * ArgInFileNameBase, char * OutFileName, char * ArgOptFileName, DWORD ArgHour, DWORD ArgMin, DWORD ArgNumMin, DWORD FirstRef, DWORD LastRef, DWORD Arg0, DWORD Arg1, DWORD Arg2, DWORD Arg3)
{
    char  * pErrStr;
    __int64 RawTme;
    BYTE    FrameBuf[300];
    BYTE    FrameLen;
    DWORD   GapTmeUs;
    int     Result;

    CmdArg[0] = Arg0;
    CmdArg[1] = Arg1;
    CmdArg[2] = Arg2;
    CmdArg[3] = Arg3;

    EquBuf[0] = '\0';

    strcpy (OptFileName,ArgOptFileName);

    if ((pErrStr=ReadOptionFile())!=NULL)
    {
        return pErrStr;
    }

    if ((OutFp=fopen(OutFileName,"wt+")) == NULL)
    {
        sprintf (ErrStr,"Unable to Open Output Text File %s",OutFileName);
        return ErrStr;
    }

//    fprintf(OutFp,CopyRightStr);

    RefNum     = 0;
    FirstFrame = true;
    FirstDelta = true;

    strcpy (InFileNameBase, ArgInFileNameBase);
    Hour   = ArgHour;
    Min    = ArgMin;
    NumMin = ArgNumMin;

    if ((pErrStr=GetNextFile ())!=NULL)
    {
        return pErrStr;
    }
    CalcTimeFactors ();

    if ((pErrStr=SyncToCapture())!=NULL)
    {
        CloseFiles(OutFp,InFp);
        return pErrStr;
    }

    while ( 1 )
    {
        int FileOfs;
next_frame:;
        if ((pErrStr=ReadFrame (&RawTme, FrameBuf, &FrameLen))!=NULL)
        {
            if ( pErrStr==(char *)0xffffffff )
            {
                fprintf(OutFp,"\nEnd of Capture Data\n");
                CloseFiles(OutFp,InFp);
                return NULL;
            }
            CloseFiles(OutFp,InFp);
            return pErrStr;
        }
        RefNum++;

        FileOfs = ftell(InFp);

#ifdef CMD_LINE_VER
        Progress = (FileOfs*100)/InFileLen;
        if (Progress != ProgressLast)
        {
            ProgressLast = Progress;
            printf ("%s %2u%%\r", InFileName, Progress);
        }
#endif
        ProcTimeStamp(RawTme, FrameLen);

        if (RefNum<FirstRef)
        {
            goto next_frame;
        }

        if (RefNum>LastRef)
        {
            fprintf(OutFp,"\nLast Reference Reached\n");
            CloseFiles(OutFp,InFp);
            return NULL;
        }

        GapTmeUs = (DWORD) (GapTime/1000);

        if ( Selective )
        {
            Result = EvaluatePostfixExpression(FrameSts, FrmDataLen, FrameSd, pFrmNode, pFrmFc, pFrmDSap, pFrmSSap, GapTmeUs, pFrmData);
        }

        if (!Selective || (Result!=0))
        {
            if (ShowFileOfs)
            {
                fprintf(OutFp,"%08x: ", FileOfs);
            }
            if ( !NoRef )
            {
                fprintf(OutFp,"%9u: ",RefNum);
            }
            PrintTimeStamp();
            PrintFrame (FrameBuf, FrameLen);
            fprintf(OutFp,"\n");
        }
    }

    CloseFiles(OutFp,InFp);
    return NULL;
}


char * ReadOptionFile ()
{
    FILE * OptFp;
    char   Buf[500];
    char * pErrStr;

    ShowFileOfs = false;
    NoRef       = false;
    NoDelim     = false;
    NoDst       = false;
    NoSrc       = false;
    NoFc        = false;
    NoDstSap    = false;
    NoSrcSap    = false;
    NoData      = false;
    DataSgn     = false;
    DataUns     = false;
    Data16      = false;
    NoBad       = false;
    DetailSts   = false;
    ShowFcbTyp  = false;
    ShowFcs     = false;
    Selective   = false;

    TmeAbsFmt[0]        = '\0';
    TmeGapFmt[0]        = '\0';
    TmeDeltaFmt[0]      = '\0';
    GrphGapWdth         = 0;
    GrphGapMax          = 0;
    GrphDeltaWdth       = 0;
    GrphDeltaMax        = 0;

    if ( OptFileName[0] == '\0' )
    {
        return NULL;
    }
    if ( (OptFp=fopen(OptFileName,"rt")) == NULL)
    {
        sprintf (ErrStr,"Unable to Open Option File %s",OptFileName);
        return ErrStr;
    }
    while (fgets (Buf,200,OptFp))
    {
        while (isspace(Buf[0]))    // get rid of any leading fillers
        {
            strcpy (&Buf[0],&Buf[1]);
        }

        if ( Buf[strlen(Buf)-1] == '\n' )
        {
            Buf[strlen(Buf)-1] = '\0';
        }

        if (Buf[0] == ';')         // skip lines that start with ';'
        {
            Buf[0] = '\0';
        }
        if (Buf[0] != '\0')
        {
            if ( !strncmpi (Buf,"ShowOnly",8 ))
            {
                Selective=true;
                if ((pErrStr=ParseExpresion(OptFp)) != NULL)
                {
                    fclose (OptFp);
                    return pErrStr;
                }
            }
            else
            {
                if ((pErrStr=ParseOptArg(Buf)) != NULL)
                {
                    fclose (OptFp);
                    return pErrStr;
                }
            }
        }
    }
    fclose (OptFp);
    return NULL;;
}

char * ParseOptArg (char *pArgStr)
{
    char * pErrStr;
    char * pEnd;
    long   Val;

    if      (!strncmpi(pArgStr,"NoRef"      , 5)) NoRef       = true;
    else if (!strncmpi(pArgStr,"ShowFileOfs", 7)) ShowFileOfs = true;
    else if (!strncmpi(pArgStr,"NoDelim"    , 7)) NoDelim     = true;
    else if (!strncmpi(pArgStr,"NoDstSap"   , 8)) NoDstSap    = true;
    else if (!strncmpi(pArgStr,"NoSrcSap"   , 8)) NoSrcSap    = true;
    else if (!strncmpi(pArgStr,"NoDst"      , 5)) NoDst       = true;
    else if (!strncmpi(pArgStr,"NoSrc"      , 5)) NoSrc       = true;
    else if (!strncmpi(pArgStr,"NoFc"       , 4)) NoFc        = true;
    else if (!strncmpi(pArgStr,"NoData"     , 6)) NoData      = true;
    else if (!strncmpi(pArgStr,"DataSgn"    , 7)) DataSgn     = true;
    else if (!strncmpi(pArgStr,"DataUns"    , 7)) DataUns     = true;
    else if (!strncmpi(pArgStr,"Data16"     , 6)) Data16      = true;
    else if (!strncmpi(pArgStr,"NoBad"      , 5)) NoBad       = true;
    else if (!strncmpi(pArgStr,"DetailSts"  , 9)) DetailSts   = true;
    else if (!strncmpi(pArgStr,"ShowFcbTyp" ,10)) ShowFcbTyp  = true;
    else if (!strncmpi(pArgStr,"ShowFcs"    , 7)) ShowFcs     = true;
    else if (!strncmpi(pArgStr,"Descrip="   , 8));
    else if (!strncmpi(pArgStr,"ArgName"    , 7));

    else if (!strncmpi(pArgStr,"TmeAbs",6))
    {
        pArgStr += 6;
        SkipToToken (&pArgStr);
        pEnd = pArgStr;
        SkipPastToken (&pEnd);
        *pEnd = '\0';
        if ( strlen(pArgStr) < sizeof(TmeAbsFmt) )
        {
            strcpy (TmeAbsFmt, pArgStr);
        }
        else
        {
            sprintf (ErrStr,"Time Format String Too Long '%s'",pArgStr);
            return ErrStr;
        }
    }
    else if (!strncmpi(pArgStr,"TmeGap",6))
    {
        pArgStr += 6;
        SkipToToken (&pArgStr);
        pEnd = pArgStr;
        SkipPastToken (&pEnd);
        *pEnd = '\0';
        if ( strlen(pArgStr) < sizeof(TmeGapFmt) )
        {
            strcpy (TmeGapFmt, pArgStr);
        }
        else
        {
            sprintf (ErrStr,"Time Format String Too Long '%s'",pArgStr);
            return ErrStr;
        }
    }
    else if (!strncmpi(pArgStr,"TmeDelta",8))
    {
        pArgStr += 8;
        SkipToToken (&pArgStr);
        pEnd = pArgStr;
        SkipPastToken (&pEnd);
        *pEnd = '\0';
        if ( strlen(pArgStr) < sizeof(TmeDeltaFmt) )
        {
            strcpy (TmeDeltaFmt, pArgStr);
        }
        else
        {
            sprintf (ErrStr,"Time Format String Too Long '%s'",pArgStr);
            return ErrStr;
        }
    }
    else if (!strncmpi(pArgStr,"GrphGap",7))
    {
        pArgStr += 7;
        SkipToToken (&pArgStr);

        if ( (pErrStr=ParseNum (&pArgStr, &Val)) != NULL)
        {
            return pErrStr;
        }

        if ( (Val<5) || (Val>100) )
        {
            sprintf (ErrStr,"Invalid GrphGap Width value '%d' (5-100)",Val);
            return ErrStr;

        }
        GrphGapWdth = (BYTE) Val;

        SkipToToken (&pArgStr);

        if ( (pErrStr=ParseTime (&pArgStr, &GrphGapMax)) != NULL)
        {
            return pErrStr;
        }
    }
    else if (!strncmpi(pArgStr,"GrphDelta",9))
    {
        pArgStr += 9;
        SkipToToken (&pArgStr);

        if ( (pErrStr=ParseNum (&pArgStr, &Val)) != NULL)
        {
            return pErrStr;
        }

        if ( (Val<5) || (Val>100) )
        {
            sprintf (ErrStr,"Invalid GrphDelta Width value '%d' (5-100)",Val);
            return ErrStr;

        }
        GrphDeltaWdth = (BYTE) Val;

        SkipToToken (&pArgStr);

        if ( (pErrStr=ParseTime (&pArgStr, &GrphDeltaMax)) != NULL)
        {
            return pErrStr;
        }
    }
    else
    {
        sprintf (ErrStr,"Invalid Option Argument '%s'",pArgStr);
        return ErrStr;
    }
    return NULL;
}


char * ParseExpresion (FILE * fp )
{
    char  * pStr;
    int     LastChar;

    DWORD   EquVal;
    int     ErrOfs;
    int     Error;
    char  * pExp;
    char    EquStr[33];
    char    ExpStr[256];
    char    TmpStr[2]={" "};
    BYTE    EquType;

    pStr = EquBuf;
    LastChar = '\0';

    while ( LastChar != '#' )
    {
        LastChar = getc(fp);

        switch (LastChar)
        {
        case '\n' :
        case '\t' :
            LastChar=' ';
            goto add_char_to_equ;

        case '#' :
            break;

        case ';' :
            while ( (LastChar != '\n') && (LastChar != EOF) )
            {
                LastChar = getc(fp);
            }
            break;
        case EOF :
            *pStr = '\0';
            sprintf (ErrStr,"Invalid Option ShowOnly Equation: End Marker '#' not found '%s'",EquBuf);
            return ErrStr;

        default:
add_char_to_equ:;
            *pStr++ = LastChar;
            if ( (pStr-EquBuf)>sizeof(EquBuf) )
            {
                *pStr = '\0';
                return "Invalid Option ShowOnly Equation: Equation Too Long";
            }
        }
    }
    *pStr = '\0';

    pStr = EquBuf;

    pExp = pStr;

    ExpStr[0] = '\0';

    while ( (*pExp != ';') && (*pExp != '\0') )
    {
        EquStr[0] = '\0';
        if ( isalpha(*pExp) || (*pExp=='_') )
        {
            while ( isalpha(*pExp) || (*pExp=='_') || isdigit(*pExp) )
            {
                TmpStr[0] = *pExp++;
                strcat (EquStr,TmpStr);
            }

            if ( !_strcmpi (EquStr,"OR" ) || !_strcmpi (EquStr,"AND" ) )
            {
            }
            else
            {
                if ( !LookUpEquate (EquStr, &EquType, &EquVal ) )
                {
                    sprintf (ErrStr,"Invalid Option ShowOnly Equation: Undefined Identifier '%s'",EquStr);
                    return ErrStr;
                }

                switch ( EquType )
                {
                case STS_CHAR :
                case LEN_CHAR :
                case SD_CHAR  :
                case NODE_CHAR :
                case FC_CHAR :
                case DSAP_CHAR :
                case SSAP_CHAR :
                case GAP_CHAR :
                    sprintf (EquStr,"%c",EquType);
                    strcat (ExpStr,EquStr);

                case KEY_CONSTANT :
                    sprintf (EquStr,"%d",EquVal);
                    break;

                case DATA_BYTE_CHAR :
                case DATA_WORD_CHAR :
                case CMD_ARG_CHAR :
                    sprintf (EquStr,"%c",EquType);
                    if ( *pExp++ != '[' )
                    {
                        sprintf (ErrStr,"Invalid Option ShowOnly Equation: '[' Expected '%s'",EquStr);
                        return ErrStr;
                    }

                    if ( !strncmpi (pExp,"0x",2 ) )
                    {
                        strcat (ExpStr,"0x");
                        pExp += 2;
                        while ( isxdigit(*pExp) )
                        {
                            strncat (EquStr,pExp++,1);
                        }
                    }
                    else
                    {
                        while ( isdigit(*pExp) )
                        {
                            strncat (EquStr,pExp++,1);
                        }
                    }
                    if ( *pExp++ != ']' )
                    {
                        sprintf (ErrStr,"Invalid Option ShowOnly Equation: ']' Expected '%s'",EquStr);
                        return ErrStr;
                    }
                    break;
                }
            }

            strcat (ExpStr,EquStr);
        }
        else if ( !strncmpi (pExp,"0x",2 ) )
        {
            strcat (ExpStr,"0x");
            pExp += 2;
            while ( isxdigit(*pExp) )
            {
                strncat (ExpStr,pExp++,1);
            }
        }
        else
        {
            TmpStr[0] = *pExp++;
            strcat (ExpStr,TmpStr);
        }
    }

    ErrOfs = InfixToPostfix(ExpStr, strlen(ExpStr), &Error);

    if ( ErrOfs != -1 )
    {
        strcpy (ErrStr,"Option ShowOnly Expression Error: ");
        switch ( Error )
        {
        case MISSINGPARENTH : strcat (ErrStr,"Missing Parenthesis '"); strcat (ErrStr,&ExpStr[ErrOfs]); break;
        case MISSINGPARAM   : strcat (ErrStr,"Missing Parameter '"  ); strcat (ErrStr,&ExpStr[ErrOfs]); break;
        case MISSINGOPER    : strcat (ErrStr,"Missing Operator '"   ); strcat (ErrStr,&ExpStr[ErrOfs]); break;
        case INVALIDPARAM   : strcat (ErrStr,"Invalid Parameter '"  ); strcat (ErrStr,&ExpStr[ErrOfs]); break;
        case INVALIDOPER    : strcat (ErrStr,"Invalid Operator '"   ); strcat (ErrStr,&ExpStr[ErrOfs]); break;
        case INVALIDVALUE   : strcat (ErrStr,"Invalid Value '"      ); strcat (ErrStr,&ExpStr[ErrOfs]); break;
        case AMBIGOPER      : strcat (ErrStr,"Ambiguous Operator '" ); strcat (ErrStr,&ExpStr[ErrOfs]); break;
        default:              strcat (ErrStr,"Unknown"); break;
        }
        return ErrStr;
    }

    return NULL;
}

bool LookUpEquate (char * pStr, BYTE * Type, DWORD *Arg )
{
    DWORD lp;

    for ( lp=0 ; lp<(sizeof(KeyWord)/sizeof(KEY_WORD)) ; lp++ )
    {
        if ( !_strcmpi(pStr,KeyWord[lp].keyWord) )
        {
            *Arg  = KeyWord[lp].keyVal;
            *Type = KeyWord[lp].keyType;
            return true;
        }
    }
    return false;
}

void ProcTimeStamp (__int64 RawTme, BYTE Len)
{

    __int64 FrameTime;

    AbsTme = (RawTme*TmeMult)/TmeDiv;

    if ( FirstFrame )
    {
        FirstFrame = false;

        LastRawTme = RawTme;
        LastDspTme = RawTme;
        LastLen = 0;
    }

    DeltaTime = RawTme-LastDspTme;
    DeltaTime = (DeltaTime*TmeMult)/TmeDiv;

    FrameTime = LastLen;
    FrameTime *= (BaudMul*11);

    GapTime   = (RawTme-LastRawTme)-FrameTime;
    GapTime   = (GapTime*TmeMult)/TmeDiv;

    LastRawTme = RawTme;
    LastLen = Len;
}


/*
TmeStmp Conversion to pico seconds

      Baud  TmeStmpClk        Mult    Div
----------  ----------  ---------- ------
12,000,000  48,000,000       1,000     48
 6,000,000  48,000,000       1,000     48
 3,000,000  48,000,000       1,000     48
 1,500,000  24,000,000       1,000     24
   500,000   8,000,000       1,000      8
   187,500   3,000,000       1,000      3
    93,750   1,500,000      10,000     15
    19,200     307,200  10,000,000  3,072
     9,600     153,600  10,000,000  1,536
*/

void CalcTimeFactors (void)
{
    switch ( CptHdr.Baud )
    {
    case PBCAP_BAUD_12M   : TmeMult =       1000 ; TmeDiv  =   48; BaudMul =  4; break;
    case PBCAP_BAUD_6M    : TmeMult =       1000 ; TmeDiv  =   48; BaudMul =  8; break;
    case PBCAP_BAUD_3M    : TmeMult =       1000 ; TmeDiv  =   48; BaudMul = 16; break;
    case PBCAP_BAUD_1M5   : TmeMult =       1000 ; TmeDiv  =   24; BaudMul = 16; break;
    case PBCAP_BAUD_500K  : TmeMult =       1000 ; TmeDiv  =    8; BaudMul = 16; break;
    case PBCAP_BAUD_187K5 : TmeMult =       1000 ; TmeDiv  =    3; BaudMul = 16; break;
    case PBCAP_BAUD_93K75 : TmeMult =      10000 ; TmeDiv  =   15; BaudMul = 16; break;
    case PBCAP_BAUD_19K2  : TmeMult =   10000000 ; TmeDiv  = 3072; BaudMul = 16; break;
    case PBCAP_BAUD_9K6   : TmeMult =   10000000 ; TmeDiv  = 1536; BaudMul = 16; break;
    }
}

void PrintTimeStamp ()
{
    if (TmeAbsFmt[0] != '\0')
    {
        fprintf(OutFp,"a");
        PrintTime (AbsTme, TmeAbsFmt);
    }

    if ( FirstDelta )
    {
        FirstDelta = false;
        DeltaTime = 0;
    }

    if (TmeDeltaFmt[0] != '\0')
    {
        fprintf(OutFp,"d");
        PrintTime (DeltaTime, TmeDeltaFmt);
    }

    if ( GrphDeltaWdth != 0 )
    {
        fprintf(OutFp,"d");
        PrintGraph (GrphDeltaWdth, DeltaTime, GrphDeltaMax);
    }

    if (TmeGapFmt[0] != '\0')
    {
        fprintf(OutFp,"g");
        PrintTime (GapTime, TmeGapFmt);
    }

    if ( GrphGapWdth != 0 )
    {
        fprintf(OutFp,"g");
        PrintGraph (GrphGapWdth, GapTime, GrphGapMax);
    }

    LastDspTme = LastRawTme;
}

void PrintTime (__int64 Time64, char * pFmt)
{
    WORD nSec;
    WORD uSec;
    WORD mSec;
    WORD Sec;
    WORD Min;
    WORD Hour;
    char SepChar;
    bool FirstField=true;

    nSec  = (WORD) (Time64%1000);
    Time64  /= 1000;

    uSec  = (WORD) (Time64%1000);
    Time64  /= 1000;

    mSec  = (WORD) (Time64%1000);
    Time64  /= 1000;

    Sec   = (WORD) (Time64%60);
    Time64  /= 60;

    Min   = (WORD) (Time64%60);
    Time64  /= 60;

    Hour  = (WORD) Time64;

    if (!strncmpi(pFmt,"hr" , 2))
    {
        pFmt+=2;
        SepChar=*pFmt;
        if(SepChar!='\0')
        {
            pFmt++;
        }
        else
        {
            SepChar=' ';
        }
        if ( FirstField )
        {
            fprintf(OutFp,"%2u%c",Hour ,SepChar);
        }
        else
        {
            fprintf(OutFp,"%02u%c",Hour ,SepChar);
        }
        FirstField=false;
    }
    if (!strncmpi(pFmt,"mn" , 2))
    {
        pFmt+=2;
        SepChar=*pFmt;
        if(SepChar!='\0')
        {
            pFmt++;
        }
        else
        {
            SepChar=' ';
        }
        if ( FirstField )
        {
            fprintf(OutFp,"%2u%c",Min   ,SepChar);
        }
        else
        {
            fprintf(OutFp,"%02u%c",Min   ,SepChar);
        }
        FirstField=false;
    }
    if (!strncmpi(pFmt,"sc" , 2))
    {
        pFmt+=2;
        SepChar=*pFmt;
        if(SepChar!='\0')
        {
            if ( isalpha(SepChar) )
            {
                SepChar='\0';
            }
            else
            {
                pFmt++;
            }
        }
        else
        {
            SepChar=' ';
        }
        if ( FirstField )
        {
            fprintf(OutFp,"%2u",Sec);
        }
        else
        {
            fprintf(OutFp,"%02u",Sec);
        }
        FirstField=false;

        if ( SepChar!='\0' )
        {
            fprintf(OutFp,"%c",SepChar);
        }
    }
    if (!strncmpi(pFmt,"ms" , 2))
    {
        pFmt+=2;
        SepChar=*pFmt;
        if(SepChar!='\0')
        {
            if ( isalpha(SepChar) )
            {
                SepChar='\0';
            }
            else
            {
                pFmt++;
            }
        }
        else
        {
            SepChar=' ';
        }
        if ( FirstField )
        {
            fprintf(OutFp,"%3u",mSec);
        }
        else
        {
            fprintf(OutFp,"%03u",mSec);
        }
        FirstField=false;

        if ( SepChar!='\0' )
        {
            fprintf(OutFp,"%c",SepChar);
        }
    }
    if (!strncmpi(pFmt,"us" , 2))
    {
        pFmt+=2;
        SepChar=*pFmt;
        if(SepChar!='\0')
        {
            if ( isalpha(SepChar) )
            {
                SepChar='\0';
            }
            else
            {
                pFmt++;
            }
        }
        else
        {
            SepChar=' ';
        }
        if ( FirstField )
        {
            fprintf(OutFp,"%3u",uSec);
        }
        else
        {
            fprintf(OutFp,"%03u",uSec);
        }
        FirstField=false;

        if ( SepChar!='\0' )
        {
            fprintf(OutFp,"%c",SepChar);
        }
    }
    if (!strncmpi(pFmt,"ns" , 2))
    {
        pFmt+=2;
        SepChar=*pFmt;
        if(SepChar!='\0')
        {
            if ( isalpha(SepChar) )
            {
                SepChar='\0';
            }
            else
            {
                pFmt++;
            }
        }
        else
        {
            SepChar=' ';
        }
        if ( FirstField )
        {
            fprintf(OutFp,"%3u",nSec);
        }
        else
        {
            fprintf(OutFp,"%03u",nSec);
        }
        FirstField=false;

        if ( SepChar!='\0' )
        {
            fprintf(OutFp,"%c",SepChar);
        }
    }
}

void PrintGraph (BYTE Wdth, __int64 Tme, __int64 Max)
{
    char TmpStr[101];

    memset (TmpStr,' ',Wdth);
    TmpStr[Wdth] = '\0';
    if (Tme > Max)
    {
        TmpStr[0]      = '*';
        TmpStr[Wdth-1] = '*';
//      memset (TmpStr,'*',Wdth);
        fprintf(OutFp,TmpStr);
    }
    else
    {
        TmpStr[Wdth-1] = '|';
        Tme *= Wdth;
        Tme /= Max;
        memset (TmpStr,'.',(DWORD)Tme);
        fprintf(OutFp,TmpStr);
    }
}

void PrintFrame (BYTE * pBuf, BYTE Len)
{
    BYTE Sts;

    Sts = pBuf[Len];

    if ( DetailSts )
    {
        if ( Sts&PBC_STS_STP_ERR )  fprintf(OutFp,"s"); else fprintf(OutFp,".");
        if ( Sts&PBC_STS_PAR_ERR )  fprintf(OutFp,"p"); else fprintf(OutFp,".");
        if ( Sts&PBC_STS_SD_ERR  )  fprintf(OutFp,"d"); else fprintf(OutFp,".");
        if ( Sts&PBC_STS_RPT_ERR )  fprintf(OutFp,"r"); else fprintf(OutFp,".");
        if ( Sts&PBC_STS_UND_ERR )  fprintf(OutFp,"u"); else fprintf(OutFp,".");
        if ( Sts&PBC_STS_OVR_ERR )  fprintf(OutFp,"o"); else fprintf(OutFp,".");
        if ( Sts&PBC_STS_FCS_ERR )  fprintf(OutFp,"c"); else fprintf(OutFp,".");
        if ( Sts&PBC_STS_ED_ERR  )  fprintf(OutFp,"e"); else fprintf(OutFp,".");
    }
    else
    {
        if ( pBuf[Len] == PBC_STS_OK)
        {
            fprintf(OutFp," ");
        }
        else
        {
            fprintf(OutFp,"*");
        }
    }

    if ( Len<1 )
    {
        fprintf(OutFp,"FrmLen?(%u)",Len);
    }

    switch ( *pBuf )
    {
    case PBC_SD_SD1 :
        if (!NoDelim)
        {
            fprintf(OutFp,"SD1 ");
        }
        if ( Len != 6)
        {
            fprintf(OutFp,"Len(%u)? ",Len);
            PrintRaw (pBuf,Len);
        }
        else
        {
            Len -= 1;
            pBuf     += 1;
            PrintLunit (pBuf, Len);
        }
        break;

    case PBC_SD_SD2 :
        if (!NoDelim)
        {
            fprintf(OutFp,"SD2 ");
        }
        if ( Len < 9)
        {
            fprintf(OutFp,"SD2 Len(%u)? ",Len);
            PrintRaw (pBuf,Len);
        }
        else if ( pBuf[1] != (Len-6) )
        {
            fprintf(OutFp,"SD2 LE?(%u) ",Len);
            PrintRaw (pBuf,Len);
        }
        else if ( pBuf[2] != pBuf[1] )
        {
            fprintf(OutFp,"SD2 LEr? ");
            PrintRaw (pBuf,Len);
        }
        else if ( pBuf[3] != PBC_SD_SD2 )
        {
            fprintf(OutFp,"SD2r? ");
            PrintRaw (pBuf,Len);
        }
        else
        {
            Len -= 4;
            pBuf     += 4;
            PrintLunit (pBuf, Len);
        }
        break;

    case PBC_SD_SD3 :
        if (!NoDelim)
        {
            fprintf(OutFp,"SD3 ");
        }
        if ( Len != 14)
        {
            fprintf(OutFp,"SD3 Len(%u)? ",Len);
            PrintRaw (pBuf,Len);
        }
        else
        {
            Len -= 1;
            pBuf     += 1;
            PrintLunit (pBuf, Len);
        }
        break;

    case PBC_SD_SD4 :
        if (!NoDelim)
        {
            fprintf(OutFp,"SD4 ");
        }
        if ( Len != 3)
        {
            fprintf(OutFp,"Len(%u)? ",Len);
            PrintRaw (pBuf,Len);
        }
        else
        {
            pBuf++;
            PrintDstSrc (pBuf[0], pBuf[1]);
        }
        break;

    case PBC_SD_SC   :
        if (!NoDelim)
        {
            fprintf(OutFp,"SC  ");
        }

        if (!NoDst)
        {
            fprintf(OutFp,"   ");
        }

        if ((!NoDst) || (!NoSrc))
        {
            fprintf(OutFp,"  ");
        }

        if (!NoSrc)
        {
            fprintf(OutFp,"   ");
        }

        if ( !NoFc )
        {
            if ( ShowFcbTyp )
            {
                fprintf(OutFp,"   ");
            }
            fprintf(OutFp,"SHAK ");
        }
        if ( Len != 1)
        {
            fprintf(OutFp,"Len(%u)? ",Len);
            PrintRaw (pBuf,Len);
        }
        break;

    default:
        fprintf(OutFp,"SD?%02x ", *pBuf);
        PrintRaw (pBuf,Len);
    }
}

void PrintLunit (BYTE * pBuf,BYTE Len)
{
    BYTE Dst, DstSap=0;
    BYTE Src, SrcSap=0;

    Dst  = *pBuf++;
    Src  = *pBuf++;
    Len -= 2;

    PrintDstSrc (Dst, Src);

    PrintFC (*pBuf++);
    Len -= 3;

    if ( Dst&0x80 )
    {
        DstSap  = *pBuf++;
        Len--;
    }

    if ( Src&0x80 )
    {
        SrcSap  = *pBuf++;
        Len--;
    }

    PrintDstSapSrcSap (Dst, Src, DstSap, SrcSap);

    if ( !NoData )
    {
        PrintFrameData (pBuf, Len );
    }

    pBuf += Len;

    if ( ShowFcs )
    {
        fprintf(OutFp,"[%02x] ", *pBuf);
    }

    pBuf++;

    if ( *pBuf == PBC_ED )
    {
        if (!NoDelim)
        {
            fprintf(OutFp,"ED ");
        }
    }
    else
    {
        fprintf(OutFp,"ED?(%02x) ", *pBuf);
    }
}

void PrintDstSrc (BYTE Dst, BYTE Src)
{
    if (NoDst && NoSrc)
    {
        return;
    }

    Dst &= 0x7f;
    Src &= 0x7f;
    if (!NoDst)
    {
        fprintf(OutFp,"%3u",Dst);
    }
    fprintf(OutFp,"<");

    if (!NoSrc)
    {
        fprintf(OutFp,"%-3u",Src);
    }

    fprintf(OutFp," ");
}

void PrintDstSapSrcSap (BYTE Dst, BYTE Src, BYTE DstSap, BYTE SrcSap)
{
    if (NoDstSap && NoSrcSap)
    {
        return;
    }

    if ( !NoDstSap )
    {
        if ( Dst&0x80 )
        {
            fprintf(OutFp,"%2u", DstSap );
        }
        else
        {
            fprintf(OutFp,"  ");
        }
    }

    if ( ((!NoDstSap) && (Dst&0x80)) || ((!NoSrcSap) && (Src&0x80)) )
    {
        fprintf(OutFp,"{");
    }
    else
    {
        fprintf(OutFp," ");
    }

    if ( !NoSrcSap )
    {
        if ( Src&0x80 )
        {
            fprintf(OutFp,"%-2u", SrcSap );
        }
        else
        {
            fprintf(OutFp,"  ");
        }
    }
    fprintf(OutFp," ");
}


void PrintFC (BYTE FrmCtl)
{
/*
    if ( FrmCtl&0x80 )
    {
        fprintf(OutFp,"FC?(%02x) ", FrmCtl);
        return;
    }
*/
    if ( NoFc )
    {
        return;
    }

    if ( FrmCtl&0x40 )
    {
        if ( ShowFcbTyp )
        {
            fprintf(OutFp,"%u", (FrmCtl>>5)&1);
            if ( FrmCtl&0x10 )
            {
                fprintf(OutFp,"v ");
            }
            else
            {
                fprintf(OutFp,"  ");
            }
        }

        switch ( FrmCtl&0x8f )
        {
        case PBC_FCS_SmTIME1 :
            fprintf(OutFp,"MTM1 ");
            break;
        case PBC_FCS_SmSRD :
            fprintf(OutFp,"MSRD ");
            break;
        case PBC_FCS_SmSDN :
            fprintf(OutFp,"MSDN ");
            break;
        case PBC_FCS_SDAL :
            fprintf(OutFp,"SDAL ");
            break;
        case PBC_FCS_SDNL :
            fprintf(OutFp,"SDNL ");
            break;
        case PBC_FCS_SDAH :
            fprintf(OutFp,"SDAH ");
            break;
        case PBC_FCS_SDNH :
            fprintf(OutFp,"SDNH ");
            break;
        case PBC_FCS_RDD  :
            fprintf(OutFp,"RDD  ");
            break;
        case PBC_FCS_DiagSRD :
            fprintf(OutFp,"GSRD ");
            break;
        case PBC_FCS_RFDL :
            fprintf(OutFp,"RFDL ");
            break;
        case PBC_FCS_SmSRDSltDel :
            fprintf(OutFp,"MDLY ");
            break;
        case PBC_FCS_SmSRDSltKeep :
            fprintf(OutFp,"MKEP ");
            break;
        case PBC_FCS_SRDL :
            fprintf(OutFp,"SRDL ");
            break;
        case PBC_FCS_SRDH :
            fprintf(OutFp,"SRDH ");
            break;
        case PBC_FCS_RIR  :
            fprintf(OutFp,"RIR  ");
            break;
        case PBC_FCS_RLSR :
            fprintf(OutFp,"RLSR ");
            break;
        case PBC_FCS_SmTIME2 :
            fprintf(OutFp,"MTM2 ");
            break;
        default:
            fprintf(OutFp,"Typ?(%02x) ", FrmCtl);
        }
    }
    else
    {
        if ( ShowFcbTyp )
        {
            switch ( (FrmCtl>>4)&0x03 )
            {
            case 0 :
                fprintf(OutFp,"ss ");
                break;
            case 1 :
                fprintf(OutFp,"mn ");
                break;
            case 2 :
                fprintf(OutFp,"mr ");
                break;
            case 3 :
                fprintf(OutFp,"mi ");
                break;
            }
        }

        switch ( FrmCtl&0x0f )
        {
        case PBC_FCR_OK  :
            fprintf(OutFp,"OK   ");
            break;
        case PBC_FCR_UE  :
            fprintf(OutFp,"UE   ");
            break;
        case PBC_FCR_RR  :
            fprintf(OutFp,"RR   ");
            break;
        case PBC_FCR_RS  :
            fprintf(OutFp,"RS   ");
            break;
        case PBC_FCR_DL  :
            fprintf(OutFp,"DL   ");
            break;
        case PBC_FCR_NR  :
            fprintf(OutFp,"NR   ");
            break;
        case PBC_FCR_DH  :
            fprintf(OutFp,"DH   ");
            break;
        case PBC_FCR_RDL :
            fprintf(OutFp,"RDL  ");
            break;
        case PBC_FCR_RDH :
            fprintf(OutFp,"RDH  ");
            break;
        default:
            fprintf(OutFp,"Typ?(%02x) ", FrmCtl);
        }
    }
}


void PrintFrameData (BYTE * pBuf, BYTE Len)
{
    BYTE Ofs;

    if ( (Len&1) || !Data16 )
    {
        for ( Ofs=0 ; Ofs<Len ; Ofs++ )
        {
            if ( DataSgn )
            {
                fprintf(OutFp,"%4d ",*((char *)pBuf)++);
            }
            else if ( DataUns )
            {
                fprintf(OutFp,"%3u ",*pBuf++);
            }
            else
            {
                fprintf(OutFp,"%02x ",*pBuf++);
            }

        }
    }
    else
    {
        ushrt Val;
        Len >>= 1;

        for ( Ofs=0 ; Ofs<Len ; Ofs++ )
        {

            Val  = (*pBuf++)<<8;
            Val |= *pBuf++;

            if ( DataSgn )
            {
                fprintf(OutFp,"%6d ",((short)Val));
            }
            else if ( DataUns )
            {
                fprintf(OutFp,"%5u ",Val);
            }
            else
            {
                fprintf(OutFp,"%04x ",Val);
            }

        }
    }
}

void PrintRaw (BYTE * pBuf, BYTE Len)
{
    BYTE Ofs;

    for ( Ofs=0 ; Ofs<Len ; Ofs++ )
    {
        fprintf(OutFp,"%02x ",*pBuf++);
    }
}

char * SyncToCapture ()
{
    WORD    SyncRetries;
    WORD    SyncSrchOfs;
    WORD    SyncCount;
    DWORD   SyncPos;

    PBC_FRM_HDR Hdr;

    SyncPos = ftell(InFp);
    SyncRetries=0;
    while ( SyncRetries++<280 )
    {
        fseek (InFp, SyncPos, SEEK_SET);

        SyncSrchOfs=0;
        while ( SyncSrchOfs++<280 )
        {
            fread (&Hdr, 1, 1, InFp);
            if ( Hdr.SyncMark==PBC_SYNC_MARK )
            {
                goto found_sync_mark;
            }
        }
        sprintf (ErrStr,"Capture File Sync Error: SYNC_MARK not found");
        return ErrStr;

found_sync_mark:;
        SyncPos = ftell(InFp)-1;
        fseek (InFp, SyncPos, SEEK_SET);

        SyncCount = 0;
        while ( SyncCount++<100 )
        {
            fread (&Hdr, sizeof(PBC_FRM_HDR)-1, 1, InFp);
            if ( Hdr.SyncMark!=PBC_SYNC_MARK )
            {
                SyncPos++;
                goto retry_sync;
            }
            fseek (InFp, Hdr.Len+1, SEEK_CUR);
        }
        fseek (InFp, SyncPos, SEEK_SET);
        return NULL;

retry_sync:;
    }

    sprintf (ErrStr,"Capture File Sync Error: Unable to Sync");
    return ErrStr;
}

char * ReadFrame (__int64 * pRawTme, BYTE * pBuf, BYTE * pLen)
{
    BYTE    HdrBuf[8];
    char  * pErrStr;
    static  DWORD LastSyncPos=0;


    if ((pErrStr=PbcFileFread (HdrBuf, 8))!=NULL)
    {
        return pErrStr;
    }

    if ( HdrBuf[0]!=PBC_SYNC_MARK )
    {
        fprintf(OutFp,"**** Synchronization Lost ****\n");
        fprintf(OutFp,"%9u: Ofs=%x Mark=%02x\n",
                RefNum, ftell(InFp)-8, HdrBuf[0]);
        fprintf(OutFp,"           PrvLen=%02x PrvTme=%08x\n",
                *pLen, *pRawTme);



        fseek (InFp, LastSyncPos, SEEK_SET);
        if ((pErrStr=SyncToCapture())!=NULL)
        {
            CloseFiles(OutFp,InFp);
            return pErrStr;
        }

        if ((pErrStr=PbcFileFread (HdrBuf, 8))!=NULL)
        {
            return pErrStr;
        }
    }
    *pRawTme = 0;
    memcpy (pRawTme, &HdrBuf[1], 6);
    *pLen = HdrBuf[7];

    if ((pErrStr=PbcFileFread (pBuf, (*pLen)+1))!=NULL)
    {
        return pErrStr;
    }

    LastSyncPos = ftell(InFp);

    FrameSd     = 0;
    FrmDataLen  = 0;
    pFrmNode    = 0;
    pFrmFc      = 0;
    pFrmDSap    = 0;
    pFrmSSap    = 0;
    pFrmData    = 0;
    FrameSts    = 0;

    FrameSts    = pBuf[*pLen];

    if ( *pLen > 0 )
    {

        FrameSd = *pBuf;

        switch ( FrameSd )
        {
        case PBC_SD_SD1 :
            pFrmNode = &pBuf[1];
            pFrmFc   = &pBuf[3];
            break;

        case PBC_SD_SD2 :
            pFrmNode = &pBuf[4];
            pFrmFc   = &pBuf[6];
            pFrmData = &pBuf[7];
            FrmDataLen = pBuf[1]-3;

            if (pFrmNode[0]&0x80)
            {
                pFrmDSap = pFrmData++;
                FrmDataLen--;
            }
            if (pFrmNode[1]&0x80)
            {
                pFrmSSap = pFrmData++;
                FrmDataLen--;
            }
            break;

        case PBC_SD_SD3 :
            pFrmNode = &pBuf[1];
            pFrmFc   = &pBuf[3];
            pFrmData = &pBuf[4];
            FrmDataLen = 8;

            if (pFrmNode[0]&0x80)
            {
                pFrmDSap = pFrmData++;
                FrmDataLen--;
            }
            if (pFrmNode[1]&0x80)
            {
                pFrmSSap = pFrmData++;
                FrmDataLen--;
            }
            break;

        case PBC_SD_SD4 :
            pFrmNode = &pBuf[1];
            break;
        }
    }

    return NULL;
}

char * PbcFileFread (BYTE * pBuf, size_t RqLen)
{
    size_t  RdLen;
    char  * pErrStr;

    if ( InFp == 0)
    {
        if ((pErrStr=GetNextFile ())!=NULL)
        {
            return pErrStr;
        }
    }

    if ( (RdLen=fread (pBuf,1,RqLen,InFp)) < RqLen )
    {
        if ((pErrStr=GetNextFile ())!=NULL)
        {
            return pErrStr;
        }
        RqLen -= RdLen;
        pBuf  += RdLen;
        if ( (RdLen=fread (pBuf,1,RqLen,InFp)) != RqLen )
        {
            sprintf (ErrStr,"Capture File Read Error: Data Under Run");
            return ErrStr;
        }
    }
    return NULL;
}

char BaudName[][10]=
{
    "???",
    "12M",
    "6M",
    "3M",
    "1M5",
    "500K",
    "187K5",
    "93K75",
    "19K2",
    "9K6",
};

char * GetNextFile ()
{

    if ( InFp )
    {
        fclose (InFp);
        InFp = 0;
    }

    if ( NumMin == 0 )
    {
        return (char *)0xffffffff;
    }
    NumMin--;
    sprintf (InFileName,"%s%02d%02d.PbcCapt",InFileNameBase,Hour,Min);
    if ( (InFp=fopen(InFileName,"rb+")) == NULL)
    {
        CloseFiles();
        sprintf (ErrStr,"Unable to Open Input File %s",InFileName);
        return ErrStr;
    }

#ifdef CMD_LINE_VER
    fseek(InFp, 0, SEEK_END);
    InFileLen = ftell(InFp);
    fseek(InFp, 0, SEEK_SET);
    Progress     = 0;
    ProgressLast = 100;
#endif

    fread (&CptHdr,sizeof(CptHdr),1,InFp);
    fprintf(OutFp,"File      : %s\n", InFileName);
    fprintf(OutFp,"AN-X Name : %s\n", CptHdr.AnxName);
    fprintf(OutFp,"AN-X IP   : %u.%u.%u.%u\n", (CptHdr.AnxIp>>24)&0xff, (CptHdr.AnxIp>>16)&0xff, (CptHdr.AnxIp>>8)&0xff, (CptHdr.AnxIp>>0)&0xff);
    fprintf(OutFp,"Baud      : %s\n", BaudName[CptHdr.Baud]);
    fprintf(OutFp,"Opt File  : %s\n", OptFileName);

    if ( EquBuf[0]!='\0' )
    {
        fprintf(OutFp,"Show Only : %s\n", EquBuf);
    }
    fprintf(OutFp,"\n");

    if (Min < 59)
    {
        Min++;
    }
    else
    {
        if ( Hour<23 )
        {
            Hour++;
        }
        else
        {
            Hour = 0;
        }
        Min = 0;
    }
    return NULL;
}

void CloseFiles()
{
    if ( OutFp )
    {
        fclose (OutFp);
    }
    OutFp = 0;
    if ( InFp )
    {
        fclose (InFp);
    }
    InFp = 0;
}

void SkipToToken (char ** ppStr)
{
    while (isspace(**ppStr))    // get rid of any leading fillers
    {
        (*ppStr)++;
    }

    if (**ppStr == ';')         // skip anything after the ';'
    {
        **ppStr = '\0';
    }
}

void SkipPastToken (char ** ppStr)
{
    while ( !isspace(**ppStr) && ** ppStr)
    {
        if (**ppStr == ';')         // skip anything after the ';'
        {
            **ppStr = '\0';
            return;
        }
        (*ppStr)++;
    }
}


char * ParseTime (char ** ppStr, __int64 * pVal)
{
    char * pErrStr;
    char * pTmeUnit;
    char * pEnd;
    char   TmpChr;
    static char TmpBuf[100];
    long   Val;
    __int64 Mult;

    pEnd = *ppStr;
    SkipPastToken (&pEnd);

    TmpChr = *pEnd;
    *pEnd = '\0';

    if ( strlen(*ppStr) < 2 )
    {
        sprintf (ErrStr,"Time Numeric String too short '%s'", *ppStr);
        return ErrStr;
    }

    pTmeUnit = pEnd-2;
    if      (!strncmpi(pTmeUnit,"hr" , 2)) Mult = (__int64)60*60*1000*1000*1000;
    else if (!strncmpi(pTmeUnit,"mn" , 2)) Mult = (__int64)   60*1000*1000*1000;
    else if (!strncmpi(pTmeUnit,"sc" , 2)) Mult = (__int64)      1000*1000*1000;
    else if (!strncmpi(pTmeUnit,"ms" , 2)) Mult = (__int64)           1000*1000;
    else if (!strncmpi(pTmeUnit,"us" , 2)) Mult = (__int64)                1000;
    else if (!strncmpi(pTmeUnit,"ns" , 2)) Mult = (__int64)                   1;
    else
    {
        sprintf (ErrStr,"Time Numeric String Unit Expected '%s' (",pTmeUnit);
        return ErrStr;
    }

    *pTmeUnit = '\0';

    if ( (pErrStr=ParseNum (ppStr, &Val)) != NULL)
    {
        return pErrStr;
    }

    Mult *= Val;
    *pVal = Mult;

    *pEnd  = TmpChr;
    *ppStr = pEnd;
    return NULL;
}


char * ParseNum (char ** ppStr, long * pVal)
{
    static char TmpBuf[100];

    if ( !_strnicmp(*ppStr,"0x",2))
    {
        if (sscanf(&(*ppStr)[2],"%lx",pVal) != 1)
        {
            sprintf (ErrStr,"Invalid Hex Numeric String '%s'", *ppStr);
            return ErrStr;
        }
    }
    else if ( **ppStr == '\'')
    {
        (*ppStr)++;
        *pVal = **ppStr;
    }
    else
    {
        if (sscanf (*ppStr,"%ld",pVal) != 1)
        {
            sprintf (ErrStr,"Invalid Dec Numeric String '%s'",*ppStr);
            return ErrStr;
        }
    }
    while ( (**ppStr!='\0') && !isspace(**ppStr) )    // skip past this number
    {
        (*ppStr)++;
    }
    return NULL;
}

#ifdef __cplusplus
}
#endif