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

  1. /*! wscanform() and wprintform()
  2.  *
  3.  * This file contains wscanform() and wprintform(),
  4.  *    which are the two form-handling routines for the windows package
  5.  *    Also contains slave routines that do small tasks for the two major()
  6.  *
  7.  * WSCANFORM -  collects all the initial values for the form into a buffer,
  8.  *              draws the form, along with a highlighted selection bar
  9.  *        accepts user keystrokes, which can either...
  10.  *            move the highlight bar to another item
  11.  *            enter new data to the item
  12.  *            restore original data to fields.
  13.  *            Save data and quit, or just plain quit
  14.  *        if new data is entered, it is validated:
  15.  *            numeric data is checked for correct format
  16.  *            optional special editting functions are called
  17.  *        when all data is entered,
  18.  *            Entire form can be validated
  19.  *            data stored to program areas
  20.  *
  21.  *
  22.  * WPRINTFORM - MUCH SIMPLER, output only version.
  23.  *        start with this routine to decipher wscanform
  24.  *        gathers initial values into buffer,
  25.  *        prints values and labels on screen,
  26.  *        returns.
  27.  *
  28.  *
  29.  *
  30.  * See typedef WFORM, provided as a comment below:
  31.  *
  32.  * the table is terminated by a NULL in the wflabel position.
  33.  *
  34.  * FIRST LINE line of the table is the header: form title, final validation
  35.  *
  36.  * DATA LINES may be type 's' (string) 'c' (char) 'f' (float) or 'i' (int)
  37.  *    doubles, long int, octal, hex, and pointers not supported.
  38.  * a picklist may be specified instead of hand-typed entry.
  39.  * a form item may be a 'pure label' ie, only the wflabel is printed,
  40.  * the x,y positions for data items determine the screen start of the data
  41.  *    the label is placed before the data.
  42.  *    Be sure the label fits in the space you provided.
  43.  *
  44.  * LAST LINE is markded by a NULL in the wflabel position,
  45.  *    provide an x,y size of the form
  46.  *
  47.  *    CAUTION: code strongly depends on first and last lines not being 'labels'
  48.  *
  49.  *    RETURNS:  ENTER or ESCAPE
  50.  */
  51. #include "wsys.h"
  52.  
  53.  
  54.  
  55.     /* FAR POINTER COMPARISON MACROS
  56.      *    These macros allow far ptrs to be compared looking only at offset part.
  57.      *
  58.      *  This improves code size and speed, but is dangerous...
  59.      *     only will work if the segment portions of ptrs are same
  60.      *        (ie, NORMALIZE macro only applied once and all ptrs then computed)
  61.      *
  62.      * ALSO, don't use to compare against the NULL pointer, won't work.
  63.      * AND, don't even think about fooling with the extra ().
  64.      *
  65.      *    IF this coding practice scares you, 
  66.      *            convert the (void near*) to (void huge*) which is always safe
  67.      *
  68.      *    NOTE that simply comparing the pointers without either cast 
  69.      *        may also generate incorrect code in large model
  70.      *
  71.      *    REFERENCE: TURBO C user's guide, 'MEMORY MODELS...POINTERS'
  72.      *        note that the < and > macros are redundant, but included for clarity
  73.      */
  74. #define FARPTR_EQ(aa,bb)  ( ((void near*)(aa))  ==  ((void near*)(bb)) ) 
  75. #define FARPTR_GT(aa,bb)  ( ((void near*)(aa))  >   ((void near*)(bb)) ) 
  76. #define FARPTR_LT(aa,bb)  ( ((void near*)(aa))  <   ((void near*)(bb)) ) 
  77.  
  78.  
  79.  
  80. char wfmatr_lbl = CYAN,                    /* labels                             */
  81.      wfmatr_lbl_active =(LIGHTGRAY<<4),    /* label indicating active data item */
  82.      wfmatr_border = CYAN,                /* form border                         */
  83.      wfmatr_title  = CYAN,                /* form title                        */
  84.      wfmatr_data   = CYAN,                 /* inactive data                    */
  85.      wfmatr_data_active=LIGHTCYAN;        /*active data item (while typing)     */
  86.  
  87. int     wfm_border_type = DOUBLE_BORDER;
  88.  
  89. char wfm_autoskip =0;                    /* set to WGETS_SKIP for autoskip */
  90.  
  91.  
  92. /*! local functions
  93.  *
  94.  *  print_labels:
  95.  *    local function to draw the labels in the form
  96.  *    with the current choice highlighted,
  97.  *
  98.  *  print_values:
  99.  *    print on the screen the current values of all the data items.
  100.  *
  101.  *  get_user_data:
  102.  *    pull user data (original values) into the work buffer
  103.  *
  104.  *  numeric2workarea:
  105.  *    convert numeric data of any type into string.
  106.  *    type and maximum length indicated by form table.
  107.  *
  108.  *  setup_window:
  109.  *    scan the form table, compute size of window,
  110.  *    fill in data type values in form table,
  111.  *    compute size of workarea, allocate workarea buffers,
  112.  *
  113.  *
  114.  */
  115. static void     W_NEAR    print_labels ( WFORM *form, WFORM *mark );
  116. static void     W_NEAR    print_label_line ( WFORM *form, unsigned char attr );
  117. static void     W_NEAR    get_user_data ( WFORM *form, char *workarea );
  118. static void     W_NEAR    numeric2workarea
  119.                 (WFORM *form, char *workarea, void *data );
  120.  
  121. static void     W_NEAR    print_values (WFORM *form, char *workarea );
  122. static void     W_NEAR    print_single_value (WFORM *form, char *workarea );
  123.  
  124. static void     W_NEAR    setup_window
  125.         (WFORM *formstart, WFORM **formlast,
  126.          char **workstart, int *worksize, char **worklast);
  127.  
  128.  
  129.  
  130.  
  131. /* Use the 'reserved' byte in the form table to count the length of
  132.  * the string data storage area.
  133.  */
  134. #define  wftype wfspecial
  135.  
  136.  
  137. /* minimum width of a form, required by buttons
  138.  */
  139. #define MIN_WIDTH       41
  140.  
  141.  
  142. /*! wscanform()
  143.  *
  144.  */
  145. int wscanform (char *title, WFORM *formstart)
  146.     {
  147.  
  148.     /* pointers into the MENU tables
  149.      *    the following pointers point to which pointers to use
  150.      *    'item' is the line currently being examined
  151.      *    'mark' is the most recent user choice
  152.      *
  153.      */
  154.     WFORM     *item,        /* ptr to a   form line in table*/ 
  155.             *mark,        /* ptr to the form line currently active */  
  156.             *old_mark,    /* ptr to prev.    line */ 
  157.             *formlast;    /* ptr to last valid (non-NULL) form line in table */
  158.  
  159.     WFORM *msitem, *mouse_mark;    /* mouse scratch areas */
  160.     char  *mschar, *mouse_workarea;
  161.  
  162.     int     key = 0, control_key =0, errors, done =0;
  163.  
  164.     char     *workarea, *workstart, *worklast;
  165.     int     worksize;
  166.  
  167.     /* numeric (conversion) work areas
  168.      */
  169.     int     n;
  170.     char     numbers[40];    /* long enough to hold any float */
  171.  
  172.     /* picklist work pointer
  173.      */
  174.     char *pickptr;
  175.     
  176.     char gets_behavior;        /* flag to govern wgets() */
  177.  
  178.     char save_title_atr;
  179.  
  180.  
  181.     /* global validation function (see last line of form)
  182.      */
  183.     int  (*glob_func)(WFORM *, char *);
  184.  
  185.     _NORMALIZE (formstart);        /* model-dependent */
  186.  
  187.  
  188.     setup_window
  189.         (formstart, &formlast, &workstart, &worksize, &worklast);
  190.  
  191.     if ( title != NULL )
  192.         {
  193.         save_title_atr = w0-> winboxcolor;
  194.           w0-> winboxcolor = wfmatr_title;
  195.         wtitle (title);
  196.         w0-> winboxcolor = save_title_atr;
  197.         }
  198.  
  199.  
  200.  
  201.     /* setup the 'mark' ptr to indicate which field is active
  202.      */
  203.     mark      = formstart;
  204.  
  205.     workarea = workstart;    /* point to work string */
  206.  
  207.  
  208.  
  209.  
  210.     get_user_data (formstart, workstart);
  211.     print_values  (formstart, workstart);
  212.  
  213.     /* write instructions
  214.      *
  215.      *
  216.      */
  217.     n= w0->winymax;                                        /* options */
  218.     wbutton_add ("ESCAPE",             1, n, 7, ESCAPE,     0);
  219.     wbutton_add ("Ctrl-Original",      8, n, 14, CTRL('O'), 0);
  220.     wbutton_add ("Ctrl-Save",         22, n, 10, CTRL('S'), 0);
  221.     wbutton_add ("F1-HELP",           32, n,  8, FKEY(1),   0);
  222.  
  223.     old_mark = mark;
  224.     print_labels (formstart, mark);
  225.  
  226.     /*! loop
  227.      *
  228.      *
  229.      *     main loop for form routine
  230.      *                {
  231.      *                get key
  232.      *                check for mouse field movement 
  233.      *                keyboard field movement (and/or termination cmds)
  234.      *                data entry
  235.      *                }
  236.      *
  237.      *
  238.      */
  239.     while ( ! done )
  240.     {
  241.     whelp_ptr = mark-> wflabel;        /* setup help ptr for this form item */
  242.  
  243.     /* if we need to process a control key code from last time around, do it
  244.      * else, get next keystroke from keyboard 
  245.      */
  246.     key =  ( control_key ) ? control_key : wgetc ();
  247.     
  248.     control_key = 0;        /* prevent re-use of control key */
  249.  
  250.     /*----------------- MOUSE FIELD MOVEMENT CONTROL -----------*/
  251.     if ( key == MOUSE )
  252.         {
  253.         if ( (wmouse.wms_used & WMS_LEFT_RLS) && wmouse.wms_inwindow )
  254.             {
  255.             /* left button and mouse in window */
  256.  
  257.             /* scan  the form
  258.              * (and move through workarea simultaneously)
  259.              *
  260.              */
  261.             mouse_mark = NULL;
  262.             mouse_workarea = NULL;
  263.             for (mschar = workstart, msitem = formstart;    
  264.                  msitem-> wflabel !=NULL;                    
  265.                  mschar += msitem-> wflen, ++msitem )    /* keep them together */
  266.                 {
  267.                 /* as long as current entry is above
  268.                  * mouse position, keep as a 'possible' selection
  269.                  */
  270.                 if ( msitem-> wfy <= wmouse.wms_y
  271.                      && msitem-> wfx <= wmouse.wms_x
  272.                      && msitem-> wfuser != NULL
  273.                    )
  274.                     {
  275.                     /* hang on to choice - will end up using highest one
  276.                      */
  277.                     mouse_mark = msitem;
  278.                     mouse_workarea = mschar;
  279.                     }
  280.                 }    /* end scan for mouse line */
  281.             
  282.             if ( mouse_mark != NULL )        /* mouse found a data item */
  283.                 {
  284.                 /* move to 'moused' line. 
  285.                  */
  286.                 mark = mouse_mark;
  287.                 workarea = mouse_workarea;
  288.                 key = ENTER;                /* triggers data entry below */
  289.                 }
  290.  
  291.             }
  292.         }    /* end of MOUSE field movement control */
  293.  
  294.     /* KEYBOARD FIELD MOVEMENT CONTROL */
  295.     
  296.     switch (key) 
  297.         {
  298.     case (BACKTAB):
  299.     case (UP_ARROW):
  300.         /* loop backwards until a field is found
  301.          */
  302.         while ( FARPTR_GT (mark, formstart )) 
  303.         /* backwards until a field is found*/
  304.             { 
  305.             --mark;
  306.             /* leave loop when a data field is found (ie, not a label)
  307.              */
  308.             if ( mark -> wfuser != NULL )   
  309.                 {
  310.                 /* keep the workarea pointer in the right place
  311.                  */
  312.                 workarea -= mark->wflen;
  313.                 break;                        /* break from while(mark) */
  314.                 }
  315.             }
  316.         break;        /* break from switch(key) */
  317.  
  318.     case (TAB):
  319.     case (DOWN_ARROW):
  320.  
  321.         if ( FARPTR_EQ (mark, formlast) )  /*roll to top if at bottom */
  322.             {
  323.             mark = formstart;
  324.             workarea = workstart;
  325.             }
  326.         else                        /* advance until a field is found*/
  327.         while (FARPTR_LT (mark, formlast) )         
  328.             { 
  329.             /* keep the workarea pointer in the right place
  330.              * NOTE this has to be done before moving mark.
  331.              */
  332.             workarea += mark->wflen;
  333.             
  334.             ++mark;
  335.             /* leave loop when a data field is found (ie, not a label)
  336.              */
  337.             if ( mark -> wfuser != NULL )   
  338.                 {
  339.                 break;                        /* break from while(mark) */
  340.                 }
  341.             }
  342.  
  343.         break;        /* break from switch (key) */
  344.  
  345.     case ( ESCAPE ):
  346.  
  347.         wsetlocation ( WLOC_ATWIN, 2, w0->winymax +1 );
  348.         if     (ESCAPE == ( wpromptc (NULL,
  349.                                 "Quit without saving or Continue form entry?",
  350.                                  "CONTINUE", NULL) )
  351.             )
  352.             {
  353.             done = ESCAPE;
  354.             }
  355.         
  356.     case (HOME):
  357.         mark = formstart;
  358.         workarea = workstart;
  359.         break;
  360.  
  361.     case (END):
  362.         mark = formlast;
  363.         workarea = worklast;
  364.         break;
  365.  
  366.     case ( CTRL('S') ):
  367.         /* see if data in form is valid
  368.          */
  369.         glob_func = (formlast+1)-> wfvalidate;
  370.  
  371.         if ( glob_func != NULL)
  372.             {
  373.             errors = (*glob_func)(formstart, workstart);
  374.             }
  375.         else
  376.             {
  377.             errors = 0;
  378.             }
  379.  
  380.  
  381.         /* update and then quit
  382.          */
  383.         if ( ! errors )
  384.             {
  385.             wsetlocation ( WLOC_ATWIN, 31, w0->winymax+1 );
  386.  
  387.             if     ('S' ==  (wpromptc (NULL, "Save new values ?","Save", NULL) ) )
  388.                 {
  389.                 /* update user data from workarea
  390.                  */
  391.                 for (    item= formstart, workarea= workstart;
  392.                     item->wflabel != NULL;
  393.                     workarea += item->wflen,  ++item
  394.                     )
  395.                     {
  396.                     if (item ->wfuser != NULL)
  397.                         {
  398.                         switch ( item ->wftype )
  399.                             {
  400.                         case ( 'c' ):
  401.                             *((char*)(item->wfuser))= *workarea;
  402.                             break;
  403.  
  404.                         case ( 's' ):
  405.                             strcpy( (char*)(item->wfuser), workarea );
  406.                             break;
  407.  
  408.                         default:
  409.                             sscanf (workarea, item->wformat, item->wfuser);
  410.                             }/* end switch */
  411.                         }
  412.                     }
  413.                 /* end of updating */
  414.                 done =ENTER;
  415.                 }    /* end if (key) */
  416.             }       /* end if (errors) */
  417.  
  418.         break;
  419.  
  420.     case ( CTRL('O') ):
  421.         /* refresh workarea with original data */
  422.         wsetlocation ( WLOC_ATWIN, 10, w0->winymax +1);
  423.  
  424.         if     ('O'== (wpromptc (NULL, "Refresh form with original data?",
  425.                 "Original data", NULL))
  426.             )
  427.             {
  428.             get_user_data   (formstart, workstart);
  429.             print_values    (formstart, workstart);
  430.             }
  431.         break;
  432.     default: ;
  433.     }                // end switch (key)
  434.  
  435.     /* If we've changed lines 
  436.      *   by TAB or BACKTAB in pass thru loop),
  437.      * then need to draw label to indicate new active line.
  438.      */
  439.     if ( !  FARPTR_EQ (old_mark, mark ) )
  440.         {
  441.         print_label_line ( old_mark, wfmatr_lbl );
  442.         print_label_line ( mark,     wfmatr_lbl_active );
  443.         wsetattr (wfmatr_lbl);    /* keep attribute set as wformattr */
  444.         old_mark = mark;
  445.         }
  446.     /*----- end of FIELD MOVEMENT CONTROL -----------*/
  447.  
  448.  
  449.     /*------------------- DATA ENTRY -------------------*/
  450.  
  451.     if ( (isascii(key) && isprint (key))
  452.          || key == RIGHT_ARROW     || key == DELETE
  453.          || key == INSERT         || key == ENTER
  454.        )
  455.         {
  456.         /* Start data entry at currently marked field.
  457.          * put key back in buffer for wgets() or for wpicklist() to use
  458.          */
  459.         if ( key != ENTER )
  460.             {
  461.             wungetc(key);
  462.             }
  463.         control_key = 0;
  464.         if ( mark-> wfpick != NULL )    /* this field uses a picklist */
  465.             {
  466.             /* adjust location of list to under and right of item
  467.              *
  468.              */
  469.             wgoto ( mark ->wfx, mark -> wfy );
  470.             wlocation.wloc_type = WLOC_ATCUR;
  471.             wlocation.wloc_x    = 4;
  472.             wlocation.wloc_y    = 1;
  473.  
  474.             n = wpicklist (NULL, mark->wfpick);
  475.  
  476.             pickptr = (mark->wfpick) [n];
  477.  
  478.             if ( pickptr != NULL )        /* not ESCAPE from user */
  479.                 {
  480.                 memcpy ( workarea, pickptr, mark->wflen );
  481.                 *(workarea +((mark->wflen)-1) ) = 0;
  482.                 control_key = ENTER;        /* move to next form line */
  483.                 }
  484.  
  485.             }    /*end get picklist */
  486.         else
  487.             {
  488.  
  489.             /* activate wgets()
  490.              * setup screen position, attribute changes, and form control flag
  491.              */
  492.             switch ( mark->wftype )
  493.                 {
  494.             case ( 'f' ):
  495.             case ( 'e' ):
  496.             case ( 'g' ):
  497.             case ( 'E' ):
  498.             case ( 'G' ):
  499.                     gets_behavior = WGETS_FORM + WGETS_INT + WGETS_DEC;
  500.                     break;
  501.             case ( 'u' ):
  502.             case ( 'i' ):
  503.             case ( 'd' ):
  504.                     gets_behavior = WGETS_FORM + WGETS_INT;
  505.                     break;
  506.             default:
  507.                     gets_behavior = WGETS_FORM;
  508.                 }
  509.                 /* end switch */
  510.                 
  511.             gets_behavior  |=  wfm_autoskip;
  512.             
  513.             wgoto (mark->wfx, mark->wfy);
  514.             
  515.             wsetattr (wfmatr_data_active);        /* highlight */
  516.             control_key = wgets ( mark-> wflen, workarea, gets_behavior );
  517.             wsetattr (wfmatr_lbl);
  518.  
  519.             if  ( control_key == ESCAPE || control_key == CTRL('O') ) 
  520.                     {
  521.                     /*These requests apply to single field only, not whole form
  522.                      */                    
  523.                     control_key = 0;
  524.                     }
  525.  
  526.             /* If numeric, (ie, not string or char)          
  527.              *    convert strings into numeric values and back again
  528.              *    so user can see whether his input was valid
  529.              * make sure the terminal nulls don't get lost.
  530.              */
  531.             if ( ! (mark-> wftype == 's' || mark->wftype == 'c'))
  532.                 {
  533.                 sscanf (workarea, mark->wformat, (void *) numbers);
  534.                 numeric2workarea (mark, workarea, numbers);
  535.                 }
  536.                 /* end integer data conversion */
  537.                 /* end numeric data conversion */
  538.             }  /* end if ... else... use wgets() to get data */
  539.  
  540.  
  541.         /* if a wfvalidate() function was specified
  542.          * for this field, execute it now.
  543.          */
  544.         if (  ( (mark->wfvalidate) != NULL )
  545.             &&
  546.               ( 0 != (*mark->wfvalidate) (mark, workarea) )
  547.             )
  548.             {
  549.             /* invalid data
  550.              */
  551.             control_key = RIGHT_ARROW;    /*force to re-enter this item */
  552.             }
  553.             
  554.         else
  555.             {
  556.             if ( control_key == ENTER )    /* returned code from wgets() */
  557.                 {
  558.                 control_key =TAB;        /* valid data ENTER'd, so move down */
  559.                 }
  560.             }
  561.         /* The string was highlighted while doing wgets()
  562.          * now replace it with a non-highlighted version
  563.          */
  564.         print_single_value ( mark, workarea );
  565.  
  566.         }    /* end if ... get new data     END DATA ENTRY */
  567.  
  568.  
  569.  
  570.  
  571.     }    /*end of while(!done) loop for menu control*/
  572.  
  573.  
  574.     /* terminate form processing = cleanup
  575.      */
  576.  
  577.     free (workstart);
  578.  
  579.     wclose ();
  580.  
  581.     return (done);        /* wscanform */
  582.     }
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590.  
  591. /* wprintform()
  592.  *    like wscanform() but output only, and leaves window on screen
  593.  *    This is obviously a simple program,
  594.  *    it just calls the setup and output routines used by wscanform()
  595.  *
  596.  */
  597.  
  598.  
  599. void wprintform (char *title, WFORM *formstart)
  600.     {
  601.  
  602.     /* pointers into the MENU tables
  603.      *    the following pointers point to which pointers to use
  604.      *    'item' is the line currently being examined
  605.      *    'mark' is the most recent user choice
  606.      *
  607.      */
  608.     WFORM   *formlast;
  609.  
  610.     char save_title_atr;
  611.  
  612.  
  613.  
  614.     char     *workstart, *worklast;
  615.     int     worksize;
  616.  
  617.  
  618.     _NORMALIZE (formstart);        /* model-dependent */
  619.  
  620.  
  621.  
  622.  
  623.     setup_window
  624.         (formstart, &formlast, &workstart, &worksize, &worklast);
  625.  
  626.     if ( title !=  NULL )
  627.         {
  628.         save_title_atr = w0-> winboxcolor;
  629.           w0-> winboxcolor = wfmatr_title;
  630.         wtitle (title);
  631.         w0-> winboxcolor = save_title_atr;
  632.         }
  633.  
  634.     get_user_data (formstart, workstart);
  635.     print_values  (formstart, workstart);
  636.  
  637.  
  638.     print_labels (formstart, NULL);
  639.  
  640.  
  641.     free (workstart);
  642.  
  643.  
  644.     return;        /* wprintform */
  645.     }
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.  
  662. /*! print_labels ()
  663.  *    local function to draw the all the labels in the form
  664.  *    with the current choice highlighted,
  665.  */
  666. static  void     W_NEAR print_labels ( WFORM *form, WFORM *mark )
  667.     {
  668.  
  669.     /* loop through the form
  670.      */
  671.  
  672.     do    {
  673.         if ( FARPTR_EQ (form, mark) )
  674.             {
  675.             print_label_line ( form, wfmatr_lbl_active);
  676.             }
  677.         else
  678.             {
  679.             print_label_line ( form, wfmatr_lbl );
  680.             }
  681.         }
  682.     while ( (++form) ->wflabel != NULL );
  683.  
  684.     wsetattr (wfmatr_lbl);
  685.  
  686.     return;    /* print_labels */
  687.     }
  688.  
  689. /* draw an individual label, in the indicated attribute.
  690.  */
  691. static void     W_NEAR    print_label_line ( WFORM *form, unsigned char attr )
  692.     {
  693.     int x;
  694.     x= form->wfx -strlen(form->wflabel);
  695.     if ( x < 0 )
  696.         {
  697.         x=0;
  698.         }
  699.     wgoto ( x, form-> wfy);
  700.  
  701.     wsetattr(attr);
  702.     wputs (form->wflabel);
  703.     return;        /* print_label_line */
  704.     }
  705.  
  706.  
  707.  
  708. static void W_NEAR get_user_data ( WFORM *form, char *workarea )
  709.     {
  710.  
  711.  
  712.     /* loop through the form
  713.      */
  714.  
  715.  
  716.     do    {
  717.         if ( form->wfuser != NULL )
  718.             {
  719.             switch ( form ->wftype )
  720.                 {
  721.             case ( 'c' ):
  722.                 *workarea = *((char *) (form->wfuser));
  723.                 *(workarea+1) =0;
  724.                 break;
  725.  
  726.             case ( 's' ):
  727.                 memcpy (workarea, ((char *)(form->wfuser)),
  728.                         form->wflen);
  729.  
  730.                 break;
  731.  
  732.             default:
  733.                 numeric2workarea (form, workarea, form->wfuser);
  734.  
  735.  
  736.                 }  /* end switch */
  737.  
  738.             } /* end if user data */
  739.  
  740.         /* next item */
  741.         workarea += form->wflen;
  742.         ++form;
  743.         /* guarantee terminal NULL on last item
  744.          * (we've just moved past the area
  745.          */
  746.         *(workarea -1) =0;
  747.         }
  748.     while ( form->wflabel != NULL );
  749.  
  750.  
  751.     return; /* get_user_data */
  752.     }
  753.  
  754.  
  755. static void W_NEAR numeric2workarea (WFORM *form, char *workarea, void *data )
  756.     {
  757.     char scratch[80];
  758.  
  759.  
  760.     switch ( form->wftype )
  761.         {
  762.     case ( 'f' ):
  763.     case ( 'e' ):
  764.     case ( 'g' ):
  765.     case ( 'E' ):
  766.     case ( 'G' ):
  767.         sprintf (scratch, form->wformat,
  768.             *((float*)(data)) );
  769.             break;
  770.     case ( 'i' ):
  771.     case ( 'd' ):
  772.         sprintf (scratch, form->wformat,
  773.                  *((int*)(data)) );
  774.         break;
  775.     case ( 'u' ):
  776.     case ( 'x' ):
  777.     case ( 'X' ):
  778.     case ( 'o' ):
  779.         sprintf (scratch, form->wformat,
  780.             *((unsigned int*)(data)) );
  781.         break;
  782.         }
  783.         /* end swicth */
  784.  
  785.     memcpy (workarea, scratch, form->wflen);
  786.     *(workarea + form->wflen -1) =0;
  787.  
  788.     return;  /* numeric2workarea */
  789.     }
  790.  
  791.  
  792.     /* loop through the form, print all user values onscreen.
  793.      */
  794. static void W_NEAR print_values (WFORM *form, char *workarea )
  795.     {
  796.     do    {
  797.         if ( form->wfuser != NULL)
  798.             {
  799.             print_single_value ( form, workarea );
  800.             
  801.             wputc(';');    /* mark end of field */
  802.  
  803.             workarea += form-> wflen;
  804.             }
  805.         }
  806.     while ( (++form) ->wflabel != NULL );
  807.  
  808.     return;     /* print_values */
  809.     }
  810.  
  811. /* print a single line of data, clear field that follows.
  812.  */
  813. static void W_NEAR print_single_value ( WFORM *form, char *workarea )
  814.     {
  815.     wgoto (form->wfx, form-> wfy);
  816.     wputfl (workarea, (form->wflen) );
  817.  
  818.     return;        /* print_single_value */
  819.     }
  820.  
  821.  
  822.  
  823. static void W_NEAR setup_window
  824.         (WFORM *formstart, WFORM **formlast,
  825.          char **workstart, int *worksize, char **worklast)
  826.  
  827.     {
  828.     int left, top, width, height;
  829.     char *buffer;
  830.     int buffsize;
  831.  
  832.     WFORM *item;
  833.  
  834.  
  835.  
  836.  
  837.  
  838.     /* scan the form table, calculate the size of the window
  839.      *    and the size of the work area
  840.      * Place the data type (single char) into wfreserved for later use.
  841.      *
  842.      */
  843.     buffsize = 0;
  844.     for (item = formstart;  item->wflabel != NULL; ++item   )
  845.         {
  846.         if (item->wfuser == NULL)
  847.             {
  848.             /* fields with no data, only labels */
  849.             item->wflen =0;                /* prevent errors later */
  850.             }
  851.         else    {
  852.             buffsize += item->wflen;
  853.             }
  854.         /* check data type against supported types,
  855.          * move single char type into form table
  856.          */
  857.         item->wftype = *(item->wformat +
  858.                 strcspn ( item->wformat, "csidfegEGouxX") );
  859.  
  860.  
  861.         _NORMALIZE ( (item->wfpick) );
  862.  
  863.  
  864.         } /* end for... scanning table ... */
  865.  
  866.     *formlast = item -1;    /* last line before NULL line. */
  867.  
  868.  
  869.  
  870.  
  871.     buffer      = wmalloc (buffsize, "form input");
  872.  
  873.  
  874.     /* setup window location
  875.      */
  876.  
  877.  
  878.     width   = item     ->wfx;    /* last entry gives lower/right */
  879.     height  = item        ->wfy;
  880.  
  881.  
  882.     width   = max ( width, MIN_WIDTH );
  883.     width   = min ( width, wxabsmax-2 );    /* fits onscreen */
  884.  
  885.  
  886.     wlocate ( &left, &top, width, height );
  887.  
  888.  
  889.     wopen   ( left, top, width, height,
  890.         wfmatr_lbl, wfm_border_type, wfmatr_border, WSAVE2RAM );
  891.  
  892.  
  893.     /* point to last string in the workarea
  894.      * find item by going to the end of the workarea
  895.      * and the stepping backwards by the sizeof the last entry
  896.      */
  897.  
  898.     *worklast  = buffer +buffsize - ( (*formlast) ->wflen);
  899.  
  900.  
  901.     /* setup other values in calling function's areas */
  902.  
  903.     *workstart = buffer;
  904.     *worksize  = buffsize;
  905.  
  906.     return;    /* setup_window */
  907.     }
  908.  
  909.  
  910. /*-----------------END of WFORM.C--------------------------------------*/
  911.  
  912.  
  913.  
  914.