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

  1. procedure getdatestr
  2.  
  3.    (date_prompt:      screen_text;
  4.     atr,atc:          byte;        {screen co-ords}
  5. var datestr:          string;
  6.     status:           byte);       {use SystemDefault: bit 2; mandatory: bit 1}
  7.  
  8. begin
  9.   getdatestring(date_prompt,Default_pattr,atr,atc,Default_dattr,
  10.                 Default_cursor_attr,Default_pattr,datestr,status);
  11. end;
  12.  
  13. procedure getdatestring
  14.  
  15.    (date_prompt:      screen_text;
  16.     pattr:            byte;        {prompt attribute}
  17.     atr,atc,                       {screen co-ords}
  18.     dattr,                         {date attribute}
  19.     cursor_attr,                   {cursor attribute}
  20.     separator_attr:   byte;        {date subfield separator attribute}
  21. var datestr:          string;
  22.     status:           byte);       {use SystemDefault: bit 2; mandatory: bit 1}
  23.  
  24. {
  25.   It is expected that the format of the date entered e.g. dd/mm/yy will
  26.   match that indicated by the global variables DateFormat and YearFormat.
  27.   No validation is performed to assure this.
  28.  
  29.   Expected        DateFormat
  30.  
  31.   mm/dd/[yy]yy    American
  32.   dd/mm/[yy]yy    European
  33.   [yy]yy/mm/dd    Japanese
  34.  
  35.   [19]yy or yyyy controlled by value of YearFormat: YY, NY, YYYY
  36.  
  37.   YearFormat = NY means 19yy (N for Nineteen)
  38.  
  39.   datestr is expected to be 10 characters long if YearFormat is YYYY
  40.   otherwise (YearFormat = NY or YY) it is expected to be 8 characters
  41.   long.
  42.  
  43.   Dates are expected with and are returned with separators between
  44.   component subfields.
  45.  
  46.   In a blank date field enter_default (^J) is acceptable in the first
  47.   subfield ONLY.
  48. }
  49. var
  50.     old_datestr,
  51.     year_picture,
  52.     month,day,year: string;
  53.     code:           integer;
  54.     M,D:            longint; {for compatibility with 'value' procedure}
  55.     Y:              word;    {used for determining leap years}
  56.     lastedit:       word;
  57.  
  58.     SystemDefault,           {use system date as default}
  59.     finished,
  60.     mandatory,               {date field as a whole}
  61.     MandatoryDay,
  62.     MandatoryMonth,
  63.     MandatoryYear,
  64.     OldInsLock,
  65.     OldAutoTab,
  66.     OldPainting,
  67.     OldStringFieldWrap,
  68.     Old_Top_n_tail,
  69.     DateOk:         boolean;
  70.  
  71.  
  72.     sf1,sf2:        char;    {subfield separators}
  73.  
  74.     OldTabsize,
  75.     field,
  76.     fm1,fm2,
  77.     jybias,
  78.     field_size,
  79.     year_picture_size,
  80.     year_field_size,
  81.     yxpos,
  82.     dpos,mpos,ypos: byte;    {screen positions}
  83.  
  84.  
  85. function IsLeapYear (Y: word): boolean;
  86. {
  87.   To be recast in assembler.
  88.  
  89.   Years divisible 4, except centuries not divisible by 400 and millenia
  90.   divisible by 4000, are leap years.
  91.  
  92.   'and $03' is equivalent to 'mod 4'
  93. }
  94. begin
  95.   IsLeapYear := (Y and $03 = 0) and
  96.     (Y mod 4000 <> 0) and ((Y mod 100 <> 0) or (Y mod 400 = 0));
  97. end;
  98.  
  99.  
  100. function no_date_entered: boolean;
  101. begin
  102.   val(day,D,code);
  103.   val(month,M,code);
  104.   val(year,Y,code);
  105.  
  106.   no_date_entered :=  (D + M + Y = 0) or
  107.                      ((D + M + Y = 1900) and (YearFormat = NY));
  108. end;
  109.  
  110.  
  111. function LegalExitCommand: boolean;
  112. {
  113.   This function is used to take out of line some code used for determining
  114.   when a subfield can be exited, to keep code readable. Modify as needed.
  115. }
  116. var LocalAction: edit;
  117. begin
  118.   LocalAction := get_edit(command);
  119.   LegalExitCommand :=
  120.     LocalAction in [del_block, restore_block, exit_screen];
  121. end;
  122.  
  123.  
  124. procedure assemble_date;
  125. begin
  126.   case DateFormat of
  127.     American: datestr := month + sf1 + day + sf2 + year;
  128.     European: datestr := day + sf1 + month + sf2 + year;
  129.     Japanese: datestr := year + sf1 + month + sf2 + day;
  130.   end;
  131. end;
  132.  
  133.  
  134. procedure getday;
  135. var GoodDay: boolean;
  136. begin
  137.   repeat
  138.  
  139.     if DateZeroAsBlank and (day = '00') then
  140.       day := '';
  141.  
  142.     getstring('',Default_pattr,atr,atc + pred(dpos),dattr,cursor_attr,
  143.               day,'99',2,2 + ord(MandatoryDay)); {status}
  144.  
  145.     if day = '' then
  146.       day := '00';
  147.  
  148.     GoodDay := escaped or PaintingFields or LegalExitCommand;
  149.  
  150.     if not GoodDay then
  151.  
  152.       if day = '00' then
  153.  
  154.         if MandatoryDay then
  155.           error2(Null_input_not_allowed)
  156.         else
  157.            begin
  158.              GoodDay := true;
  159.              finished := DateFormat = European;
  160.            end
  161.  
  162.       else {day != '00'}
  163.  
  164.         begin
  165.           value(day,D,31,code);
  166.  
  167.           GoodDay := (code = 0) and (D > 0);
  168.  
  169.           if not GoodDay then
  170.             begin
  171.               error2(Enter_a_number_between +
  172.                      brighten('1') + AndWord + brighten('31'));
  173.               cp := 1;
  174.             end;
  175.         end;
  176.  
  177.   until GoodDay;
  178. end;
  179.  
  180.  
  181. procedure getmonth;
  182. var GoodMonth: boolean;
  183. begin
  184.   repeat
  185.  
  186.    if DateZeroAsBlank and (month = '00') then
  187.       month := '';
  188.  
  189.     getstring('',Default_pattr,atr,atc + pred(mpos),dattr,cursor_attr,
  190.               month,'99',2,2 + ord(MandatoryMonth));
  191.  
  192.     if month = '' then
  193.       month := '00';
  194.  
  195.     GoodMonth := escaped or PaintingFields or LegalExitCommand;
  196.  
  197.     if not Goodmonth then
  198.  
  199.       if month = '00' then
  200.  
  201.         if MandatoryMonth then
  202.           error2(Null_input_not_allowed)
  203.         else
  204.           begin
  205.             GoodMonth := true;
  206.             finished := DateFormat = American;
  207.           end
  208.  
  209.       else {month != '00'}
  210.  
  211.         begin
  212.           value(month,M,12,code);
  213.  
  214.           GoodMonth := (code = 0) and (M > 0);
  215.  
  216.           if not GoodMonth then
  217.             begin
  218.               error2(Enter_a_number_between +
  219.                      brighten('1') + AndWord + brighten('12'));
  220.               cp := 1;
  221.             end;
  222.         end;
  223.  
  224.   until GoodMonth;
  225. end;
  226.  
  227.  
  228. procedure getyear;
  229. var GoodYear: boolean;
  230. begin
  231.   repeat
  232.  
  233.     if DateZeroAsBlank and ((year = '00') or (year = '0000')) then
  234.       year := '';
  235.  
  236.     getstring('',Default_pattr,atr,atc + pred(ypos),dattr,cursor_attr,year,
  237.               year_picture,year_field_size,2 + ord(MandatoryYear));
  238.  
  239.     if year = '' then
  240.       repeat
  241.         year := '00' + year;
  242.       until length(year) = year_picture_size;
  243.  
  244.     val(year,Y,code);
  245.  
  246.     GoodYear := escaped or PaintingFields or (Y <> 0) or LegalExitCommand;
  247.  
  248.     if not GoodYear then {year is 00 or 0000, is it legal?}
  249.  
  250.       if MandatoryYear then
  251.         error2(Null_input_not_allowed)
  252.       else
  253.          begin
  254.            GoodYear := true;
  255.            finished := DateFormat = Japanese;
  256.          end;
  257.  
  258.   until GoodYear;
  259.  
  260.   if YearFormat = NY then
  261.     Y := Y + 1900; {used in calculating leap years}
  262. end;
  263.  
  264.  
  265. procedure get_subfield (field: byte);
  266. begin
  267.   case field of
  268.     1: case DateFormat of
  269.          American: getmonth;
  270.          European: getday;
  271.          Japanese: getyear;
  272.        end; {case}
  273.  
  274.     2: if DateFormat = American then
  275.          getday
  276.        else getmonth;
  277.  
  278.     3: if DateFormat = Japanese then
  279.          getday
  280.        else getyear;
  281.   end;
  282. end;
  283.  
  284.  
  285. procedure validate_date
  286. ;
  287. {
  288.   Validates month and day (M & D). Not executed if PaintingFields.
  289. }
  290. var monthOk,
  291.     BlankdateOk: boolean;
  292.  
  293. function daysOk: boolean;
  294. begin
  295.   if D in [1..28] then {valid for all months: 12 * 28 = 336 days or 92%}
  296.     daysOk := true
  297.   else
  298.     case D of
  299.            0: daysOk := M = 0;
  300.       29..31: case M of
  301.                 2       : daysOk := D < 29 + ord(IsLeapYear(Y));
  302.                 4,6,9,11: daysOk := D < 31;
  303.               else
  304.                 daysOk := true;
  305.               end; {case}
  306.     else
  307.       daysOk := false;
  308.     end; {case}
  309. end;
  310.  
  311.  
  312. procedure day_error (subfield: byte);
  313. begin
  314.   error2(Invalid_no_of_days_in_month);
  315.   field := subfield;
  316. end;
  317.  
  318.  
  319. procedure month_error (subfield: byte);
  320. begin
  321.   error2(Invalid_month_number);
  322.   field := subfield;
  323. end;
  324.  
  325. begin
  326.   BlankdateOk := (not mandatory) and no_date_entered;
  327.   monthOk := (M in [1..12])       or BlankdateOk;
  328.   DateOk  := (daysOk and monthOk) or BlankdateOk;
  329.  
  330.   if not DateOk then
  331.     if mandatory and no_date_entered then
  332.       begin
  333.         error2(Null_input_not_allowed);
  334.         field := 1;
  335.         cp := 1;
  336.       end
  337.     else
  338.  
  339.       if DateFormat = European then
  340.         if not daysOk then
  341.           day_error(1)
  342.         else if not monthOk then
  343.                month_error(2)
  344.              else {;}
  345.       else
  346.         begin
  347.           if not monthOk then
  348.             month_error(1 + ord(DateFormat = Japanese))
  349.           else if not daysOk then
  350.             day_error(2 + ord(DateFormat = Japanese))
  351.         end;
  352. end;
  353.  
  354.  
  355. procedure display_date;
  356. var OldPainting: boolean;
  357.     fattr:       byte;
  358. begin
  359.   assemble_date;
  360.  
  361.   if PaintingFields or finished then
  362.     fattr := dattr
  363.   else fattr := separator_attr;
  364.  
  365.   OldPainting := PaintingFields;
  366.   PaintingFields := true;
  367.  
  368. { paint field }
  369.  
  370.     get_subfield(1);
  371.     Qwrite(atr,atc + pred(fm1),fattr,sf1);
  372.     get_subfield(2);
  373.     Qwrite(atr,atc + pred(fm2),fattr,sf2);
  374.     get_subfield(3);
  375.  
  376.   PaintingFields := OldPainting;
  377. end;
  378.  
  379.  
  380. procedure setup_date (strdate: string);
  381. {
  382.   Get day, month and year string variables from the input string: strdate
  383.   Reconstruct an 8 or 10 character datestr. This procedure used to reset
  384.   datestr and dependent variables after reset_block command.
  385. }
  386. var I: byte; a:char; {delete a}
  387. begin
  388.  
  389.   datestr := strdate;
  390.   field_size := 8;
  391.  
  392.   case YearFormat of
  393.       NY: year_picture := '~19~99';
  394.       YY: year_picture := '99';
  395.     YYYY: begin
  396.             year_picture := '9999';
  397.             field_size := 10;
  398.           end;
  399.   end; {case}
  400.  
  401.   year_field_size   := field_size - 6;
  402.   year_picture_size := length_without_tears(year_picture,'~');
  403.  
  404.   fm1 := 3;    {position of field marker between dd/mm or mm/dd}
  405.   fm2 := 6;    {position of field marker between mm/[yy]yy}
  406.   ypos := 7;   {same for American and European date formats}
  407.   jybias := 0; {to help locate month and day subfields in Japanese (ymd) date}
  408.  
  409.   MandatoryDay   := true;
  410.   MandatoryMonth := true;
  411.   MandatoryYear  := true;
  412. {
  413.   SystemDefault controls whether or not the enter_default command enters
  414.   the system date into the date field. If SystemDefault is true the first
  415.   field may be blank on return from the appropriate call to GETSTRING (this
  416.   is to enable use of enter_default command).
  417. }
  418.   case DateFormat of
  419.     American: begin
  420.                 mpos := 1;
  421.                 dpos := 4;
  422.                 MandatoryMonth := mandatory and not SystemDefault;
  423.               end;
  424.     European: begin
  425.                 dpos := 1;
  426.                 mpos := 4;
  427.                 MandatoryDay := mandatory and not SystemDefault;
  428.               end;
  429.     Japanese: begin
  430.                 jybias := year_picture_size - year_field_size;
  431.  
  432.                 ypos := 1;
  433.                 mpos := year_picture_size + 2;
  434.                 dpos := mpos + 3;
  435.  
  436.                 fm1 := pred(mpos); {fm1 & 2 are offset positions on screen}
  437.                 fm2 := pred(dpos);
  438.                 MandatoryYear := mandatory and not SystemDefault;
  439.               end;
  440.   end; {case}
  441.  
  442.   if (year_field_size = 2) and (length(datestr) = 10) then       {yyyy passed}
  443.     yxpos := ypos + 2                           {skip over first two Y digits}
  444.   else yxpos := ypos;         {yxpos = position to start extracting year from}
  445.  
  446.   if ord(datestr[0]) > 0 then        {convert any spaces in date string to 0s}
  447.     for I := 1 to length(datestr) do
  448.       if datestr[I] = ' ' then
  449.         datestr[I] := '0';
  450.  
  451.   if length(datestr) = field_size then {assume good date}
  452.     begin
  453.       sf1 := datestr[fm1 - jybias];
  454.       sf2 := datestr[fm2 - jybias];
  455.     end
  456.   else {ensure we don't get nonsense subfield separators}
  457.     begin
  458.       sf1 := DefaultDateSeparator;
  459.       sf2 := sf1;
  460.     end;
  461. {
  462.   short date strings are prefaced with zeros
  463. }
  464.   while length(datestr) < field_size do
  465.     datestr := '0' + datestr;
  466.  
  467.   day   := copy(datestr,dpos - jybias,2);
  468.   month := copy(datestr,mpos - jybias,2);
  469.   year  := copy(datestr,yxpos,year_field_size);
  470.  
  471.   val(day,D,code);
  472.   val(month,M,code);
  473.   val(year,Y,code);
  474. end;
  475.  
  476.  
  477. procedure get_system_date;
  478. {
  479.   Sets month, day and year strings using current system date.
  480.   Leading zeros inserted if necessary.
  481. }
  482. var
  483.   system_year,
  484.   system_month,
  485.   system_day,
  486.   weekday:     word;
  487.  
  488. begin
  489.   getdate(system_year, system_month, system_day, weekday);
  490.  
  491.   str(system_month,month);
  492.   if system_month < 10 then
  493.     month := '0' + month;
  494.  
  495.   str(system_day,day);
  496.   if system_day < 10 then
  497.     day := '0' + day;
  498.  
  499.   str(system_year,year);
  500.   if YearFormat <> YYYY then
  501.     delete(year,1,2);
  502.  
  503.   assemble_date; {turn day, month and year strings into datestr}
  504.   setup_date(datestr);
  505.   finished := true;
  506. end;
  507.  
  508.  
  509. procedure get_input;
  510. begin
  511.   finished := false;
  512.   get_subfield(field); {getstring takes care of clearerror}
  513.  
  514.   action := get_edit(command);
  515.   case action of
  516.  
  517.     leftchar : if (field > 1) or OldStringFieldWrap then
  518.                  begin
  519.                    dec(field);
  520.                    cp := 255; {move cursor to end of previous field}
  521.                  end;
  522.  
  523.     rightchar: if (field < 3) or OldStringFieldWrap then
  524.                  begin
  525.                    inc(field);
  526.                    cp := 1;
  527.                  end;
  528.  
  529.  
  530.     del_block: begin {^Y for date field}
  531.                  setup_date('');
  532.                  field := 1;
  533.                  cp := 1;
  534.                  display_date;
  535.                end;
  536.  
  537.     restore_block: {^U for date field}
  538.  
  539.                begin
  540.                  setup_date(old_datestr);
  541.                  display_date;
  542.                end;
  543.  
  544.     enter_default:
  545.  
  546.                get_system_date;
  547.  
  548.     carriage_return:
  549.  
  550.                begin
  551.                  if SystemDefault and no_date_entered then
  552.                    get_system_date;
  553.  
  554.                  finished := true;
  555.                end;
  556.  
  557.     tabback:   begin
  558.                  dec(field);
  559.                  cp := 255;
  560.                end;
  561.  
  562.     tabover,
  563.     post_letter: begin
  564.                    inc(field);
  565.                    cp := 1;
  566.                  end;
  567.  
  568.     escapefrom,
  569.     help,
  570.     upchar,
  571.     downchar,
  572.     pageup,
  573.     pagedown,
  574.     scrollup,
  575.     scrolldown,
  576.     goto_top,
  577.     goto_bottom,
  578.     abort,
  579.     exit_screen,
  580.     quit:
  581.                 begin
  582.                   setup_date(old_datestr);
  583.                   escaped := (get_edit(command) = escapefrom);
  584.                   finished := not escaped;       {1 or other is true}
  585.                 end;
  586.  
  587.   else
  588.     error2(Invalid_key);
  589.   end; {case}
  590.  
  591.   finished := finished or (field in [0,4]);
  592. end;
  593.  
  594.  
  595. begin {getdatestring}
  596.  
  597.   setup_date(datestr); {set up field_size, used in display_prompt}
  598.   display_prompt(date_prompt,atr,atc,pattr,field_size);
  599.  
  600.   if not PaintingFields then
  601.     begin
  602.  
  603.       finished           := false; {tested in display_date}
  604.       display_date;
  605.  
  606.       old_datestr := datestr;
  607.  
  608.       mandatory          := (status and $01) > 0;
  609.       SystemDefault      := (status and $02) > 0;
  610.       Old_Top_n_tail     := Top_n_tail;
  611.       Top_n_tail         := false;   {don't turn '00' into '' in getday etc}
  612.       OldInsLock         := Inslock;
  613.       InsLock            := true;    {disable}
  614.       OldAutoTab         := AutoTab;
  615.       AutoTab            := true;
  616.       OldStringFieldWrap := StringFieldWrap;
  617.       StringFieldWrap    := true;
  618.       OldTabsize         := tabsize; {disable <tab> within date field}
  619.       tabsize            := 0;
  620.  
  621.       escaped := false;
  622.       field   := 1;
  623.  
  624.       repeat
  625.         cp := 1;
  626.  
  627.         repeat
  628.           get_input
  629.         until escaped or finished;
  630.  
  631.         if not escaped then
  632.           validate_date;
  633.  
  634.       until DateOk or escaped;
  635.  
  636.       InsLock         := OldInslock;
  637.       Top_n_tail      := Old_Top_n_tail;
  638.       AutoTab         := OldAutoTab;
  639.       StringFieldWrap := OldStringFieldWrap;
  640.       Tabsize         := OldTabsize;
  641.     end;
  642.  
  643.   display_date; {ALWAYS (even if unchanged) to reset attributes}
  644.  
  645. end;
  646.