
/***************************************************************************
**
**    $Header:   D:/EPSLDV1/SRC/LOG/CTRCBUF.CPP   1.5   20 Jun 1996 09:29:48   ZJRD  $
**
**    $Log:   D:/EPSLDV1/SRC/LOG/CTRCBUF.CPP  $
** 
**    Rev 1.5   20 Jun 1996 09:29:48   ZJRD
** EasyPack/SLD Version 1.20a
** 
**    Rev 1.4   11 Jun 1996 10:27:42   ZJRD
** EasyPack/SLD Version 1.97
** 
**    Rev 1.2   05 Jun 1996 14:56:20   ZJRD
** EasyPack/SLD Version 1.96
** 
**    Rev 1.1   29 May 1996 09:36:26   ZJRD
** EasyPack/SLD Version 1.95
** 
**    Rev 1.0   16 May 1996 09:09:20   ZJRD
** Initial revision.
** 
****************************************************************************/

/***************************************************************************
**
** File name : CTRCBUF.CPP
** Author: Chris Fang
** Description:   functions to list trace in source mode
**
**
**    coding from: Apr. 29, 1996
**   
**   status: preliminary
**    Copyright (C) 1996 Microtek International, Inc.
**    All Rights Reserved
**
****************************************************************************/

//////////////////////////////////////////////////////////////////////////
//include
#include "stdafx.h"

#include "ctrcbuf.h"

#include "trcserve.h"
#include "cpust.h"
#include "symblsvr.h"                //use:    SymMapAddr2LinenumModule
                                     //       SymGetLinenum
#include "hosterrs.h"

//////////////////////////////////////////////////////////////////////////
//define
#define FRAME(e)     (WORD((e)&0xffff))
#define ADDRESS(e)      (WORD((e>>16)&0xffff))

#define CHRIS_FRAMESPERLINE 50
#define CHRIS_FRAMESPERPAGE 49

//////////////////////////////////////////////////////////////////////////
//extern varible
extern CSrcFile SrcFile;

//////////////////////////////////////////////////////////////////////////
//extern function
extern int SrcIsLoaded(void);
extern void TraceWnd(unsigned char trace);
extern STATUS AbiGetTraceSource(UINT startFrame, BYTE count, WORD addrRange[10],
                         BYTE rangeCount,
                         BYTE* retCount,DWORD* pInputBuf );

//////////////////////////////////////////////////////////////////////////
//static global
static class TraceSrcBuf   tsb;
static DWORD g_framebuf[CHRIS_FRAMESPERPAGE];

//////////////////////////////////////////////////////////////////////////
//export function

//////////////////////////////////////////////////////////////////////////
//ResetTraceBuf: 
//    caller condition -- every time when trace buffer is changed, for example:
//                   when go command executed.
void ResetTraceBuf(void)
{
   tsb.reset();
}

//////////////////////////////////////////////////////////////////////////
//ListTrcMixedToWnd:
//    description --    main routine to offer trace mixed info to trace window.
BOOL ListTrcMixedToWnd(int readDirect,       //2,1,0,-1,-2
                  WORD* beginNo,           //abi frame
                  WORD* endNo,             //not care
                    WORD* LineCnt,           //viewport lines
                      FrameC* frameC)         //output buffer(contain c and instruction)
{
//unsigned char   status;
WORD  dummy, nextsrcframeno;
BOOL  bret;
WORD  beginNobak=*beginNo, instcount=*LineCnt;
struct FrameC     pSrc[10];
struct FrameInst  pInst[36];

   ASSERT(instcount<34);
   bret=ListTrcInstToWnd(readDirect, beginNo, endNo,
                          &instcount, (struct FrameInst*)pInst);
   ASSERT(instcount<34);
   if(!bret)
   {
      *LineCnt=0;
      return FALSE;
   }
   ASSERT(instcount);
   int i=0;
   WORD frameno=pInst[0].phisicalNo, framenobak;
   WORD srccount=1;
   do
   {
      framenobak=frameno;
      ListTrcCToWnd(0, &frameno, &dummy, &srccount, &pSrc[i]);
      if(frameno<framenobak)        //in special case, this will cause dead cycle
         break;
      i+=srccount;
      if(srccount)
         frameno=pSrc[i-1].phisicalNo+1;
   }while(srccount==1&&frameno<=pInst[instcount-1].phisicalNo);
   ASSERT(i<=10);
   srccount=WORD(i);
   int ii=0, imix=0;
   //now put c and instruction data a one buf:
   //ii: index of instruction buf, i: index of source buf
   //imix: index of mixed buf, srccount: source count
   if(srccount?(pSrc[0].phisicalNo>pInst[0].phisicalNo):1)
      for(; srccount?((pInst[ii].phisicalNo<pSrc[0].phisicalNo)&&
            WORD(ii)<instcount&&imix<32):imix<32&&WORD(ii)<instcount; ii++, imix++)
      {
         frameC[imix].phisicalNo=pInst[ii].phisicalNo;
         strcpy(frameC[imix].frameNo, pInst[ii].frameNo);
         strcpy(frameC[imix].line, "  ");
         strcat(frameC[imix].line, pInst[ii].addr);
         strcpy((char*)frameC[imix].c, (char*)pInst[ii].instruction);
      }
   for(i=0;srccount?imix<32&&i<srccount&&ii<instcount:0;i++)
   {
      frameC[imix++]=pSrc[i];
      nextsrcframeno=(i==srccount-1)?0xffff:pSrc[i+1].phisicalNo;
      for(;imix<32&&ii<instcount&&pInst[ii].phisicalNo<nextsrcframeno; ii++, imix++)
      {
         frameC[imix].phisicalNo=pInst[ii].phisicalNo;
         strcpy(frameC[imix].frameNo, pInst[ii].frameNo);
         strcpy(frameC[imix].line, "  ");
         strcat(frameC[imix].line, pInst[ii].addr);
         strcpy((char*)frameC[imix].c, (char*)pInst[ii].instruction);
      }
   }
   ASSERT(imix<=33);
   ASSERT(ii<instcount+1);
   ASSERT(i<srccount+1);
   if(readDirect==0)
      *LineCnt=min(imix, *LineCnt);
   else if(readDirect==-1||readDirect==1||readDirect==2)
   {
      *LineCnt=min(imix, *LineCnt);
   }
   else if(readDirect==-2)
   {
      int more=imix-*LineCnt;
      *LineCnt=min(imix, *LineCnt);
      for(i=0; more>0&&i<*LineCnt; i++)
         frameC[i]=frameC[i+more];
   }
   return TRUE;
   //now imix is the count of mixed buffer
/* srccount=-1;
   if(beginNobak<=frameC[0].phisicalNo)
      srccount=0;
   else if(beginNobak>=frameC[imix-1].phisicalNo)
      srcount=imix-1;
   if(srccount==-1)  
      for(i=0; i<imix; i++)
         if(beginNobak<=frameC[i].phisicalNo)
            break;
   //now i is index of beginNobak
   if(readDirect==-2)
      i=i>(LineCnt-2)?i+2-LineCnt:0;
// else if(readDirct==-1)
//    i=i?i--?0;
// else if(readDirect==1)
//    i=i<imix-1?i++:i;
   else if(readDirect==2)
      i=0;
*/
}

