home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / GET10.ZIP / GETNUM.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-11-09  |  12.8 KB  |  461 lines

  1. procedure getnumber
  2.  
  3.    (num_prompt:   screen_text;
  4.     atr,atc:      byte;        {screen co-ords}
  5.     low,high:     longint;     {not checked if equal}
  6.     pattr,nattr:  byte;        {attributes}
  7. var number:       longint;
  8.     maxvalue:     longint;     {implied type}
  9.     default:      numstring);
  10.  
  11. {
  12.   Get an integer. Value of maxvalue determines implied type of argument
  13.   returned in 'number' parameter. Set maxvalue to 65535 for a word, 255
  14.   for a byte etc. Use predefined constants maxword, maxshortint etc.
  15.  
  16.   If low = high range checking is off, legal range then determined by type.
  17.   If either low or high is not appropriate for the implied type then they
  18.   are BOTH reset to their respective minimum and maximum legal values.
  19.  
  20.   Field size is determined in the first instance by the required number of
  21.   digits for the implied type (3 for a byte, 5 for a word etc.). Validation
  22.   criteria may constrain this further (byte in range 0..99 will require a
  23.   field size of only 2 digits), unless the user has ValidationOverride
  24.   privilege in which case the nominal (full) field size is used.
  25.  
  26.   If number passed is too big to be displayed in the field allowed then the
  27.   field is asterisk filled. ^Y clears, <ret> sets a blank field to a default
  28.   value if one has been specified and <esc> leaves the field unchanged.
  29. }
  30.  
  31. var
  32.     strminvalue,
  33.     strmaxvalue,
  34.     lostr,histr,
  35.     instr:         numstring;
  36.  
  37.     default_number,
  38.     minvalue,
  39.     last_number,               {last number in input loop}
  40.     save_number:   longint;    {original number}
  41.     I,code,
  42.     nominal_field_size,        {max field size for type}
  43.     field_size:    integer;    {field size currently in effect}
  44.  
  45.     dchar:         char;
  46.     finished,
  47.     negative,
  48.     numberok:      boolean;
  49.  
  50.  
  51.  
  52. function validation_on: boolean;
  53. {
  54.   Dynamic validation not attempted unless: low <= 0 <= high (and low <> high)
  55. }
  56. begin
  57.   validation_on := (low <> high) and
  58.                    (finished or ((low <= 0) and (high >= 0)));
  59. end;
  60.  
  61.  
  62. function illegal_value: boolean;
  63. begin
  64.   illegal_value := (number < minvalue) or (number > maxvalue);
  65. end;
  66.  
  67.  
  68. function IntOutOfRange: boolean;
  69. begin
  70.   IntOutOfRange :=
  71.     (validation_on and ((number < low) or (number > high))) or
  72.     illegal_value;
  73. end;
  74.  
  75.  
  76. function field_complete: boolean;
  77. begin
  78.   field_complete := ((length(instr) = field_size) and (instr[1] <> '*'));
  79. end;
  80.  
  81.  
  82. procedure reset_number (reset_value: longint);
  83. {
  84.   This procedure is used to translate a number into a string (instr) and
  85.   to reset 'negative' and 'finished' boolean variables.
  86. }
  87. begin
  88.   number := reset_value;
  89.   last_number := number;
  90.   str(number,instr);
  91.   if instr = '0' then
  92.     instr := '';
  93.   negative := number < 0;
  94.   finished := false;
  95. end;
  96.  
  97.  
  98. procedure display_number (signed_number: longint; SetFinished: boolean);
  99. {
  100.   This procedure accepts a number, transforms it to a string or series
  101.   of asterisks and displays it. The string version of the number: 'instr'
  102.   is global to the getnumber procedure.
  103.  
  104.   oldsize is used to control use of default value: instr will remain
  105.   blank, not '0', if last instr was = ''.
  106.  
  107.   instr = '0' followed by <ret> means instr := '0'
  108.   instr = ''  followed by <ret> means instr := default (if default <> '')
  109.  
  110.   default = '' means no default specified
  111.   default = 'nnn' (a number) means use this default
  112.  
  113.   low = high means no user specified range checking in effect
  114.  
  115.   Numbers outside the range for the type in effect are displayed as a string
  116.   of *'s, e.g., 999 for an implied type of byte (max value 255). This
  117.   shouldn't ever happen if this procedure is called properly using the
  118.   procedures: getlongint, getint, getshortint, getbyte and getword.
  119.  
  120.   Numbers falling outside the validation range are ALSO displayed this way.
  121.   E.g, -1 in a field of type integer (range -32768..32767) with a validation
  122.   range of 0..999.
  123.  
  124.   This is primarily because any validation range specified is used in
  125.   determining the field size (to facilitate the use of automatic field
  126.   completion -- the AutoTab option).
  127.  
  128.   However, if ValidationOverride is in effect (meaning the user has privilege
  129.   to override the validation) the maximum field size for the integer type is
  130.   used. The number failing the validation check may then be displayed by
  131.   issuing the appropriate command (^R) to temporarily (NB) relax the
  132.   validation.
  133. }
  134. var oldsize: integer;
  135.     fattr:   byte;
  136.  
  137. begin
  138.  
  139.   finished := SetFinished;
  140.  
  141.   if EditingField and not finished and (fieldcursor <> 0) then
  142.     fattr := fieldcursor
  143.   else fattr := nattr;
  144.  
  145.   oldsize := length(instr); {must precede next line}
  146.   str(signed_number,instr); {assume number in range}
  147.  
  148.   if IntOutOfRange then
  149.    {number is illegal for type or outside validation constraints}
  150.     begin       
  151.       if not escaped then
  152.         if EditingField and not illegal_value then  {no msg if field painting}
  153.           error2(NumberWord + brighten(instr) + outside_validation_range
  154.                 + brighten(lostr) + ToWord + brighten(histr));
  155.  
  156.       fillchar (instr[1],field_size,'*'); {* fill field + length byte}
  157.       instr[0] := chr(field_size);        {set length byte}
  158.       oldsize := field_size;
  159.     end;
  160.  
  161.  
  162.   if not finished then
  163.  
  164.     begin
  165.       if negative and not (instr[1] in ['-','*']) then
  166.         instr := '-' + instr;
  167.       instr := copy(instr,1,oldsize);
  168.     end
  169.  
  170.   else if instr[1] <> '*' then
  171.  
  172.     begin
  173.       if (instr = '0') and ZeroAsBlank then
  174.         instr := '';
  175.  
  176.       if ZeroFillNumbers then {takes precedence over ZeroAsBlank}
  177.         begin
  178.           if signed_number < 0 then
  179.             delete(instr,1,1);
  180.           while length(instr) < field_size do
  181.             instr := '0' + instr;
  182.           if signed_number < 0 then
  183.             instr[1] := '-';
  184.         end
  185.  
  186.       else if RightJustifyNumbers then
  187.              while length(instr) < field_size do
  188.                instr := ' ' + instr
  189.     end;
  190.  
  191.   Qfill(atr,atc,1,field_size,fattr,' ');
  192.  
  193.   if RightJustifyNumberEntry then
  194.     Qwrite(atr,atc + field_size - length(instr),fattr,instr)
  195.   else Qwrite(atr,atc,fattr,instr);
  196. end;
  197.  
  198.  
  199. procedure enter_default_value;
  200. {
  201.   Enter default if default is a valid number (illegal default values are
  202.   ignored) and either ValidationOveride is true or the number falls within
  203.   the validation range.
  204.  
  205.   This procedure may be amended to prompt for confirmation of default values.
  206. }
  207. begin
  208.   value(default,default_number,maxvalue,code);
  209.  
  210.   if code = 0 then {default is valid number}
  211.     begin
  212.       {Use ConfirmDefault here}
  213.  
  214.       if ValidationOverride then
  215.         begin
  216.           low := 0;
  217.           high := 0;
  218.         end;
  219.  
  220.       if (low <> high) and
  221.         ((default_number < low) or
  222.         (default_number > high)) then
  223.         error2(No_privilege)
  224.       else reset_number(default_number);
  225.  
  226.     end
  227.   else error2(default_is_invalid);
  228. end; {enter default}
  229.  
  230.  
  231. procedure get_input;
  232. begin
  233.   reset_number(number); {sets up instr}
  234.  
  235.   display_number(number,false);
  236.  
  237.   if RightJustifyNumberEntry then
  238.     getdigit(atr,atc + field_size,0)
  239.   else getdigit(atr,atc + length(instr),0);
  240.  
  241.   clearerror2;
  242.  
  243.   if scancode = 0 then
  244.     begin
  245.  
  246.       dchar := chr(asciicode);
  247.  
  248.       if (length(instr) = field_size) and (dchar in ['0'..'9']) then
  249.        if instr[1] = '*' then
  250.          instr := ''
  251.        else dchar := ^I; {don't allow it to get longer}
  252.  
  253.       case dchar of
  254.         ^H       : if instr[1] = '*' then
  255.                      reset_number(0)
  256.                    else if length(instr) > 0 then
  257.                      begin
  258.                        dec(ord(instr[0]));
  259.                        negative := negative and (length(instr) > 0);
  260.                      end;
  261. {
  262.                                           NOTE
  263.  
  264.                     + & -: Check if sign change allowed by validation
  265.                     constraints, then by type constraints. Asymmetry of
  266.                     or clause for + results from the fact that all
  267.                     integer types allow positive numbers
  268. }
  269.          '-'     : if instr[1] <> '*' then
  270.                      if (low < 0) or
  271.                        ((not validation_on) and (minvalue < 0)) then
  272.                        negative := not negative;
  273.  
  274.          '+'     : if instr[1] <> '*' then
  275.                      if (high > 0) or (not validation_on) then
  276.                        negative := false;
  277.  
  278.          '.',^I  : finished := instr[1] <> '*';
  279.  
  280.          ^J,^M   : if instr[1] = '*' then
  281.                      reset_number(save_number)
  282.                    else
  283.  
  284.                      begin
  285.                        if (default <> '') and
  286.                          ((dchar = ^J) or (instr = '')) then
  287.                          enter_default_value;
  288.                        finished := true;
  289.                      end;
  290.  
  291.          ^[      : begin
  292.                      reset_number(save_number);
  293.                      escaped := true;
  294.                    end;
  295.  
  296.          ^Y      : reset_number(0);
  297.  
  298.          ^U      : reset_number(save_number);
  299.  
  300.          '0'..'9': begin
  301.                      if (dchar = '0') and
  302.                        ((instr = '0') or (instr = '-0')) then
  303.                        {do nothing}
  304.                      else instr := instr + dchar;
  305.                    end;
  306.  
  307.       end; {case}
  308.  
  309.  
  310.       if not escaped and (instr[1] <> '*') then {turn string into number}
  311.         begin
  312.  
  313.           if negative then
  314.             begin
  315.               if (instr[1] <> '-') then
  316.                 instr := '-' + instr;
  317.             end
  318.           else if instr[1] = '-' then
  319.                  delete(instr,1,1);
  320.  
  321.           last_number := number;
  322.  
  323.           value(instr,number,maxvalue,code);
  324.  
  325.           if (code <> 0) then {value returns 0 for '' and '-'}
  326.             begin
  327.               error2(Number_must_be_in_range + brighten(strminvalue) +
  328.                      ToWord + brighten(strmaxvalue));
  329.               reset_number(last_number);
  330.             end;
  331.  
  332.           finished := finished or (field_complete and AutoTab);
  333.  
  334.         end; {not escaped}
  335.     end
  336.  
  337.   else {extended key}
  338.  
  339.     begin
  340.       action := get_edit(command);
  341.  
  342.       {amend here to control what extended keys are acceptable}
  343.  
  344.       case action of
  345.  
  346.         tabback: finished := instr[1] <> '*';
  347.  
  348.         reset: if ValidationOverride then {user has privilege}
  349.                  begin
  350.                    if low <> high then
  351.                      info2(Range_checking_suspended);
  352.  
  353.                    low := 0;
  354.                    high := 0;
  355.  
  356.                    reset_number(save_number);
  357.                  end
  358.                else error2(No_privilege);
  359.  
  360.         help,
  361.         upchar,
  362.         downchar,
  363.         leftchar,
  364.         rightchar,
  365.         pageup,
  366.         pagedown,
  367.         scrollup,
  368.         scrolldown,
  369.         goto_top,
  370.         goto_bottom,
  371.         abort,
  372.         exit_screen,
  373.         quit:
  374.  
  375.                  begin
  376.                    reset_number(save_number);
  377.                    finished := true;
  378.                  end;
  379.  
  380.  
  381.       else error2(Invalid_key);
  382.       end; {case}
  383.     end;
  384. end;
  385.  
  386.  
  387. procedure warn_user_number_is_invalid;
  388. begin
  389.   if abs(high - low) > 1 then
  390.     error2(Enter_a_number_between + brighten(lostr) + AndWord +
  391.            brighten(histr))
  392.   else
  393.     error2(Enter_either + brighten(lostr) + OrWord + brighten(histr));
  394.  
  395.   reset_number(save_number);
  396. end;
  397.  
  398.  
  399. begin {getnumber}
  400.   escaped := false;
  401.   finished := false;  {used in setting validation_on}
  402.  
  403.   save_number := number;
  404.   last_number := number;
  405.  
  406.   if low > high then
  407.     begin
  408.       low := 0;
  409.       high := 0;
  410.     end;
  411. {
  412.   Nominal field size depends on implied type of integer to return
  413. }
  414.   if (maxvalue = maxword) or (maxvalue = maxbyte) then
  415.     minvalue := 0
  416.   else minvalue := pred(-maxvalue);
  417.  
  418.   str(minvalue,strminvalue);
  419.   str(maxvalue,strmaxvalue);
  420.   nominal_field_size := maxW(ord(strminvalue[0]),ord(strmaxvalue[0]));
  421.  
  422.   if (low < minvalue) or (high > maxvalue) then
  423.     begin
  424.       low := minvalue;
  425.       high := maxvalue;
  426.     end;
  427. {
  428.   Find out how many digits to allow for input. Lower number may be longer,
  429.   e.g., a range of -999 to 99. Decrease field size if necessary.
  430. }
  431.   str(low,lostr);
  432.   str(high,histr);
  433.  
  434.   if ValidationOverride or not validation_on then
  435.     field_size := nominal_field_size
  436.   else field_size := minW(maxW(ord(lostr[0]),ord(histr[0])),nominal_field_size);
  437.  
  438.   SetCursor(CursorOn or CursorUnderline);
  439.   clearerror2;
  440.   numberok := false;
  441.  
  442.   display_prompt(num_prompt,atr,atc,pattr,field_size);
  443.  
  444.   if not PaintingFields then
  445.     repeat
  446.       repeat
  447.         get_input
  448.       until finished or escaped or IntOutOfRange;
  449.  
  450.       numberok := (not IntOutOfRange) or Escaped;
  451.       if not numberok then
  452.         warn_user_number_is_invalid;
  453.  
  454.     until numberok
  455.   else 
  456.     reset_number(number); {sets up instr}
  457.  
  458.   display_number(number,true);
  459.   SetCursor(CursorOff);
  460. end; {getnum}
  461.