home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 328_02 / wgets.c < prev    next >
C/C++ Source or Header  |  1991-03-24  |  13KB  |  641 lines

  1. /*! wgets
  2.  *
  3.  *
  4.  *    get a string form the console, echo it,
  5.  *    and allow simple editing and recall of prior strings
  6.  *
  7.  *
  8.  */
  9. #include "wsys.h"
  10.  
  11.  
  12.     /* FAR POINTER COMPARISON MACROS
  13.      *    These macros allow far ptrs to be compared looking only at offset part.
  14.      *
  15.      *  This improves code size and speed, but is dangerous...
  16.      *     only will work if the segment portions of ptrs are same
  17.      *        (ie, NORMALIZE macro only applied once and all ptrs then computed)
  18.      *
  19.      * ALSO, don't use to compare against the NULL pointer, won't work.
  20.      * AND, don't even think about fooling with the extra ().
  21.      *
  22.      *    IF this coding practice scares you, 
  23.      *            convert the (void near*) to (void huge*) which is always safe
  24.      *
  25.      *    NOTE that simply comparing the pointers without either cast 
  26.      *        may also generate incorrect code in large model
  27.      *
  28.      *    REFERENCE: TURBO C user's guide, 'MEMORY MODELS...POINTERS'
  29.      *        note that the < and > macros are redundant, but included for clarity
  30.      */
  31. #define FARPTR_EQ(aa,bb)  ( ((void near*)(aa))  ==  ((void near*)(bb)) ) 
  32. #define FARPTR_GT(aa,bb)  ( ((void near*)(aa))  >   ((void near*)(bb)) ) 
  33. #define FARPTR_LT(aa,bb)  ( ((void near*)(aa))  <   ((void near*)(bb)) ) 
  34.  
  35.  
  36.  
  37. /* local function: inch() moves x,y position 1 forward
  38.  *           backup() moves x,y 1 position back.
  39.  *           curse () toggles pseudo_cursor on/off.
  40.  *           show_insert (ON/OFF) places 'I' in upper right corner
  41.  *           rewrite() rewrite text onscreen
  42.  *            from current position to end of buffer, padding ' '
  43.  *            keystroke_OK () tests for numeric input if required 
  44.  */
  45. static void W_NEAR inch(int *px, int *py);
  46. static void W_NEAR backup ( int *px, int *py );
  47. static void W_NEAR curse (int x, int y);
  48. static void W_NEAR show_insert (void);
  49. static void W_NEAR  rewrite ( char *buffer, int x, int y, int endx, int endy );
  50.  
  51. static int  keystroke_OK ( int ch, char behavior, char *already_have );
  52.     #define HAVE_DEC    0x01
  53.     #define HAVE_SOME    0x02 
  54.  
  55. static  int     W_NEAR insert_mode = 0;
  56.  
  57.  
  58. int wgets(int nlimit, char *user_area, char behavior)
  59.     {
  60.     char *buffer, *buffer_start, *terminal_null;
  61.     unsigned char save_style, save_flag;
  62.     
  63.     char already_have =0;        /* keep track of signs and points */
  64.  
  65.     char doing_form = behavior & WGETS_FORM;
  66.     
  67.     int     x, y, startx, starty, endx, endy, n;
  68.     int     ch;
  69.     char     *ptr;
  70.     int     more =1;
  71.     int     ms_offset;    /* mouse offset from start of string */
  72.  
  73.     if ( nlimit <= 0)
  74.         {
  75.         return (ESCAPE);
  76.         }
  77.  
  78.     /* clean up user string address and contents after end of valid string
  79.      * This makes sure that string is terminated by NULLs
  80.      * and remainder of buffer is also NULL (prevent garbage after CTRL-O)
  81.      */
  82.     _NORMALIZE (user_area);        /*model-dependent*/
  83.     for (n = strlen(user_area); n < nlimit; ++n )
  84.         {
  85.         user_area[n] = 0;        /*stuff 0's into remainder of string ver 1.1*/
  86.         }
  87.  
  88.     if ( nlimit <= 0)
  89.         {
  90.         return (ESCAPE);
  91.         }
  92.  
  93.     buffer_start = wmalloc ( nlimit, "wgets" );
  94.     memcpy (buffer_start, user_area, nlimit);
  95.  
  96.     buffer = buffer_start;
  97.     terminal_null = buffer_start + nlimit -1;
  98.  
  99.     save_style = w0->winputstyle;
  100.     save_flag  = w0->winflag;
  101.     startx = x = wherex();
  102.     starty = y = wherey();
  103.  
  104.  
  105.     /* figure # lines as intermediate to figuring stop postions onscreen
  106.      */
  107.     n    = w0-> winxmax+1;                 /* bytes per line     */
  108.     endy = nlimit / n;            /* # times line wraps */
  109.     endx = x + (nlimit-(n*endy)) -1;    /* add in remainder   */
  110.  
  111.     if ( endx >= n )
  112.         {
  113.         /* beyond end of line
  114.          */
  115.         endx -= n;
  116.         endy++;
  117.         }
  118.     endy += y;                /* add #wraps to start*/
  119.  
  120.  
  121.  
  122.  
  123.     if ( wmode == 'T' )
  124.         {
  125.         wcursor(OFF);
  126.         }
  127.  
  128.  
  129.     /* turn on wrap and scroll, turn ANSI chars off
  130.      */
  131.     w0->winputstyle =  ( WPUTWRAP | WPUTSCROLL );
  132.  
  133.     show_insert ();
  134.  
  135.  
  136.     rewrite ( user_area, startx, starty, endx, endy );
  137.  
  138.  
  139.     while (more) {
  140.         wgoto (x,y);
  141.  
  142.         /* toggle cursor on */
  143.         curse (x, y);
  144.  
  145.         ch = wgetc();
  146.  
  147.         /* toggle cursor off */
  148.         curse (x, y);
  149.  
  150.         if ( ch == MOUSE &&  (wmouse.wms_used & WMS_LEFT_RLS) )
  151.             {
  152.             if ( wmouse.wms_inwindow )
  153.                 {
  154.                 /* convert mouse x,y to new position
  155.                  */
  156.  
  157.                 /* compute byte offset from mouse
  158.                  * to start of string
  159.                  *
  160.                  * NOTE mult (#lines below start) * linelen
  161.                  */
  162.                 ms_offset = (wmouse.wms_y - starty)
  163.                         * (1+ w0-> winxmax )
  164.                         + ( wmouse.wms_x - startx );
  165.  
  166.                 /* see if mouse points inside the string.
  167.                  */
  168.                 if ( ms_offset  >= 0
  169.                    && ms_offset <= strlen(buffer_start)
  170.                     )
  171.                     {
  172.                     /* mouse points inside string
  173.                      */
  174.                     buffer = buffer_start + ms_offset;
  175.                     x      = wmouse.wms_x;
  176.                     y      = wmouse.wms_y;
  177.  
  178.                     if ( ms_offset == 0 )        /* see if we're on first char */
  179.                         {
  180.                         already_have &= ( 0xff - HAVE_SOME );    
  181.                         }
  182.                     else
  183.                         {
  184.                         already_have |= HAVE_SOME;
  185.                         }
  186.                     }
  187.                 else        /* mouse outside this string, inside window */
  188.                     {
  189.                     if ( doing_form )    /* move to another form position */
  190.                         {
  191.                         more =0;
  192.                         }
  193.                     }
  194.  
  195.  
  196.                 }    /* end of mouse inside window */
  197.  
  198.             else
  199.                 {
  200.                 /* mouse outside of window -- see if INSERT clicked*/
  201.                 if ( wmouse.wms_xabs == 1+ w0->winleft + w0->winxmax
  202.                  && wmouse.wms_yabs == w0->wintop -1 )
  203.                     {
  204.                     /* clicked on the insert indicator */
  205.                     wungetc (INSERT);
  206.  
  207.                     }
  208.  
  209.                 }
  210.  
  211.             }    /* end if char = MOUSE */
  212.  
  213.         else
  214.         if (isascii (ch) && isprint(ch))        /* printable, not control code*/
  215.             {
  216.             if (  keystroke_OK ( ch, behavior, &already_have ) )
  217.                 {
  218.                 if (insert_mode)
  219.                     {
  220.                     /* push old characters back*/
  221.                     for (    ptr = terminal_null -1;
  222.                         FARPTR_GT (ptr, buffer);
  223.                         --ptr
  224.                         )
  225.                         {
  226.                         *(ptr) = *(ptr-1);
  227.                         }
  228.                     *buffer = ch;
  229.                     wputs ( buffer );        /* write new remaining portion */
  230.                     }
  231.                 else
  232.                     {
  233.                     /* overstrike mode -see if we're typing over a '.' 
  234.                      */
  235.                     if ( *buffer == '.' )  
  236.                         {
  237.                         already_have &= ( 0xff - HAVE_DEC );    /* removal */
  238.                         }
  239.                     *buffer = ch;
  240.                     wputc ( ch );            /* write new single char   */
  241.                     
  242.                     }
  243.                 /* no need to clear rest of line,
  244.                  * as inserting writes 1 byte more.
  245.                  */
  246.                 inch(&x,&y);
  247.                 ++buffer;
  248.  
  249.                 already_have |= HAVE_SOME;
  250.                 }
  251.             }
  252.         else    /* not mouse or printable, must be keypad... */
  253.         switch     (ch) {
  254.  
  255.         case    (ENTER):
  256.             more =0;
  257.             break;
  258.  
  259.         case    (RIGHT_ARROW):
  260.             /* wants next letter in old line*/
  261.             ptr = buffer +1;
  262.             if (FARPTR_LT (ptr, terminal_null) )
  263.                 {
  264.                 buffer = ptr;        /* advance */
  265.                 inch(&x,&y);
  266.                 
  267.                 if ( *ptr == 0 )        /* we're at end of a short string */
  268.                     {
  269.                     *(ptr+1) =0;        /* make sure there's a \0 here */    
  270.                     }
  271.                 
  272.                 already_have |= HAVE_SOME;
  273.                 
  274.                 }
  275.             break;
  276.  
  277.  
  278.         case    (CTRL('S')):                /* save data for form entry */
  279.             if ( doing_form )
  280.                 {
  281.                 more = 0;
  282.                 } 
  283.             break;
  284.             
  285.             
  286.         case    (LEFT_ARROW):    /*back up cursor*/
  287.         case     (BACKSPACE):
  288.             if ( FARPTR_GT (buffer, buffer_start) )
  289.                 /*byond start */
  290.                 {
  291.                 backup ( &x, &y );
  292.                 --buffer;
  293.                 if ( FARPTR_EQ (buffer, buffer_start ) )
  294.                     {
  295.                     already_have &= ( 0xff - HAVE_SOME );    /* on first ltr*/
  296.                     }
  297.                 if (ch == BACKSPACE)
  298.                     {
  299.                     /* rubout prev char -- first see if we're removing a '.' 
  300.                      */
  301.                     if ( *buffer == '.' )  
  302.                         {
  303.                         already_have &= ( 0xff - HAVE_DEC );    /* removal */
  304.                         }
  305.                     /*remove prior character from buffer and slide leftward
  306.                      */
  307.                     for (ptr =buffer;  
  308.                         FARPTR_LT (ptr, terminal_null);
  309.                         ptr++
  310.                         ) 
  311.                         {
  312.                         *(ptr) = *(ptr+1);
  313.                         }
  314.                     /* rewrite remainder of string
  315.                      */
  316.                     wgoto (x,y);
  317.                     rewrite (buffer,x,y,endx,endy);
  318.  
  319.                     }
  320.  
  321.                 }
  322.  
  323.             break;
  324.  
  325.         case     (TAB):
  326.         case      (UP_ARROW):
  327.         case     (DN_ARROW):
  328.         case    (BACKTAB):      /*request move to another field */
  329.  
  330.             if ( doing_form )
  331.                 {
  332.                 more = 0;
  333.                 }
  334.  
  335.             break;
  336.  
  337.         case     (INSERT):
  338.             insert_mode ^= 1;     /* toggle (XOR) */
  339.             show_insert ();
  340.             break;
  341.  
  342.         case    (DELETE):    /* delete 1 from old buffer */
  343.             
  344.             if ( *buffer == '.' )        /* are we deleting a '.' ??? */  
  345.                 {
  346.                 already_have &= ( 0xff - HAVE_DEC );    /* removal */
  347.                 }
  348.     
  349.             /* slide everything after this one char to left
  350.              */
  351.             for ( ptr =buffer;
  352.                   FARPTR_LT (ptr, terminal_null);
  353.                   ++ptr )
  354.                 {
  355.                 *(ptr) = *(ptr+1);
  356.                 }
  357.             rewrite (buffer,x,y,endx,endy);
  358.             break;
  359.  
  360.         case    (ESCAPE):
  361.             /* request to quit */
  362.             more =0;
  363.             
  364.  
  365.         case (HOME):
  366.             wgoto (startx, starty);
  367.             x=startx;
  368.             y=starty;
  369.             buffer = buffer_start;
  370.             break;
  371.         
  372.         case (END):
  373.             while ( FARPTR_LT (buffer, terminal_null) )
  374.                 {
  375.                 ++buffer;
  376.                 inch(&x,&y);
  377.                 if ( *buffer == 0 )        /* moving to last char in nonfull buff*/
  378.                     {
  379.                     *(buffer+1) = 0;
  380.                     break;                /* break from while */
  381.                     }    
  382.                 }
  383.             wgoto (x,y);
  384.             break;
  385.         
  386.         case ( CTRL_END ):
  387.         case ( CTRL('Y') ):
  388.             /* eliminate the remainder of the buffer
  389.              */
  390.             *buffer = 0x0;
  391.             rewrite (buffer,x,y,endx,endy);
  392.             break;
  393.  
  394.         case ( CTRL('O') ):
  395.             /* replace buffer with original contents
  396.              */
  397.             memcpy (buffer_start, user_area, nlimit);
  398.             x = startx;
  399.             y = starty;
  400.             wgoto (x,y);
  401.             buffer = buffer_start;
  402.                         rewrite (buffer,x,y,endx,endy);
  403.             if ( doing_form )
  404.                 {
  405.                 more =0;        
  406.                 }
  407.  
  408.         }  /*end switch (ch) */
  409.  
  410.         if ( FARPTR_EQ (buffer, terminal_null) )
  411.             {
  412.             backup ( &x, &y );
  413.             --buffer;
  414.             
  415.             if ( behavior & WGETS_SKIP )    /* test for autoskip at end */
  416.                 {
  417.                 more = 0;
  418.                 
  419.                 if ( doing_form )
  420.                     {
  421.                     /* in form mode, return ENTER to move to next field,
  422.                      * and wungetc() to reuse the ch as first char in field.
  423.                      */
  424.                     wungetc (ch);
  425.                     ch = ENTER;
  426.                     }
  427.                 }
  428.             }
  429.  
  430.  
  431.         }  /*end while - no more room or string terminated by user */
  432.  
  433.  
  434.  
  435.     /* wrapup */
  436.  
  437.  
  438.     w0->winputstyle = save_style;
  439.     w0->winflag     = save_flag;
  440.  
  441.     if ( w0->winflag & WFL_CURSOR )
  442.         {
  443.         wcursor (ON);
  444.         }
  445.  
  446.     if ( insert_mode )
  447.         {
  448.         insert_mode = OFF;
  449.         show_insert ();            /* erases onscreen 'I' marker */
  450.         insert_mode = ON;
  451.         }
  452.  
  453.  
  454.  
  455.     if ( ch != ESCAPE )
  456.         {
  457.         memcpy (user_area, buffer_start, nlimit);
  458.         }
  459.     else     {
  460.         /* ESCAPE means reject the newly typed values
  461.          * need to replace changed values onscreen with originals.
  462.          */
  463.         wgoto ( startx, starty );
  464.  
  465.         rewrite ( user_area, startx, starty, endx, endy );
  466.         }
  467.  
  468.     free (buffer_start);
  469.  
  470.     return(ch);
  471.     } /*end of wgets*/
  472.  
  473.  
  474.  
  475. static void W_NEAR inch (int *px, int *py)
  476.     {
  477.  
  478.     register int x,y;
  479.     x = *px;
  480.     y = *py;
  481.  
  482.     if ( ++x > w0->winxmax )
  483.         {
  484.         x =0;
  485.         if (++y > w0->winymax )
  486.             {
  487.             --y;
  488.             wgoto(x,y);
  489.             wscroll();
  490.             }
  491.         }
  492.  
  493.     *px =x;
  494.     *py =y;
  495.  
  496.     return;    /* inch*/
  497.  
  498.     }
  499.  
  500. static void W_NEAR show_insert ()
  501.     {
  502.     unsigned char ch, at;
  503.  
  504.  
  505.  
  506.  
  507.     if ( ! w0->winbox )
  508.         return;
  509.  
  510.     at = w0->winboxcolor;
  511.  
  512.     if ( insert_mode )
  513.         {
  514.         ch = 'I';
  515.         at |= BLINK;
  516.         }
  517.     else
  518.         {
  519.         ch = wbox [w0->winbox].ne;
  520.         }
  521.  
  522.  
  523.     wputcabs( w0->winleft  + w0->winxmax +1,
  524.           w0->wintop   -1,
  525.           ch, at,
  526.           WGOVERWRITE);
  527.  
  528.     return;     /* show_insert */
  529.     }
  530.  
  531.  
  532. static void W_NEAR curse (int x, int y)
  533.     {
  534.     unsigned char new_state;
  535.  
  536.  
  537.  
  538.  
  539.     #ifdef  TEXTONLY
  540.         new_state = (w0-> winflag & WFL_CURSOR ) ?
  541.                          OFF  : ON ;
  542.  
  543.         wcursor (new_state);
  544.  
  545.  
  546.  
  547.     #else    /* not TEXTONLY */
  548.  
  549.         if ( wmode == 'G' )
  550.             {
  551.             wputcabs (w0->winleft + x, w0->wintop +y,
  552.             ' ', 0xf0, WGXOR );
  553.             }
  554.         else
  555.             {
  556.             new_state = (w0-> winflag & WFL_CURSOR ) ?
  557.                          OFF  : ON ;
  558.             wcursor (new_state);
  559.             }
  560.  
  561.     #endif    /* not TEXTONLY */
  562.  
  563.  
  564.     return;     /* curse () */
  565.  
  566.     }
  567.  
  568.  
  569.  
  570.  
  571.  
  572. static void W_NEAR backup ( int *px, int *py )
  573.     {
  574.     register int x = *px;
  575.     register int y = *py;
  576.  
  577.  
  578.     if (--x < 0)  {  /*at start of line*/
  579.         /* goto end of last line */
  580.         x = w0-> winxmax ;
  581.         if (--y < 0)
  582.             {
  583.             x= 0;    /*start of window*/
  584.             y= 0;
  585.             }
  586.         }
  587.  
  588.     *px =x;
  589.     *py =y;
  590.  
  591.     return;    /* backup */
  592.     }
  593.  
  594. /* write string to screen and pad remainder of area with ' '
  595.  */
  596.  
  597. static void W_NEAR  rewrite ( char *buffer, int x, int y, int endx, int endy )
  598.     {
  599.     register int nleft;
  600.     
  601.     nleft =   (w0->winxmax+1)*(endy-y)  + (endx-x);
  602.     wputfl ( buffer, nleft );        /* fixed len string put */
  603.  
  604.  
  605.     return;        /* rewrite */
  606.     }
  607.  
  608.  
  609. static int  keystroke_OK ( int ch, char behavior, char *already_have )
  610.     {
  611.     int ch_OK = 1;    
  612.     char temp_have = *already_have;
  613.     
  614.     if ( behavior & WGETS_INT )
  615.         {
  616.         if     ( ! isdigit (ch) )  
  617.             {
  618.             if ( ch== '.'             && ! (temp_have & HAVE_DEC) )
  619.                 {
  620.                 temp_have |= HAVE_DEC;
  621.                 }
  622.             else
  623.             if ( ! ( (ch=='-' || ch=='+') && ! (temp_have & HAVE_SOME)  )   ) 
  624.                 {
  625.                 ch_OK = 0;
  626.                 }
  627.             }
  628.         }
  629.     
  630.     *already_have = temp_have;
  631.     
  632.     return  ch_OK;
  633.     }
  634.  
  635.  
  636.  
  637.  
  638.  
  639. /*------------------------- end of WGETS.C ------------------------------*/
  640.  
  641.