//////////////////////////////////////////////////////////////////////////
//ListTrcCToWnd:
//    description --    main routine to offer trace source info to trace window.
BOOL ListTrcCToWnd(int readDirect,        //
               WORD* beginNo,           //
               WORD* /* endNo */,
                   WORD* LineCnt,
                   FrameC* frameC)
{
unsigned char  status;

   int tmp=int(*LineCnt);
    tmp=min(tmp,CHRIS_FRAMESPERPAGE);

    if(!GetCpuStatus(status)||0!=SrcIsLoaded())
   {
      AfxMessageBox("Please load source first!");
      for(WORD i=0;i<*LineCnt;i++)
      {
         wsprintf(frameC[i].frameNo,"%4s"," ");
         wsprintf(frameC[i].line,"%5s"," ");
         wsprintf((char *)(&(frameC[i].c[0])),"%s"," ");
      }           
        *LineCnt=0;
        return FALSE;
   }
   if(status==STATUS_GO)            //CPU is run
   {
      TraceWnd(0);               //TRACE OFF
      //must call AbiGetTraceBuffer once, for FW reason.
      QUALIFY aQualify;
      TRACE_INFO traceInfo[2];
      UCHAR frameNum;
      FLAG readEnd;
      aQualify.setMode=0;
      AbiGetTraceBuffer(0, 0, 1, aQualify, traceInfo, &frameNum, &readEnd);
   }

    BOOL result = tsb.getctrace(readDirect, *beginNo, tmp, frameC);
/*
    for(WORD i=WORD(tmp);i<*LineCnt;i++)
   { 
      wsprintf(frameC[i].frameNo,"%4s"," ");
      wsprintf(frameC[i].line,"%5s"," ");
      wsprintf((char *)(&(frameC[i].c[0])),"%s"," ");
   }
*/
    *LineCnt=tmp;
    return result;
}

//////////////////////////////////////////////////////////////////////////
//member funciton: for struct MRUSrcLine

/*****************************************************
**
** Name : next
**
** Description :
**
**    Input  :
**    Output :return:
**
** Notes:
**
*****************************************************/
const MRUSrcLine MRUSrcLine::next(void)
{
   MRUSrcLine nextline(0, 0, 0, 0);
   if(moduleDesc==0)
      return nextline;

ADDR_RANGE_TYPE    addrRange;
LINENUM_TYPE       actualLinenum;
COLUMN_TYPE        actualColumn;
LINENUM_DESCRIPTOR nextIndex;

   if(GOOD!=SymGetLinenum(moduleDesc,  linenum+1, &addrRange, &actualLinenum,
            &actualColumn, &nextIndex))
      return nextline;
// if(GOOD!=SymGetLinenumByIndex(moduleDesc, nextIndex, &addrRange, &next2,
//          &actualLinenum, &actualColumn))
//    return nextline;
   nextline.moduleDesc=moduleDesc;
   nextline.linenum=actualLinenum;
   nextline.startAddr=addrRange.startAddr;
   nextline.endAddr=addrRange.endAddr;
   return nextline;
}

//////////////////////////////////////////////////////////////////////////
//member funciton: for class TraceSrcPage

/*****************************************************
**
** Name : TraceSrcPage
**
** Description:   constructive function
**
**    Input  :
**                   
**
**    Output :
**
** Notes:
**
*****************************************************/
TraceSrcPage::TraceSrcPage(TraceSrcPage* pp, TraceSrcPage* pn)
{
   m_wFirstFrame=0xffff;
   m_wLastFrame=0;
   m_nFrameNum=0;
   m_pNext=pn;
   m_pPrev=pp;
}

/*****************************************************
**
** Name : TraceSrcPage
**
** Description:   destructive function
**
**    Input  :
**                   
**
**    Output :
**
** Notes:
**
*****************************************************/
TraceSrcPage::~TraceSrcPage()
{
   reset();
}

/*****************************************************
**
** Name : isinpage
**
** Description :
**
**    Input  :frame: frame which be search in page
**                   
**
**    Output :return:   TRUE -- that frame is in this page
**                FALSE-- that frame is not in this page
**         index: when return TRUE,index is frame'index(down direction)
**
** Notes:
**
*****************************************************/
BOOL TraceSrcPage::isinpage(WORD frame, int& index)
{
   index=0;
   if(!m_nFrameNum)
      return FALSE;
   if(frame>m_wLastFrame)
   {
       index=m_nFrameNum;
      return FALSE;
   }
   if(frame<m_wFirstFrame)
   {
      index=0;
      return FALSE;
   }
   int small=0, big=m_nFrameNum-1;
   WORD f;
   while((big-small)>1)
   {
      f=FRAME(GetAt((big+small)/2));
      if(f<frame)
         small=(big+small)/2;
      else if(f>frame)
         big=(small+big)/2;
      else
      {
         index=(big+small)/2;
         return TRUE;
      };
   }
   if(FRAME(GetAt(small))>=frame)
      index=small;
   else if(FRAME(GetAt(big))>=frame)
      index=big;
   else
      index=big+1;
   return TRUE;
}

/*****************************************************
**
** Name : getaddrfromframe
**
** Description : caller should ensure that frame is in this page
**
**    Input  :frame: frame which be search in page
**                   
**
**    Output :return:   ADDRESS value of this frame
**
** Notes:
**
*****************************************************/
WORD TraceSrcPage::getaddrfromframe(WORD frame)
{
int index;
   if(!isinpage(frame, index))
   {
      if(index)
         return (ADDRESS(GetAt(index-1)));
      ASSERT(0);
   }  
   return   (ADDRESS(GetAt(index)));
}

