/* * Author....: Mike Taylor * CIS ID....: ? * * This is an original work by Mike Taylor and is placed in the * public domain. * * Modification history: * --------------------- * * Rev 1.10 22 Apr 2004 15:32:00 David G. Holm * Corrected all hb_fsSeek calls to use FS_ defines instead of using * redefined SEEK_ ones that conflict with the C-level SEEK_ defines. * Rev 1.9 ? ? * An unknown number of changes were made between Rev 1.8 and Rev 1.10. * * Rev 1.8 24 May 2002 19:25:00 David G. Holm * Fixed some problems that caused C++ compiles to fail. * * Rev 1.7 29 Mar 2002 17:00:00 Walter Negro * Ported to Harbour * * Rev 1.6 01 Jan 1995 03:01:00 TED * Changed some prototypes to eliminate compiler warnings. * * Rev 1.5 14 Feb 1994 16:58:42 GLENN * Steve Tyrakowski and Kevin Maher modified to be CPMI-compliant. * * Rev 1.4 18 Nov 1991 02:20:20 GLENN * Mike fixed a bug in _ft_DFInit() related to allocating memory. Some * users had been reporting problems, but everyone who tested this patch * reported success. * * Rev 1.3 17 Aug 1991 15:25:46 GLENN * Don Caton fixed some spelling errors in the doc * * Rev 1.2 15 Aug 1991 23:08:14 GLENN * Forest Belt proofread/edited/cleaned up doc * * Rev 1.1 14 Jun 1991 19:53:42 GLENN * Minor edit to file header * * Rev 1.0 01 Apr 1991 01:02:46 GLENN * Nanforum Toolkit * * */ /* TOFIX: support for reading files with any encoding and translating it to unicode for the GT */ #include "hbapi.h" #include "hbapifs.h" #include "hbapigt.h" #include "hbstack.h" #define K_STRING 0 #define K_LIST ( ! K_STRING ) #define CR ( ( char ) 13 ) #define LF ( ( char ) 10 ) #define FEOF ( ( char ) 26 ) #define BUFFERSIZE 4096 /* maximum size of the file buffer */ #define MAXLINE 255 /* default maximum size of a line */ #define TABSET 8 typedef struct { HB_FOFFSET buffoffset; /* offset into buffer of current line */ HB_FOFFSET fsize; /* file size in bytes */ HB_ISIZ bufftop, buffbot; /* first and last character in buffer */ int wintop, winbot; /* first and last character in window */ int winrow, wincol; /* row and column of window highlight */ int sline, eline; /* start and end line of window */ int scol, ecol; /* start and end col of window */ int height, width; /* height and width of window */ HB_FHANDLE infile; /* input file handle */ int maxlin; /* line size */ HB_ISIZ buffsize; /* buffer size */ int hlight; /* highlight attribute */ int norm; /* normal attribute */ HB_ISIZ kcount; /* number of keys in terminate key list*/ int colinc; /* col increment amount */ HB_BOOL bBrowse; /* browse flag */ HB_BOOL bRefresh; /* HB_TRUE means refresh screen */ int keylist[ 24 ]; /* terminate key list */ int keytype; /* K_STRING or K_LIST */ HB_BOOL bIsAllocated; /* if buffers were allocated */ char * buffer; /* file buffer pointer */ char * lbuff; /* line buffer pointer */ HB_UCHAR * vseg; /* video segment variable */ int iCellSize; /* size of one buffer cell */ } FT_DISPC, * PFT_DISPC; static HB_TSD_NEW( s_dispc, sizeof( FT_DISPC ), NULL, NULL ); /* prototypes */ static void chattr( PFT_DISPC dispc, int x, int y, int len, int attr ); static HB_FOFFSET getblock( PFT_DISPC dispc, HB_FOFFSET offset ); static void buff_align( PFT_DISPC dispc ); static void win_align( PFT_DISPC dispc ); static void disp_update( PFT_DISPC dispc, int offset ); static void windown( PFT_DISPC dispc ); static void winup( PFT_DISPC dispc ); static void linedown( PFT_DISPC dispc ); static void lineup( PFT_DISPC dispc ); static void filetop( PFT_DISPC dispc ); static void filebot( PFT_DISPC dispc ); /* * chattr() replace the color attribute with a new one starting at * location x, y and going for length len. * */ static void chattr( PFT_DISPC dispc, int x, int y, int len, int attr ) { int i; /* calc the screen memory coord */ HB_UCHAR * vmem; vmem = dispc->vseg + ( y * ( dispc->width + 1 ) * dispc->iCellSize ) + ( x * dispc->iCellSize ) + 1; if( dispc->iCellSize == 4 ) vmem++; for( i = 0; i <= len; i++, vmem += dispc->iCellSize ) /* write the new attribute value */ *vmem = ( char ) attr; } /* * function getblock() reads the text file and returns the a block. * the variables offset and buffsize tell it where to start reading and * how many bytes to try to read. if the block read in would not fill * the buffer then the offset is adjusted so that the start or end of * of the file is positioned at the head or tail of the buffer. * * it returns the offset into the file of the first byte of the buffer. * */ static HB_FOFFSET getblock( PFT_DISPC dispc, HB_FOFFSET offset ) { /* set the file pointer to the proper offset and if an error occured then check to see if a positive offset was requested, if so then set the pointer to the offset from the end of the file, otherwise set it from the beginning of the file. */ hb_fsSeekLarge( dispc->infile, offset, FS_SET ); /* read in the file and set the buffer bottom variable equal */ /* to the number of bytes actually read in. */ dispc->buffbot = hb_fsReadLarge( dispc->infile, dispc->buffer, dispc->buffsize ); /* if a full buffer's worth was not read in, make it full. */ if( dispc->buffbot != dispc->buffsize && dispc->fsize > dispc->buffsize ) { if( offset > 0 ) hb_fsSeekLarge( dispc->infile, -dispc->buffsize, FS_END ); else hb_fsSeekLarge( dispc->infile, dispc->buffsize, FS_SET ); dispc->buffbot = hb_fsReadLarge( dispc->infile, dispc->buffer, dispc->buffsize ); } /* return the actual file position */ return hb_fsSeekLarge( dispc->infile, 0, FS_RELATIVE ) - dispc->buffbot; } /* * buff_align makes sure the buffer top and bottom variables point * to actual complete lines of text. * */ static void buff_align( PFT_DISPC dispc ) { HB_ISIZ i; dispc->bufftop = 0; dispc->buffbot = dispc->buffsize; if( dispc->buffoffset != 0 ) /* if the buffoffset is otherthan 0 */ { i = dispc->bufftop; /* start at the top of the file and scan */ /* forward until a CR is reached. */ while( dispc->buffer[ i ] != CR && i < dispc->buffbot ) i++; dispc->bufftop = i + 2; } /* if the buffer offset is not a complete */ /* buffer's length away from the file end */ if( dispc->buffoffset + dispc->buffbot != dispc->fsize ) { /* if the file position of the last byte of the buffer would end up past the end of the file, then the buffer does contain a complete buffer full and the buffer end pointer needs to be set to the last character of the file. */ if( dispc->buffoffset + dispc->buffbot > dispc->fsize ) dispc->buffbot = ( HB_ISIZ ) ( dispc->fsize - dispc->buffoffset ); i = dispc->buffbot; /* point the end of the buffer to a valid */ /* complete text line. */ while( dispc->buffer[ i ] != CR && i > dispc->bufftop ) i--; dispc->buffbot = i + 2; } } /* * win_align takes the value for wintop and then figures out where * winbot would be. if winbot would extend past the end of the * buffer, then the top of the window is adjusted to ensure that a full * screen of text will appear. This simplifies the cursor routines. * */ static void win_align( PFT_DISPC dispc ) { int i; dispc->winbot = dispc->wintop; /* find out if there is enough text for */ i = 0; /* full window. */ while( dispc->winbot < dispc->buffbot && i < dispc->height ) { if( dispc->buffer[ dispc->winbot ] == CR ) i++; dispc->winbot++; } if( i < dispc->height ) /* if there is not a full window, */ { /* then retrofit winbot to the end of a line */ while( dispc->buffer[ dispc->winbot ] != LF && dispc->winbot > dispc->bufftop ) dispc->winbot--; dispc->wintop = dispc->winbot; i = 0; /* and setup dispc->wintop */ while( dispc->wintop > dispc->bufftop && i <= dispc->height ) { if( dispc->buffer[ dispc->wintop ] == LF ) i++; dispc->wintop--; } if( dispc->wintop != dispc->bufftop ) dispc->wintop += 2; } } /* * this routine displays the actual text in the window. This is done * by taking each line and placing it in a string. the screen line * is then taken from the appropriate group of characters in the string. * this allows a window to page left-right across the buffer without * having to use any complex algorithm to calc the needed chars. * */ static void disp_update( PFT_DISPC dispc, int offset ) { int line, col, pos, i; dispc->bRefresh = HB_FALSE; line = 0; while( line < dispc->height ) { /* calculate the initial position, this save execution time because each column is considered as a offset from the line start */ pos = ( line * ( dispc->width + 1 ) * dispc->iCellSize ); /* copy string to temp buffer */ for( i = 0; dispc->buffer[ offset ] != CR && offset <= dispc->winbot; offset++ ) { if( i <= dispc->maxlin ) { if( dispc->buffer[ offset ] == '\t' ) /* check for a tab */ { dispc->lbuff[ i++ ] = ' '; /* pad with spaces */ while( i % TABSET && i <= dispc->maxlin ) /* until tab stop */ dispc->lbuff[ i++ ] = ' '; /* is reached or EOL */ } else dispc->lbuff[ i++ ] = dispc->buffer[ offset ]; } } for(; i <= dispc->maxlin; i++ ) /* fill out with spaces */ dispc->lbuff[ i ] = ' '; /* place the proper characters onto the screen */ for( i = dispc->wincol, col = 0; col <= dispc->width; col++ ) { HB_UCHAR * vmem = dispc->vseg + pos + ( col * dispc->iCellSize ); *vmem = dispc->lbuff[ i++ ]; } line += 1; offset += 2; } hb_gtRest( dispc->sline, dispc->scol, dispc->eline, dispc->ecol, dispc->vseg ); } /* * move the window pointers so that a new window's worth of information * is visible. it adjusts the pointers within the buffer and if necessary * it calls the getblock function to load in a new buffer * */ static void winup( PFT_DISPC dispc ) { int k; HB_FOFFSET i, j; dispc->bRefresh = HB_TRUE; k = dispc->wintop - 3; while( dispc->buffer[ k ] != CR && k > dispc->bufftop ) k--; if( k >= dispc->bufftop ) { if( dispc->buffer[ k ] == CR ) k += 2; dispc->wintop = k; k = dispc->winbot - 3; while( dispc->buffer[ k ] != CR ) k--; dispc->winbot = k + 2; } else if( dispc->bufftop + dispc->buffoffset > 0 && dispc->fsize > dispc->buffsize ) { i = dispc->buffoffset + dispc->wintop; j = dispc->buffoffset - ( dispc->buffsize / 2 ); if( j < 0 ) j = 0; dispc->buffoffset = getblock( dispc, j ); dispc->wintop = ( int ) ( i - dispc->buffoffset ); buff_align( dispc ); win_align( dispc ); } } /* * move the window pointers so that a new window's worth of information * is visible. it adjusts the pointers within the buffer and if necessary * it calls the getblock function to load in a new buffer * */ static void windown( PFT_DISPC dispc ) { int k; HB_FOFFSET i, j; dispc->bRefresh = HB_TRUE; k = dispc->winbot; while( dispc->buffer[ k ] != CR && k <= dispc->buffbot ) k++; k += 2; if( k <= dispc->buffbot ) { dispc->winbot = k; k = dispc->wintop; while( dispc->buffer[ k ] != CR ) k++; dispc->wintop = k + 2; } else if( ( dispc->buffbot + dispc->buffoffset ) < dispc->fsize && dispc->fsize > dispc->buffsize ) { i = dispc->buffoffset + dispc->wintop; j = i; if( j > dispc->fsize ) j = dispc->fsize - dispc->buffsize; dispc->buffoffset = getblock( dispc, j ); if( i < dispc->buffoffset ) dispc->wintop = 0; else dispc->wintop = ( int ) ( i - dispc->buffoffset ); buff_align( dispc ); win_align( dispc ); } } /* move the cursor one line down */ static void linedown( PFT_DISPC dispc ) { if( dispc->winrow < dispc->eline ) /* if cursor not at last line */ ++dispc->winrow; else /* otherwise adjust the window top variable */ windown( dispc ); } /* move the cursor one line up */ static void lineup( PFT_DISPC dispc ) { if( dispc->winrow > dispc->sline ) --dispc->winrow; else winup( dispc ); } /* go to the top of the file */ static void filetop( PFT_DISPC dispc ) { if( dispc->buffoffset != 0 ) { dispc->buffoffset = getblock( dispc, 0 ); buff_align( dispc ); } dispc->bRefresh = HB_TRUE; dispc->wintop = ( int ) dispc->buffoffset; dispc->winrow = dispc->sline; dispc->wincol = 0; win_align( dispc ); } /* goto the bottom of the file */ static void filebot( PFT_DISPC dispc ) { if( ( dispc->buffbot + dispc->buffoffset ) < dispc->fsize && dispc->fsize > dispc->buffsize ) { dispc->buffoffset = getblock( dispc, dispc->fsize + 1 ); buff_align( dispc ); } dispc->bRefresh = HB_TRUE; dispc->wintop = ( int ) dispc->buffbot - 3; dispc->winrow = dispc->eline; dispc->wincol = 0; win_align( dispc ); } HB_FUNC( _FT_DFINIT ) { PFT_DISPC dispc = ( PFT_DISPC ) hb_stackGetTSD( &s_dispc ); int rval; HB_ISIZ j; HB_ISIZ i; HB_SIZE nSize; rval = 0; dispc->sline = hb_parni( 2 ); /* top row of window */ dispc->scol = hb_parni( 3 ); /* left col */ dispc->eline = hb_parni( 4 ); /* bottom row */ dispc->ecol = hb_parni( 5 ); /* right col */ dispc->width = dispc->ecol - dispc->scol; /* calc width of window */ dispc->height = dispc->eline - dispc->sline + 1; /* calc height of window */ hb_gtRectSize( 0, 0, 0, 0, &nSize ); dispc->iCellSize = ( int ) nSize; hb_gtRectSize( dispc->sline, dispc->scol, dispc->eline, dispc->ecol, &nSize ); dispc->vseg = ( HB_UCHAR * ) hb_xalloc( nSize ); if( dispc->vseg != NULL ) hb_gtSave( dispc->sline, dispc->scol, dispc->eline, dispc->ecol, dispc->vseg ); dispc->maxlin = hb_parni( 12 ); dispc->buffsize = hb_parns( 13 ); /* yes - load value */ dispc->buffer = ( char * ) hb_xalloc( dispc->buffsize ); /* allocate memory */ dispc->lbuff = ( char * ) hb_xalloc( dispc->maxlin + 1 ); /* for buffers */ dispc->bIsAllocated = ! ( dispc->buffer == NULL || dispc->lbuff == NULL || dispc->vseg == NULL ); /* memory allocated? */ if( ! dispc->bIsAllocated ) { rval = 8; /* return error code 8 (memory) */ if( dispc->buffer != NULL ) hb_xfree( dispc->buffer ); if( dispc->lbuff != NULL ) hb_xfree( dispc->lbuff ); if( dispc->vseg != NULL ) hb_xfree( dispc->vseg ); } else /* get parameters */ { dispc->infile = hb_numToHandle( hb_parnint( 1 ) ); /* file handle */ j = hb_parni( 6 ); /* starting line value */ dispc->norm = hb_parni( 7 ); /* normal color attribute */ dispc->hlight = hb_parni( 8 ); /* highlight color attribute */ if( HB_ISARRAY( 9 ) ) { dispc->keytype = K_LIST; dispc->kcount = hb_parinfa( 9, 0 ); if( dispc->kcount > 24 ) dispc->kcount = 24; for( i = 1; i <= dispc->kcount; i++ ) dispc->keylist[ i - 1 ] = hb_parvni( 9, i ); /* get exit key list */ } else { const char * pszKeys = hb_parcx( 9 ); dispc->keytype = K_STRING; dispc->kcount = hb_parclen( 9 ); if( dispc->kcount > 24 ) dispc->kcount = 24; for( i = 1; i <= dispc->kcount; i++ ) dispc->keylist[ i - 1 ] = pszKeys[ i - 1 ]; /* get exit key list */ } dispc->bBrowse = hb_parl( 10 ); /* get browse flag */ dispc->colinc = hb_parni( 11 ); /* column skip value */ dispc->bufftop = 0; /* init buffer top pointer */ dispc->buffbot = dispc->buffsize; /* init buffer bottom pointer */ dispc->buffoffset = 0; /* curr line offset into buffer */ dispc->winrow = dispc->sline; /* init window row */ dispc->wincol = 0; /* init window col */ dispc->wintop = 0; /* init window top pointer */ dispc->winbot = 0; /* init window bottom pointer */ /* get file size */ dispc->fsize = hb_fsSeek( dispc->infile, 0, FS_END ) - 1; /* get the first block */ hb_fsSeek( dispc->infile, 0, FS_SET ); /* if block less than buffsize */ if( dispc->fsize < dispc->buffbot ) dispc->buffbot = ( int ) dispc->fsize; /* then set buffer bottom */ /* set the current lines buffer offset pointer */ dispc->buffoffset = getblock( dispc, dispc->bufftop ); /* align buffer and window pointer to valid values */ buff_align( dispc ); win_align( dispc ); /* point line pointer to line passed by caller */ for( i = 1; i < j; i++ ) linedown( dispc ); hb_gtRest( dispc->sline, dispc->scol, dispc->eline, dispc->ecol, dispc->vseg ); } hb_retni( rval ); } HB_FUNC( _FT_DFCLOS ) { PFT_DISPC dispc = ( PFT_DISPC ) hb_stackGetTSD( &s_dispc ); if( dispc->bIsAllocated ) { if( dispc->buffer != NULL ) hb_xfree( dispc->buffer ); /* free up allocated buffer memory */ if( dispc->lbuff != NULL ) hb_xfree( dispc->lbuff ); if( dispc->vseg != NULL ) hb_xfree( dispc->vseg ); } } HB_FUNC( FT_DISPFILE ) { PFT_DISPC dispc = ( PFT_DISPC ) hb_stackGetTSD( &s_dispc ); int i; char rval[ 2 ]; HB_BOOL bDone; int ch; /* make sure buffers were allocated and file was opened */ if( dispc->bIsAllocated && dispc->infile > 0 ) { bDone = HB_FALSE; dispc->bRefresh = HB_TRUE; /* draw inside of window with normal color attribute */ for( i = 0; i < dispc->height; i++ ) chattr( dispc, 0, i, dispc->width, dispc->norm ); hb_gtRest( dispc->sline, dispc->scol, dispc->eline, dispc->ecol, dispc->vseg ); /* main processing loop -- terminated by user key press */ do { if( dispc->bRefresh ) /* redraw window contents? */ disp_update( dispc, dispc->wintop ); hb_gtRest( dispc->sline, dispc->scol, dispc->eline, dispc->ecol, dispc->vseg ); /* if not browse, highlight the current line */ if( ! dispc->bBrowse ) chattr( dispc, 0, dispc->winrow - dispc->sline, dispc->width, dispc->hlight ); hb_gtRest( dispc->sline, dispc->scol, dispc->eline, dispc->ecol, dispc->vseg ); hb_gtSetPos( dispc->winrow, dispc->scol ); ch = hb_inkey( HB_TRUE, 0.0, INKEY_ALL ); /* if not browse, then un-highlight current line */ if( ! dispc->bBrowse ) chattr( dispc, 0, dispc->winrow - dispc->sline, dispc->width, dispc->norm ); hb_gtRest( dispc->sline, dispc->scol, dispc->eline, dispc->ecol, dispc->vseg ); /* figure out what the user wants to do */ switch( ch ) { case K_DOWN: if( dispc->bBrowse ) /* if browse flag */ dispc->winrow = dispc->eline; /* is set, force */ /* active line to */ linedown( dispc ); /* be last line */ break; case K_UP: if( dispc->bBrowse ) /* if browse flag */ dispc->winrow = dispc->sline; /* is set, force */ /* active line to */ lineup( dispc ); /* be first line */ break; case K_LEFT: dispc->wincol -= dispc->colinc; /* move cursor */ dispc->bRefresh = HB_TRUE; /* to the left */ if( dispc->wincol < 0 ) dispc->wincol = 0; break; case K_RIGHT: dispc->wincol += dispc->colinc; /* move cursor */ dispc->bRefresh = HB_TRUE; /* to the right */ if( dispc->wincol > ( dispc->maxlin - dispc->width ) ) dispc->wincol = dispc->maxlin - dispc->width; break; case K_HOME: dispc->wincol = 0; /* move cursor */ dispc->bRefresh = HB_TRUE; /* to first col */ break; /* move cursor to last col */ case K_END: dispc->wincol = dispc->maxlin - dispc->width; dispc->bRefresh = HB_TRUE; break; case K_CTRL_LEFT: dispc->wincol -= 16; /* move cursor */ dispc->bRefresh = HB_TRUE; /* 16 col to left */ if( dispc->wincol < 0 ) dispc->wincol = 0; break; case K_CTRL_RIGHT: dispc->wincol += 16; /* move cursor */ dispc->bRefresh = HB_TRUE; /* 16 col to right */ if( dispc->wincol > ( dispc->maxlin - dispc->width ) ) dispc->wincol = dispc->maxlin - dispc->width; break; case K_PGUP: for( i = 0; i < dispc->height; i++ ) /* move window */ winup( dispc ); /* up one page */ break; case K_PGDN: for( i = 0; i < dispc->height; i++ ) /* move window */ windown( dispc ); /* down 1 page */ break; case K_CTRL_PGUP: filetop( dispc ); /* move cursor to */ break; /* to top of file */ case K_CTRL_PGDN: filebot( dispc ); /* move cursor to */ break; /* to bot of file */ case K_ENTER: bDone = HB_TRUE; /* carriage return */ break; /* terminates */ case K_ESC: bDone = HB_TRUE; /* escape key */ break; /* terminates */ /* scan key list and see if key pressed is there */ default: for( i = 0; i < dispc->kcount; i++ ) { if( dispc->keylist[ i ] == ch ) bDone = HB_TRUE; } } } while( ! bDone ); } else ch = 0; /* store the key pressed as a character to be returned */ /* return key value to caller */ if( dispc->keytype == K_STRING ) { rval[ 0 ] = ( char ) ch; rval[ 1 ] = '\0'; hb_retc( rval ); } else hb_retni( ch ); }