home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / progmisc / nfsrc21.zip / DISPC.C < prev    next >
C/C++ Source or Header  |  1991-11-18  |  28KB  |  934 lines

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