/*****************************************************
**
** Name : reset
**
** Description :
**
**    Input  :
**                   
**
**    Output :
**
** Notes:
**
*****************************************************/
void TraceSrcPage::reset(TraceSrcPage* pp, TraceSrcPage* pn)
{
   m_wFirstFrame=0xffff;
   m_wLastFrame=0;
   m_nFrameNum=0;
   m_pNext=pn;
   m_pPrev=pp;
   RemoveAll();
}

//////////////////////////////////////////////////////////////////////////
//member funciton: for class TraceSrcBuf

/*****************************************************
**
** Name : TraceSrcBuf
**
** Description:   constructive function
**
**    Input  :
**                   
**
**    Output :
**
** Notes:
**
*****************************************************/
TraceSrcBuf::TraceSrcBuf()
{
   m_pFirstPage=NULL;
   m_pLastPage=NULL;
   m_Hitstatus.ishit=FALSE;
   m_nARNum=0;
   m_wAbiFrameNum=0;
   m_bIncLib=FALSE;
   m_bOldFW=FALSE;
}

/*****************************************************
**
** Name : ~TraceSrcBuf
**
** Descrition: destructive function
**
**    Input  :
**                   
**
**    Output :
**
** Notes:
**
*****************************************************/
TraceSrcBuf::~TraceSrcBuf()
{
   reset();
}

void TraceSrcBuf::reset(void)
{
   while(m_pFirstPage)
   {
      m_pLastPage=m_pFirstPage;
      m_pFirstPage=m_pFirstPage->m_pNext;
      delete m_pLastPage;
   }
    m_pFirstPage=m_pLastPage=NULL;
    m_Hitstatus.ishit=FALSE;
   m_nARNum=0;
   m_wAbiFrameNum=0;
}

/*****************************************************
**
** Name : getctrace
**
** Description :
**
**    Input  :readflag: -2:   pageup
**                -1: lineup
**                       0: refresh
**                       1: linedown
**                       2: pagedown
**         fromframe:
**         linenum:           
**
**    Output :return:   TRUE -- success
**                FALSE-- failure
**         linenum:  get line number   
**
** Notes:
**
*****************************************************/
BOOL TraceSrcBuf::getctrace(int readflag,
                     WORD& fromframe,
                     int& linenum,
                     FrameC* buf)
{
TraceSrcPage*  pPage;
int            index, direct, temp, linenumbak;
UINT  abiframenum;

   int nErrorID = AbiGetTraceLastFrame(&abiframenum);
   if(ICE_OK != nErrorID)
    {
      linenum=0;
      return FALSE;
   }
   if(abiframenum==0)
   {
      linenum=0;
      return TRUE;
    }
   if(m_wAbiFrameNum!=abiframenum)
   {
      reset();
      m_wAbiFrameNum=WORD(abiframenum);
   }
    if(m_bOldFW)
    {
      ErrDisplayError(12345 /*ER_FW_ISOLD*/);
      linenum=0;
      return FALSE;
    }
    pPage=isinbuf(readflag, fromframe, linenum, index);
   if(!pPage)
   {
      WORD tmpframe;
      int  tmpnum;
      if(!m_Hitstatus.ishit)
      {
         if(readflag)            //ajust to begin
         {
            readflag=0;
            fromframe=0;
         }
         pPage=addpage(fromframe);
         TRACE("Add a Page\n");
         tmpframe=fromframe;
         tmpnum=linenum;
      }
      else              //have need some frames, but not all
      {
         pPage=m_Hitstatus.phitpage;
         tmpframe=m_Hitstatus.edgeframe;
         tmpnum=m_Hitstatus.needline;
      }
      //set tmpframe to a suitable value
      tmpnum=max(tmpnum, CHRIS_FRAMESPERPAGE);
      if(direct=editpage(readflag<0, tmpframe, tmpnum, pPage))
         pPage=linkpage(pPage, direct);
      if(direct==2)
      {
          linenum=0;
         return TRUE;
      }
      //calc index.
      if(!pPage->isinpage(fromframe, index))
         ASSERT(0);
      temp=pPage->m_nFrameNum-1;
      if(readflag==-2)
         index=index>linenum?index-linenum:0;
      else if(readflag==-1)
         index=index>0?index-1:0;
      else if(readflag==1)
         index=min(index+1, temp);
      else if(readflag==2)
         index=min(index+linenum, temp);
      linenum=min(linenum, temp-index+1);
   }                   
   linenum=min(linenum, pPage->m_nFrameNum-index);
   linenumbak=linenum;
   setdata(pPage, index, buf, linenumbak);
   fromframe=buf[0].phisicalNo;
   return TRUE;
}

/*****************************************************
**
** Name : isinbuf
**
** Description :
**
**    Input  :readflag: -2:   pageup
**                -1: lineup
**                       0: refresh
**                       1: linedown
**                       2: pagedown
**         fromframe:
**         linenum:           
**
**    Output :return:      point to total hit page
**         m_Hitstatus:    have meaning when return FALSE
**         fromframe:   when total hit, be changed to start 
**                   frame according to readflag
**         index:    when total hit, set to frame index in page
**
** Notes:
**
*****************************************************/
TraceSrcPage* TraceSrcBuf::isinbuf(int readflag, 
                     WORD& fromframe,
                     int linenum, int& hitindex)
{
   int index;
   m_Hitstatus.phitpage=m_pFirstPage;
   m_Hitstatus.ishit=FALSE;
   if(!m_Hitstatus.phitpage)
      return NULL;
   for(;m_Hitstatus.phitpage;
      m_Hitstatus.phitpage=m_Hitstatus.phitpage->m_pNext)
   {
      if(m_Hitstatus.phitpage->isinpage(fromframe, index))
         break;
   }
   if(!m_Hitstatus.phitpage)
      return NULL;
   m_Hitstatus.ishit=TRUE;
   if(readflag==-1)           //line up
   {
      if(index>=1)
      {
         hitindex=index-1;
         fromframe=FRAME(m_Hitstatus.phitpage->GetAt(hitindex));
         return (m_Hitstatus.phitpage);   //all in page
      }
      if(!m_Hitstatus.phitpage->m_wFirstFrame)
      {
         hitindex=0;
         return (m_Hitstatus.phitpage);
      }
      m_Hitstatus.needline=1;
      m_Hitstatus.edgeframe=m_Hitstatus.phitpage->m_wFirstFrame;
      return NULL;
   }
   if(readflag==-2)
   {
      if(index>=linenum-1)
      {
          hitindex=index-linenum+1;
         fromframe=FRAME(m_Hitstatus.phitpage->GetAt(hitindex));
         return (m_Hitstatus.phitpage);
      }
      if(!m_Hitstatus.phitpage->m_wFirstFrame)
      {
         hitindex=0;
         return (m_Hitstatus.phitpage);
      }  
      m_Hitstatus.needline=linenum-index;
      m_Hitstatus.edgeframe=m_Hitstatus.phitpage->m_wFirstFrame;
      return NULL;
   }
   int frames=m_Hitstatus.phitpage->GetSize();
   if(readflag==1)
      index++;
   if(readflag==2)
      index+=linenum-1;
   if(m_Hitstatus.phitpage->m_wLastFrame==m_wAbiFrameNum)
   {
      hitindex=min(index, frames-1);
      return   m_Hitstatus.phitpage;
   }
   if(frames-index>=linenum)
   {
      hitindex=index;
      fromframe=FRAME(m_Hitstatus.phitpage->GetAt(hitindex));
      return (m_Hitstatus.phitpage);
   }  
   m_Hitstatus.needline=linenum-frames+index;
   m_Hitstatus.edgeframe=m_Hitstatus.phitpage->m_wLastFrame;
   return NULL;
}

