home *** CD-ROM | disk | FTP | other *** search
- /*
- * File......: DISPC.C
- * Author....: Mike Taylor
- * Date......: $Date: 18 Nov 1991 02:20:20 $
- * Revision..: $Revision: 1.4 $
- * Log file..: $Logfile: E:/nanfor/src/dispc.c_v $
- *
- * This is an original work by Mike Taylor and is placed in the
- * public domain.
- *
- * Modification history:
- * ---------------------
- *
- * $Log: E:/nanfor/src/dispc.c_v $
- *
- * 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 "extend.h"
- #include "dfkey.h"
-
-
- #define MK_FP(seg, ofs) ((void far *) (((unsigned long)(seg) << 16) | (unsigned)(ofs)))
-
- #define FP_SEG(fp) (*((unsigned *)&(fp) + 1)) // copied from MSC 5.1
- #define FP_OFF(fp) (*((unsigned *)&(fp))) // include file 'dos.h'
-
- #define OFF 0
- #define ON (!OFF)
- #define NO 0
- #define YES (!NO)
- #define OK 0
-
- #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 MDASEG 0x0b000 // mono video memory segment
- #define CGASEG 0x0b800 // color video memory segment
-
- #define BUFFERSIZE 4096 // maximum size of the file buffer
- #define MAXLINE 255 // default maximum size of a line
-
- 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
-
- char far *buffer; // file buffer pointer
- char far *lbuff; // line buffer pointer
- char far *vseg; // video segment variable
-
-
- // prototypes
-
-
- CLIPPER _ft_dfinit(void);
- CLIPPER _ft_dfclos(void);
-
- unsigned char keyin(void);
- void chattr(int x, int y, int len, int attr);
- long getblock(long offset);
- void buff_align(void);
- void win_align(void);
- void disp_update(int offset);
- void windown(void);
- void winup(void);
- void linedown(void);
- void lineup(void);
- void filetop(void);
- void filebot(void);
-
- // found in dispa.asm
-
- int _ft_fileread(int handle, char far *buffer, int bytes);
- long _ft_fileseek(int handle, long offset, int direction);
- void _ft_gotoxy(int x, int y);
- char _ft_getkey(void);
- char far * _ft_vconfig(void);
-
- // this is defined because I found out that CLIPPER has a version
- // strcpy linked in normally - this just shut's up the LINT check
-
- extern char *strcpy(char far *, char far *);
-
-
- /*
- * 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 far *vmem;
-
- vmem = vseg;
- FP_OFF(vmem) = (y * 160) + (x * 2) + 1; // calc the screen memory coord
-
- for (i = 0; i <= len; i++, vmem += 2) // write the new attribute value
- *vmem = (char) attr;
- }
-
-
-
-
- /*
- * 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 unsigned char keyin()
- {
- unsigned char ch;
-
- ch = (unsigned char) _ft_getkey(); // get the next key
-
- if ( ch == 0x00 ) // check to see if it's extended
- {
- ch = (unsigned char) _ft_getkey(); // if so, read the second part
-
- switch ( ch ) // and convert it
- {
- case 75 : ch = LFT; break;
- case 77 : ch = RGT; break;
- case 72 : ch = UP; break;
- case 80 : ch = DN; break;
- case 71 : ch = HOME; break;
- case 79 : ch = ENND; break;
- case 73 : ch = PGUP; break;
- case 81 : ch = PGDN; break;
- case 62 : ch = F4; break;
- case 117 : ch = CENND; break;
- case 119 : ch = CHOME; break;
- case 118 : ch = CPGDN; break;
- case 132 : ch = CPGUP; break;
- case 116 : ch = CRGT; break;
- case 115 : ch = CLFT; break;
- case 82 : ch = INS; break;
- case 83 : ch = DEL; break;
- case 68 : ch = F0; break;
- case 59 : ch = F1; break;
- case 60 : ch = F2; break;
- case 61 : ch = F3; break;
- case 63 : ch = F5; break;
- case 64 : ch = F6; break;
- case 65 : ch = F7; break;
- case 66 : ch = F8; break;
- case 67 : ch = F9; break;
- case 113 : ch = AF0; break;
- case 104 : ch = AF1; break;
- case 105 : ch = AF2; break;
- case 106 : ch = AF3; break;
- case 107 : ch = AF4; break;
- case 108 : ch = AF5; break;
- case 109 : ch = AF6; break;
- case 110 : ch = AF7; break;
- case 111 : ch = AF8; break;
- case 112 : ch = AF9; break;
- case 94 : ch = CF1; break;
- case 95 : ch = CF2; break;
- case 96 : ch = CF3; break;
- case 97 : ch = CF4; break;
- case 98 : ch = CF5; break;
- case 99 : ch = CF6; break;
- case 100 : ch = CF7; break;
- case 101 : ch = CF8; break;
- case 102 : ch = CF9; break;
- case 103 : ch = CF0; break;
- case 120 : ch = ALT1; break;
- case 121 : ch = ALT2; break;
- case 122 : ch = ALT3; break;
- case 123 : ch = ALT4; break;
- case 124 : ch = ALT5; break;
- case 125 : ch = ALT6; break;
- case 126 : ch = ALT7; break;
- case 127 : ch = ALT8; break;
- case 128 : ch = ALT9; break;
- case 129 : ch = ALT0; break;
- case 130 : ch = ADASH; break;
- case 131 : ch = AEQL; break;
- case 30 : ch = ALTA; break;
- case 48 : ch = ALTB; break;
- case 46 : ch = ALTC; break;
- case 32 : ch = ALTD; break;
- case 18 : ch = ALTE; break;
- case 33 : ch = ALTF; break;
- case 34 : ch = ALTG; break;
- case 35 : ch = ALTH; break;
- case 23 : ch = ALTI; break;
- case 36 : ch = ALTJ; break;
- case 37 : ch = ALTK; break;
- case 38 : ch = ALTL; break;
- case 50 : ch = ALTM; break;
- case 49 : ch = ALTN; break;
- case 24 : ch = ALTO; break;
- case 25 : ch = ALTP; break;
- case 16 : ch = ALTQ; break;
- case 19 : ch = ALTR; break;
- case 31 : ch = ALTS; break;
- case 20 : ch = ALTT; break;
- case 22 : ch = ALTU; break;
- case 47 : ch = ALTV; break;
- case 17 : ch = ALTW; break;
- case 45 : ch = ALTX; break;
- case 21 : ch = ALTY; break;
- case 44 : ch = ALTZ; break;
- default : ch = 0; break;
- }
- }
-
- return ( ch );
- }
-
-
-
-
-
- /*
- * 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.
-
- _ft_fileseek(infile, offset, SEEK_SET);
-
- // read in the file and set the buffer bottom variable equal
- // to the number of bytes actually read in.
-
- buffbot = _ft_fileread(infile, buffer, buffsize);
-
- // if a full buffer's worth was not read in, make it full.
-
- if (( buffbot != buffsize ) && ( fsize > buffsize ))
- {
- if ( offset > 0 )
- _ft_fileseek(infile, (long) -buffsize, SEEK_END);
- else
- _ft_fileseek(infile, (long) buffsize, SEEK_SET);
-
- buffbot = _ft_fileread(infile, buffer, buffsize);
- }
-
- // return the actual file position */
-
- return(_ft_fileseek(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; // skip past the CR/LF to the first char
- }
-
- // 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; // skip past the CR/LF to the first char */
- }
- }
-
-
-
-
-
- /*
- * 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,
- {
- while ( buffer[winbot] != LF ) // then retrofit winbot
- winbot--; // to the end of a line
-
- 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 far *vmem;
-
- vmem = vseg;
-
- 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 = ((sline + line) * 160) + (scol * 2);
-
- // copy string to temp buffer
-
- for (i = 0; buffer[offset] != CR && offset <= winbot; offset++)
- {
- if ( i <= maxlin )
- 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++)
- {
- FP_OFF(vmem) = pos + (col * 2);
-
- *vmem = lbuff[i++];
- }
-
- line += 1;
- offset += 2;
- }
- }
-
-
-
-
-
- /*
- * 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();
- }
-
-
- CLIPPER _ft_dfinit()
- {
- int rval, i, j;
-
- rval = 0;
-
- vseg = MK_FP(_ft_vconfig(), 0x0000); // get video segment
-
- maxlin = _parni(12);
- buffsize = _parni(13); // yes - load value
-
- buffer = _xalloc(buffsize); // allocate memory
- lbuff = _xalloc(maxlin + 1); // for buffers
-
- if (( buffer == NULL ) || ( lbuff == NULL )) // memory allocated?
- {
- rval = 8; // return error code 8 (memory)
- }
- else // get parameters
- {
- infile = _parni(1); // file handle
- sline = _parni(2); // top row of window
- scol = _parni(3); // left col
- eline = _parni(4); // bottom row
- ecol = _parni(5); // right col
- j = _parni(6); // starting line value
- norm = _parni(7); // normal color attribute
- hlight = _parni(8); // highlight color attribute
-
- strcpy(kstr, _parc(9)); // get exit key list
-
- brows = _parl(10); // get browse flag
-
- colinc = _parni(11); // column skip value
-
- width = ecol - scol; // calc width of window
- height = eline - sline + 1; // calc height of window
-
-
- kcount = strlen(kstr); // get # of exit keys in list
- 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 = _ft_fileseek(infile, 0L, SEEK_END) - 1;
-
- // get the first block
-
- _ft_fileseek(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();
-
- }
-
- _retni(rval);
- }
-
- CLIPPER _ft_dfclos()
- {
- _xfree(buffer); // free up allocated buffer memory
- _xfree(lbuff);
- }
-
-
- /* $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$
- */
-
- CLIPPER FT_DISPFIL( void )
- {
- int i, done;
- char rval[2];
-
- unsigned char ch;
-
- done = NO;
- refresh = YES;
-
- // draw inside of window with normal color attribute
-
- for (i = sline; i <= eline; i++)
- chattr(scol, i, width, norm);
-
- // main processing loop -- terminated by user key press
-
- do
- {
- if ( refresh == YES ) // redraw window contents?
- disp_update(wintop);
-
- // if not browse, highlight the current line
-
- if ( brows == NO )
- chattr(scol, winrow, width, hlight);
-
- _ft_gotoxy(scol, winrow); // adjust cursor
-
- ch = keyin(); // get user key press
-
- // if not browse, then un-highlight current line
-
- if ( brows == NO )
- chattr(scol, winrow, width, norm);
-
- // figure out what the user wants to do
-
- switch (ch)
- {
- case DN : if ( brows == YES ) // if browse flag
- winrow = eline; // is set, force
- // active line to
- linedown(); // be last line
- break;
-
- case UP : if ( brows == YES ) // if browse flag
- winrow = sline; // is set, force
- // active line to
- lineup(); // be first line
- break;
-
- case LFT : wincol -= colinc; // move cursor
- refresh = YES; // to the left
-
- if ( wincol < 0 )
- wincol = 0;
-
- break;
-
- case RGT : wincol += colinc; // move cursor
- refresh = YES; // to the right
-
- if ( wincol > (maxlin - width) )
- wincol = maxlin - width;
-
- break;
-
- case HOME : wincol = 0; // move cursor
- refresh = YES; // to first col
-
- break;
-
- // move cursor to last col
-
- case ENND : wincol = maxlin - width;
- refresh = YES;
-
- break;
-
- case CLFT : wincol -= 16; // move cursor
- refresh = YES; // 16 col to left
-
- if ( wincol < 0 )
- wincol = 0;
-
- break;
-
- case CRGT : wincol += 16; // move cursor
- refresh = YES; // 16 col to right
-
- if ( wincol > (maxlin - width) )
- wincol = maxlin - width;
-
- break;
-
- case PGUP : for (i = 0; i < height; i++) // move window
- winup(); // up one page
-
- break;
-
- case PGDN : for (i = 0; i < height; i++) // move window
- windown(); // down 1 page
-
- break;
-
- case CPGUP : filetop(); // move cursor to
- break; // to top of file
-
- case CPGDN : filebot(); // move cursor to
- break; // to bot of file
-
- case RET : done = YES; // carriage return
- break; // terminates
-
- case ESC : done = YES; // escape key
- break; // terminates
-
- // scan key list and see if key pressed is there
-
- default : for (i = 0; i <= kcount; i++)
- if ( kstr[i] == (char) ch )
- done = YES;
- break; // if so terminate
- }
- } while ( done == NO );
-
- // store the key pressed as a character to be returned
-
- rval[0] = (char) ch;
- rval[1] = '\0';
-
- // return key value to caller
-
- _retc(rval);
- }
-