/******************************************************************************
*
* project name:  TIGCC Tools Suite
* file name:     tthdex.c
* initial date:  22/01/2001
* author:        thomas.nussbaumer@gmx.net
*                xdanger1@caramail.com
*
* description:   HANDLE-Explorer
*
*
* TI-89  - compile with:   tigcc -Os -DUSE_TI89  -fomit-frame-pointer tthdex.c
* TI-92p - compile with:   tigcc -Os -DUSE_TI92P -fomit-frame-pointer tthdex.c
*
* [current implementation uses TIGCC 0.93]
*
* (*) the details page contains a secret key: press 'H' to hide the file!
* (*) by pressing '(' or ')' you can decrease or increase the paging speed
*     within the HEX view
*
* credits go to Zeljko Juric and Samuel Stearley for providing me some new
* infos which makes this program possible
*
* $Id: tthdex.c,v 2.8 2002/02/28 14:12:45 tnussb Exp $
*
******************************************************************************/

#define TTHDEX_VERSION "v2.8"

// No SAVE_SCREEN, even if it's extremely unlikely that stack overflows ever
// occur: in the worst case there are at least 7 KB stack left.

#if defined(USE_TI89) && defined(USE_TI92P)
#error cannot produce both versions at once
#elif defined(USE_TI89)
#define C89_92(x,y) (x)
#elif defined(USE_TI92P)
#define C89_92(x,y) (y)
#else
#error Please specify either -DUSE_TI89 or -DUSE_TI92P on commandline
#endif

#define OPTIMIZE_ROM_CALLS
#define NO_EXIT_SUPPORT

#include <tigcclib.h>

//#define NO_HELP

#define KEY_UP2ND    C89_92(4433,4434)
#define KEY_DOWN2ND  C89_92(4436,4440)
#define KEY_UPDIAM   C89_92(16721,8530)
#define KEY_DOWNDIAM C89_92(16724,8536)
#define KEY_OFF2     C89_92(16651,8459)
#define MAXHANDLES   2000  // should be enough, indeed ...


//-----------------------------------------------------------------------------
// NOTE: FastestDrawHLine is a specialized version of the ExtGraph routine
// FastDrawHLine.
//-----------------------------------------------------------------------------
/*===========================================================================*/
/* draws a horizontal line at line y in given plane                          */
/*===========================================================================*/
void FastestDrawHLine(unsigned char* plane,short y);
#if defined(USE_TI89)
asm("xdef FastestDrawHLine\n"
"FastestDrawHLine:\n"
"  pea    (%a0)\n"
"  move.l %d0,-(%sp)\n"
"  move.l %d1,-(%sp)\n"
"  move.l 16(%sp),%a0\n"
"  moveq  #0,%d0\n"
"  move.w 20(%sp),%d0\n"
"  lsl.w  #1,%d0\n"
"  move.w %d0,%d1\n"
"  lsl.w  #4,%d0\n"
"  sub.w  %d1,%d0\n"
"  adda.l %d0,%a0\n"
"  moveq  #-1,%d1\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)\n"
"  move.l (%sp)+,%d1\n"
"  move.l (%sp)+,%d0\n"
"  move.l (%sp)+,%a0\n"
"  rts");

#else

asm("xdef FastestDrawHLine\n"
"FastestDrawHLine:\n"
"  pea    (%a0)\n"
"  move.l %d0,-(%sp)\n"
"  move.l %d1,-(%sp)\n"
"  move.l 16(%sp),%a0\n"
"  moveq  #0,%d0\n"
"  move.w 20(%sp),%d0\n"
"  lsl.w  #1,%d0\n"
"  move.w %d0,%d1\n"
"  lsl.w  #4,%d0\n"
"  sub.w  %d1,%d0\n"
"  adda.l %d0,%a0\n"
"  moveq  #-1,%d1\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)+\n"
"  move.l %d1,(%a0)+\n"
"  move.w %d1,(%a0)\n"
"  move.l (%sp)+,%d1\n"
"  move.l (%sp)+,%d0\n"
"  move.l (%sp)+,%a0\n"
"  rts");

#endif


//-----------------------------------------------------------------------------
// The program doesn't allocate memory for the HANDLE_ENTRY list, but uses a
// list allocated on the heap. This approach prevents the system from heap
// compression and doesn't show a temporary handle for the list.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Structure used for the heap list.
// The memlock entry wouldn't be necessary, but structures on the TI are also
// of an even size, so otherwise we would waste one byte for nothing, and slow
// down the program by about 0%...
//-----------------------------------------------------------------------------
typedef struct {
    HANDLE        h;
    unsigned char memlock;
    unsigned char type;
} HANDLE_ENTRY;

// Globals...
// charset2 and charwidth accelerate LittleString because we no longer have to
// compute them from charset each time...
unsigned char*  charset    = NULL;
unsigned char*  charset2   = NULL;
unsigned short* charwidth  = NULL;
void*           savescreen = NULL;
void*           backb      = NULL;
unsigned char   redraw     = 1;
unsigned char   type       = 0;
unsigned char   previous   = 0;
unsigned char   valb       = 0;
unsigned short  valw       = 0;
unsigned long   vall       = 0;
unsigned short  delay      = 50;

#define TYPE_NONE    0
#define TYPE_VAT     1
#define TYPE_WINDOW  2
#define TYPE_HISTORY 3
#define TYPE_CHARSET 4
#define TYPE_ESTACK  5
#define TYPE_EVHK    6

/*===========================================================================*/
/* get input key pressed by user (!!! RETURNS ONLY UPPERCASE LETTERS !!!)    */
/*                                                                           */
/* replacement for ngetchx() and/or GKeyIn(), because:                       */
/*                                                                           */
/* (1) ngetchx() won't check the APD timer value                             */
/* (2) GKeyIn() destroys the display due to setting the status display       */
/*                                                                           */
/* additionally this function handles the CALCULATOR OFF combinations        */
/*===========================================================================*/
unsigned short GetUserInput(void) {
    void           *kbq = kbd_queue();
    unsigned short  key;

    //-------------------------------------------
    // restart the APD timer now
    //-------------------------------------------
    OSTimerRestart(APD_TIMER);

    while (1) {
        //---------------------------------------
        // wait until we get a key
        // if the APD timer expires -> turn
        // calculator off
        //---------------------------------------
        while (OSdequeue(&key, kbq)) {
            idle();
            if (OSTimerExpired(APD_TIMER)) {
                off();
                OSTimerRestart(APD_TIMER);
            }
        }

        //---------------------------------------
        // handle calculator-off key combinations
        // if the APD timer expires
        // [2nd] + [ON] & [diamond]+[ON]
        // calculator off
        //---------------------------------------
        if (key == KEY_OFF || key == KEY_OFF2) {
            off();
            OSTimerRestart(APD_TIMER);
        }

        else {  // NOTE: the [ON] doesn't trigger a comeback from this loop!!
            key = toupper(key);
#ifdef USE_TI89
            // if / else if smaller than switch...
            if (key == '=') key = 'A';
            else if (key == '(') key = 'B';
            else if (key == ')') key = 'C';
            else if (key == ',') key = 'D';
            else if (key == '/') key = 'E';
            else if (key == '|') key = 'F';
#endif

            return key & ~(unsigned short)0x800; // map out key repeat flag
        }
    }
}