//if line number is same, but addrrange not same, keep it
void TraceSrcBuf::compressmrusrcline(void)
{
int i, index, goodindex;
BOOL isrepeat=FALSE;
   for(index=goodindex=0; index<m_nARNum; index++)
   {
      if(!m_MRUSrcLine[index].moduleDesc)
         continue;
      isrepeat=FALSE;
      for(i=0; i<goodindex; i++)
         if(m_MRUSrcLine[i]==m_MRUSrcLine[index]
            &&m_MRUSrcLine[i].startAddr==m_MRUSrcLine[index].startAddr)
         {
            isrepeat=TRUE;
            break;
         }
      if(isrepeat)
         continue;   
      if(index!=goodindex)
         m_MRUSrcLine[goodindex]=m_MRUSrcLine[index];
      goodindex++;
   }
   m_nARNum=goodindex;
}

TraceSrcPage* TraceSrcBuf::addpage(WORD frame)
{
   if(!m_pFirstPage)
   {
      m_pLastPage=m_pFirstPage=new TraceSrcPage(NULL, NULL);
      return m_pFirstPage;
   }
   TraceSrcPage* ptmppage=m_pFirstPage;
   for(;ptmppage;ptmppage=ptmppage->m_pNext)
   {
      if(frame<ptmppage->m_wFirstFrame)
         break;
   }
   if(!ptmppage)     //must add tail
   {
      ptmppage=m_pLastPage;
      ptmppage->m_pNext=new TraceSrcPage(ptmppage,NULL);
      if(!ptmppage->m_pNext)     //not enough memory, recycle use
      {
         ptmppage->m_pNext=m_pFirstPage;
         m_pFirstPage=m_pFirstPage->m_pNext;
         m_pFirstPage->m_pPrev=NULL;
         ptmppage->m_pNext->reset(ptmppage, NULL);
      }
      m_pLastPage=ptmppage->m_pNext;
      return ptmppage->m_pNext;
   }
   if(ptmppage==m_pFirstPage)    //must add head
   {
      ptmppage=new TraceSrcPage(NULL, m_pFirstPage);
      if(!ptmppage)     //not enough memory, recycle use
      {
         ptmppage=m_pLastPage;
         m_pLastPage=m_pLastPage->m_pPrev;
         m_pLastPage->m_pNext=NULL;
         ptmppage->reset(NULL, m_pFirstPage);
      }
      m_pFirstPage->m_pPrev=ptmppage;
      m_pFirstPage=ptmppage;
      return ptmppage;
   }
   //must add before ptmppage
   
   TraceSrcPage* ptmppage2=new TraceSrcPage(ptmppage->m_pPrev, ptmppage);
   if(!ptmppage2)    //not enough memory: use first object
   {
      ptmppage2=m_pFirstPage;
      m_pFirstPage=m_pFirstPage->m_pNext;
      m_pFirstPage->m_pPrev=NULL;
      ptmppage2->reset(ptmppage->m_pPrev, ptmppage);
   }
   ptmppage=ptmppage2;  
   ptmppage->m_pPrev->m_pNext=ptmppage;
   ptmppage->m_pNext->m_pPrev=ptmppage;
   return ptmppage;
}

/*****************************************************
**
** Name : editpage
**
** Description :
**
**    Input  :isup:
**         fromframe:
**         number:   not include fromframe               
**
**    Output :return: -1 -- touch previous page
**                0 -- 
**                1 -- touch next page
**                2 -- touch to end and no any frame found  
**         result: have meaning when return FALSE     
**
** Notes:
**
*****************************************************/
int TraceSrcBuf::editpage(BOOL isup,
                    WORD fromframe,
                    int number,
                    TraceSrcPage* pPage)
{
int   getframe=0, temp;

   if(isup)
   {
      ASSERT(pPage->m_nFrameNum);
      WORD begframe, begframebak;
      BOOL isout=FALSE;
      while(getframe<number&&!isout)
      {
         begframe=fromframe>WORD(number*CHRIS_FRAMESPERLINE)?
                  WORD(fromframe-number*CHRIS_FRAMESPERLINE):0;
         begframebak=begframe;
         if(begframe==0)
            isout=TRUE;
         if(pPage->m_pPrev)
            if(pPage->m_pPrev->m_wLastFrame>=begframe)
            {
               ASSERT(pPage->m_nFrameNum);
               while(editpage(FALSE, pPage->m_pPrev->m_wLastFrame,
                  -1, pPage->m_pPrev)!=1);   //recurse depth: 1 level
               return -1;
            }
         temp=setfirstsrcframe(begframe, fromframe, pPage);
         if(temp)
         {
            getframe+=temp;
            temp=setsrcframe(begframe, fromframe,
                              -1, pPage);
            getframe+=temp;
         }
         fromframe=begframebak;
      }
      return 0;
   }
   //isdown:
   WORD toframe=m_wAbiFrameNum;
   if(pPage->m_pNext?pPage->m_pNext->m_nFrameNum:0)
      toframe=pPage->m_pNext->m_wFirstFrame;
   if (pPage->m_nFrameNum==0)    //new page
   {
      temp=setfirstsrcframe(fromframe,toframe, pPage);
      if(temp==0)
      {  if(pPage->m_pNext)
            return 1;
         else
            return 2;
      }  
      number-=temp;
   }
   else
   {
   //prepare m_MRUSrcLine
      SYM_DESCRIPTOR modDesc;
      ADDR_RANGE_TYPE modRange;
      LINENUM_TYPE line;
      COLUMN_TYPE column;
      ADDR_RANGE_TYPE lineRange;
      LINENUM_DESCRIPTOR index;

      if(GOOD != SymMapAddr2LinenumModule(pPage->getaddrfromframe(fromframe),
                                 &modDesc,
                                 &modRange,
                                 &line,
                                 &column,
                                 &lineRange,
                                 &index))
         ASSERT(0);
      m_MRUSrcLine[0].moduleDesc=modDesc;
      m_MRUSrcLine[0].linenum=line;
      m_MRUSrcLine[0].startAddr=lineRange.startAddr;
      m_MRUSrcLine[0].endAddr=lineRange.endAddr;
      m_MRUSrcLine[1]=m_MRUSrcLine[0].next();
      m_MRUSrcLine[2]=m_MRUSrcLine[1].next();
      m_MRUSrcLine[3]=m_MRUSrcLine[2].next();
      m_MRUSrcLine[4]=m_MRUSrcLine[3].next();
      compressmrusrcline();
   }
   getframe=setsrcframe(fromframe, toframe, number, pPage);
   if(fromframe>=toframe&&pPage->m_pNext)
      return 1;
   else
      return 0;   
}

