home *** CD-ROM | disk | FTP | other *** search
/ Jason Aller Floppy Collection / 125.img / PRO-C4.ZIP / BENCH1.ZIP / BENCH / INPUT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-28  |  30.2 KB  |  1,558 lines

  1. /* ==( memo/inputt.c )== */
  2.  
  3. /* ----------------------------------------------- */
  4. /* Pro-C  Copyright (C) 1989 - 1990 Vestronix Inc. */
  5. /* Modification to this source is not supported    */
  6. /* by Vestronix Inc.                               */
  7. /*            All Rights Reserved                  */
  8. /* ----------------------------------------------- */
  9. /* Written   JPK   1-May-89                        */
  10. /* Modified  Geo  12-Dec-89  See comments below    */
  11. /* ----------------------------------------------- */
  12. /* %W%  (%H% %T%) */
  13.  
  14. /*
  15.  *  Modifications
  16.  *
  17.  *  16-Dec-89  JH  - rewrite of input masks, bug fixes
  18.  *  12-Dec-89  Geo - V2 version
  19.  *
  20. */
  21.  
  22. /*
  23.  * Inputt.c contains the routines to implement text field inut. These include
  24.  * mask validation, character input and validation and field formatting for 
  25.  * display.
  26. */
  27. # include <stdio.h>
  28. # include <bench.h>
  29. # include "field.h"
  30.  
  31. # include <time.h>
  32.  
  33. # ifndef MIN
  34. #  define MIN(a,b)    (a > b ? b : a)
  35. # endif
  36. # ifndef MAX
  37. #  define MAX(a,b)    (a < b ? b : a)
  38. # endif
  39.  
  40. # ifdef ANSI
  41. static void int_disp_text(FIELD *, int, char *);
  42. static void expand_mask(char *, char *);
  43. static void build_display_buff(FIELD *, char *);
  44. static int power(int, int);
  45. static char *end_field(FIELD *, char *);
  46. static char *forward(FIELD *, char *);
  47. static char *backspace(FIELD *, char *);
  48. static void del_text_char(FIELD *);
  49. static void home_cursor(FIELD *);
  50. static void forward_cursor(FIELD *);
  51. static void back_cursor(FIELD *);
  52. static void put_cursor(FIELD *, int);
  53. static int check_char(int *, char *, FIELD *);
  54. static int realign_decimals(FIELD *, char *);
  55. static void scroll_field_left(FIELD *);
  56. static void scroll_field_right(void);
  57. static void set_negative_flag(char *);
  58. static void fill_mask(FIELD *, char *);
  59. static int endinput(int);
  60. static void setcur_shape(void);
  61. void home_field(FIELD *);
  62. int length_mask(FIELD *);
  63. static int text_mask(FIELD *, char);
  64. static void count_special_chars_in_mask(FIELD *, char *);
  65. # else
  66. static void int_disp_text();
  67. static void expand_mask();
  68. static void build_display_buff();
  69. static int power();
  70. static char *end_field();
  71. static char *forward();
  72. static char *backspace();
  73. static void del_text_char();
  74. static void home_cursor();
  75. static void forward_cursor();
  76. static void back_cursor();
  77. static void put_cursor();
  78. static int check_char();
  79. static int realign_decimals();
  80. static void scroll_field_left();
  81. static void scroll_field_right();
  82. static int text_mask();
  83. static void set_negative_flag();
  84. static void fill_mask();
  85. static int endinput();
  86. static void setcur_shape();
  87. void home_field();
  88. int length_mask();
  89. static void count_special_chars_in_mask();
  90. # endif
  91.  
  92. int doing_memos = FALSE;
  93.  
  94. /* static variables */
  95. static char *field_buffer;            /* internal field buffer */
  96. static char display_buff[MAX_MASK]; /* display buff, should alloc dynamically */
  97. static char *disp_buff_ptr;    /*points to current screen start of display_buff*/
  98. static int end_display;        /* TRUE if leaving a field, display buffer in full*/
  99. static int field_negative;
  100. static int number_negative;
  101. static int num_special_chars_in_mask = 0;
  102.  
  103. int field_overflow = FALSE;
  104. int cursor_col;        /* column of cursor , used again in memo.c */
  105. int homed_field = FALSE;
  106.  
  107. # ifdef MSDOS
  108. static int numlock_on;
  109. # endif
  110.  
  111. extern int instos;    /* inchar.c */
  112.  
  113.  
  114. static char *save_buff;
  115.  
  116. # ifdef UNIX
  117. int input_wx(fld, va_alist)
  118. FIELD *fld;
  119. va_dcl
  120. # else
  121. int input_wx(FIELD *fld, int va_alist, ...)
  122. # endif
  123. {
  124.     int key;
  125.     int done = FALSE;
  126.     va_list ap;
  127.     int buff_len;
  128.  
  129.     /* save the fbuff, if K_ESC is hit we'll restore the buffer to its
  130.     * previous contents
  131.     */
  132.     if (!doing_memos && (buff_len = strlen(fld->fbuff)) != 0)
  133.     {
  134.         /*
  135.          * Coz' Jeff is an Egg. Memory got eaten.
  136.          * This is pretty time consuming really, considering
  137.          * this routine gets called many many times.
  138.         */
  139.         if (save_buff)
  140.             free (save_buff);
  141.         save_buff = (char *)alloc(buff_len + 1);
  142.         bytecpy(save_buff, fld->fbuff, buff_len);
  143.     }
  144.  
  145.     /* call the pre input function if it is defined */
  146.     if (fld->f_pre)
  147.         if ((*fld->f_pre)(fld) == FALSE)
  148.             return(K_ESC);
  149.  
  150.     /* loop getting input until valid end key is pressed */
  151.     while (TRUE)
  152.     {
  153. if_bad_input:
  154.         if (!fld->f_input)
  155.             disp_text(fld, fld->fattrib_on);
  156.         else
  157.             ichar = (*fld->f_input)(fld);
  158.  
  159.         if (ichar == K_CR)
  160.         {
  161.             if (fld->f_val)
  162.                 if ((*fld->f_val)(fld) == FALSE)
  163.                     continue;
  164.             break;
  165.         }
  166.         if (ichar == K_ESC)
  167.         {
  168.             if (!doing_memos && buff_len)
  169.                 bytecpy(fld->fbuff, save_buff, buff_len);
  170.             break;
  171.         }
  172.  
  173. # ifdef UNIX
  174.         va_start(ap);
  175.         key = va_arg(ap, int);
  176. # else
  177.         va_start(ap, va_alist);
  178.         key = va_alist;
  179. # endif
  180.  
  181.         while (key != 0)
  182.         {
  183.             if (ichar == key)
  184.             {
  185.                 if (fld->f_val)
  186.                     if ((*fld->f_val)(fld) == FALSE)
  187.                         goto if_bad_input;
  188.                 done = TRUE;
  189.             }
  190.             key = va_arg(ap, int);
  191.         }
  192.         va_end(ap);
  193.  
  194.  
  195.         /* check if field has over flowed before continuing */
  196.         if (field_overflow)
  197.             done = TRUE;
  198.  
  199.         /* if we're done, then we're done - and I don't mean maybe */
  200.         if (done)
  201.             break;
  202.     
  203.     }
  204.     if (ichar != K_ESC)
  205.     {
  206.         /* post input function */
  207.         if (fld->f_post)
  208.             (*fld->f_post)(fld);
  209.     }
  210.  
  211.     /* set ichar to the exitcode and return */
  212.     return(ichar);
  213. }
  214.  
  215.  
  216.  
  217. /* 
  218.  * Display a field by building the output string and displaying it.
  219. */
  220. void disp_text(field, attr)
  221.     FIELD *field;
  222.     int attr;
  223. {
  224.     char new_mask[256];
  225.     int disp_length;
  226.  
  227.     if (!disp_buff_ptr)
  228.         disp_buff_ptr = display_buff;
  229.     num_special_chars_in_mask = 0;
  230.  
  231.     end_display = TRUE;
  232.     expand_mask(field->fmask, new_mask);
  233.     count_special_chars_in_mask(field, new_mask);
  234.  
  235.     /* need a routine to build the display string from the mask and the 
  236.     * buffer. Then simply display the buffer.
  237.     */
  238.     build_display_buff(field, new_mask);
  239.     disp_length = length_mask(field);
  240.  
  241.     ndisp_w(field->frow, field->fcol, attr, disp_length, disp_buff_ptr);
  242.     put_cursor(field, 0);
  243. }
  244.  
  245. /* 
  246.  * disp_text for internal use only
  247.  */
  248. static void int_disp_text(field, attr, mask)
  249.     FIELD *field;
  250.     int attr;
  251.     char *mask;
  252. {
  253.     int disp_length;
  254.  
  255.     /* need a routine to build the display string from the mask and the 
  256.     * buffer. Then simply display the buffer.
  257.     */
  258.     build_display_buff(field, mask);
  259.     disp_length = length_mask(field);
  260.  
  261.     ndisp_w(field->frow, field->fcol, attr, disp_length, disp_buff_ptr);
  262.     put_cursor(field, 0);
  263. }
  264.  
  265.  
  266. /*
  267.  * Return a formatted string, built from the fields contents and mask.
  268.  * Same as disp_text but don't display it
  269. */
  270. char *fmt_text(field)
  271. FIELD *field;
  272. {
  273.     char new_mask[256];
  274.  
  275.     if (!disp_buff_ptr)
  276.         disp_buff_ptr = display_buff;
  277.  
  278.     end_display = TRUE;
  279.     expand_mask(field->fmask, new_mask);
  280.  
  281.     /* need a routine to build the display string from the mask and the 
  282.     * buffer. Then simply display the buffer.
  283.     */
  284.     build_display_buff(field, new_mask);
  285.  
  286.     return(disp_buff_ptr);
  287. }
  288.  
  289.  
  290. /*
  291.  * Read in a text, numeric, date or memo field in from the keyboard 
  292. */
  293. int text_input(field)
  294.     FIELD *field;
  295. {
  296.     char msk[MAX_MASK];
  297.     char *mask;
  298.     int c;
  299.     int done = FALSE;
  300.     int curstate;
  301.     int did_money = FALSE;  /* only bleep past first money symbol */
  302.     int first_time_disp = TRUE;
  303.  
  304. #ifdef MOUSE
  305.  
  306.     int mr, mc, mh, mw;
  307.  
  308.     abs_w(&mr, &mc, &mw, &mh);
  309.     mouse_add_object(mr + field->frow, mc + field->fcol, mr + field->frow, mc + field->fcol + length_mask(field) - 1, 0, 0, "INPUT");
  310.  
  311. #endif
  312.  
  313.     /* do the initial bits
  314.     */
  315.     curstate = cursor(ON);
  316.     end_display = FALSE;
  317.     field_overflow = FALSE;
  318.     num_special_chars_in_mask = 0;
  319.     disp_buff_ptr = display_buff;
  320.     expand_mask(field->fmask, msk);
  321.     mask = msk;
  322.     set_negative_flag(mask);
  323.     count_special_chars_in_mask(field, mask);
  324.     if (field->ftype == F_TEXT)
  325.         fill_mask(field, mask);
  326.  
  327.     if (field->ftype == F_NUMERIC && *field->fbuff == '-')
  328.     {
  329.         /* increment the fbuff past the negative sign, it gets in the way */
  330.         move_text(field->fbuff, field->fbuff+1, strlen(field->fbuff)-1);
  331.         number_negative = TRUE;
  332.     }
  333.     else
  334.         number_negative = FALSE;
  335.     
  336.     clean_buffer(field);
  337.     setcur_shape();
  338.  
  339.     if (!homed_field)
  340.         home_field(field);
  341.     else
  342.     {
  343.         int i;
  344.         int fx;
  345.         fx = field->fx;
  346.         field->fx = 0;
  347.  
  348.         for (i=0; i<fx; i++)
  349.             mask = forward(field, mask);
  350.         homed_field = FALSE;
  351.     }
  352.  
  353.  
  354.     /* have a case for all of the characters possible for input
  355.     */
  356.     while (TRUE)
  357.     {
  358.  
  359.         while (*mask)
  360.         {
  361.             int done = FALSE;
  362.             char msk_sav = '\0';
  363.  
  364.             switch (text_mask(field, *mask))
  365.             {
  366.             case FILL :
  367.                 if (*mask == '*' && msk_sav == '*')
  368.                 {
  369.                     *mask = 'Z';
  370.                     done = TRUE;
  371.                     break;
  372.                 }
  373.                 msk_sav = *mask;
  374.                 forward_cursor(field);
  375.  
  376.             case SPECIAL :
  377.                 mask++;
  378.                 break;
  379.  
  380.             default :
  381.                 switch(*mask)
  382.                 {
  383.                 case '(' :
  384.                 case '-' :
  385.                 case ')' :
  386.                     if (*++mask)
  387.                         forward_cursor(field);
  388.                     break;
  389.                 case MASK_MONEY :
  390.                     if (!did_money)
  391.                     {
  392.                         if (*++mask)    
  393.                             forward_cursor(field);
  394.                         did_money = TRUE;
  395.                         break;
  396.                     }
  397.                 default :
  398.                     done = TRUE;
  399.                     break;
  400.                 }
  401.                 break;
  402.             }
  403.             if (done)
  404.                 break;
  405.         }
  406.  
  407.         int_disp_text(field, field->fattrib_on, msk);
  408.         c = inchar();
  409.  
  410.         switch (c)
  411.         {
  412. #ifdef MOUSE
  413.         case M_PRESS :
  414.             if (!mouse_check_bounds())
  415.                 break;
  416.         case M_RELEASE :
  417.             {
  418.                 int dummy;
  419.                 if (mouse_row == w_nrows)
  420.                     mouse_click(&dummy, c);
  421.                 else if (mouse_click(&dummy, M_PRESS))
  422.                 {
  423.                     if (c == M_PRESS)
  424.                     {
  425.                         dummy = cursor_col + mc;
  426.                         if (mouse_col > dummy)
  427.                             while (mouse_col > dummy++)
  428.                             {
  429.                                 if (dummy > (mc + field->fcol + strlen(field->fbuff)))
  430.                                     break;
  431.                                 unget_inchar(K_RIGHT);
  432.                             }
  433.                         else if (mouse_col < dummy)
  434.                             while (mouse_col < dummy--)
  435.                                 unget_inchar(K_LEFT);
  436.                     }
  437.                 }
  438.             }
  439.             break;
  440. #endif
  441.         case K_HOME :
  442.             if ((field->fcontrol&NO_HOME_END) != NO_HOME_END)
  443.             {
  444.                 mask = msk;
  445.                 home_field(field);
  446.                 break;
  447.             }
  448.             else
  449.             goto is_default;
  450.  
  451.         case K_END :
  452.             if ((field->fcontrol&NO_HOME_END) != NO_HOME_END)
  453.             {
  454.                 mask = msk;
  455.                 mask = end_field(field, mask);
  456.                 break;
  457.             }
  458.             else
  459.                 goto is_default;
  460.  
  461.         case K_RIGHT :
  462.             if (!*field_buffer || field_buffer == field->fbuff + field->fieldlen + num_special_chars_in_mask || (doing_memos && field->fx == field->fieldlen+ num_special_chars_in_mask ))
  463.                 done = TRUE;
  464.             else
  465.                     mask = forward(field, mask);
  466.             break;
  467.  
  468.         case K_LEFT :
  469.         case K_BS :
  470.             if (field_buffer != field->fbuff)
  471.                 mask = backspace(field, mask);
  472.             else
  473.                 done = TRUE;
  474.             if (c == K_LEFT)
  475.                 break;
  476.  
  477.         case K_DEL :
  478.             del_text_char(field);
  479.             if (doing_memos && !strlen(field->fbuff))
  480.                 done = TRUE;
  481.             break;
  482.  
  483.         case K_INS :
  484.             instos ^= TRUE;
  485.             setcur_shape();
  486.             break;
  487.  
  488.         case K_F1 :
  489.             help_msg(field->fhelp);
  490.             break;
  491.  
  492.         case '-' :
  493.             if (field->ftype ==F_NUMERIC && field_negative && c == '-')
  494.             {
  495.                 number_negative ^= TRUE;
  496.                 break;
  497.             }
  498.  
  499.         case '.' :
  500.             /* make sure it is not a fall thru */
  501.             if (field->ftype == F_NUMERIC && *mask != '.' && strchr(mask, '.') && c == '.')
  502.             {
  503.                 /* move the data to the decimal */
  504.                 while (*mask != '.')
  505.                 {
  506.                     forward_cursor(field);
  507.                     mask++;
  508.                 }
  509.             }
  510.  
  511.         case K_UP :
  512.         case K_F4 :
  513.         case K_DOWN :
  514.         case K_F3 :
  515.  
  516.         default :
  517.         is_default:
  518.             if (endinput(c))
  519.             {
  520.                 done = TRUE;
  521.                 end_display = TRUE;
  522.                 break;
  523.             }
  524.  
  525.             if (*mask)
  526.             {
  527.                 if (!check_char(&c, mask, field))
  528.                 {
  529.                     do_bell();
  530.                     break;
  531.                 }
  532.                 if (instos && strlen(field->fbuff) < field->fieldlen+ num_special_chars_in_mask )
  533.                     move_text(field_buffer+1, field_buffer, strlen(field_buffer)-1);
  534.             }
  535.             else
  536.             {
  537.                 if ((field->fcontrol&OVERFLOW_RETURN) == OVERFLOW_RETURN)
  538.                 {
  539.                     field_overflow = TRUE;
  540.                     break;
  541.                 }
  542.                 else if ((field->fcontrol&CONFIRM_NEEDED) != CONFIRM_NEEDED)
  543.                 {    
  544.                     /* quit and return K_CR to application */
  545.                     done = TRUE;
  546.                     c = K_CR;
  547.                     break;
  548.                 }
  549.  
  550.  
  551.                 mask = backspace(field, mask);
  552.                 if (!check_char(&c, mask, field))
  553.                 {
  554.                     errmsg("Invalid data entry - Please retry");
  555.                     mask = forward(field, mask);
  556.                     break;
  557.                 }
  558.             }
  559.             *field_buffer = (char) c;
  560.             mask = forward(field, mask);
  561.             if (!doing_memos && !*mask && (field->fcontrol&CONFIRM_NEEDED) != CONFIRM_NEEDED)
  562.                /* last char in field, do overflow */
  563.                 field_overflow = TRUE;
  564.             break;
  565.         }
  566.         if (done || field_overflow)
  567.             break;
  568.     }
  569.     if (field->ftype == F_NUMERIC && !*field->fbuff)
  570.         *field->fbuff = '0';
  571.  
  572.     disp_buff_ptr = display_buff;
  573.     int_disp_text(field, field->fattrib_off, msk);
  574.  
  575.     if (number_negative)
  576.     {
  577.         move_text(field->fbuff+1, field->fbuff, strlen(field->fbuff)-1);
  578.         *field->fbuff = '-';
  579.     }
  580.  
  581. # ifdef MOUSE
  582.     mouse_delete_object(0, 0, "INPUT");
  583. # endif
  584.     cursor(curstate);
  585.     return c;
  586. }
  587.  
  588. /*
  589.  * Expand the mask field from any short forms to a string of format chars 
  590. */
  591. static void expand_mask(mask, new_mask)
  592.     char *mask;
  593.     char *new_mask;
  594. {
  595.     char *msk;
  596.     char msk_sav;
  597.     int num = 0;
  598.     int i = 0;
  599.  
  600.     msk = mask;
  601.     msk_sav = *msk;
  602.  
  603.     while(*msk)
  604.     {
  605.         if (*msk == '(' && *(msk-1) != HARDSPACE && *(msk-1) != MASK_SPECIAL && msk_sav != '(')
  606.         {
  607.             while (*msk && *msk != ')')
  608.                 msk++;
  609.  
  610.             /* parse format length out of msk string */
  611.             msk--;
  612.             while (*msk != '(')
  613.             {
  614.                 num += (int)(*msk - '0') * power(10,i);
  615.                 msk--;
  616.                 i++;
  617.             }
  618.             while (*msk != ')')
  619.                 msk++;
  620.  
  621.             /* build up new format string */
  622.             for (i=0; i<num-1; i++, new_mask++)
  623.                 *new_mask = msk_sav;
  624.  
  625.             i=0;
  626.             num = 0;
  627.         }
  628.         else
  629.             *new_mask++ = *msk;
  630.  
  631.         msk_sav = *msk++;
  632.     }
  633.     *new_mask = '\0';
  634.  
  635. }
  636.  
  637.  
  638. /*
  639. * This routine takes the data buffer and together with the mask fills
  640. * the display buffer with the properly formatted data
  641. */
  642. static void build_display_buff(field, mask)
  643.     FIELD *field;
  644.     char *mask;
  645. {
  646.     char *m = mask;
  647.     char *b = field->fbuff;
  648.     char *d = display_buff;
  649.     char fill_char;
  650.     int asterisk_fill = FALSE;
  651.     int decimal_increment = 0;
  652.     int save_decimal_inc = 0;
  653.     int first_dollar = TRUE;
  654.     int i;
  655.  
  656.     for (i=0; i<MAX_MASK; *d++ = HARDSPACE, i++);
  657.     d = display_buff;
  658.  
  659.     if (field->ftype == F_NUMERIC)
  660.     {
  661.         decimal_increment = realign_decimals(field, m);
  662.         save_decimal_inc = decimal_increment;
  663.     }
  664.  
  665.     while (*m)
  666.     {
  667.         switch(text_mask(field, *m))
  668.         {
  669.         case TEMPLATE :
  670.             switch (*m)
  671.             {
  672.             case MASK_YEAR :
  673.             case MASK_MONTH :
  674.             case MASK_DAY :
  675.             case MASK_HOUR :
  676.             case MASK_MINUTE :
  677.             case MASK_SECOND :
  678.             case MASK_WEEKDAY :
  679.             case MASK_DAY_SUFFIX :
  680.                 if (field->ftype == F_DATE || field->ftype == F_TIME)
  681.                     *d++ = ( *b ? *b++ : *m);
  682.                 break;
  683.  
  684.             case MASK_8 :
  685.             case MASK_z :
  686.             case MASK_Z :
  687.                 if (field->ftype == F_NUMERIC)
  688.                 {
  689.                     if (asterisk_fill)
  690.                         fill_char = ASTERISK_FILL;
  691.                     else
  692.                         fill_char = HARDSPACE;
  693.  
  694.                     *d++ = ( *b && *b != HARDSPACE && !decimal_increment ? *b : fill_char);
  695.                     if (*b && !decimal_increment)
  696.                         b++;
  697.                     if (decimal_increment)
  698.                         decimal_increment--;
  699.                     break;
  700.                 }
  701.  
  702.             case MASK_I :
  703.             case MASK_C :
  704.             case MASK_c :
  705.             case MASK_P :
  706.             case MASK_p :
  707.             case MASK_Q :
  708.             case MASK_A :
  709.             case MASK_a :
  710.             case MASK_B :
  711.             case MASK_x :
  712.             case MASK_X :
  713.             case MASK_Y :
  714.                 *d++ = (*b && !decimal_increment ? *b : HARDSPACE);
  715.                 if (*b && !decimal_increment)
  716.                     b++;
  717.                 if (decimal_increment)
  718.                     decimal_increment--;
  719.                 break;
  720.  
  721.             case MASK_MONEY :
  722.                 /* the first one should always be reserved for DOLLAR_SIGN */
  723.                 if (first_dollar)
  724.                 {
  725.                     *d++ = DOLLAR_SIGN;
  726.                     first_dollar = FALSE;
  727.                 }
  728.                 else
  729.                 {
  730.                     *d++ = ( *b && !decimal_increment ? *b : DOLLAR_SIGN);
  731.                     if (*b && !decimal_increment)
  732.                         b++;
  733.                 }
  734.                 if (decimal_increment)
  735.                     decimal_increment--;
  736.                 break;
  737.  
  738.             case MASK_9 :
  739.                 if (end_display)
  740.                     fill_char = '0';
  741.                 else
  742.                     fill_char = HARDSPACE;
  743.  
  744.                 if (field->ftype == F_NUMERIC)
  745.                     *d++ = ( *b && *b != HARDSPACE && !decimal_increment ?*b :fill_char);
  746.                 else
  747.                     *d++ = ( *b ? *b : HARDSPACE);
  748.  
  749.                 if (*b && !decimal_increment)
  750.                     b++;
  751.                 if (decimal_increment)
  752.                     decimal_increment--;
  753.                 break;
  754.  
  755.             case '.' :
  756.                 *d++ = '.';
  757.                 if (*b && *b != '.')
  758.                     *display_buff = '?';
  759.                 if (*b)
  760.                     b++;
  761.                 break;
  762.  
  763.             case '(' :
  764.                 if (field->ftype ==F_NUMERIC &&field_negative &&number_negative)
  765.                     *d++ = '(';
  766.                 else
  767.                     *d++ = HARDSPACE;
  768.                 break;
  769.  
  770.             case ')' :
  771.                 if (field->ftype ==F_NUMERIC &&field_negative &&number_negative)
  772.                     *d++ = ')';
  773.                 else
  774.                     *d++ = HARDSPACE;
  775.                 break;
  776.  
  777.             case '-' :
  778.                 if (field->ftype ==F_NUMERIC &&field_negative &&number_negative)
  779.                     *d++ = '-';
  780.                 else
  781.                     *d++ = HARDSPACE;
  782.                 break;
  783.  
  784.             default :
  785.                 *d++ = HARDSPACE;
  786.                 break;
  787.             }
  788.             break;
  789.  
  790.         case PASSWORD :
  791.             *d++ = ( *b ? '*' : HARDSPACE);
  792.             if (*b)
  793.                 b++;
  794.             break;
  795.  
  796.         case FILL :
  797.             /* need bits here to handle fills and floats */
  798.             if (field->ftype == F_NUMERIC && *m == '*' && *(m-1) == '*')
  799.             {
  800.                 asterisk_fill = TRUE;
  801.                 *d++ = ( *b && !decimal_increment ? *b : '*');
  802.                 if (*b && !decimal_increment)
  803.                     b++;
  804.                 if (decimal_increment)
  805.                     decimal_increment--;
  806.             }
  807.             else if (*m == ',' && *(d-1) == HARDSPACE)
  808.                 *d++ = HARDSPACE;
  809.             else if (*m == ',' && *(d-1) == DOLLAR_SIGN)
  810.                 *d++ = DOLLAR_SIGN;
  811.             else if (*m == ',' && *(d-1) == '*')
  812.                 *d++ = '*';
  813.             else
  814.                 *d++ = *m;
  815.  
  816.         case SPECIAL :
  817.         default :
  818.             break;
  819.         }
  820.         m++;
  821.     }
  822.     if (*b && isdigit(*b) && field->ftype == F_NUMERIC)
  823.         *(display_buff+save_decimal_inc+1) = '?';
  824.  
  825.     *d = '\0';
  826. }
  827.  
  828.  
  829.  
  830. /*
  831. * Simple routine to evaluate powers
  832. */
  833. static int power(x, y)
  834.     int x, y;
  835. {
  836.     int i = 0;
  837.     int result = 1;
  838.  
  839.     while ( i<y )
  840.     {
  841.         result *= x;
  842.         i++;
  843.     }
  844.     return(result);
  845. }
  846.  
  847.  
  848. /*
  849. * This routine calculates the character length of a mask
  850. */
  851. int length_mask(field)
  852.     FIELD *field;
  853. {
  854.     char new_mask[256];
  855.     char *m;
  856.     int msk_count = 0;
  857.  
  858.     /* if the mask has a ?(#) type of construction expand it */
  859.     if (strchr(field->fmask, '('))
  860.         expand_mask(field->fmask, new_mask);
  861.     else
  862.         strcpy(new_mask, field->fmask);
  863.  
  864.     m = new_mask;
  865.  
  866.     while (*m)
  867.     {
  868.         switch(text_mask(field, *m))
  869.         {
  870.         case PASSWORD :
  871.         case TEMPLATE :
  872.             if (field->ftype == F_NUMERIC)
  873.                 msk_count++;
  874.             else 
  875.                 if (*m != '(' && *m != ')' && *m != '-')
  876.                     msk_count++;
  877.             break;
  878.         case FILL :
  879.             msk_count++;
  880.         default :
  881.             break;
  882.         }
  883.         m++;
  884.     }
  885.     return(msk_count);
  886. }
  887.  
  888.  
  889. /* 
  890. * This routine moves the cursor to the beginning of the field
  891. */
  892. void home_field(field)
  893.     FIELD *field;
  894. {
  895.     field_buffer = field->fbuff;
  896.     /*
  897.     * start at column 0
  898.     */
  899.     field->fx = 0;
  900.     disp_buff_ptr = display_buff;
  901.  
  902.     home_cursor(field);
  903. }
  904.  
  905.  
  906. /*
  907. * This routine moves the cursor to the end of the field
  908. */
  909. static char *end_field(field, mask)
  910.     FIELD *field;
  911.     char *mask;
  912. {
  913.     field_buffer = field->fbuff;
  914.     field->fx = 0;
  915.     disp_buff_ptr = display_buff;
  916.     home_cursor(field);
  917.  
  918.     /* forward() increments the field_buffer */
  919.     while(*field_buffer && *mask && field->fx < field->fieldlen+ num_special_chars_in_mask )
  920.         mask = forward(field, mask);
  921.  
  922.     return mask;
  923. }
  924.  
  925.  
  926. /*
  927. *  This routine moves the cursor back one position 
  928. */
  929. static char *backspace(field, mask)
  930.     FIELD *field;
  931.     char *mask;
  932. {
  933.     field_buffer--;
  934.     mask--;
  935.     if (field->fx > 1)
  936.         field->fx--;
  937.  
  938.     while (mask != field->fmask)
  939.     {
  940.         int done = FALSE;
  941.  
  942.         switch(text_mask(field, *mask))
  943.         {
  944.         case TEMPLATE :
  945.             if (*mask == '-' || *mask == '(' || *mask == ')')
  946.                 mask--;
  947.             else
  948.                 done = TRUE;
  949.             break;
  950.         case FILL :
  951.             back_cursor(field);
  952.         case SPECIAL :
  953.             mask--;
  954.             break;
  955.         default :
  956.             done = TRUE;
  957.             break;
  958.         }
  959.         if (done)
  960.             break;
  961.     }
  962.  
  963.     /* scroll the text if possible */
  964.     if ( cursor_col - field->fcol == 0)
  965.         scroll_field_right();
  966.     else
  967.     {
  968.         if (field_buffer == field->fbuff + field->fieldlen - 1)
  969.         {
  970.             if (cursor_col != field->fcol + MIN(field->fieldlen+ num_special_chars_in_mask, length_mask(field)) - 1)
  971.                 back_cursor(field);
  972.         }
  973.         else
  974.             back_cursor(field);
  975.     }
  976.  
  977.     return mask;
  978. }
  979.  
  980.  
  981. /*
  982. * This routine moves the cursor forward one space
  983. */
  984. static char *forward(field, mask)
  985.     FIELD *field;
  986.     char *mask;
  987. {
  988.     field_buffer++;
  989.     field->fx++;
  990.  
  991.     while (*mask)
  992.     {
  993.         int done = FALSE;
  994.  
  995.         switch(text_mask(field, *mask))
  996.         {
  997.         case FILL :
  998.             forward_cursor(field);
  999.         case SPECIAL :
  1000.             mask++;
  1001.             break;
  1002.         default :
  1003.             /* if it's negative move past that sign too */
  1004.             if (*mask == ')' || *mask == '(' || *mask == '-')
  1005.             {
  1006.                 forward_cursor(field);
  1007.                 mask++;
  1008.             }
  1009.             mask++;
  1010.             done = TRUE;
  1011.             break;
  1012.         }
  1013.         if (done)
  1014.             break;
  1015.     }
  1016.  
  1017.     /* if at end of display space do not move cursor, 
  1018.     * scroll through field_buffer
  1019.     */
  1020.     if ( cursor_col - field->fcol + 1 >= length_mask(field))
  1021.         scroll_field_left(field);
  1022.     else if ( cursor_col - field->fcol +1 < length_mask(field))
  1023.         forward_cursor(field);
  1024.  
  1025.     return mask;
  1026. }
  1027.  
  1028.  
  1029. /* 
  1030. * This routine deletes a character from the buffer
  1031. */
  1032. static void del_text_char(field)
  1033.     FIELD *field;
  1034. {
  1035.  
  1036.     int tmp_len;
  1037.  
  1038.     tmp_len = field->fieldlen + num_special_chars_in_mask - (field_buffer - field->fbuff) - 1;
  1039.     if (tmp_len < 0)
  1040.         tmp_len = 0;
  1041.  
  1042.     if (*field_buffer)
  1043.     {
  1044.         if (*field_buffer == '.')
  1045.             cursor_col = field->fcol + strlen(field->fbuff) - 1;
  1046.         if (tmp_len)
  1047.             move_text(field_buffer, field_buffer+1, tmp_len);
  1048.         field_buffer[tmp_len] = '\0';
  1049.     }
  1050. }
  1051.  
  1052.  
  1053. /* 
  1054. * The next two routines handle the scrolling.  We have the display buffer
  1055. * and a pointer to it.  We increment and decrement the pointer to the 
  1056. * start of the display buffer and then display the buffer from the pointer
  1057. */
  1058. static void scroll_field_left(field)
  1059. FIELD *field;
  1060. {
  1061.     if (*disp_buff_ptr && strlen(disp_buff_ptr) > length_mask(field))
  1062.         disp_buff_ptr++;
  1063. }
  1064.  
  1065. static void scroll_field_right()
  1066. {
  1067.     if (*disp_buff_ptr && disp_buff_ptr != display_buff)
  1068.         disp_buff_ptr--;
  1069. }
  1070.  
  1071.  
  1072.  
  1073. /*
  1074. * The next 4 routines handle the cursor position.  We keep the cursor
  1075. * column in a static variable so that moving the cursor becomes
  1076. * an elementary task, so long as the cursor_col variable does not
  1077. * get screwed up.
  1078. */
  1079.  
  1080. static void put_cursor(field, pos)
  1081.     FIELD *field;
  1082.     int pos;
  1083. {
  1084.     if (pos)
  1085.         cursor_col = pos;
  1086.     moveto_w(field->frow, cursor_col);
  1087. }
  1088.  
  1089. static void forward_cursor(field)
  1090.     FIELD *field;
  1091. {
  1092.     cursor_col++;
  1093.     moveto_w(field->frow, cursor_col);
  1094. }
  1095.  
  1096. static void back_cursor(field)
  1097.     FIELD *field;
  1098. {
  1099.     cursor_col--;
  1100.     moveto_w(field->frow, cursor_col);
  1101. }
  1102.  
  1103. static void home_cursor(field)
  1104.     FIELD *field;
  1105. {
  1106.     cursor_col = field->fcol;
  1107.     moveto_w(field->frow, cursor_col);
  1108. }
  1109.  
  1110.  
  1111. /*
  1112.  * Check that an input character is valid by looking at the current mask
  1113.  * character. 
  1114. */
  1115. static int check_char(c, mask, field)
  1116.     int *c;
  1117.     char *mask;
  1118.     FIELD *field;
  1119. {
  1120.     if (*mask == MASK_I)
  1121.         return(TRUE);
  1122.  
  1123.     if (!isprint(*c))
  1124.         return(FALSE);
  1125.  
  1126.     switch(*mask)
  1127.     {
  1128.     case MASK_C :
  1129.         /* alphabetic - convert to lower case */
  1130.         if (isupper(*c))
  1131.              *c = tolower(*c);
  1132.         if (isalpha(*c))
  1133.             return(TRUE);
  1134.         return(FALSE);
  1135.     case MASK_c :
  1136.         /* alphanumeric - convert to lower case */
  1137.         if (isalpha(*c) && isupper(*c))
  1138.             *c = tolower(*c);
  1139.         if (isalpha(*c) || isdigit(*c) || *c == '_')
  1140.             return(TRUE);
  1141.         return(FALSE);
  1142.     case MASK_X :
  1143.         /* any character - convert to upper case */
  1144.         if (islower(*c))
  1145.              *c = toupper(*c);
  1146.     case MASK_x :
  1147.         /* any character */
  1148.         return(TRUE);
  1149.     case MASK_Y :
  1150.         /* any character - convert to lower case */
  1151.         if (isupper(*c))
  1152.              *c = tolower(*c);
  1153.         return(TRUE);
  1154.     case MASK_P :
  1155.         /* alphanumeric - convert to upper case */
  1156.         if (isalpha(*c) && islower(*c))
  1157.             *c = toupper(*c);
  1158.     case MASK_p :
  1159.         /* alphanumeric */
  1160.         if (isalpha(*c) || isdigit(*c) || *c == '_' || isspace(*c))
  1161.             return(TRUE);
  1162.         return(FALSE);
  1163.     case MASK_Q :
  1164.         /* alphanumeric - convert to lower case */
  1165.         if (isalpha(*c) && isupper(*c))
  1166.             *c = tolower(*c);
  1167.         if (isalpha(*c) || isdigit(*c) || *c == '_' || isspace(*c))
  1168.             return(TRUE);
  1169.         return(FALSE);
  1170.     case MASK_A :
  1171.         /* alphabetic - convert to upper case */
  1172.         if (islower(*c))
  1173.              *c = toupper(*c);
  1174.     case MASK_a :
  1175.         if (isalpha(*c) || isspace(*c))
  1176.             return(TRUE);
  1177.         return(FALSE);
  1178.     case MASK_B :
  1179.         /* alphabetic - convert to lower case */
  1180.         if (isupper(*c))
  1181.              *c = tolower(*c);
  1182.         if (isalpha(*c) || isspace(*c))
  1183.             return(TRUE);
  1184.         return(FALSE);
  1185.     case MASK_8 :
  1186.         if (isdigit(*c) || (*c == '.' && !strchr(field->fbuff, '.')))
  1187.             return(TRUE);
  1188.         return(FALSE);
  1189.     case MASK_MONEY :
  1190.     case MASK_9 :
  1191.     case MASK_Z :
  1192.     case MASK_z :
  1193.         /* numeric */
  1194.         if (isdigit(*c))
  1195.             return(TRUE);
  1196.         return(FALSE);
  1197.     case MASK_AT :
  1198.         return(TRUE);
  1199.     case MASK_PSWD :
  1200.         if (*c == HARDSPACE)
  1201.             return(FALSE);
  1202.         return(TRUE);
  1203.     case '.' :
  1204.         if (*c == '.')
  1205.             return(TRUE);
  1206.         return(FALSE);
  1207.     case MASK_YEAR :
  1208.     case MASK_MONTH :
  1209.     case MASK_DAY :
  1210.     case MASK_HOUR :
  1211.     case MASK_MINUTE :
  1212.     case MASK_SECOND :
  1213.     case MASK_WEEKDAY :
  1214.     case MASK_DAY_SUFFIX :
  1215.         if (isdigit(*c))
  1216.             return(TRUE);
  1217.         return(FALSE);
  1218.     default :
  1219.         return(FALSE);
  1220.     }
  1221. }
  1222.  
  1223.  
  1224. static int realign_decimals(field, mask)
  1225.     FIELD *field;
  1226.     char *mask;
  1227. {
  1228.     int buf_count= 0;
  1229.     int msk_count= 0;
  1230.     int move_amount = 0;
  1231.     char *tmp1;
  1232.     char *m = mask;
  1233.  
  1234.     if (*field->fbuff)
  1235.         tmp1 = strchr(field->fbuff, '.');
  1236.     if (tmp1)
  1237.         buf_count = (int)(tmp1 - field->fbuff);
  1238.     else
  1239.     {
  1240.         if (end_display)
  1241.             buf_count = strlen(field->fbuff);
  1242.         else
  1243.             return 0;
  1244.     }
  1245.  
  1246.     while (*m)
  1247.     {
  1248.         int done = FALSE;
  1249.  
  1250.         switch (text_mask(field, *m))
  1251.         {
  1252.         case TEMPLATE :
  1253.             if (*m == '.' )
  1254.                 done = TRUE;
  1255.             if (*m != '.' && *m != '-' && *m != ')' && *m != '(') 
  1256.                 msk_count++;
  1257.             break;
  1258.         case FILL :
  1259.             if (*m == '*' && *(m-1) == '*')
  1260.                 msk_count++;
  1261.         default :
  1262.             break;
  1263.         }
  1264.         if (done)
  1265.             break;
  1266.         m++;
  1267.     }
  1268.  
  1269.     move_amount = msk_count - buf_count;
  1270.     if (move_amount < 0)
  1271.         move_amount = 0;
  1272.  
  1273.     return move_amount;
  1274. }
  1275.  
  1276. /*
  1277. *
  1278. */
  1279. static void count_special_chars_in_mask(field, mask)
  1280.     FIELD *field;
  1281.      char *mask;
  1282. {
  1283.     char *tmp_mask;
  1284.  
  1285.     tmp_mask = mask;
  1286.  
  1287.     while(*tmp_mask)
  1288.     {
  1289.         switch(*tmp_mask)
  1290.         {
  1291.         case '(' :
  1292.         case ')' :
  1293.         case '-' :
  1294.         case ' ' :
  1295.             if (field->ftype != F_DATE)
  1296.                 num_special_chars_in_mask++;
  1297.         default:
  1298.             break;
  1299.         }
  1300.         tmp_mask++;
  1301.     }
  1302.  
  1303. }
  1304.  
  1305.  
  1306. /*
  1307.  * Check the front of the input mask to see if dollar or asterisk fill / float
  1308.  * are desired during input of a numeric or calculator field 
  1309. */
  1310. static void set_negative_flag(smask)
  1311.     char *smask;
  1312. {
  1313.  
  1314.     field_negative = FALSE;
  1315.  
  1316. # ifdef MSDOS
  1317.     /* set numlock flag */
  1318.     numlock_on = FALSE;
  1319.     if (*smask == '&')
  1320.     {
  1321.         numlock_on = TRUE;
  1322.         smask++;
  1323.     }
  1324. # endif
  1325.  
  1326.     /* set the negative flags */
  1327.     if (*smask == '-' || *smask == '(' || *(smask + strlen(smask) -1) == '-' )
  1328.         field_negative = TRUE;
  1329.  
  1330. }
  1331.  
  1332.  
  1333. void clean_buffer(field)
  1334.     FIELD *field;
  1335. {
  1336.     char *b = field->fbuff;
  1337.     int fill_with_null = FALSE;
  1338.     int i;
  1339.     for (i=0; i<field->fieldlen && i<MAX_MASK; i++)
  1340.     {
  1341.         if (!*b || (field->ftype == F_NUMERIC && *b == ' '))
  1342.             fill_with_null = TRUE;
  1343.  
  1344.         *b = ( fill_with_null ? '\0' : *b);
  1345.         b++;
  1346.     }
  1347.     if (field->ftype == F_NUMERIC && *field->fbuff == '0')
  1348.         *field->fbuff = '\0';
  1349. }
  1350.  
  1351.  
  1352. static void fill_mask(field, mask)
  1353.     FIELD *field;
  1354.     char *mask;
  1355. {
  1356.     char *m = mask;
  1357.     char msk_sav;
  1358.     int i;
  1359.  
  1360.     i = strlen(m);
  1361.     if (i > field->fieldlen + num_special_chars_in_mask)
  1362.         m[field->fieldlen + num_special_chars_in_mask] = '\0';
  1363.     else if ( i < field->fieldlen && i > 1)
  1364.     {
  1365.         m += i-1;
  1366.         msk_sav = *m++;
  1367.         while ( i < field->fieldlen && i < MAX_MASK)
  1368.         {
  1369.             *m++ = msk_sav;    
  1370.             i++;
  1371.         }
  1372.         *m = '\0';
  1373.     }
  1374.  
  1375. }
  1376.  
  1377.  
  1378.  
  1379. /*
  1380.  * Check a character against all the valid mask characters for a text type
  1381.  * of field
  1382. */
  1383. static int text_mask(fld, c)
  1384.     FIELD *fld;
  1385.     char c;
  1386. {
  1387.     static int special = FALSE;
  1388.  
  1389.     /* check if c is a valid mask character */
  1390.     if (fld->ftype == F_NUMERIC)
  1391.     {
  1392.         switch (c)
  1393.         {
  1394.         case MASK_8 :
  1395.         case MASK_MONEY :
  1396.         case MASK_9 :
  1397.         case MASK_Z :
  1398.         case MASK_z :
  1399.             return(special ? FILL : TEMPLATE);
  1400.         case MASK_SPECIAL :
  1401.             special ^= TRUE;
  1402.             return(SPECIAL);
  1403.         default :
  1404.             switch (c)
  1405.             {
  1406.             case '.' :
  1407.             case '-' :
  1408.             case '(' :
  1409.             case ')' :
  1410.                 return(TEMPLATE);
  1411.             default :
  1412.                 return(FILL);
  1413.             }
  1414.         }
  1415.     }
  1416.     else if (fld->ftype == F_TEXT)
  1417.     {
  1418.         switch (c)
  1419.         {
  1420.         case MASK_I :
  1421.         case MASK_C :
  1422.         case MASK_c :
  1423.         case MASK_x :
  1424.         case MASK_X :
  1425.         case MASK_Y :
  1426.         case MASK_P :
  1427.         case MASK_p :
  1428.         case MASK_Q :
  1429.         case MASK_a :
  1430.         case MASK_A :
  1431.         case MASK_B :
  1432.         case MASK_8 :
  1433.         case MASK_MONEY :
  1434.         case MASK_9 :
  1435.         case MASK_Z :
  1436.         case MASK_z :
  1437.         case MASK_AT :
  1438.             return(special ? FILL : TEMPLATE);
  1439.         case MASK_PSWD :
  1440.             return(special ? FILL : PASSWORD);
  1441.         case MASK_SPECIAL :
  1442.             special ^= TRUE;
  1443.             return(SPECIAL);
  1444.         default :
  1445.             return(FILL);
  1446.         }
  1447.     }
  1448.     else  /* F_DATE or F_TIME */
  1449.     {
  1450.         switch (c)
  1451.         {
  1452.         case MASK_YEAR :
  1453.         case MASK_MONTH :
  1454.         case MASK_DAY :
  1455.         case MASK_HOUR :
  1456.         case MASK_MINUTE :
  1457.         case MASK_SECOND :
  1458.         case MASK_WEEKDAY :
  1459.         case MASK_DAY_SUFFIX :
  1460.             return(special ? FILL : TEMPLATE);
  1461.         case MASK_SPECIAL :
  1462.             special ^= TRUE;
  1463.             return(SPECIAL);
  1464.         default :
  1465.             return(FILL);
  1466.         }
  1467.     }
  1468. }
  1469.  
  1470.  
  1471. /* 
  1472.  * Test to see if a character is a end of input character 
  1473. */
  1474. static int endinput(c)
  1475. int c;
  1476. {
  1477.     switch (c)
  1478.     {
  1479.     case K_CR :
  1480.     case K_ESC :
  1481.     case K_UP :
  1482.     case K_DOWN :
  1483.     case K_RIGHT :
  1484.     case K_LEFT :
  1485.     case K_PGUP :
  1486.     case K_PGDN :
  1487.     case K_HOME :
  1488.     case K_END :
  1489.     case K_TAB :
  1490.     /*
  1491.     case K_BTAB :
  1492.     */
  1493.     case K_F1 :
  1494.     case K_F2 :
  1495.     case K_F3 :
  1496.     case K_F4 :
  1497.     case K_F5 :
  1498.     case K_F6 :
  1499.     case K_F7 :
  1500.     case K_F8 :
  1501.     case K_F9 :
  1502.     case K_F10 :
  1503.         return TRUE;
  1504.     default:
  1505.         return FALSE;
  1506.     }
  1507. }
  1508.  
  1509. /* 
  1510.  * Set the cursor shape.
  1511. */
  1512. # ifdef MSDOS
  1513. # include "../win/dos/pregs.h"
  1514. # endif
  1515.  
  1516. /* keep in os dependent code */
  1517. static void setcur_shape()
  1518. {
  1519. # ifdef MSDOS
  1520.  
  1521.     RegStorage;
  1522.     unsigned int cursor_size;
  1523.  
  1524.     /* set instos for inchar() and set the shape of the cursor */
  1525.    cursor_size = (instos ? 0x0106 : 0x0607);
  1526.  
  1527.     Regs_ah = 0x01;
  1528.     Regs_cx = cursor_size;
  1529.     Video();
  1530.  
  1531. # endif
  1532. }
  1533.  
  1534. /*
  1535.  * Move specified amount of text to destination from source. Do the move
  1536.  * intelligently by checking which memory location is greater.
  1537.  * (from GEO.)
  1538. */
  1539. void move_text(dest, src, cnt)
  1540.     char *dest;
  1541.     char *src;
  1542.     int cnt;
  1543. {
  1544.     int i;
  1545.     if (src == NULL || dest == NULL)
  1546.         return;
  1547.     if (src == dest)
  1548.         return;
  1549.     if (src < dest)
  1550.         /* Move up */
  1551.         for (i = cnt; i >= 0; i--)
  1552.             *(dest+i) = *(src+i);
  1553.     else
  1554.         /* Move down */
  1555.         for (i = 0; i <= cnt; i++)
  1556.             *(dest+i) = *(src+i);
  1557. }
  1558.