-- file: TimeExtraImpl.mesa, last edit:
-- AlHall, 9-Jul-82 14:28:40
-- Bruce, March 16, 1979  6:10 PM
-- HGM, January 27, 1981  5:35 PM	
-- Hankins	Klamath update (time zone chagne)	24-Jul-84 14:54:10

-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  String USING [
    InvalidNumber, StringBoundsFault, StringToNumber, AppendChar,
    EquivalentSubString, UpperCase, SubStringDescriptor],
  System USING [gmtEpoch],
  Time USING [Pack, Packed, Unpacked, Invalid],
  TimeExtra USING [];

TimeExtraImpl: PROGRAM IMPORTS String, Time EXPORTS TimeExtra =
  BEGIN

  Empty: PROCEDURE [s: LONG STRING] RETURNS [BOOLEAN] =
    BEGIN RETURN[s = NIL OR s.length = 0] END;

  EquivalentChar: PUBLIC PROCEDURE [c1, c2: CHARACTER] RETURNS [BOOLEAN] =
    BEGIN RETURN[String.UpperCase[c1] = String.UpperCase[c2]] END;

  GetToken: PROCEDURE [storage: LONG STRING, s: LONG STRING, c: CARDINAL]
    RETURNS [is: CARDINAL] =
    BEGIN
    ch: CHARACTER;
    FOR is ← c, is + 1 UNTIL is >= s.length DO
      SELECT String.UpperCase[ch ← s[is]] FROM
        IN ['A..'Z], IN ['0..'9] => String.AppendChar[storage, ch];
        ':, '- => EXIT;  -- terminator

        '  => IF ~Empty[storage] THEN EXIT;  --terminating blank

        ENDCASE;
      ENDLOOP;
    RETURN[is + 1];
    END;

  PackedTimeFromString: PUBLIC PROCEDURE [s: LONG STRING]
    RETURNS [t: Time.Packed] =
    BEGIN
    --  string format must be: bDD-MMM-YYbbHH:MM:SSbbZZTb
    t ← DoIt[
      s !
      String.InvalidNumber, String.StringBoundsFault, Time.Invalid =>
        BEGIN t ← System.gmtEpoch; CONTINUE END]
    END;

  DoIt: PROCEDURE [s: LONG STRING] RETURNS [t: Time.Packed] =
    BEGIN

    Get: PROCEDURE =
      BEGIN s1.length ← 0; nextChar ← GetToken[s1, s, nextChar] END;

    GetNumber: PROCEDURE RETURNS [CARDINAL] =
      BEGIN Get[]; RETURN[String.StringToNumber[s1, 10]]; END;

    m: String.SubStringDescriptor ← [
      base: "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"L, offset: NULL, length: 3];
    s1: LONG STRING ← [3];
    month: String.SubStringDescriptor ← [base: s1, offset: 0, length: NULL];
    time: Time.Unpacked ← [
      year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0, weekday: 0,
      zone: [direction: west, zone: 8, zoneMinutes: 0, beginDST: 0, endDST: 0],
      dst: FALSE];
    nextChar: CARDINAL ← 0;
    i: CARDINAL;
    packIt: BOOLEAN ← TRUE;


    IF Empty[s] THEN RETURN[System.gmtEpoch];
    time.day ← GetNumber[];
    Get[];
    month.length ← s1.length;
    FOR i IN [0..12) DO
      m.offset ← i * 3;
      IF String.EquivalentSubString[@month, @m] THEN
        BEGIN time.month ← i; EXIT END;
      ENDLOOP;
    time.year ← GetNumber[];
    time.year ← time.year + 1900;
    time.hour ← GetNumber[];
    time.minute ← GetNumber[];
    time.second ← GetNumber[];
    Get[];
    IF s1.length # 0 THEN
      BEGIN
      zones: PACKED ARRAY [5..8] OF CHARACTER = ['E, 'C, 'M, 'P];
      FOR i IN [5..8] DO
        IF EquivalentChar[s1[0], zones[i]] THEN
          BEGIN time.zone.zone ← i; EXIT END;
        REPEAT FINISHED => time.zone.zone ← 0;  -- GMT

        ENDLOOP;
      time.dst ← EquivalentChar[s1[1], 'D];
      packIt ← FALSE;
      END;
    t ← Time.Pack[time, packIt]
    END;

  END.