/*****************************************************
**
** Name : linkpage
**
** Description:
**
**    Input  :pPage:
**         direct:  1 -- link to next page
**               -1 -- link to prev page  
**
**    Output :return: the united page
**
** Notes:
**
*****************************************************/
TraceSrcPage* TraceSrcBuf::linkpage(TraceSrcPage* pPage, int direct)
{
   if(direct==2)
   {
      if(pPage->m_pPrev)
      {
         pPage->m_pPrev->m_pNext=pPage->m_pNext;
         if(!pPage->m_pNext)
            m_pLastPage=pPage->m_pPrev;
         else
            pPage->m_pNext->m_pPrev=pPage->m_pPrev;
      }
      else     //is first page
      {
         m_pFirstPage=pPage->m_pNext;
         if(pPage->m_pNext)
            pPage->m_pNext->m_pPrev=NULL;
         else
            m_pLastPage=NULL;
      }
      TRACE("Delete a Page\n");
      delete pPage;
      return NULL;
   }
   if(direct==-1)
   {
      ASSERT(pPage->m_pPrev);
      pPage=pPage->m_pPrev;
      direct=1;
   }
   if(direct==1)
   {
      ASSERT(pPage->m_pNext);
      ASSERT(pPage->m_wLastFrame<=pPage->m_pNext->m_wFirstFrame);
      if(!pPage->m_nFrameNum)
      {
         pPage->m_pNext->m_wFirstFrame=pPage->m_wLastFrame;
         if(pPage->m_pPrev)
         {
            pPage->m_pNext->m_pPrev=pPage->m_pPrev;
            pPage->m_pPrev->m_pNext=pPage->m_pNext;
         }  
         else
         {
             pPage->m_pNext->m_pPrev=NULL;
            m_pFirstPage=pPage->m_pNext;
         }
         TraceSrcPage* pretPage=pPage->m_pNext;
         delete pPage;
         return pretPage;
      }  
      if(pPage->m_wLastFrame!=pPage->m_pNext->m_wFirstFrame)
      {
         if(!checksameline(pPage->GetAt(pPage->m_wLastFrame-1),
                      pPage->m_pNext->GetAt(0)))
         {
            pPage->m_pNext->RemoveAt(0);
            pPage->m_pNext->m_nFrameNum--;
         }  
      }
      else
      {
         pPage->m_pNext->RemoveAt(0);
         pPage->m_pNext->m_nFrameNum--;
      }
      pPage->InsertAt(pPage->m_nFrameNum, pPage->m_pNext);
      pPage->m_nFrameNum+=pPage->m_pNext->m_nFrameNum;
      ASSERT(pPage->GetSize()==pPage->m_nFrameNum);
      pPage->m_wLastFrame=pPage->m_pNext->m_wLastFrame;
      
      TraceSrcPage* ptemp=pPage->m_pNext;
      pPage->m_pNext=ptemp->m_pNext;
      if(!pPage->m_pNext)
         m_pLastPage=pPage;
      TRACE("Delete a Page\n");
      delete ptemp;
      return pPage;
   }
   ASSERT(0);
   return NULL;
}

/*****************************************************
**
** Name : writetopage
**
** Description
**
**    Input  : pPage -- the page which be written
**          count -- written frames that store in g_framebuf
**
**    Output :
**         
**
** Notes:
**
*****************************************************/
void TraceSrcBuf::writetopage(TraceSrcPage* pPage, BYTE& countself)
{
int index, i;  
BYTE count;
int r;

   //delete same line in g_framebuf, for .dbg file
   for(i=0; i<countself-1; i++)
   {
      r=checksameline(g_framebuf[i], g_framebuf[i+1]);
      if(r==0||r==10)
      {
         int ii;
         for(ii=i+1; ii<countself-1; ii++)
            g_framebuf[ii]=g_framebuf[ii+1];
         countself--;
         i=i?i-1:i;
      }
   }
   i=0;
   count=countself;
   if(pPage->isinpage(FRAME(g_framebuf[0]), index))
   {
      //check with last frame
      
      r=checksameline(g_framebuf[count-1], pPage->GetAt(index));
      if(r==10)
         pPage->SetAt(index, g_framebuf[count-1]);
      if(r==10||r==0)
         count--;
         
      //check with first frame
      if(index)
      {
         r=checksameline(pPage->GetAt(index-1), g_framebuf[0]);
         if(r==10)
            pPage->SetAt(index-1, g_framebuf[0]);
         if(r==10||r==0)   
            i=1;
      }
   }
   //add at head, so check with last frame
   else if(pPage->m_nFrameNum&&index==0)
   {                 
      r=checksameline(g_framebuf[count-1], pPage->GetAt(0));
      if(r==10)
          pPage->SetAt(0, g_framebuf[count-1]);
      if(r==10||r==0)    
         count--;
   }
   //add at tail, so check with first frame
   else if(pPage->m_nFrameNum&&index)
   {
      index=pPage->m_nFrameNum;
      r=checksameline(pPage->GetAt(index-1), g_framebuf[0]);
      if(r==10)
          pPage->SetAt(index-1, g_framebuf[0]);
      if(r==10||r==0)
         i=1;
   }
   else index=0;
   countself=BYTE(count-i);
   if(countself<=0)
   {
      countself=0;
      return;
   }  
   if(pPage->m_wFirstFrame>FRAME(g_framebuf[i]))
      pPage->m_wFirstFrame=FRAME(g_framebuf[i]);
   if(pPage->m_wLastFrame<FRAME(g_framebuf[count-1]))
      pPage->m_wLastFrame=FRAME(g_framebuf[count-1]);
   pPage->m_nFrameNum+=count-i;
   for(; i<count; i++, index++)
      pPage->InsertAt(index, g_framebuf[i]);
}

