From 36a0968f06e835efc39ea2fbd762822b5eee0436 Mon Sep 17 00:00:00 2001 From: Walter Negro Date: Thu, 18 Apr 2002 03:40:44 +0000 Subject: [PATCH] * contrib/libnf/dispc.c + ported to Harbour of FT_DISPFILE(). See also FT_DFSETUP() and FT_DFCLOSE(). This function permit browse for a file without loading it in memory. --- harbour/contrib/libnf/dispc.c | 930 ++++++++++++++++++++++++++++++++++ 1 file changed, 930 insertions(+) create mode 100644 harbour/contrib/libnf/dispc.c diff --git a/harbour/contrib/libnf/dispc.c b/harbour/contrib/libnf/dispc.c new file mode 100644 index 0000000000..b948e9e8df --- /dev/null +++ b/harbour/contrib/libnf/dispc.c @@ -0,0 +1,930 @@ +/* + * $Id$ + */ + +/* + * File......: DISPC.C + * Author....: Mike Taylor + * CIS ID....: ? + * + * This is an original work by Mike Taylor and is placed in the + * public domain. + * + * Modification history: + * --------------------- + * + * 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 + * + * + */ + + +#include "hbdefs.h" +#include "hbapi.h" +#include "hbapifs.h" +#include "hbapigt.h" + +#include "fm.api" +#include "inkey.ch" + +#define OFF 0 +#define ON (!OFF) +#define NO 0 +#define YES (!NO) +#define OK 0 +#define K_STRING 0 +#define K_LIST (!K_STRING) + +#define CR ((char) 13) +#define LF ((char) 10) +#define FEOF ((char) 26) + +#define SEEK_END 2 /* file seek directions */ +#define SEEK_CUR 1 +#define SEEK_SET 0 + +#define READONLY 0 /* open file modes */ +#define WRITEONLY 1 +#define READWRITE 2 + +#define BUFFERSIZE 4096 /* maximum size of the file buffer */ +#define MAXLINE 255 /* default maximum size of a line */ + +#define TABSET 8 + +long buffoffset; /* offset into buffer of current line */ +long fsize; /* file size in bytes */ +int 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 */ +int infile; /* input file handle */ +int maxlin; /* line size */ +int buffsize; /* buffer size */ +int hlight; /* highlight attribute */ +int norm; /* normal attribute */ +int kcount; /* number of keys in terminate key list*/ +int colinc; /* col increment amount */ +int brows; /* browse flag */ +char refresh; /* YES means refresh screen */ +char kstr[25]; /* terminate key string */ +int keylist[24]; /* terminate key list */ +int keytype; /* K_STRING or K_LIST */ + +int isallocated; /* if buffers were allocated */ +char *buffer; /* file buffer pointer */ +char *lbuff; /* line buffer pointer */ +char *vseg; /* video segment variable */ + + /* prototypes */ + + +static int keyin(void); +static void chattr(int x, int y, int len, int attr); +static long getblock(long offset); +static void buff_align(void); +static void win_align(void); +static void disp_update(int offset); +static void windown(void); +static void winup(void); +static void linedown(void); +static void lineup(void); +static void filetop(void); +static void filebot(void); +static void strcpyn(char *dest, const char *source, int len); + + + +/* + * chattr() replace the color attribute with a new one starting at + * location x, y and going for length len. + * + */ + +static void chattr(int x, int y, int len, int attr) +{ + int i; + char *vmem; + + vmem = vseg + (y * (width + 1) * 2) + (x * 2) + 1; + /* calc the screen memory coord */ + + for (i = 0; i <= len; i++, vmem += 2) /* 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 long getblock(long 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_fsSeek( infile, offset, SEEK_SET ); + + /* read in the file and set the buffer bottom variable equal */ + /* to the number of bytes actually read in. */ + + buffbot = hb_fsReadLarge( infile, buffer, buffsize ); + + /* if a full buffer's worth was not read in, make it full. */ + + if (( buffbot != buffsize ) && ( fsize > buffsize )) + { + if ( offset > 0 ) + hb_fsSeek( infile, (long) -buffsize, SEEK_END ); + else + hb_fsSeek( infile, (long) buffsize, SEEK_SET ); + + buffbot = hb_fsReadLarge( infile, buffer, buffsize ); + } + + /* return the actual file position */ + + return( hb_fsSeek( infile, 0L, SEEK_CUR ) - buffbot); +} + + + + + + +/* + * buff_align makes sure the buffer top and bottom variables point + * to actual complete lines of text. + * + */ + +static void buff_align() +{ + int i; + + bufftop = 0; + buffbot = buffsize; + + if ( buffoffset != 0L ) /* if the buffoffset is otherthan 0 */ + { + i = bufftop; /* start at the top of the file and scan */ + /* forward until a CR is reached. */ + + while (( buffer[i] != CR ) && ( i < buffbot )) + i++; + + bufftop = i + 2; + } + + /* if the buffer offset is not a complete */ + /* buffer's length away from the file end */ + + if ( buffoffset + ((long) buffbot) != 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 ( buffoffset + ((long) buffbot) > fsize ) + buffbot = (int) (fsize - buffoffset); + + i = buffbot; /* point the end of the buffer to a valid */ + /* complete text line. */ + + while (( buffer[i] != CR ) && ( i > bufftop )) + i--; + + 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() +{ + int i; + + winbot = wintop; /* find out if there is enough text for */ + i = 0; /* full window. */ + + while (( winbot < buffbot ) && ( i < height )) + { + if ( buffer[winbot] == CR ) + i++; + winbot++; + } + + if ( i < height ) /* if there is not a full window, */ + { + /* then retrofit winbot to the end of a line */ + while ( buffer[winbot] != LF && winbot > bufftop) + winbot--; + + wintop = winbot; + i = 0; /* and setup wintop */ + + while (( wintop > bufftop ) && ( i <= height )) + { + if ( buffer[wintop] == LF ) + i++; + wintop--; + } + + if ( wintop != bufftop ) + 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(int offset) +{ + int line, col, pos, i; + char *vmem; + + + refresh = NO; + line = 0; + + while ( line < height ) + { + /* + calculate the initial position, this save execution + time because each column is considered as a offset + from the line start + */ + + pos = (line * (width + 1) * 2); + + /* copy string to temp buffer */ + + for (i = 0; buffer[offset] != CR && offset <= winbot; offset++) + { + if ( i <= maxlin ) + { + if (buffer[offset] == '\t') /* check for a tab */ + { + lbuff[i++] = ' '; /* pad with spaces */ + while (i % TABSET && i <= maxlin) /* until tab stop */ + lbuff[i++] = ' '; /* is reached or EOL */ + } + else lbuff[i++] = buffer[offset]; + + } + } + + for (; i <= maxlin; i++) /* fill out with spaces */ + lbuff[i] = ' '; + + /* place the proper characters onto the screen */ + + for (i = wincol, col = 0; col <= width; col++) + { + vmem = vseg + pos + (col * 2); + + *vmem = lbuff[i++]; + } + + line += 1; + offset += 2; + } + hb_gtRest( sline, scol, eline, ecol, 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() +{ + int k; + long i, j; + + refresh = YES; + k = wintop - 3; + + while (( buffer[k] != CR ) && ( k > bufftop )) + k--; + + if ( k >= bufftop ) + { + if (buffer[k] == CR) k += 2; + + wintop = k; + k = winbot - 3; + + while ( buffer[k] != CR ) + k--; + + winbot = k + 2; + } + else + if ( ((long) bufftop) + buffoffset > 0 && fsize > buffsize ) + { + i = buffoffset + wintop; + j = buffoffset - ((long) (buffsize / 2)); + + if ( j < 0 ) + j = 0; + + buffoffset = getblock(j); + wintop = ((int) (i - buffoffset)); + + buff_align(); + win_align(); + } +} + + + + + +/* + * 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() +{ + int k; + long i, j; + + refresh = YES; + k = winbot; + + while (( buffer[k] != CR ) && ( k <= buffbot )) + k++; + k += 2; + + if ( k <= buffbot ) + { + winbot = k; + k = wintop; + + while ( buffer[k] != CR ) + k++; + wintop = k + 2; + } + else + if ( (((long) buffbot) + buffoffset) < fsize && fsize > buffsize) + { + i = buffoffset + wintop; + j = i; + + if ( j > fsize ) + j = fsize - ((long) buffsize); + + buffoffset = getblock(j); + + if ( i < buffoffset ) + wintop = 0; + else + wintop = ((int) (i - buffoffset)); + + buff_align(); + win_align(); + } +} + + + + + +/* move the cursor one line down */ + +static void linedown() +{ + if ( winrow < eline ) /* if cursor not at last line */ + winrow += 1; + else /* otherwise adjust the window top variable */ + windown(); +} + + + + + +/* move the cursor one line up */ + +static void lineup() +{ + if ( winrow > sline ) + winrow -= 1; + else + winup(); +} + + + + + +/* go to the top of the file */ + +static void filetop() +{ + if ( buffoffset != 0 ) + { + buffoffset = getblock(0L); + + buff_align(); + } + + refresh = YES; + wintop = (int) buffoffset; + winrow = sline; + wincol = 0; + + win_align(); +} + + + + + +/* goto the bottom of the file */ + +static void filebot() +{ + if ( (((long) buffbot) + buffoffset) < fsize && fsize > buffsize ) + { + buffoffset = getblock(fsize + 1); + + buff_align(); + } + + refresh = YES; + wintop = buffbot - 3; + winrow = eline; + wincol = 0; + + win_align(); +} + + +HB_FUNC( _FT_DFINIT ) +{ + int rval, i, j; + USHORT uiSize; + + rval = 0; + + sline = hb_parni(2); /* top row of window */ + scol = hb_parni(3); /* left col */ + eline = hb_parni(4); /* bottom row */ + ecol = hb_parni(5); /* right col */ + + width = ecol - scol; /* calc width of window */ + height = eline - sline + 1; /* calc height of window */ + + hb_gtRectSize( sline, scol, eline, ecol, &uiSize ); + vseg = (char * ) hb_xalloc( uiSize ); + if (vseg != NULL) + hb_gtSave( sline, scol, eline, ecol, vseg ); + + maxlin = hb_parni(12); + buffsize = hb_parni(13); /* yes - load value */ + + buffer = hb_xalloc(buffsize); /* allocate memory */ + lbuff = hb_xalloc(maxlin + 1); /* for buffers */ + + + isallocated = !(buffer == NULL || lbuff == NULL || vseg == NULL); + /* memory allocated? */ + if (isallocated == FALSE) + { + rval = 8; /* return error code 8 (memory) */ + if (buffer != NULL) hb_xfree(buffer); + if (lbuff != NULL) hb_xfree(lbuff); + if (vseg != NULL) hb_xfree(vseg); + } + else /* get parameters */ + { + infile = hb_parni(1); /* file handle */ + j = hb_parni(6); /* starting line value */ + norm = hb_parni(7); /* normal color attribute */ + hlight = hb_parni(8); /* highlight color attribute */ + + if ((hb_parinfo(9) && 512) == 512) /* if array */ + { + keytype = K_LIST; + kcount = hb_parinfa( 9, 0 ); + if (kcount > 24) + kcount = 24; + for (i = 1; i <= kcount; i++) + keylist[i - 1] = hb_parni( 9, i ); /* get exit key list */ + } + else + { + keytype = K_STRING; + kcount = hb_parclen( 9 ); + if (kcount > 24) + kcount = 24; + strcpyn(kstr, hb_parc(9), kcount); /* get exit key string */ + } + + brows = hb_parl(10); /* get browse flag */ + + colinc = hb_parni(11); /* column skip value */ + + + + bufftop = 0; /* init buffer top pointer */ + buffbot = buffsize; /* init buffer bottom pointer */ + buffoffset = 0; /* curr line offset into buffer */ + winrow = sline; /* init window row */ + wincol = 0; /* init window col */ + wintop = 0; /* init window top pointer */ + winbot = 0; /* init window bottom pointer */ + + + + /* get file size */ + + fsize = hb_fsSeek( infile, 0L, SEEK_END ) - 1; + + /* get the first block */ + + hb_fsSeek( infile, 0L, SEEK_SET ); + + /* if block less than buffsize */ + + if ( fsize < ((long) buffbot) ) + buffbot = (int) fsize; /* then set buffer bottom */ + + /* set the current lines buffer offset pointer */ + + buffoffset = getblock((long) bufftop); + + /* align buffer and window pointer to valid values */ + + buff_align(); + win_align(); + + /* point line pointer to line passed by caller */ + + for (i = 1; i < j; i++) + linedown(); + + hb_gtRest( sline, scol, eline, ecol, vseg ); + + } + + hb_retni(rval); +} + +HB_FUNC ( _FT_DFCLOS ) +{ + if (isallocated == TRUE) + { + if (buffer != NULL) hb_xfree(buffer); /* free up allocated buffer memory */ + if (lbuff != NULL) hb_xfree(lbuff); + if (vseg != NULL) hb_xfree(vseg); + } +} + +/* $DOC$ + * $FUNCNAME$ + * FT_DISPFILE() + * $CATEGORY$ + * File I/O + * $ONELINER$ + * Browse a text file + * $SYNTAX$ + * FT_DISPFILE() -> cExitkey + * $ARGUMENTS$ + * None + * $RETURNS$ + * The ASCII keystroke that terminated FT_DISPFILE() + * $DESCRIPTION$ + * This routine displays a text file within a defined window using as + * little memory as possible. The text file to display has to be + * present or an error value of 0 is returned (as a character.) + * + * Assumptions: The routine assumes that all lines are terminated + * with a CR/LF sequence (0x0d and 0x0a). + * + * Note: Make sure you allocate a buffer large enough to hold + * enough data for the number of lines that you have + * in the window. Use the following formula as a + * guideline - buffer size = (# of line) + 1 * RMargin + * this is the smallest you should make the buffer and + * for normal use I recommend 4096 bytes. + * + * Cursor Keys: Up, Down - moves the highlight line + * Left, Right - moves the window over nColSkip col's + * Home - moves the window to the far left + * End - moves the window to the nRMargin column + * PgUp, PgDn - moves the highlight one page + * Ctrl-PgUp - moves the highlight to the file top + * Ctrl-PgDn - moves the highlight to the file bottom + * Ctrl-Right - moves the window 16 col's to the right + * Ctrl-Left - moves the window 16 col's to the left + * + * Esc, Return - terminates the function + * + * All other keys are ignored unless they are specified + * within cExitKeys parameter. This list will tell the + * routine what keys terminate the function. Special + * keys must be passed by a unique value and that value + * can be found by looking in the keys.h file. + * $EXAMPLES$ + * @ 4,9 TO 11,71 + * + * FT_DFSETUP("test.txt", 5, 10, 10, 70, 1, 7, 15,; + * "AaBb" + Chr(143), .T., 5, 132, 4096) + * + * cKey = FT_DISPFILE() + * + * FT_DFCLOSE() + * + * @ 20,0 SAY "Key that terminated FT_DISPFILE() was: " + '[' + cKey + ']' + * $SEEALSO$ + * FT_DFSETUP() FT_DFCLOSE() + * $END$ + */ + +HB_FUNC( FT_DISPFILE ) +{ + int i, done; + char rval[2]; + + int ch; + + + /* make sure buffers were allocated and file was opened */ + if (isallocated == TRUE && infile > 0) + { + done = NO; + refresh = YES; + + /* draw inside of window with normal color attribute */ + + for (i = 0; i < height; i++) + chattr(0, i, width, norm); + + hb_gtRest( sline, scol, eline, ecol, vseg ); + + /* main processing loop -- terminated by user key press */ + + do + { + if ( refresh == YES ) /* redraw window contents? */ + disp_update(wintop); + + hb_gtRest( sline, scol, eline, ecol, vseg ); + + /* if not browse, highlight the current line */ + + if ( brows == NO ) + chattr(0, winrow - sline, width, hlight); + + hb_gtRest( sline, scol, eline, ecol, vseg ); + + hb_gtSetPos( winrow, scol ); + + ch = keyin(); /* get user key press */ + + /* if not browse, then un-highlight current line */ + + if ( brows == NO ) + chattr(0, winrow - sline, width, norm); + + hb_gtRest( sline, scol, eline, ecol, vseg ); + + /* figure out what the user wants to do */ + + switch (ch) + { + case K_DOWN : if ( brows == YES ) /* if browse flag */ + winrow = eline; /* is set, force */ + /* active line to */ + linedown(); /* be last line */ + break; + + case K_UP : if ( brows == YES ) /* if browse flag */ + winrow = sline; /* is set, force */ + /* active line to */ + lineup(); /* be first line */ + break; + + case K_LEFT : wincol -= colinc; /* move cursor */ + refresh = YES; /* to the left */ + + if ( wincol < 0 ) + wincol = 0; + + break; + + case K_RIGHT : wincol += colinc; /* move cursor */ + refresh = YES; /* to the right */ + + if ( wincol > (maxlin - width) ) + wincol = maxlin - width; + + break; + + case K_HOME : wincol = 0; /* move cursor */ + refresh = YES; /* to first col */ + + break; + + /* move cursor to last col */ + + case K_END : wincol = maxlin - width; + refresh = YES; + + break; + + case K_CTRL_LEFT : wincol -= 16; /* move cursor */ + refresh = YES; /* 16 col to left */ + + if ( wincol < 0 ) + wincol = 0; + + break; + + case K_CTRL_RIGHT : wincol += 16; /* move cursor */ + refresh = YES; /* 16 col to right */ + + if ( wincol > (maxlin - width) ) + wincol = maxlin - width; + + break; + + case K_PGUP : for (i = 0; i < height; i++) /* move window */ + winup(); /* up one page */ + + break; + + case K_PGDN : for (i = 0; i < height; i++) /* move window */ + windown(); /* down 1 page */ + + break; + + case K_CTRL_PGUP : filetop(); /* move cursor to */ + break; /* to top of file */ + + case K_CTRL_PGDN : filebot(); /* move cursor to */ + break; /* to bot of file */ + + case K_ENTER : done = YES; /* carriage return */ + break; /* terminates */ + + case K_ESC : done = YES; /* escape key */ + break; /* terminates */ + + /* scan key list and see if key pressed is there */ + + default : if (keytype == K_STRING) + { + for (i = 0; i <= kcount; i++) + if ((ch > 0) && (ch < 256)) + if ( (int) kstr[i] == ch ) + done = YES; + break; /* if so terminate */ + } + else + { + for (i = 0; i < kcount; i++) + if ( keylist[i] == ch ) + done = YES; + break; + } + } + } while ( done == NO ); + } + else + ch = 0; + + + /* store the key pressed as a character to be returned */ + + /* return key value to caller */ + + if (keytype == K_STRING) + { + rval[0] = (char) ch; + rval[1] = '\0'; + hb_retc( rval ); + } + else + hb_retni( ch ); +} + + + +/* + * keyin() gets the next key typed and does any translation needed. + * Some keys are converted to a common name - like the up arrow is + * converted to the UP value which also is the Ctrl-E value. This + * allows the Wordstar-like control keys to be used. Only extended + * keys are translated - the values of the defines were chosen to + * match up with the non-extended key codes. + * + */ + +static int keyin() +{ + int ch; + + + ch = 0; + while ( ch == 0x00 ) /* check to see if it's extended */ + { + ch = hb_inkeyTranslate( hb_gtReadKey( 0 ), 0); + if (ch == 257) /* error compiling with bcc55 */ + ch = 27; /* ESC with CapsLock ON = 257, with CapsLock OFF = 27 */ + hb_idleState(); + } + + + return ( ch ); +} + + +static void strcpyn( char *dest, const char *source, int len ) +{ + int i; + + for (i = 0; i < len; i++) + dest[i] = source[i]; + + dest[len+1] = 0x00; +} +