home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / NFSRC305.ZIP / C / DISPC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-01  |  28.2 KB  |  953 lines

  1. /*
  2.  * File......: DISPC.C
  3.  * Author....: Mike Taylor
  4.  * CIS ID....: ?
  5.  *
  6.  * This is an original work by Mike Taylor and is placed in the
  7.  * public domain.
  8.  *
  9.  * Modification history:
  10.  * ---------------------
  11.  *
  12.  *    Rev 1.6   01 Jan 1995 03:01:00   TED
  13.  * Changed some prototypes to eliminate compiler warnings.
  14.  *
  15.  *    Rev 1.5   14 Feb 1994 16:58:42   GLENN
  16.  * Steve Tyrakowski and Kevin Maher modified to be CPMI-compliant.
  17.  *
  18.  *    Rev 1.4   18 Nov 1991 02:20:20   GLENN
  19.  * Mike fixed a bug in _ft_dfinit() related to allocating memory.  Some
  20.  * users had been reporting problems, but everyone who tested this patch
  21.  * reported success.
  22.  *
  23.  *    Rev 1.3   17 Aug 1991 15:25:46   GLENN
  24.  * Don Caton fixed some spelling errors in the doc
  25.  *
  26.  *    Rev 1.2   15 Aug 1991 23:08:14   GLENN
  27.  * Forest Belt proofread/edited/cleaned up doc
  28.  *
  29.  *    Rev 1.1   14 Jun 1991 19:53:42   GLENN
  30.  * Minor edit to file header
  31.  *
  32.  *    Rev 1.0   01 Apr 1991 01:02:46   GLENN
  33.  * Nanforum Toolkit
  34.  *
  35.  *
  36.  */
  37.  
  38. #include <EXTEND.API>
  39. #include <FM.API>
  40. #include <DFKEY.H>
  41.  
  42. #define MK_FP(seg, ofs) ((void far *) (((unsigned long)(seg) << 16) | (unsigned)(ofs)))
  43.  
  44. #define FP_SEG(fp) (*((unsigned *)&(fp) + 1))   // copied from MSC 5.1
  45. #define FP_OFF(fp) (*((unsigned *)&(fp)))       //  include file 'dos.h'
  46.  
  47. #define OFF 0
  48. #define ON  (!OFF)
  49. #define NO  0
  50. #define YES (!NO)
  51. #define OK  0
  52.  
  53. #define CR   ((char) 13)
  54. #define LF   ((char) 10)
  55. #define FEOF ((char) 26)
  56.  
  57. #define SEEK_END 2              // file seek directions
  58. #define SEEK_CUR 1
  59. #define SEEK_SET 0
  60.  
  61. #define READONLY  0             // open file modes
  62. #define WRITEONLY 1
  63. #define READWRITE 2
  64.  
  65. #define MDASEG 0x0b000          // mono video memory segment
  66. #define CGASEG 0x0b800          // color video memory segment
  67.  
  68. #define BUFFERSIZE 4096         // maximum size of the file buffer
  69. #define MAXLINE    255          // default maximum size of a line
  70.  
  71. #define TABSET  8
  72.  
  73. long buffoffset;            // offset into buffer of current line
  74. long fsize;                 // file size in bytes
  75. int  bufftop, buffbot;      // first and last character in buffer
  76. int  wintop, winbot;        // first and last character in window
  77. int  winrow, wincol;        // row and column of window highlight
  78. int  sline, eline;          // start and end line of window
  79. int  scol, ecol;            // start and end col of window
  80. int  height, width;         // height and width of window
  81. int  infile;                // input file handle
  82. int  maxlin;                // line size
  83. int  buffsize;              // buffer size
  84. int  hlight;                // highlight attribute
  85. int  norm;                  // normal attribute
  86. int  kcount;                // number of keys in terminate key list
  87. int  colinc;                // col increment amount
  88. int  brows;                 // browse flag
  89. char refresh;               // YES means refresh screen
  90. char kstr[25];              // terminate key string
  91.  
  92. int isallocated;            // if buffers were allocated
  93. char far *buffer;           // file buffer pointer
  94. char far *lbuff;            // line buffer pointer
  95. char far *vseg;             // video segment variable
  96.  
  97.     // prototypes
  98.  
  99.  
  100. CLIPPER _ft_dfinit(void);
  101. CLIPPER _ft_dfclos(void);
  102.  
  103. static unsigned char keyin(void);
  104. static void          chattr(int x, int y, int len, int attr);
  105. static long          getblock(long offset);
  106. static void          buff_align(void);
  107. static void          win_align(void);
  108. static void          disp_update(int offset);
  109. static void          windown(void);
  110. static void          winup(void);
  111. static void          linedown(void);
  112. static void          lineup(void);
  113. static void          filetop(void);
  114. static void          filebot(void);
  115.  
  116.     // found in dispa.asm
  117.  
  118. int           _ft_fileread(int handle, char far *buffer, int bytes);
  119. long          _ft_fileseek(int handle, long offset, int direction);
  120. void          _ft_gotoxy(int x, int y);
  121. char          _ft_getkey(void);
  122. unsigned int  _ft_vconfig(void);
  123.  
  124. // this is defined because I found out that CLIPPER has a version
  125. //  strcpy linked in normally - this just shuts up the LINT check
  126.  
  127. extern char * strcpy( char far *, char far * );
  128. extern unsigned int strlen( char * );
  129.  
  130. /*
  131.  * chattr() replace the color attribute with a new one starting at
  132.  * location x, y and going for length len.
  133.  *
  134.  */
  135.  
  136.  
  137. static void chattr(int x, int y, int len, int attr)
  138. {
  139.     int i;
  140.     char far *vmem;
  141.  
  142.     vmem = vseg;
  143.     FP_OFF(vmem) = (y * 160) + (x * 2) + 1;     // calc the screen memory coord
  144.  
  145.     for (i = 0; i <= len; i++, vmem += 2)       // write the new attribute value
  146.         *vmem = (char) attr;
  147. }
  148.  
  149.  
  150.  
  151.  
  152. /*
  153.  *  keyin() gets the next key typed and does any translation needed.
  154.  *  Some keys are converted to a common name - like the up arrow is
  155.  *  converted to the UP value which also is the Ctrl-E value.  This
  156.  *  allows the Wordstar-like control keys to be used.  Only extended
  157.  *  keys are translated - the values of the defines were chosen to
  158.  *  match up with the non-extended key codes.
  159.  *
  160.  */
  161.  
  162. static unsigned char keyin()
  163. {
  164.     unsigned char ch;
  165.  
  166.     ch = (unsigned char) _ft_getkey();      // get the next key
  167.  
  168.     if ( ch == 0x00 )                       // check to see if it's extended
  169.     {
  170.         ch = (unsigned char) _ft_getkey();  // if so, read the second part
  171.  
  172.         switch ( ch )                       //  and convert it
  173.         {
  174.             case 75   : ch = LFT;    break;
  175.             case 77   : ch = RGT;    break;
  176.             case 72   : ch = UP;     break;
  177.             case 80   : ch = DN;     break;
  178.             case 71   : ch = HOME;   break;
  179.             case 79   : ch = ENND;   break;
  180.             case 73   : ch = PGUP;   break;
  181.             case 81   : ch = PGDN;   break;
  182.             case 62   : ch = F4;     break;
  183.             case 117  : ch = CENND;  break;
  184.             case 119  : ch = CHOME;  break;
  185.             case 118  : ch = CPGDN;  break;
  186.             case 132  : ch = CPGUP;  break;
  187.             case 116  : ch = CRGT;   break;
  188.             case 115  : ch = CLFT;   break;
  189.             case 82   : ch = INS;    break;
  190.             case 83   : ch = DEL;    break;
  191.             case 68   : ch = F0;     break;
  192.             case 59   : ch = F1;     break;
  193.             case 60   : ch = F2;     break;
  194.             case 61   : ch = F3;     break;
  195.             case 63   : ch = F5;     break;
  196.             case 64   : ch = F6;     break;
  197.             case 65   : ch = F7;     break;
  198.             case 66   : ch = F8;     break;
  199.             case 67   : ch = F9;     break;
  200.             case 113  : ch = AF0;    break;
  201.             case 104  : ch = AF1;    break;
  202.             case 105  : ch = AF2;    break;
  203.             case 106  : ch = AF3;    break;
  204.             case 107  : ch = AF4;    break;
  205.             case 108  : ch = AF5;    break;
  206.             case 109  : ch = AF6;    break;
  207.             case 110  : ch = AF7;    break;
  208.             case 111  : ch = AF8;    break;
  209.             case 112  : ch = AF9;    break;
  210.             case 94   : ch = CF1;    break;
  211.             case 95   : ch = CF2;    break;
  212.             case 96   : ch = CF3;    break;
  213.             case 97   : ch = CF4;    break;
  214.             case 98   : ch = CF5;    break;
  215.             case 99   : ch = CF6;    break;
  216.             case 100  : ch = CF7;    break;
  217.             case 101  : ch = CF8;    break;
  218.             case 102  : ch = CF9;    break;
  219.             case 103  : ch = CF0;    break;
  220.             case 120  : ch = ALT1;   break;
  221.             case 121  : ch = ALT2;   break;
  222.             case 122  : ch = ALT3;   break;
  223.             case 123  : ch = ALT4;   break;
  224.             case 124  : ch = ALT5;   break;
  225.             case 125  : ch = ALT6;   break;
  226.             case 126  : ch = ALT7;   break;
  227.             case 127  : ch = ALT8;   break;
  228.             case 128  : ch = ALT9;   break;
  229.             case 129  : ch = ALT0;   break;
  230.             case 130  : ch = ADASH;  break;
  231.             case 131  : ch = AEQL;   break;
  232.             case 30   : ch = ALTA;   break;
  233.             case 48   : ch = ALTB;   break;
  234.             case 46   : ch = ALTC;   break;
  235.             case 32   : ch = ALTD;   break;
  236.             case 18   : ch = ALTE;   break;
  237.             case 33   : ch = ALTF;   break;
  238.             case 34   : ch = ALTG;   break;
  239.             case 35   : ch = ALTH;   break;
  240.             case 23   : ch = ALTI;   break;
  241.             case 36   : ch = ALTJ;   break;
  242.             case 37   : ch = ALTK;   break;
  243.             case 38   : ch = ALTL;   break;
  244.             case 50   : ch = ALTM;   break;
  245.             case 49   : ch = ALTN;   break;
  246.             case 24   : ch = ALTO;   break;
  247.             case 25   : ch = ALTP;   break;
  248.             case 16   : ch = ALTQ;   break;
  249.             case 19   : ch = ALTR;   break;
  250.             case 31   : ch = ALTS;   break;
  251.             case 20   : ch = ALTT;   break;
  252.             case 22   : ch = ALTU;   break;
  253.             case 47   : ch = ALTV;   break;
  254.             case 17   : ch = ALTW;   break;
  255.             case 45   : ch = ALTX;   break;
  256.             case 21   : ch = ALTY;   break;
  257.             case 44   : ch = ALTZ;   break;
  258.             default   : ch = 0;      break;
  259.         }
  260.     }
  261.  
  262.     return ( ch );
  263. }
  264.  
  265.  
  266.  
  267.  
  268.  
  269. /*
  270.  * function getblock() reads the text file and returns the a block.
  271.  *  the variables offset and buffsize tell it where to start reading and
  272.  *  how many bytes to try to read.  if the block read in would not fill
  273.  *  the buffer then the offset is adjusted so that the start or end of
  274.  *  of the file is positioned at the head or tail of the buffer.
  275.  *
  276.  * it returns the offset into the file of the first byte of the buffer.
  277.  *
  278.  */
  279.  
  280. static long getblock(long offset)
  281. {
  282.  
  283.         // set the file pointer to the proper offset
  284.         //  and if an error occured then check to see
  285.         //  if a positive offset was requested, if so
  286.         //  then set the pointer to the offset from
  287.         //  the end of the file, otherwise set it from
  288.         //  the beginning of the file.
  289.  
  290.     _ft_fileseek(infile, offset, SEEK_SET);
  291.  
  292.         // read in the file and set the buffer bottom variable equal
  293.         //  to the number of bytes actually read in.
  294.  
  295.     buffbot = _ft_fileread(infile, buffer, buffsize);
  296.  
  297.         // if a full buffer's worth was not read in, make it full.
  298.  
  299.     if (( buffbot != buffsize ) && ( fsize > buffsize ))
  300.     {
  301.         if ( offset > 0 )
  302.             _ft_fileseek(infile, (long) -buffsize, SEEK_END);
  303.         else
  304.             _ft_fileseek(infile, (long) buffsize, SEEK_SET);
  305.  
  306.         buffbot = _ft_fileread(infile, buffer, buffsize);
  307.     }
  308.  
  309.         // return the actual file position */
  310.  
  311.     return(_ft_fileseek(infile, 0L, SEEK_CUR) - buffbot);
  312. }
  313.  
  314.  
  315.  
  316.  
  317.  
  318.  
  319. /*
  320.  * buff_align makes sure the buffer top and bottom variables point
  321.  * to actual complete lines of text.
  322.  *
  323.  */
  324.  
  325. static void buff_align()
  326. {
  327.     int i;
  328.  
  329.     bufftop = 0;
  330.     buffbot = buffsize;
  331.  
  332.     if ( buffoffset != 0L )     // if the buffoffset is otherthan 0
  333.     {
  334.         i = bufftop;            // start at the top of the file and scan
  335.                                 // forward until a CR is reached.
  336.  
  337.         while (( buffer[i] != CR ) && ( i < buffbot ))
  338.             i++;
  339.  
  340.         bufftop = i + 2;
  341.     }
  342.  
  343.         // if the buffer offset is not a complete */
  344.         // buffer's length away from the file end */
  345.  
  346.     if ( buffoffset + ((long) buffbot) != fsize )
  347.     {
  348.             // if the file position of the last byte
  349.             //  of the buffer would end up past the
  350.             //  end of the file, then the buffer does
  351.             //  contain a complete buffer full and the
  352.             //  buffer end pointer needs to be set to
  353.             //  the last character of the file.
  354.  
  355.         if ( buffoffset + ((long) buffbot) > fsize )
  356.             buffbot = (int) (fsize - buffoffset);
  357.  
  358.         i = buffbot;            // point the end of the buffer to a valid
  359.                                 // complete text line.
  360.  
  361.         while (( buffer[i] != CR ) && ( i > bufftop ))
  362.             i--;
  363.  
  364.         buffbot = i + 2;
  365.     }
  366. }
  367.  
  368.  
  369.  
  370.  
  371.  
  372. /*
  373.  * win_align takes the value for wintop and then figures out where
  374.  * winbot would be.  if winbot would extend past the end of the
  375.  * buffer, then the top of the window is adjusted to ensure that a full
  376.  * screen of text will appear.  This simplifies the cursor routines.
  377.  *
  378.  */
  379.  
  380. static void win_align()
  381. {
  382.     int i;
  383.  
  384.     winbot = wintop;            // find out if there is enough text for
  385.     i      = 0;                 // full window.
  386.  
  387.     while (( winbot < buffbot ) && ( i < height ))
  388.     {
  389.         if ( buffer[winbot] == CR )
  390.             i++;
  391.         winbot++;
  392.     }
  393.  
  394.     if ( i < height )           // if there is not a full window,
  395.     {
  396.         // then retrofit winbot to the end of a line
  397.          while ( buffer[winbot] != LF && winbot > bufftop)
  398.             winbot--;
  399.  
  400.         wintop = winbot;
  401.         i      = 0;                         // and setup wintop
  402.  
  403.         while (( wintop > bufftop ) && ( i <= height ))
  404.         {
  405.             if ( buffer[wintop] == LF )
  406.                 i++;
  407.             wintop--;
  408.         }
  409.  
  410.         if ( wintop != bufftop )
  411.             wintop += 2;
  412.     }
  413. }
  414.  
  415.  
  416.  
  417.  
  418.  
  419. /*
  420.  * this routine displays the actual text in the window.  This is done
  421.  * by taking each line and placing it in a string.  the screen line
  422.  * is then taken from the appropriate group of characters in the string.
  423.  * this allows a window to page left-right across the buffer without
  424.  * having to use any complex algorithm to calc the needed chars.
  425.  *
  426.  */
  427.  
  428. static void disp_update(int offset)
  429. {
  430.     int line, col, pos, i;
  431.     char far *vmem;
  432.  
  433.     vmem = vseg;
  434.  
  435.     refresh = NO;
  436.     line        = 0;
  437.  
  438.     while ( line < height )
  439.     {
  440.             // calculate the initial position, this save execution
  441.             // time because each column is considered as a offset
  442.             // from the line start
  443.  
  444.         pos = ((sline + line) * 160) + (scol * 2);
  445.  
  446.             // copy string to temp buffer
  447.  
  448.         for (i = 0; buffer[offset] != CR && offset <= winbot; offset++)
  449.         {
  450.            if ( i <= maxlin )
  451.              {
  452.                if (buffer[offset] == '\t')          // check for a tab
  453.                  {
  454.                   lbuff[i++] = ' ';                 // pad with spaces
  455.                   while (i % TABSET && i <= maxlin) // until tab stop
  456.                     lbuff[i++] = ' ';               // is reached or EOL
  457.                  }
  458.                else lbuff[i++] = buffer[offset];
  459.  
  460.              }
  461.         }
  462.  
  463.         for (; i <= maxlin; i++)        // fill out with spaces
  464.             lbuff[i] = ' ';
  465.  
  466.             // place the proper characters onto the screen
  467.  
  468.         for (i = wincol, col = 0; col <= width; col++)
  469.         {
  470.             FP_OFF(vmem) = pos + (col * 2);
  471.  
  472.             *vmem = lbuff[i++];
  473.         }
  474.  
  475.         line   += 1;
  476.         offset += 2;
  477.     }
  478. }
  479.  
  480.  
  481.  
  482.  
  483.  
  484. /*
  485.  * move the window pointers so that a new window's worth of information
  486.  * is visible.  it adjusts the pointers within the buffer and if necessary
  487.  * it calls the getblock function to load in a new buffer
  488.  *
  489.  */
  490.  
  491. static void winup()
  492. {
  493.     int  k;
  494.     long i, j;
  495.  
  496.     refresh = YES;
  497.     k       = wintop - 3;
  498.  
  499.     while (( buffer[k] != CR ) && ( k > bufftop ))
  500.         k--;
  501.  
  502.     if ( k >= bufftop )
  503.     {
  504.       if (buffer[k] == CR) k += 2;
  505.  
  506.         wintop = k;
  507.         k      = winbot - 3;
  508.  
  509.         while ( buffer[k] != CR )
  510.             k--;
  511.  
  512.         winbot = k + 2;
  513.     }
  514.     else
  515.         if ( ((long) bufftop) + buffoffset > 0 && fsize > buffsize )
  516.         {
  517.             i = buffoffset + wintop;
  518.             j = buffoffset - ((long) (buffsize / 2));
  519.  
  520.             if ( j < 0 )
  521.                 j = 0;
  522.  
  523.             buffoffset = getblock(j);
  524.             wintop     = ((int) (i - buffoffset));
  525.  
  526.             buff_align();
  527.             win_align();
  528.         }
  529. }
  530.  
  531.  
  532.  
  533.  
  534.  
  535. /*
  536.  * move the window pointers so that a new window's worth of information
  537.  * is visible.  it adjusts the pointers within the buffer and if necessary
  538.  * it calls the getblock function to load in a new buffer
  539.  *
  540.  */
  541.  
  542. static void windown()
  543. {
  544.     int  k;
  545.     long i, j;
  546.  
  547.     refresh = YES;
  548.     k       = winbot;
  549.  
  550.     while (( buffer[k] != CR ) && ( k <= buffbot ))
  551.         k++;
  552.     k += 2;
  553.  
  554.     if ( k <= buffbot )
  555.     {
  556.         winbot = k;
  557.         k      = wintop;
  558.  
  559.         while ( buffer[k] != CR )
  560.             k++;
  561.         wintop = k + 2;
  562.     }
  563.     else
  564.         if ( (((long) buffbot) + buffoffset) < fsize && fsize > buffsize)
  565.         {
  566.             i = buffoffset + wintop;
  567.             j = i;
  568.  
  569.             if ( j > fsize )
  570.                 j = fsize - ((long) buffsize);
  571.  
  572.             buffoffset = getblock(j);
  573.  
  574.             if ( i < buffoffset )
  575.                 wintop = 0;
  576.             else
  577.                 wintop = ((int) (i - buffoffset));
  578.  
  579.             buff_align();
  580.             win_align();
  581.         }
  582. }
  583.  
  584.  
  585.  
  586.  
  587.  
  588. /* move the cursor one line down */
  589.  
  590. static void linedown()
  591. {
  592.     if ( winrow < eline )   // if cursor not at last line
  593.         winrow += 1;
  594.     else                            // otherwise adjust the window top variable
  595.         windown();
  596. }
  597.  
  598.  
  599.  
  600.  
  601.  
  602. /* move the cursor one line up */
  603.  
  604. static void lineup()
  605. {
  606.     if ( winrow > sline )
  607.         winrow -= 1;
  608.     else
  609.         winup();
  610. }
  611.  
  612.  
  613.  
  614.  
  615.  
  616. /* go to the top of the file */
  617.  
  618. static void filetop()
  619. {
  620.     if ( buffoffset != 0 )
  621.     {
  622.         buffoffset = getblock(0L);
  623.  
  624.         buff_align();
  625.     }
  626.  
  627.     refresh = YES;
  628.     wintop  = (int) buffoffset;
  629.     winrow  = sline;
  630.     wincol  = 0;
  631.  
  632.     win_align();
  633. }
  634.  
  635.  
  636.  
  637.  
  638.  
  639. /* goto the bottom of the file */
  640.  
  641. static void filebot()
  642. {
  643.     if ( (((long) buffbot) + buffoffset) < fsize && fsize > buffsize )
  644.     {
  645.         buffoffset = getblock(fsize + 1);
  646.  
  647.         buff_align();
  648.     }
  649.  
  650.     refresh = YES;
  651.     wintop  = buffbot - 3;
  652.     winrow  = eline;
  653.     wincol  = 0;
  654.  
  655.     win_align();
  656. }
  657.  
  658.  
  659. CLIPPER _ft_dfinit()
  660. {
  661.     int rval, i, j;
  662.  
  663.     rval = 0;
  664.  
  665.     vseg = MK_FP(_ft_vconfig() , 0x0000);     // get video segment
  666.  
  667.     maxlin   = _parni(12);
  668.     buffsize = _parni(13);                  // yes - load value
  669.  
  670.     buffer = _xalloc(buffsize);             // allocate memory
  671.     lbuff  = _xalloc(maxlin + 1);           //  for buffers
  672.  
  673.  
  674.     isallocated = !(buffer == NULL || lbuff == NULL); // memory allocated?
  675.     if (isallocated == FALSE)
  676.     {
  677.         rval = 8;                   // return error code 8 (memory)
  678.         if (buffer != NULL) _xfree(buffer);
  679.         if (lbuff != NULL)  _xfree(lbuff);
  680.     }
  681.     else                            // get parameters
  682.     {
  683.         infile = _parni(1);                 // file handle
  684.         sline  = _parni(2);                 // top row of window
  685.         scol   = _parni(3);                 // left col
  686.         eline  = _parni(4);                 // bottom row
  687.         ecol   = _parni(5);                 // right col
  688.         j      = _parni(6);                 // starting line value
  689.         norm   = _parni(7);                 // normal color attribute
  690.         hlight = _parni(8);                 // highlight color attribute
  691.  
  692.         strcpy(kstr, _parc(9));             // get exit key list
  693.  
  694.         brows = _parl(10);                  // get browse flag
  695.  
  696.         colinc = _parni(11);                // column skip value
  697.  
  698.         width  = ecol - scol;               // calc width of window
  699.         height = eline - sline + 1;         // calc height of window
  700.  
  701.  
  702.         kcount     = strlen(kstr);          // get # of exit keys in list
  703.         bufftop    = 0;                     // init buffer top pointer
  704.         buffbot    = buffsize;              // init buffer bottom pointer
  705.         buffoffset = 0;                     // curr line offset into buffer
  706.         winrow     = sline;                 // init window row
  707.         wincol     = 0;                     // init window col
  708.         wintop     = 0;                     // init window top pointer
  709.         winbot     = 0;                     // init window bottom pointer
  710.  
  711.             // get file size
  712.  
  713.         fsize = _ft_fileseek(infile, 0L, SEEK_END) - 1;
  714.  
  715.             // get the first block
  716.  
  717.         _ft_fileseek(infile, 0L, SEEK_SET);
  718.  
  719.             // if block less than buffsize
  720.  
  721.         if ( fsize < ((long) buffbot) )
  722.             buffbot = (int) fsize;          // then set buffer bottom
  723.  
  724.             // set the current lines buffer offset pointer
  725.  
  726.         buffoffset = getblock((long) bufftop);
  727.  
  728.             // align buffer and window pointer to valid values
  729.  
  730.         buff_align();
  731.         win_align();
  732.  
  733.             // point line pointer to line passed by caller
  734.  
  735.         for (i = 1; i < j; i++)
  736.             linedown();
  737.  
  738.     }
  739.  
  740.     _retni(rval);
  741. }
  742.  
  743. CLIPPER _ft_dfclos()
  744. {
  745.   if (isallocated == TRUE)
  746.     {
  747.       if (buffer != NULL) _xfree(buffer); // free up allocated buffer memory
  748.       if (lbuff != NULL)  _xfree(lbuff);
  749.  
  750.     }
  751. }
  752.  
  753.  
  754. /*  $DOC$
  755.  *  $FUNCNAME$
  756.  *     FT_DISPFILE()
  757.  *  $CATEGORY$
  758.  *     File I/O
  759.  *  $ONELINER$
  760.  *     Browse a text file
  761.  *  $SYNTAX$
  762.  *     FT_DISPFILE() -> cExitkey
  763.  *  $ARGUMENTS$
  764.  *     None
  765.  *  $RETURNS$
  766.  *     The ASCII keystroke that terminated FT_DISPFILE()
  767.  *  $DESCRIPTION$
  768.  *     This routine displays a text file within a defined window using as
  769.  *     little memory as possible.  The text file to display has to be
  770.  *     present or an error value of 0 is returned (as a character.)
  771.  *
  772.  *     Assumptions: The routine assumes that all lines are terminated
  773.  *                  with a CR/LF sequence (0x0d and 0x0a).
  774.  *
  775.  *     Note:        Make sure you allocate a buffer large enough to hold
  776.  *                  enough data for the number of lines that you have
  777.  *                  in the window.  Use the following formula as a
  778.  *                  guideline - buffer size = (# of line) + 1 * RMargin
  779.  *                  this is the smallest you should make the buffer and
  780.  *                  for normal use I recommend 4096 bytes.
  781.  *
  782.  *     Cursor Keys: Up, Down    - moves the highlight line
  783.  *                  Left, Right - moves the window over nColSkip col's
  784.  *                  Home        - moves the window to the far left
  785.  *                  End         - moves the window to the nRMargin column
  786.  *                  PgUp, PgDn  - moves the highlight one page
  787.  *                  Ctrl-PgUp   - moves the highlight to the file top
  788.  *                  Ctrl-PgDn   - moves the highlight to the file bottom
  789.  *                  Ctrl-Right  - moves the window 16 col's to the right
  790.  *                  Ctrl-Left   - moves the window 16 col's to the left
  791.  *
  792.  *                  Esc, Return - terminates the function
  793.  *
  794.  *                  All other keys are ignored unless they are specified
  795.  *                  within cExitKeys parameter.  This list will tell the
  796.  *                  routine what keys terminate the function.  Special
  797.  *                  keys must be passed by a unique value and that value
  798.  *                  can be found by looking in the keys.h file.
  799.  *  $EXAMPLES$
  800.  *     @ 4,9 TO 11,71
  801.  *
  802.  *     FT_DFSETUP("test.txt", 5, 10, 10, 70, 1, 7, 15,;
  803.  *                 "AaBb" + Chr(143), .T., 5, 132, 4096)
  804.  *
  805.  *     cKey = FT_DISPFILE()
  806.  *
  807.  *     FT_DFCLOSE()
  808.  *
  809.  *     @ 20,0 SAY "Key that terminated FT_DISPFILE() was: " + '[' + cKey + ']'
  810.  *  $SEEALSO$
  811.  *     FT_DFSETUP() FT_DFCLOSE()
  812.  *  $END$
  813.  */
  814.  
  815. CLIPPER FT_DISPFIL( void )
  816. {
  817.     int  i, done;
  818.     char rval[2];
  819.  
  820.     unsigned char ch = 0;
  821.  
  822.     // make sure buffers were allocated and file was opened
  823.     if (isallocated == TRUE && infile > 0)
  824.       {
  825.         done    = NO;
  826.         refresh = YES;
  827.  
  828.         // draw inside of window with normal color attribute
  829.  
  830.         for (i = sline; i <= eline; i++)
  831.             chattr(scol, i, width, norm);
  832.  
  833.             // main processing loop -- terminated by user key press
  834.  
  835.         do
  836.         {
  837.             if ( refresh == YES )           // redraw window contents?
  838.                 disp_update(wintop);
  839.  
  840.                 // if not browse, highlight the current line
  841.  
  842.             if ( brows == NO )
  843.                 chattr(scol, winrow, width, hlight);
  844.  
  845.             _ft_gotoxy(scol, winrow);       // adjust cursor
  846.  
  847.             ch = keyin();                   // get user key press
  848.  
  849.                 // if not browse, then un-highlight current line
  850.  
  851.             if ( brows == NO )
  852.                 chattr(scol, winrow, width, norm);
  853.  
  854.                 // figure out what the user wants to do
  855.  
  856.             switch (ch)
  857.             {
  858.                 case DN    : if ( brows == YES )           // if browse flag
  859.                                   winrow = eline;           // is set, force
  860.                                                             // active line to
  861.                               linedown();                   // be last line
  862.                               break;
  863.  
  864.                 case UP    : if ( brows == YES )           // if browse flag
  865.                                   winrow = sline;           // is set, force
  866.                                                             // active line to
  867.                               lineup();                     // be first line
  868.                               break;
  869.  
  870.                 case LFT   : wincol -= colinc;             // move cursor
  871.                               refresh = YES;                // to the left
  872.  
  873.                               if ( wincol < 0 )
  874.                                   wincol = 0;
  875.  
  876.                               break;
  877.  
  878.                 case RGT   : wincol += colinc;             // move cursor
  879.                               refresh = YES;                // to the right
  880.  
  881.                               if ( wincol > (maxlin - width) )
  882.                                   wincol = maxlin - width;
  883.  
  884.                               break;
  885.  
  886.                 case HOME  : wincol  = 0;                  // move cursor
  887.                               refresh = YES;                // to first col
  888.  
  889.                               break;
  890.  
  891.                     // move cursor to last col
  892.  
  893.                 case ENND  : wincol  = maxlin - width;
  894.                               refresh = YES;
  895.  
  896.                               break;
  897.  
  898.                 case CLFT  : wincol -= 16;                 // move cursor
  899.                               refresh = YES;                // 16 col to left
  900.  
  901.                               if ( wincol < 0 )
  902.                                   wincol = 0;
  903.  
  904.                               break;
  905.  
  906.                 case CRGT  : wincol += 16;                 // move cursor
  907.                               refresh = YES;                // 16 col to right
  908.  
  909.                               if ( wincol > (maxlin - width) )
  910.                                   wincol = maxlin - width;
  911.  
  912.                               break;
  913.  
  914.                 case PGUP  : for (i = 0; i < height; i++)  // move window
  915.                                   winup();                  // up one page
  916.  
  917.                               break;
  918.  
  919.                 case PGDN  : for (i = 0; i < height; i++)  // move window
  920.                                   windown();                // down 1 page
  921.  
  922.                               break;
  923.  
  924.                 case CPGUP : filetop();                    // move cursor to
  925.                               break;                        // to top of file
  926.  
  927.                 case CPGDN : filebot();                    // move cursor to
  928.                               break;                        // to bot of file
  929.  
  930.                 case RET   : done = YES;                   // carriage return
  931.                               break;                        // terminates
  932.  
  933.                 case ESC   : done = YES;                   // escape key
  934.                               break;                        // terminates
  935.  
  936.                     // scan key list and see if key pressed is there
  937.  
  938.                 default    : for (i = 0; i <= kcount; i++)
  939.                                   if ( kstr[i] == (char) ch )
  940.                                       done = YES;
  941.                               break;                        // if so terminate
  942.             }
  943.         } while ( done == NO );
  944.       }
  945.  
  946.     // store the key pressed as a character to be returned
  947.     rval[0] = (char) ch;
  948.     rval[1] = '\0';
  949.  
  950.         // return key value to caller
  951.  
  952.     _retc(rval);
  953. }