/*****************************************************
**
** Name : checksameline
**
** Description  can check lib frame
**
**    Input  : first -- 
**          second --
**
**    Output :  return:  1 -- first line is great than second line
**                 2 -- different module
**                 3 -- fail
**                    0 -- same line
**                -1 -- first line is less than second line
**                10 -- same line, different statement
**
** Notes:
**
*****************************************************/
int TraceSrcBuf::checksameline(DWORD first, DWORD second)
{
   SYM_DESCRIPTOR modDesc1, modDesc2;
   ADDR_RANGE_TYPE modRange;
   LINENUM_TYPE line1, line2;
   COLUMN_TYPE column;
   ADDR_RANGE_TYPE lineRange, lineRange2;
   LINENUM_DESCRIPTOR index;
    
    BOOL aislib=FALSE, bislib=FALSE;
   if(GOOD != SymMapAddr2LinenumModule(ADDRESS(first),
                                 &modDesc1,
                                 &modRange,
                                 &line1,
                                 &column,
                                 &lineRange,
                                 &index))
      aislib=TRUE;
   if(GOOD != SymMapAddr2LinenumModule(ADDRESS(second),
                                 &modDesc2,
                                 &modRange,
                                 &line2,
                                 &column,
                                 &lineRange2,
                                 &index))
      bislib=TRUE;
   if(aislib||bislib)
   {
      if(aislib&&bislib)
         return 0;
      return 1;   
   }
   if(modDesc1!=modDesc2)
      return 2;
   if(line1>line2)
      return 1;
   else if(line1==line2)
   {
      if(ADDRESS(second)!=lineRange2.startAddr)
      {
          if(lineRange2.startAddr!=lineRange.startAddr)//different statement
            return 10;  
         return 0;
      }
      else return 1;
   }  
   else return -1;         
}

/*****************************************************
**
** Name : setfirstsrcframe
**
** Description
**
**    Input  :fromframe:we don't know whether this frame is a src frame
**         toframe:
**         pPage:
**
**    Output :return: find source frame num
**         result: have meaning when return FALSE     
**
** Notes:
**
*****************************************************/
int TraceSrcBuf::setfirstsrcframe(WORD& fromframe,
                          WORD toframe,
                          TraceSrcPage* pPage)
{
   SYM_DESCRIPTOR modDesc;
   ADDR_RANGE_TYPE modRange;
   LINENUM_TYPE line;
   COLUMN_TYPE column;
   ADDR_RANGE_TYPE lineRange;
   LINENUM_DESCRIPTOR index;
   
   unsigned char retcount, i, j, srcframe=0;
   int n;
   BOOL bsameline;
   m_nARNum=0;
   if(pPage->m_wFirstFrame>fromframe)
      pPage->m_wFirstFrame=fromframe;
   while(fromframe<=toframe&&!srcframe)
   {
      if(AbiGetTraceSource(fromframe, CHRIS_FRAMESPERPAGE,
                     m_AddressRange,
                     0, &retcount, g_framebuf)==ICE_COMMAND_INVALID)
      {
         m_bOldFW=TRUE;
         return 0;
      }
      else 
         m_bOldFW=FALSE;
      if(retcount==0)
      {  
         fromframe=toframe;
         break;
      }
      for(i=0; m_nARNum<5&&i<retcount&&FRAME(g_framebuf[i])<=toframe; i++)
      {
         if(GOOD != SymMapAddr2LinenumModule(ADDRESS(g_framebuf[i]),
                                 &modDesc,
                                 &modRange,
                                 &line,
                                 &column,
                                 &lineRange,
                                 &index))
            continue;
         if(srcframe)
         {
            bsameline=FALSE;
            for(j=0; j<m_nARNum; j++)
               if(ADDRESS(g_framebuf[i])>m_MRUSrcLine[j].startAddr
                  &&ADDRESS(g_framebuf[i])<=m_MRUSrcLine[j].endAddr)
               {
                  bsameline=TRUE;
                  break;
               }
            if(bsameline)
               continue;
         }
         m_MRUSrcLine[m_nARNum].moduleDesc=modDesc;
         m_MRUSrcLine[m_nARNum].linenum=line;
         m_MRUSrcLine[m_nARNum].startAddr=lineRange.startAddr;
         m_MRUSrcLine[m_nARNum].endAddr=lineRange.endAddr;
         m_nARNum++;
         g_framebuf[srcframe]=g_framebuf[i];
         srcframe++;
      }
      if(FRAME(g_framebuf[i])>toframe&&i<retcount)
      {
         fromframe=FRAME(g_framebuf[i]);
         break;
      }  
      else if(fromframe==FRAME(g_framebuf[i==0?0:i-1]))
         break;
      fromframe=FRAME(g_framebuf[i==0?0:i-1]);
   }
   if(srcframe)
   {
      fromframe=FRAME(g_framebuf[srcframe-1]);
      writetopage(pPage, srcframe);
      ASSERT(m_nARNum);
      m_MRUSrcLine[0]=m_MRUSrcLine[m_nARNum-1];
      m_nARNum=1;
      for(n=m_nARNum; n<5; n++)
         m_MRUSrcLine[n]=m_MRUSrcLine[n-1].next();
      m_nARNum=5;
      compressmrusrcline();
   }
   return srcframe;
}