/*===========================================================================*/
/* setup charset - draws all characters of the little and medium font set    */
/* into internal buffers and uses later own sprite routines to draw them.    */
/* This is a much faster way for drawing than using the DrawChar() routine.  */
/*===========================================================================*/
static inline void SetupCharSet(void) {
    unsigned short i;

    // Little font
    FontSetSys(F_4x6);
    memset(charset,0,5*256+8*256);
    PortSet(charset+8*256,7,5*256-1);

    for (i=0;i<256;i++) {
        charwidth[i] = FontCharWidth(i);
        DrawChar(0,i*5,i,A_REPLACE);
    }

    // Medium font
    FontSetSys(F_6x8);
    PortSet(charset,7,8*256-1);

    for (i=0;i<256;i++) DrawChar(0,i<<3,i,A_REPLACE);

    PortRestore();
}

/*===========================================================================*/
/* replaces string using own sprites (F_6x8) (much faster than DrawStr)      */
/*===========================================================================*/
void NormalString(short x,short y,const unsigned char* s,void *plane) {
    unsigned char* sprite;
    long           addr;
    long           addr_const = ((long)plane)+(y<<5)-(y<<1);
    unsigned short cnt;
    long           mask;

    while (*s) {
        sprite = &charset[((short)(*s))<<3];
        addr   = addr_const+((x>>3)&0xfffe);
        cnt    = 24-(x&15);
        mask   = ~((long)(0xff)<<cnt);
        // unrolled loop for more speed ...
        *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr&=mask; *(long*)addr|=(long)(*sprite)<<cnt;

        x+=6;
        s++;
    }
}

/*===========================================================================*/
/* draws string using own sprites (F_4x6) (much faster than DrawStr)         */
/*===========================================================================*/
void LittleString(short x,short y,const unsigned char* s,void *plane) {
    unsigned char* sprite;
    long           addr;
    unsigned short cnt;
    short          ytemp;

    while (*s) {
        sprite = &charset2[(short)(*s)*5];
        ytemp  = y;
        if((*s) == 0x67) ytemp++;  // move letter 'g' one pixel down

        addr = ((long)plane)+(ytemp<<5)-(ytemp<<1)+((x>>3)&0xfffe);
        cnt  = 24-(x&15);

        // unrolled loop for more speed ...
        *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
        *(long*)addr|=(long)(*sprite)<<cnt;

        x+=charwidth[*s++];
    }
}

/*===========================================================================*/
/* replaces single character using own sprites                               */
/*===========================================================================*/
void FastChar(short x,short y,unsigned char c,void *plane) {
    unsigned char* sprite=&charset[((short)c)<<3];
    long           addr = ((long)plane)+(y<<5)-(y<<1)+((x>>3)&0xfffe);
    unsigned short cnt  = 24-(x&15);
    long           mask = ~((long)(0xff)<<cnt);

    // unrolled loop for more speed ...
    *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
    *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
    *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
    *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
    *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
    *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
    *(long*)addr&=mask; *(long*)addr|=(long)(*sprite++)<<cnt; addr+=30;
    *(long*)addr&=mask; *(long*)addr|=(long)(*sprite)<<cnt;
}

// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Quite dirty ... DON'T do this normally
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#undef printf_xy
#define printf_xy(x,y,f...) \
  ({char __s[100]; _rom_call(short,(char*,const char*,...),53)(__s ,##f); \
  NormalString(x,y,__s,LCD_MEM);})


/*===========================================================================*/
/* clears screen and displays page header                                    */
/*===========================================================================*/
void DisplayHeader(const char* text_left, const char* text_right, void *plane) {
    memset(plane,0,LCD_SIZE);
    NormalString(0,0,text_left,plane);
    NormalString((C89_92(159,239))-6*strlen(text_right),0,text_right,plane);
    FastestDrawHLine(plane,8);
}


// I made this table global, this decreases size...
unsigned char hex[] = "0123456789ABCDEF";
/*===========================================================================*/
/* put a single hexvalue on the screen                                       */
/*===========================================================================*/
void PutHexNumber(short x, short y, unsigned char value) {
    FastChar(x,y,hex[(value >> 4) & 0x0f],backb);
    FastChar(x+6,y,hex[value & 0x0f],backb);
}

#define NR_LINES           C89_92(9,12)
#define HEX_NR_BYTES       C89_92(6,10)
#define HEX_BYTES_PER_PAGE (NR_LINES*HEX_NR_BYTES)
#define HEX_2NDUPDOWN      C89_92(0x100,0x200)

/*===========================================================================*/
/* display a complete hexcode page                                           */
/*===========================================================================*/
void DisplayHexPage(char* title,unsigned char* src,unsigned long idx,unsigned char* end) {
    short          x,y;
    unsigned char* act = src + idx;

    DisplayHeader(title,"",backb);

    for (y=10;y<=NR_LINES*10;y+=10) {
        //---------------------------------------------------------------------
        // draw the address ...
        //---------------------------------------------------------------------
        PutHexNumber(0, y,(unsigned char)((idx>>8)&0xff));
        PutHexNumber(12,y,(unsigned char)(idx & 0xff));
        idx+=HEX_NR_BYTES;
        for (x=0;x<HEX_NR_BYTES;x++) {
            //-----------------------------------------------------------------
            // draw the hex display part (bytes) ...
            //-----------------------------------------------------------------
            PutHexNumber(x*13+27,y,*act);
            //-----------------------------------------------------------------
            // draw the character display part ...
            //-----------------------------------------------------------------
            FastChar(C89_92(108,159)+(x<<3),y,*act,backb);
            act++;
            if (act == end) goto end;
        }
    }
    end:
    LCD_restore(backb);

    // The following routine is extracted from TI-Chess and modified.
    // NOTE: this wait loop is done to fit approximatively on both
    // HW models, it is very accurate neither on HW1 nor on HW2.
    // It is inlined to save speed and space.
    asm("     movem.l %d0-%d3,-(%sp)\n"
    "         move.w  delay,%d2\n"
    "         tst.w   %d2\n"
    "         beq.s   ____end\n"
    "         move.l  #31,%d1\n"
    "         move.l  #31,%d3\n"
    "__wl2_:  move.w  #132,%d0    /* modify this value for exact timing !!! */\n"
    "__wl1_:  rol.l   %d3,%d1\n"
    "         dbra    %d0,__wl1_\n"
    "         dbra    %d2,__wl2_\n"
    "____end:\n"
    "         movem.l (%sp)+,%d0-%d3");
}

const char* messages[]= {
    "Enter hexadecimal address to view (0-",
    "Enter byte to search for (range: 0-FF).",
    "Enter word to search for (range: 0-FFFF).",
    "Enter long to search for (range: 0-FFFFFFFF).",
    NULL
};


unsigned long InputString(unsigned long size, short message, short maxlen) {
    unsigned long  buf;
    short          key;
    short          i;
    unsigned char  addressb[maxlen+1];

    memset(LCD_MEM,0,LCD_SIZE);
    LittleString(0,0,messages[message],LCD_MEM);
    if(!message) {
        unsigned char mess[10];
        sprintf(mess,"%5lX",size);
        strcat(mess,").");
        LittleString(132,0,mess,LCD_MEM);
    }

    while (1) {
        i=0;
        buf=0;
        NormalString(0,9,"        ",LCD_MEM);
        OSTimerRestart(APD_TIMER);
        _memset(addressb,0,maxlen+1);

        do {
            printf_xy(0,9,"%s_       ",addressb);
            key = GetUserInput();
            if (((key >=48 && key <= 57) ||
                 (key >=65 && key <= 70) ||
                 (key >=97 && key <= 102)) &&
                 (i < maxlen)) {
                addressb[i++] = (unsigned char)toupper(key);
            }
            if (key == KEY_BACKSPACE && i) {
                i--;
                addressb[i] = 0;
            }
            if (key == KEY_CLEAR) {
                _memset(addressb,0,maxlen+1);
                i=0;
            }
        }
        while (key != KEY_ENTER && key != KEY_ESC && key != KEY_F5);

        if (key == KEY_ESC) return -1UL;
        if (key == KEY_F5)  return -2UL;
        if (key == KEY_ENTER && addressb[0] == 0) continue;

        // This piece of code does the same as buf = strtoul(addressb,NULL,16);
        // (but it's much faster and smaller).
        else {
            short j=0;
            char c;
            i--;
            while (i+1) {
                c = (addressb[i]>57?addressb[i]-55:addressb[i]-48)&0xF;
                buf |= ((unsigned long)c)<<j;
                i--;
                j+=4;
            }

            if (buf<=size) {
                redraw=1;
                return buf;
            }
        }
    }
}

short Check(unsigned long index) {
    if (   index == (unsigned long)(&valb)
        || index == (unsigned long)(&valw)
        || index == ((unsigned long)(&valw)) + 1
        || index == (unsigned long)(&vall)
        || index == ((unsigned long)(&vall)) + 1
        || index == ((unsigned long)(&vall)) + 2
        || index == ((unsigned long)(&vall)) + 3) return FALSE;
    return TRUE;
}

// The three finders may return irrelevant results if searching in various
// areas of the memory, particularly:
// - both user and supervisor stacks, that is to say 0x400 - 0x4BFF.
// - the video memory (LCD_MEM, 0x4C00 - 0x5AFF).
// - 0x5B00 to the lowest byte of the heap, particularly 0x7000-0x7FFF area
// (due to system functions: they put debug information in this area).
// - the place where is located the backbuffer used...
// - maybe elsewhere I didn't think of...
static inline unsigned long FindByte(short          direction,
                                     unsigned char* src,
                                     unsigned long  index,
                                     unsigned long  size)
{
    unsigned long siz  = (unsigned long)src + size;

    index += (unsigned long)src;

    //-----------------------------------------------------------------
    // if we are looking forward ...
    //-----------------------------------------------------------------
    if (direction) {
        //-----------------------------------------------------------------
        // skip if already pointing to an occurence of the byte.
        //-----------------------------------------------------------------
        if (index < siz && *(unsigned char *)index == valb) index++;

        while (index < siz) {
            if (*(unsigned char *)index == valb) {
                if (Check(index)) {
                    index -= (unsigned long)src;
                    return index;
                }
            }
            index++;
        }
        return 0x40000;
    }

    //-----------------------------------------------------------------
    // if we are looking backwards ...
    //-----------------------------------------------------------------
    else {
        //-----------------------------------------------------------------
        // skip if already pointing to an occurence of the byte.
        //-----------------------------------------------------------------
        if (index && *(unsigned char *)index == valb) index--;

        if (!index && (*(unsigned char *)index == valb)) return 0;

        while (index > (unsigned long)(src)) {
            if (*(unsigned char *)index == valb) {
                if (Check(index)) {
                    index -= (unsigned long)src;
                    return index;
                }
            }
            index--;
        }
        return 0x40000;
    }
}

static inline unsigned long FindWord(short          direction,
                                     unsigned char* src,
                                     unsigned long  index,
                                     unsigned long  size)
{
    unsigned char valw1 = (unsigned char)valw;
    unsigned char valw2 = (unsigned char)(valw>>8);
    unsigned long siz   = (unsigned long)src + size;

    index += (unsigned long)src;

    //-----------------------------------------------------------------
    // if we are looking forward ...
    //-----------------------------------------------------------------
    if (direction) {
        //-----------------------------------------------------------------
        // skip if already pointing to an occurence of the word.
        //-----------------------------------------------------------------
        if (index < siz
            && *(unsigned char *)index == valw2
            && *(unsigned char *)(index + 1) == valw1) index++;

        while (index < siz) {
            if (*(unsigned char *)index == valw2) {
                index++;
                if (*(unsigned char *)index == valw1) {
                    if (Check(index - 1)) {
                        index -= (unsigned long)src;
                        return (index - 1);
                    }
                }
                index--;
            }
            index++;
        }
        return 0x40000;
    }

    //-----------------------------------------------------------------
    // if we are looking backwards ...
    //-----------------------------------------------------------------
    else {
        while (index > (unsigned long)(src)) {
            if (*(unsigned char *)index == valw1) {
                index--;
                if (*(unsigned char *)index == valw2) {
                    if (Check(index)) {
                        index -= (unsigned long)src;
                        return index;
                    }
                }
                index++;
            }
            index--;
        }
        return 0x40000;
    }
}

static inline unsigned long FindLong(short          direction,
                                     unsigned char* src,
                                     unsigned long  index,
                                     unsigned long  size)
{
    unsigned char vall1 = (unsigned char)vall;
    unsigned char vall2 = (unsigned char)(vall>>8);
    unsigned char vall3 = (unsigned char)(vall>>16);
    unsigned char vall4 = (unsigned char)(vall>>24);
    unsigned long siz   = (unsigned long)src + size;

    index += (unsigned long)src;

    //-----------------------------------------------------------------
    // if we are looking forward
    //-----------------------------------------------------------------
    if(direction) {
        //-----------------------------------------------------------------
        // skip if already pointing to an occurence of the long.
        //-----------------------------------------------------------------
        if (index + 2 < siz
            && *(unsigned char *)index == vall4
            && *(unsigned char *)(index+1) == vall3
            && *(unsigned char *)(index+2) == vall2
            && *(unsigned char *)(index+3) == vall1) index++;

        while (index + 2 < siz) {
            if (*(unsigned char *)index == vall4) {
                index++;
                if (*(unsigned char *)index == vall3) {
                    index++;
                    if (*(unsigned char *)index == vall2) {
                        index++;
                        if (*(unsigned char *)index == vall1) {
                            if (Check(index - 3)) {
                                index -= (unsigned long)src;
                                return (index - 3);
                            }
                        }
                        index--;
                    }
                    index--;
                }
                index--;
            }
            index++;
        }
        return 0x40000;
    }

    //-----------------------------------------------------------------
    // if we are looking backwards.
    //-----------------------------------------------------------------
    else {
        while (index > (unsigned long)(src)) {
            if (*(unsigned char *)index == vall1) {
                if (index) index--;
                else break;
                if (*(unsigned char *)index == vall2) {
                    if (index) index--;
                    else break;
                    if (*(unsigned char *)index == vall3) {
                        if (index) index--;
                        else break;
                        if (*(unsigned char *)index == vall4) {
                            if (Check(index)) {
                                index -= (unsigned long)src;
                                return index;
                            }
                        }
                        index++;
                    }
                    index++;
                }
                index++;
            }
            index--;
        }
        return 0x40000;
    }
}


/*===========================================================================*/
/* loop for the integrated hexcode viewer                                    */
/*===========================================================================*/
unsigned long View_HEX(unsigned short input, unsigned char *src,
                       unsigned long  index, unsigned short size, short flag)
{
    unsigned long siz     = (flag)?0x3FFFF:size;
    unsigned long address = 0;

    //-----------------------------------------------------------------
    // scroll up ...
    //-----------------------------------------------------------------
    if (input == (unsigned short)KEY_UP) {
        if (index >= HEX_BYTES_PER_PAGE) index -= HEX_BYTES_PER_PAGE;
        else {
            if((index) && index <= HEX_BYTES_PER_PAGE) index = 0;
            else {
                index = (unsigned long)(siz / HEX_BYTES_PER_PAGE);
                index *= HEX_BYTES_PER_PAGE;
                if (index == siz) index -= HEX_BYTES_PER_PAGE;
            }
        }
        redraw = 1;
    }

    //-----------------------------------------------------------------
    // scroll down ...
    //-----------------------------------------------------------------
    else if (input == (unsigned short)KEY_DOWN) {
        if (index + HEX_BYTES_PER_PAGE < siz) index += HEX_BYTES_PER_PAGE;
        else index  = 0;
        redraw = 1;
    }

    //-----------------------------------------------------------------
    // jump up of 0x100 (89) or 0x200 (92+) ...
    //-----------------------------------------------------------------
    else if (input == (unsigned short)KEY_UP2ND) {
        if (index >= HEX_2NDUPDOWN) index -= HEX_2NDUPDOWN;
        else {
            if((index) && index <= HEX_2NDUPDOWN) index = 0;
            else {
                index = (unsigned long)(siz / HEX_2NDUPDOWN);
                index *= HEX_2NDUPDOWN;
                if (index == siz) index -= HEX_2NDUPDOWN;
            }
        }
        redraw = 1;
    }

    //-----------------------------------------------------------------
    // jump down of 0x100 (89) or 0x200 (92+) ...
    //-----------------------------------------------------------------
    else if (input == (unsigned short)KEY_DOWN2ND) {
        if (index + HEX_2NDUPDOWN < siz) index += HEX_2NDUPDOWN;
        else index  = 0;
        redraw = 1;
    }

    //-----------------------------------------------------------------
    // jump to first page ...
    //-----------------------------------------------------------------
    else if (input == (unsigned short)KEY_UPDIAM) {
        index  = 0;
        redraw = 1;
    }

    //-----------------------------------------------------------------
    // jump to last page ...
    //-----------------------------------------------------------------
    else if (input == (unsigned short)KEY_DOWN2ND || input == (unsigned short)KEY_DOWNDIAM) {
        index = (unsigned long)(siz / HEX_BYTES_PER_PAGE);
        index *= HEX_BYTES_PER_PAGE;
        if (index == siz) index -= HEX_BYTES_PER_PAGE;
        redraw = 1;
    }

    //-----------------------------------------------------------------
    // decrease delay in milliseconds between displaying two pages ...
    // The parentheses change the delay, but they are turned into
    // B and C by GetUserInput, on 89 only...
    //-----------------------------------------------------------------

    // Lionel, the parentheses work on the TI92P!!
    else if (input == C89_92('B','(') && delay > 25) delay -=25;

    //-----------------------------------------------------------------
    // increase delay in milliseconds between displaying two pages ...
    // The parentheses change the delay, but they are turned into
    // B and C by GetUserInput, on 89 only...
    //-----------------------------------------------------------------
    else if (input == C89_92('C',')') && delay < 250) {delay +=25;

        ST_showHelp("decreased");
    }

    //-----------------------------------------------------------------
    // search for a byte ...
    //-----------------------------------------------------------------
    else if (input == (unsigned short)KEY_F6) {
        type    = 0;
        redraw  = 1;
        address = InputString((unsigned long)0xFF,1,2);
        if (address == -1UL || address == -2UL) return address;
        valb = (unsigned char)address;
        previous = 1;
    }

    //-----------------------------------------------------------------
    // search for a word ...
    //-----------------------------------------------------------------
    else if (input == (unsigned short)KEY_F7) {
        type   = 1;
        redraw = 1;
        address = InputString((unsigned long)0xFFFF,2,4);
        if (address == -1UL || address == -2UL) return address;
        valw = (unsigned short)address;
        previous = 1;
    }

    //-----------------------------------------------------------------
    // search for a long ...
    //-----------------------------------------------------------------
    else if (input == (unsigned short)KEY_F8) {
        type   = 2;
        redraw = 1;
        address = InputString(-1UL,3,8);
        if (address == -1UL || address == -2UL) return address;
        vall = address;
        previous = 1;
    }

    //-----------------------------------------------------------------
    // "Find previous", "Find next" ...
    //-----------------------------------------------------------------
    else if ((input == (unsigned short)KEY_F3 || input == (unsigned short)KEY_F2)
              && previous)
    {
        if      (!type)     address = FindByte(input-(unsigned short)KEY_F2,src,index,siz);
        else if (type == 1) address = FindWord(input-(unsigned short)KEY_F2,src,index,siz);
        else if (type == 2) address = FindLong(input-(unsigned short)KEY_F2,src,index,siz);
        redraw = 1;
        if (address != 0x40000) index = address;
        else {
            memset(LCD_MEM,0,LCD_SIZE);
            NormalString(0,0,"Value not found !",LCD_MEM);
            input = GetUserInput();
            if (input == KEY_ESC)     return -1UL;
            else if (input == KEY_F5) return -2UL;
        }
    }

    return index;
}

/*===========================================================================*/
/* integrated hexcode viewer                                                 */
/*===========================================================================*/
// The hexcode viewer may display different things in the left and in the right
// part of the screen... This may occur if displaying in various areas of the
// memory, particularly:
// - both user and supervisor stacks, that is to say 0x400 - 0x4BFF.
// - the video memory (LCD_MEM, 0x4C00 - 0x5AFF).
// - 0x5B00 to the lowest byte of the heap, particularly 0x7000-0x7FFF area
// (due to system functions: they put informations in this area).
// - the place where is located the backbuffer used...
// - maybe elsewhere I didn't think of...
static inline short ViewHEX(HANDLE_ENTRY* all,short* idx,short max,HANDLE h_myself) {
    unsigned char* src;
    unsigned char* end;
    unsigned short size;
    unsigned short input;
    unsigned long  index;
    unsigned long  indexb;
    unsigned char  buffer[100];

    //-------------------------------------------------------------------------
    // loop until user gets bored ...
    //-------------------------------------------------------------------------
    do {
        if (!(src = HeapDeref(all[*idx].h))) return KEY_ESC;
        size = HeapSize(all[*idx].h);

        //---------------------------------------------------------------------
        // compose header line ...
        //---------------------------------------------------------------------
        sprintf(buffer,"0x%03X 0x%08lX %5u %c %c",
            all[*idx].h, (unsigned long)src,size,(all[*idx].memlock)?'L':'M',
           (all[*idx].h==h_myself)?'*':' ');

        index  = 0;
        redraw = 1;

        end = src+size;

        //---------------------------------------------------------------------
        // loop until user wants to view another file or wants to leave ...
        //---------------------------------------------------------------------
        do {
            if (redraw) {
                DisplayHexPage(buffer,src,index,end);
                redraw = 0;
            }
            input = GetUserInput();
            //-----------------------------------------------------------------
            // user wants to go to an address of the file ...
            //-----------------------------------------------------------------
            if (input == (unsigned short)KEY_MODE) {
                indexb = InputString((unsigned long)size,0,4);
                redraw = 1;
                if (indexb == -1UL) continue;
                else if (indexb == -2UL) {
                    input = KEY_F5;
                    break;
                }
                else index = indexb;
            }


            indexb = View_HEX(input,src,index,size,0);
            if (indexb == -1UL) continue;
            else if (indexb == -2UL) {
                input = KEY_F5;
                break;
            }
            else index = indexb;
        }
        while (input != (unsigned short)KEY_ESC   &&
               input != (unsigned short)KEY_F5    &&
               input != (unsigned short)KEY_LEFT  &&
               input != (unsigned short)KEY_RIGHT);

        //---------------------------------------------------------------------
        // user wants to view the previous memory block ...
        //---------------------------------------------------------------------
        if (input == (unsigned short)KEY_LEFT) {
            (*idx)--;
            if (*idx < 0) *idx = max-1;
            continue;
        }
        //---------------------------------------------------------------------
        // user wants to view the next memory block ...
        //---------------------------------------------------------------------
        else if (input == (unsigned short)KEY_RIGHT) {
            (*idx)++;
            if (*idx >= max) *idx = 0;
            continue;
        }
        //---------------------------------------------------------------------
        // hey, let's go home ...
        //---------------------------------------------------------------------
        else return input;
    }
    while (1);
}

/*===========================================================================*/
/* display a page filled with HANDLE_ENTRY structures                        */
/*===========================================================================*/
static inline void DisplayPage(HANDLE_ENTRY* src,
                               short         idx,
                               short         max,
                               short         locked,
                               HANDLE        h_myself)
{
    short         y;
    short         ypos;
    short         hfree = FreeHandles();
    unsigned char buffer[100];

    //-------------------------------------------------------------------------
    // compose header and draw it ...
    //-------------------------------------------------------------------------
    sprintf(buffer,"S=%d L=%d F=%d",max,locked,hfree);
#ifndef NO_HELP
    DisplayHeader(buffer,"F1\x16Help",LCD_MEM);
#else
    DisplayHeader(buffer,"",LCD_MEM);
#endif
    //-------------------------------------------------------------------------
    // ... and draw the single lines
    //-------------------------------------------------------------------------
    ypos = 10;
    for (y=0;y<NR_LINES && idx < max;y++,idx++,ypos+=10) {
        HANDLE         act_h    = src[idx].h;
        unsigned long  address  = (unsigned long)HeapDeref(act_h);
        unsigned short size     = HeapSize(act_h);
        char           type_of  = ' ';

        switch(src[idx].type) {
            case TYPE_VAT:     type_of = 'V'; break;
            case TYPE_WINDOW:  type_of = 'W'; break;
            case TYPE_HISTORY: type_of = 'H'; break;
            case TYPE_CHARSET: type_of = 'C'; break;
            case TYPE_ESTACK:  type_of = 'S'; break;
            case TYPE_EVHK:    type_of = 'E'; break;
        }
#if defined(USE_TI89)
        printf_xy(0,ypos,
                  "%c x%03X x%08lX %5u %c %c",
                  type_of,act_h,address,size,
                  (src[idx].memlock)?'L':'M',
                  (act_h==h_myself)?'*':y+'1');
#else
        printf_xy(0,ypos,
                  "%c x%03X x%08lX %5u %c %c",
                  type_of,act_h,address,size,
                  (src[idx].memlock)?'L':'M',
                   // Dirty use of conditionals...
                  (act_h==h_myself)? '*' : ((y<=9)? y+'0' :  ((y==10)?'A':'B')));
#endif
    }
}

#ifndef NO_HELP
#define HELPPAGE_LINES 8
const char* helppage[]={
    "S=Sum  L=#Locked  F=#Free", "",
    "Column 1",                  "V=VAT W=Window H=History",
    "",                          "S=ESTACK C=Charset E=Event Hook",
    "Column 2",                  "Handle Number",
    "Column 3",                  "Memory Address",
    "Column 4",                  "Size in Bytes",
    "Column 5",                  "(M)ovable/(L)ocked",
    "Column 6",                  "Line Nr. (*=myself)"
};

/*===========================================================================*/
/* draws help page                                                           */
/*===========================================================================*/
static inline short DrawHelpPage(void) {
    short i,y;

    DisplayHeader("HANDLE-Explorer",TTHDEX_VERSION,backb);

    y=10;
    for (i=0;i<HELPPAGE_LINES*2;i+=2,y+=7) {
        LittleString(0, y,helppage[i],  backb);
        LittleString(35,y,helppage[i+1],backb);
    }
    FastestDrawHLine(backb,10+HELPPAGE_LINES*7);
    LittleString(0,10+HELPPAGE_LINES*7+3,"Press LineNr. for Details  OR  [APPS]\x16MemView",backb);
    LittleString(0,10+(HELPPAGE_LINES+1)*7+3,"F5 \x16 Exit    [2nd][Up] \x16 First    [2nd][Dn] \x16 Last",backb);
    LittleString(0,10+(HELPPAGE_LINES+2)*7+7,"HexView: F6,F7,F8 \x16 Search Byte,Word,DWord",backb);
    LittleString(0,10+(HELPPAGE_LINES+3)*7+7,"HexView: F2,F3       \x16 Find Previous,Next",backb);

    LCD_restore(backb);

    return GetUserInput();
}
#endif

const char* flagstext[]={
    "busy",
    "local",
    "collapsed",
    "twin",
    "archive",
    "in_view",
    "folder",
    "overwr.",
    "checked",
    "hidden",
    "locked",
    "statvar",
    NULL
};

const char* types[]={
    "Unknown HANDLE",
    NULL,
    "Saved Screen Area (Window)",
    "Home Screen History Entry",
    "This Program's Charset",
    "Expressions Stack",
    "Event Hook"
};

/*===========================================================================*/
/* draws details page                                                        */
/*===========================================================================*/
short DrawDetailsPage(HANDLE_ENTRY* all,short *idx, short max,HANDLE h_myself) {
    SYM_ENTRY*     symptr;
    SYM_ENTRY*     folptr;
    char           buffer[100];
    char           buffer2[10];
    unsigned long  address;
    unsigned short size;
    short          input;
    short          flags;

    do {
        HANDLE tmp_h = all[*idx].h;
        address      = (unsigned long)HeapDeref(tmp_h);
        size         = HeapSize(tmp_h);
        sprintf(buffer,"0x%03X 0x%08lX %5u %c %c",
                tmp_h, address,size,(all[*idx].memlock)?'L':'M',
                (tmp_h==h_myself)?'*':' ');

        DisplayHeader(buffer,"",LCD_MEM);

        //---------------------------------------------------------------------
        // try to find the symbol corresponding to the handle in the VAT and
        // remember also the folder where the symbol is in ...
        //---------------------------------------------------------------------
        symptr = SymFindFirst(NULL,2);
        folptr = NULL;
        while (symptr) {
            if (symptr->flags.bits.folder) folptr = symptr;
            if (symptr->handle == tmp_h) break;
            symptr=SymFindNext();
        }

        //---------------------------------------------------------------------
        // symbol not found in VAT, just print a short message ...
        //---------------------------------------------------------------------
        if (!symptr) NormalString(0,10,types[all[*idx].type],LCD_MEM);

        //---------------------------------------------------------------------
        // symbol found in VAT, print page showing it name and almost all flags
        //---------------------------------------------------------------------
        else {
            short i,y;

            buffer[8]  = 0;
            buffer2[8] = 0;
            if (folptr && symptr != folptr) {
                strncpy(buffer,folptr->name,8);
                strncpy(buffer2,symptr->name,8);
                strcat(buffer,"\\");
                strcat(buffer,buffer2);
            }
            else {
                strncpy(buffer,symptr->name,8);  // fetch name
            }

            printf_xy(0,10,"Name = %s",buffer);

            y=25;
            for (i=0;i<12;i+=2,y+=10) {
                NormalString(0, y,flagstext[i],LCD_MEM);
                NormalString(80,y,flagstext[i+1],LCD_MEM);
            }

            flags = symptr->flags.flags_n;

            FastChar(60, 15+1*10,(flags&SF_BUSY)?'1':'0',LCD_MEM);
            FastChar(135,15+1*10,(flags&SF_LOCAL)?'1':'0',LCD_MEM);

            FastChar(60, 25+1*10,(flags&SF_COLLAPSED)?'1':'0',LCD_MEM);
            FastChar(135,25+1*10,(flags&SF_TWIN)?'1':'0',LCD_MEM);

            FastChar(60, 35+1*10,(flags&SF_ARCHIVED)?'1':'0',LCD_MEM);
            FastChar(135,35+1*10,(flags&SF_INVIEW)?'1':'0',LCD_MEM);

            FastChar(60, 45+1*10,(flags&SF_FOLDER)?'1':'0',LCD_MEM);
            FastChar(135,45+1*10,(flags&SF_OVERWRITTEN)?'1':'0',LCD_MEM);

            FastChar(60, 55+1*10,(flags&SF_CHECKED)?'1':'0',LCD_MEM);
            FastChar(135,55+1*10,(flags&SF_HIDDEN)?'1':'0',LCD_MEM);

            FastChar(60, 65+1*10,(flags&SF_LOCKED)?'1':'0',LCD_MEM);
            FastChar(135,65+1*10,(flags&SF_STATVAR)?'1':'0',LCD_MEM);
        }
        FastestDrawHLine(LCD_MEM,C89_92(92,119));
        LittleString(0,C89_92(94,121),"[ENTER]\x16HexView   [LEFT]\x16Prev  [RIGHT]\x16Next",LCD_MEM);

        //---------------------------------------------------------------------
        // loop until we get a valid input ...
        //---------------------------------------------------------------------
        do {
            input = GetUserInput();

            //-----------------------------------------------------------------
            // okay, let's "hex-view" it ...
            //-----------------------------------------------------------------
            if (input == KEY_ENTER) {
                redraw = 1;
                input = ViewHEX(all,idx,max,h_myself);
                if (input == KEY_ESC) break;
            }

            //-----------------------------------------------------------------
            // show the previous file ...
            //-----------------------------------------------------------------
            if (input == KEY_LEFT || input == KEY_UP) {
                (*idx)--;
                if (*idx<0) *idx = max-1;
                redraw = 1;
                break;
            }

            //-----------------------------------------------------------------
            // show the next file ...
            //-----------------------------------------------------------------
            else if (input == KEY_RIGHT || input == KEY_DOWN) {
                (*idx)++;
                if (*idx>=max) *idx = 0;
                redraw = 1;
                break;
            }

            //-----------------------------------------------------------------
            // hide the file ...
            //-----------------------------------------------------------------
            else if (input == 'h' || input=='H' || input == '8') {
                symptr->flags.flags_n^=SF_HIDDEN;
                FastChar(135,55+1*10,(symptr->flags.flags_n&SF_HIDDEN)?'1':'0',LCD_MEM);
            }

            //-----------------------------------------------------------------
            // okay, game is over here in the details ...
            //-----------------------------------------------------------------
            else if (input == KEY_ESC || input == KEY_F5) return input;
        }
        while (1);
    }
    while (1);
}

/*===========================================================================*/
/* voila, our main ...                                                       */
/*===========================================================================*/
void _main(void) {
    HANDLE_ENTRY*  list      = NULL;
    HANDLE         h         = 0;
    HANDLE         h_myself  = 0;
    WINDOW*        pwin      = NULL;
    short          input     = 0;
    unsigned short nr_blocks = 0;
    unsigned short nr_locked = 0;
    unsigned short ix        = 0;
    unsigned long  index     = 0;
    unsigned long  indexb    = 0;
    SYM_ENTRY*     symptr;
    unsigned long  program_counter;
    unsigned short tmp_len;
    unsigned char* tmp_src;
    unsigned short i;
    unsigned short found;
    unsigned long* handle_table = NULL;
    unsigned short home_entries;
    unsigned char  buffer[60];

    asm volatile("bsr 0f; 0:move.l (%%sp)+,%0":"=g"(program_counter));

    redraw   = 1;
    previous = 0;

    if (!(h=HeapAlloc(8*256+5*256+2*256+LCD_SIZE+LCD_SIZE))) {
        ST_helpMsg("ERROR: out of memory");
        return;
    }
    if (!(charset=(unsigned char*)HLock(h))) {
        ST_helpMsg("ERROR: locking failed");
        HeapFree(h);
        return;
    }
    charset2   = (charset+8*256);
    charwidth  = (unsigned short *)((void *)(charset2+5*256));
    savescreen = (void *)(charset2+5*256+2*256);
    backb      = (void *)(savescreen+LCD_SIZE);

    SetupCharSet();
    memcpy(savescreen,LCD_MEM,LCD_SIZE);

    //-------------------------------------------------------------------------
    // get the handle table (thanx to Zeljko Juric for this trick!)
    //-------------------------------------------------------------------------
    handle_table=*(unsigned long**)(unsigned long)(*((HANDLE*)HeapDeref+4+AMS_2xx));

    i = MAXHANDLES-1;

    while (!handle_table[i]) i--;

    for (found=1;found<=i;found++) {
        if (handle_table[found]) {
            nr_blocks++;
            if (nr_blocks==MAXHANDLES-1) {
                HeapUnlock(h);
                HeapFree(h);
                ST_helpMsg("ERROR: Too many handles");
                return;
            }
        }
    }

    list = (HANDLE_ENTRY *)alloca(nr_blocks*sizeof(HANDLE_ENTRY));
    memset(list,0,nr_blocks*sizeof(HANDLE_ENTRY));

    nr_blocks=0;
    for (found=1;found<=i;found++) {
        if (handle_table[found]) {
            list[nr_blocks].h = found;
            if (HeapGetLock(found)) {
                list[nr_blocks].memlock = 1;
                nr_locked++;
            }
            nr_blocks++;
        }
    }

    //------------------------------------------------------------------------
    // mark all HANDLEs which are in VAT and setup h_myself (handle to myself)
    //------------------------------------------------------------------------
    symptr = SymFindFirst(NULL,2);
    while (symptr) {
        if (symptr->handle) {
            for (i=0;i<nr_blocks;i++) {
                if (list[i].h == symptr->handle) {
                    list[i].type = TYPE_VAT;
                    break;
                }
            }
            if (!h_myself) {
                if ((tmp_src = HeapDeref(symptr->handle))) {
                    tmp_len = HeapSize(symptr->handle);
                    if ((program_counter & 0x3FFFF) > (unsigned long)tmp_src &&
                        (program_counter & 0x3FFFF) < (unsigned long)tmp_src+tmp_len+15)
                    {
                        h_myself  = symptr->handle;
                    }
                }
            }
        }
        symptr=SymFindNext();
    }

    //-------------------------------------------------------------------------
    // traverse through window list to find all "saved screen area" handles
    //-------------------------------------------------------------------------
    pwin = FirstWindow;
    do {
        if (pwin->DupScr) {
            for (i=0;i<nr_blocks;i++) {
                if (list[i].h == pwin->DupScr) {
                    list[i].type = TYPE_WINDOW;
                    break;
                }
            }
        }
        pwin = pwin->Next;
    }
    while (pwin);

    //-------------------------------------------------------------------------
    // traverse home entries find all "history" handles
    //-------------------------------------------------------------------------
    home_entries = HS_countFIFO();
    while (home_entries) {
        HANDLE home_h;
        home_entries--;
        home_h = HS_getEntry(home_entries);
        for (i=0;i<nr_blocks;i++) {
            if (list[i].h == home_h) {
                list[i].type = TYPE_HISTORY;
                break;
            }
        }
    }

    //-------------------------------------------------------------------------
    // Find the expressions stack and the charset, as well as
    // event hooks using Kevin Kofler's convention (signature: 'evHk')
    //-------------------------------------------------------------------------
    for (i=0;i<nr_blocks;i++) {
        void *p = HeapDeref(list[i].h);
        if (p == (void *)(top_estack-2))            list[i].type = TYPE_ESTACK;
        else if (p == (void *)charset)              list[i].type = TYPE_CHARSET;
        else if (*(unsigned long *)p == 0x6576486B) list[i].type = TYPE_EVHK;
    }

    //-------------------------------------------------------------------------
    // Enter main loop ...
    //-------------------------------------------------------------------------
    do {
        if (redraw) {
            DisplayPage(list,ix,nr_blocks,nr_locked,h_myself);
            redraw = 0;
        }
        input = GetUserInput();
        //---------------------------------------------------------------------
        // SCROLL UP ...
        //---------------------------------------------------------------------
        if (input == KEY_UP || input == KEY_LEFT) {
            if (ix >= NR_LINES) ix -= NR_LINES;
            else {
                ix = nr_blocks / NR_LINES;
                ix *= NR_LINES;
                if (ix == nr_blocks) ix -= NR_LINES;
            }
            redraw = 1;
        }
        //---------------------------------------------------------------------
        // SCROLL DOWN ...
        //---------------------------------------------------------------------
        else if (input == KEY_DOWN || input == KEY_RIGHT) {
            if (ix + NR_LINES < nr_blocks) ix += NR_LINES;
            else ix = 0;
            redraw = 1;
        }
        //---------------------------------------------------------------------
        // JUMP TO FIRST PAGE ...
        //---------------------------------------------------------------------
        else if (input == KEY_UP2ND || input == KEY_UPDIAM) {
            ix     = 0;
            redraw = 1;
        }
        //---------------------------------------------------------------------
        // JUMP TO LAST PAGE ...
        //---------------------------------------------------------------------
        else if (input == KEY_DOWN2ND || input == KEY_DOWNDIAM) {
            ix = nr_blocks / NR_LINES;
            ix *= NR_LINES;
            if (ix == nr_blocks) ix -= NR_LINES;
            redraw = 1;
        }
#ifndef NO_HELP
        //---------------------------------------------------------------------
        // DO YOU REALLY READ HELP PAGES ?????
        //---------------------------------------------------------------------
        else if (input == KEY_F1) {
            input = DrawHelpPage();
            if (input == KEY_ESC) input = 0;
            if (input == KEY_F5)  input = KEY_ESC;
            redraw = 1;
        }
#endif
        //---------------------------------------------------------------------
        // USER WANTS TO SEE SOME DETAILS ...
        //
        // NOTE: due to the fact that the user can change the viewed file
        //       within the details view, we have to correct the used page
        //       when we'll come back
        //---------------------------------------------------------------------
#ifdef USE_TI89
        else if (input >= '1' && input <= '9') {
            unsigned short idx = ix + input - '1';
#else
        // Dirty use of conditionals...
        else if ((input >= '0' && input <= '9') || (input == 'A' || input == 'B'))
        {
            unsigned short idx = (input != 'A' && input != 'B')?
                                 ix + input - '0': (input == 'A')? 10:11;
#endif
            if (idx >= nr_blocks) continue;
            if (DrawDetailsPage(list,&idx,nr_blocks,h_myself) == KEY_F5) input=KEY_ESC;
            ix = idx / NR_LINES;
            ix *= NR_LINES;
            redraw = 1;
        }
        //---------------------------------------------------------------------
        // USER WANTS TO HEX-VIEW THE MEMORY
        //---------------------------------------------------------------------
        else if (input == KEY_APPS) {
            indexb = InputString(0x3FFFFUL,0,5);
            input = 0;
            redraw = 1;
            if (indexb == -1UL) continue;
            else if (indexb == -2UL) break;
            else index = indexb;
            do {
                sprintf(buffer,"0x%05lX (RAM dump, 256 KB)",index);
                if (redraw) {
                    DisplayHexPage(buffer,0,index,(unsigned char *)0x40000);
                    redraw = 0;
                }
                input = GetUserInput();

                if (input == KEY_APPS) {
                    indexb = InputString(0x3FFFFUL,0,5);
                    redraw = 1;
                    if (indexb == -1UL) continue;
                    else if (indexb == -2UL) {
                        input = KEY_F5;
                        break;
                    }
                    else index = indexb;
                }

                else indexb = View_HEX(input,0,index,0,1);
                if (indexb == -1UL) continue;
                else if (indexb == -2UL) {
                    input = KEY_F5;
                    break;
                }
                else index = indexb;

            }
            while (input != (unsigned short)KEY_ESC &&
                   input != (unsigned short)KEY_F5);

            if (input == KEY_F5) break;
            else if (input == KEY_ESC) {
                input  = 0;
                redraw = 1;
                continue;
            }
        }
        else if (input == KEY_F5) break;
    }
    while (input != KEY_ESC);

    // Restore screen and free the charset/screen save
    memcpy(LCD_MEM,savescreen,LCD_SIZE);
    HeapUnlock(h);
    HeapFree(h);
}

//#############################################################################
// Revision History
//#############################################################################
//
// $Log: tthdex.c,v $
// Revision 2.8  2002/02/28 14:12:45  tnussb
// (1) size reductions by using "static inline" for some functions
// (2) size reductions by rewriting the logic of some loops
// (3) unnecessary register keywords removed
// (4) unnecessary static keywords removed
//
// Revision 2.7  2002/02/21 09:42:23  tnussb
// size optimizations [xdanger]
//
// Revision 2.6  2002/02/18 10:03:34  tnussb
// (1) optimization of the drawing routines in tthedit here too [xdanger]
// (2) added variation of the delay in DisplayHexPage (with [(] and [)],
//     inlined and modified the waiting routine [xdanger]
// (3) modified FastestDrawLine, now it saves and restores d0, d1 and a0 [xdanger]
// (4) [2nd][UP] and [2nd][DOWN] now go up or down of 0x100 (89) or 0x200 (92+),
//     No changes for [DIAMOND][UP] and [DIAMOND][DOWN]  [xdanger]
// (5) missing cleanup in some exit points of main fixed [tnussb]
// (6) NormalString() slightly modified to suppress complete recalculation
//     of address [tnussb]
// (7) deprecation warning in inline assembler block fixed [tnussb]
//
// Revision 2.5  2002/02/14 08:48:01  tnussb
// char buffer size used for sprintf_xy redefinition increased from 30 to 100

// Revision 2.4  2002/02/13 19:49:17  tnussb
// just the version number increased
//
// Revision 2.3  2002/02/13 19:48:29  tnussb
// backslashes removed from asm constructs
//
// Revision 2.2  2002/02/13 17:29:04  tnussb
// it looks like that I have found now the correct casting for the
// HANDLE table retrieving line... - Thomas Nussbaumer
//
// Revision 2.1  2002/02/11 12:56:30  tnussb
// bugfixes by Lionel Debroux
//
// Revision 1.54  2002/02/07 10:03:51  tnussb
// many changes done by XDanger (Lionel Debroux)
//
// Revision 1.53  2001/07/31 22:56:59  Thomas Nussbaumer
// generic commit for Tools Suite version 0.99.10
//
// Revision 1.52  2001/02/04 16:43:47  Thomas Nussbaumer
// (1) complete rewrite to view all handles
// (2) bug in handle size calculation fixed
// (3) unused variables removed
//
// Revision 1.1  2001/01/22 23:30:51  Thomas Nussbaumer
// initial version (released as v1.0)
//