/*****************************************************
**
** Name : setsrcframe
**
** Description :
**
**    Input  :fromframe:
**         toframe:
**         number:   -1 -- get source frame to toframe
**
**    Output :return: find source frame num
**         result: have meaning when return FALSE     
**
** Notes:
**
*****************************************************/
int TraceSrcBuf::setsrcframe(WORD& fromframe, WORD toframe,
                        int number, TraceSrcPage* pPage)
{
//m_MRUSrcLine status: continuous m_nARNum lines
   SYM_DESCRIPTOR modDesc;
   ADDR_RANGE_TYPE modRange;
   LINENUM_TYPE line;
   COLUMN_TYPE column;
   ADDR_RANGE_TYPE lineRange;
   LINENUM_DESCRIPTOR index;
   
   int writeframe=0;          //the number of frames written to page
   int number2, i, j, libindex;
   BYTE retcount;
   BYTE rangenum;
   WORD addr;
   WORD tmpaddr;
   BOOL isout=FALSE;
   
   number=number==-1?0x7fff:number;
   rangenum=BYTE(m_nARNum);
   number2=min(number, CHRIS_FRAMESPERPAGE);
   while(fromframe<=toframe&&writeframe<number&&!isout)
   {
      //recalculate: fromframe, number2, m_MRUSrcLine
      ASSERT(number2);
#ifdef _DEBUG
      int db_i=pPage->getaddrfromframe(fromframe)>=m_MRUSrcLine[0].startAddr
            &&pPage->getaddrfromframe(fromframe)<=m_MRUSrcLine[0].endAddr;
      if(db_i==0)
         TRACE("error: fromframe out first range (AbiGetTraceSource)\n");
#endif
      addrrange();
      AbiGetTraceSource(fromframe, (BYTE)number2,
                     m_AddressRange,
                     (BYTE)m_nARNum, &retcount, g_framebuf);
////delete next line future: when fix abi bug
//    g_framebuf[0]=(g_framebuf[0]&0xffff0000)|fromframe;
      CYCLE_FY:
      //no source line any more, must rearch abilastframe
      if(retcount==0)
      {
         fromframe=toframe;
         break;
      }
      //check whether beyond toframe
      if(FRAME(g_framebuf[retcount-1])>toframe)
      {
         isout=TRUE;
         //set retcount to last frame that less equal toframe
         retcount--;
         while(retcount>=1?FRAME(g_framebuf[retcount-1])>toframe:0)
            retcount--;
      }
      if(retcount==0)
      {
         fromframe=toframe;
         break;
      }
      //check last frame
      addr=ADDRESS(g_framebuf[retcount-1]);
      for(i=0; i<m_nARNum; i++)
         if(addr>=m_MRUSrcLine[i].startAddr
            &&addr<=m_MRUSrcLine[i].endAddr)
            break;
      if(i<m_nARNum)          //in range
      {
          fromframe=FRAME(g_framebuf[retcount-1]);
         if(isout)
            fromframe=toframe;      //force caller return 1
         //mru logic1:find in self,find not in continue
         if(i>2)
         {
            m_MRUSrcLine[i]=m_MRUSrcLine[2];
            m_MRUSrcLine[0]=m_MRUSrcLine[i];
            m_MRUSrcLine[1]=m_MRUSrcLine[0].next();
            m_MRUSrcLine[2]=m_MRUSrcLine[1].next();
         }
         //mru logic2:find in self,find in continue
         else if(i>0)
         {
            m_MRUSrcLine[0]=m_MRUSrcLine[i];
            m_MRUSrcLine[1]=m_MRUSrcLine[0].next();
            m_MRUSrcLine[2]=m_MRUSrcLine[1].next();
            if(m_nARNum<3)
               m_nARNum=3;
         }
         compressmrusrcline();
         writetopage(pPage, retcount);
         writeframe+=retcount;
         number2=min(number-writeframe, CHRIS_FRAMESPERPAGE);
         continue;
      }
      //out of range, maybe in lib or in other lines
      //set tmpaddr to last hit line number'addr
      if(retcount==1)         //be sure that fromframe is already in page
         tmpaddr=pPage->getaddrfromframe(fromframe);
      else
         tmpaddr=ADDRESS(g_framebuf[retcount-2]);
      
      //set fromframe
      fromframe=FRAME(g_framebuf[retcount-1]);
      
      for(i=0; i<m_nARNum; i++)
         if(tmpaddr>=m_MRUSrcLine[i].startAddr
            &&tmpaddr<=m_MRUSrcLine[i].endAddr)
            break;
      //i is last hit line number index
      ASSERT(i<m_nARNum);
      
      if(GOOD != SymMapAddr2LinenumModule(addr,
                                 &modDesc,
                                 &modRange,
                                 &line,
                                 &column,
                                 &lineRange,
                                 &index))
      //in lib
      {
         libindex=retcount-1;
         if(retcount>1)
         {
            retcount=BYTE(m_bIncLib?retcount:retcount-1);
            writetopage(pPage, retcount);
            writeframe+=retcount;
         }
         else if(retcount==1)
         {
            if(m_bIncLib)
               writetopage(pPage, retcount);
            writeframe+=retcount;
         }
         number2=min(number-writeframe, CHRIS_FRAMESPERPAGE);
         m_MRUSrcLine[0]=m_MRUSrcLine[i];
         m_MRUSrcLine[1]=m_MRUSrcLine[0].next();
         m_MRUSrcLine[2]=m_MRUSrcLine[1].next();
         if(m_nARNum<4)
            m_MRUSrcLine[3]=m_MRUSrcLine[2].next();
         for(j=1; j<4; j++)
            if(!m_MRUSrcLine[j].moduleDesc)
               break;
         m_nARNum=j;
         U32 start, end;
         SrcGetModuleRange(m_MRUSrcLine[0].moduleDesc , start , end);
         m_MRUSrcLine[4].moduleDesc=0;
         m_MRUSrcLine[4].linenum=0;
         m_MRUSrcLine[4].startAddr=start;
         m_MRUSrcLine[4].endAddr=end;
         if(!(ADDRESS(g_framebuf[libindex])<m_MRUSrcLine[4].startAddr
            ||ADDRESS(g_framebuf[libindex])>m_MRUSrcLine[4].endAddr))
         {  
            ASSERT(0);
         }  
         addrrange();
         AbiGetTraceSource(fromframe, (BYTE)number2,
                     m_AddressRange,
                     BYTE(m_nARNum+0xf0), &retcount, g_framebuf);
////delete next line future: when fix abi bug
//       g_framebuf[0]=(g_framebuf[0]&0xffff0000)|fromframe;

         //no source line any more, must rearch abilastframe
         if(retcount==0)
         {
            fromframe=toframe;
            break;
         }  
//            if(IsLibFunction(ADDRESS(g_framebuf[retcount-1])))
//             retcount--;
//            ASSERT(retcount>0);
            goto  CYCLE_FY;
      }
      writetopage(pPage, retcount);
      writeframe+=retcount;
      number2==min(number-writeframe, CHRIS_FRAMESPERPAGE);
      //set MRUSrcLine logic:
      //1,2,3 set to new continue line from newline;
      //4 set to last found line
      //5 set to old 4
      m_MRUbak.moduleDesc=modDesc;
      m_MRUbak.linenum=line;
      m_MRUbak.startAddr=lineRange.startAddr;
      m_MRUbak.endAddr=lineRange.endAddr;
      
      if(m_nARNum?(i==(m_nARNum-1)?
            m_MRUbak==m_MRUSrcLine[m_nARNum-1].next():0):0)
      //continue lines:
      {
         //mru logic3: not find in self,find in continue(next)
         if(m_nARNum<5)
            m_MRUSrcLine[4]=m_MRUSrcLine[m_nARNum-1];
         if(m_nARNum<4)
            m_MRUSrcLine[3]=m_MRUSrcLine[0];
         m_MRUSrcLine[0]=m_MRUbak;
         m_MRUSrcLine[1]=m_MRUSrcLine[0].next();
         m_MRUSrcLine[2]=m_MRUSrcLine[1].next();
         m_nARNum=5;
         compressmrusrcline();
         continue;
      }
      //must jump to another line:
      //mru logic3: not find in self,not find in continue(next)
      m_nARNum=5;
      if(i==4)
      {
         m_MRUSrcLine[0]=m_MRUSrcLine[3];
         m_MRUSrcLine[3]=m_MRUSrcLine[4];
         m_MRUSrcLine[4]=m_MRUSrcLine[3].next();
         if(!m_MRUSrcLine[4].moduleDesc)
            m_MRUSrcLine[4]=m_MRUSrcLine[0];
      }
      else if(i==3)
      {
         if(m_MRUSrcLine[3].next())
            m_MRUSrcLine[4]=m_MRUSrcLine[3].next();
      }
      else
      {
         if(m_MRUSrcLine[i].next())
            m_MRUSrcLine[4]=m_MRUSrcLine[i].next();
         else
            m_MRUSrcLine[4]=m_MRUSrcLine[3];
         m_MRUSrcLine[3]=m_MRUSrcLine[i];
      }
      m_MRUSrcLine[0]=m_MRUbak;
      m_MRUSrcLine[1]=m_MRUSrcLine[0].next();
      m_MRUSrcLine[2]=m_MRUSrcLine[1].next();
      compressmrusrcline();
   }
   if(pPage->m_wLastFrame<fromframe)
      pPage->m_wLastFrame=fromframe;
   return writeframe;
}

void TraceSrcBuf::setdata(TraceSrcPage* pPage,
            int index, FrameC* buf, int linenum)
{
   SYM_DESCRIPTOR modDesc, lastmd=0;
   ADDR_RANGE_TYPE modRange;
   LINENUM_TYPE line1;
   COLUMN_TYPE column;
   ADDR_RANGE_TYPE lineRange;
   LINENUM_DESCRIPTOR ldindex;

   int i;
   DWORD data;
   for(i=0; i<linenum; i++)
   {
      data=pPage->GetAt(index+i);
      buf[i].phisicalNo=FRAME(data);
      wsprintf(buf[i].frameNo,"%04X",FRAME(data));
      if(GOOD != SymMapAddr2LinenumModule(ADDRESS(data),
                                 &modDesc,
                                 &modRange,
                                 &line1,
                                 &column,
                                 &lineRange,
                                 &ldindex))
      {
         wsprintf((LPSTR)buf[i].line,"%5s"," ");
         wsprintf((LPSTR)buf[i].c, "%s", "In lib");
      }
      else
      {
         wsprintf((LPSTR)buf[i].line,"%04u",line1);
         if(lastmd&&lastmd!=modDesc)
            strcat(buf[i].line, "*");
         else
            strcat(buf[i].line, " ");
         if(SrcFile.GetALine(modDesc, line1, (LPSTR)buf[i].c)!=TRUE)
               strcpy((char*)buf[i].c, " (??)");
            lastmd=modDesc;
      }
   }
}

void TraceSrcBuf::addrrange(void)
{
   for(int i=0; i<5; i++)
      m_AddressRange[i*2]=WORD(m_MRUSrcLine[i].startAddr),
      m_AddressRange[i*2+1]=WORD(m_MRUSrcLine[i].endAddr);
}

//////////////////////////////////////////////////////////////////////////
//export routine

//////////////////////////////////////////////////////////////////////////
//SpaListSource -- to Chen
//format: modname1 line   source line
//        mmmmmmmm llll   sss...
int SpaListSource(unsigned short uStartAddr, unsigned short uLength,
               CStringList* & pStrlist)
{
   SYM_DESCRIPTOR modDesc, mdbak=0;
   ADDR_RANGE_TYPE modRange;
   LINENUM_TYPE line;
   COLUMN_TYPE column;
   ADDR_RANGE_TYPE lineRange;
   LINENUM_DESCRIPTOR ldindex;
   
   OFFSET_ADDR_TYPE addr=uStartAddr;
   
    char modname[90];
   char linenum[30];
   char srcline[255];
   int getlines=0;
   CString element;

   while(addr<uStartAddr+uLength-1)
   {
      if(GOOD != SymMapAddr2LinenumModule(addr, &modDesc,   &modRange, &line,
                                 &column, &lineRange, &ldindex))
      {
         addr++;
         continue;
      }
      if(mdbak==0||mdbak!=modDesc)
      {
         mdbak=modDesc;
         if(SrcGetModuleName(modDesc , modname))
            strcpy(modname, "!unknown");
         for(int i=strlen(modname); i<8; i++)
            modname[i]=' ';
         modname[i]=0;  
      }
//    if(MyFile.GetALine(modDesc, line, srcline)!=TRUE)
//       strcat(srcline, " (??)");
      if(SrcFile.GetALine(modDesc, line, srcline)!=TRUE) {
         memset(srcline, 0, sizeof(srcline));
      }
      sprintf(linenum, "%5d", line);
      element=modname;
      element+=linenum;
      element+="   ";
      element+=srcline;
      pStrlist->AddTail(element);
        getlines++;
      addr=lineRange.endAddr+1;
   }

   return getlines;
}
