File : peh.adb


   1 ------------------------------------------------------------------------------
   2 ------------------------------------------------------------------------------
   3 -- This file is part of 'Finite Field Arithmetic', aka 'FFA'.               --
   4 --                                                                          --
   5 -- (C) 2019 Stanislav Datskovskiy ( www.loper-os.org )                      --
   6 -- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html     --
   7 --                                                                          --
   8 -- You do not have, nor can you ever acquire the right to use, copy or      --
   9 -- distribute this software ; Should you use this software for any purpose, --
  10 -- or copy and distribute it to anyone or in any manner, you are breaking   --
  11 -- the laws of whatever soi-disant jurisdiction, and you promise to         --
  12 -- continue doing so for the indefinite future. In any case, please         --
  13 -- always : read and understand any software ; verify any PGP signatures    --
  14 -- that you use - for any purpose.                                          --
  15 --                                                                          --
  16 -- See also http://trilema.com/2015/a-new-software-licensing-paradigm .     --
  17 ------------------------------------------------------------------------------
  18 ------------------------------------------------------------------------------
  19 
  20 with OS;       use OS;
  21 with CmdLine;  use CmdLine;
  22 with FFA_RNG;  use FFA_RNG;
  23 with FFA_Calc; use FFA_Calc;
  24 
  25 
  26 -- This is the 'main' procedure of Peh for all Unixlike OS.
  27 procedure Peh is
  28    
  29    PehDim  : Peh_Dimensions; -- Operator-specified spacetime footprint.
  30    
  31    RNG     : RNG_Device;     -- The selected RNG device. Peh requires a RNG.
  32    
  33 begin
  34    
  35    -- If a valid number of command line params was NOT given, print a likbez :
  36    if Arg_Count < 5 or Arg_Count > 6 then
  37       Eggog("Usage: ./peh WIDTH HEIGHT TAPESPACE LIFE [/dev/rng]");
  38    end if;
  39    
  40    declare
  41       Arg1 : CmdLineArg;
  42       Arg2 : CmdLineArg;
  43       Arg3 : CmdLineArg;
  44       Arg4 : CmdLineArg;
  45    begin
  46       
  47       -- Get commandline args:
  48       Get_Argument(1, Arg1); -- First  mandatory arg : Width
  49       Get_Argument(2, Arg2); -- Second mandatory arg : Height
  50       Get_Argument(3, Arg3); -- Third  mandatory arg : TapeSpace
  51       Get_Argument(4, Arg4); -- Fourth mandatory arg : Life
  52       
  53       if Arg_Count = 6 then
  54          
  55          -- A RNG was specified (Arg_Count includes program name itself)
  56          declare
  57             Arg5 : CmdLineArg;
  58          begin
  59             Get_Argument(5, Arg5); -- Fifth arg (optional) : RNG device
  60             
  61             -- Ada.Sequential_IO chokes on paths with trailing whitespace!
  62             -- So we have to give it a trimmed path. But we can't use
  63             -- Ada.Strings.Fixed.Trim, because it suffers from
  64             -- SecondaryStackism-syphilis. Instead we are stuck doing this:
  65             Init_RNG(RNG, Arg5(Arg5'First .. Len_Arg(5)));
  66          end;
  67          
  68       else
  69          
  70          -- If RNG was NOT explicitly specified:
  71          Init_RNG(RNG); -- Use the machine default. The '?' Op requires a RNG.
  72          
  73          -- Warn the operator that we are going to use the default system RNG:
  74          Achtung("WARNING: The '?' command will use DEFAULT entropy source : "
  75                    & Default_RNG_Path & " !");
  76          -- Generally, you do NOT want this, outside of noob exploration/tests.
  77          
  78       end if;
  79       
  80       -- Parse the four mandatory arguments into Positives:
  81       PehDim.Width     := Positive'Value(       Arg1 );
  82       PehDim.Height    := Positive'Value(       Arg2 );
  83       PehDim.TapeSpace := Peh_Tape_Range'Value( Arg3 );
  84       PehDim.Life      := Natural'Value(        Arg4 );
  85       
  86    exception
  87       
  88       -- There was an attempt to parse garbage in the init parameters:
  89       when others =>
  90          Eggog("Invalid arguments!");
  91          
  92    end;
  93    
  94    -- Validate requested Peh Dimensions. If invalid, program will terminate.
  95    Validate_Peh_Dimensions(PehDim);
  96    
  97    -- Read, from Unix 'standard input' , and then execute, the Tape:
  98    declare
  99       
 100       -- The current Tape input symbol
 101       Tape_Read_Char  : Character;
 102       
 103       -- The TapeSpace
 104       TapeSpace       : Peh_Tapes(1 .. PehDim.TapeSpace) := (others => ' ');
 105       
 106       -- 'End of File' condition when reading :
 107       EOF             : Boolean := False;
 108       
 109       -- Will contain the Verdict produced by the Tape:
 110       Verdict         : Peh_Verdicts;
 111       
 112    begin
 113       
 114       -- Attempt to read the entire expected Tapespace length, and no more:
 115       for TapePosition in TapeSpace'Range loop
 116          
 117          -- Attempt to receive a symbol from the standard input:
 118          if Read_Char(Tape_Read_Char) then
 119             
 120             -- Save the successfully-read symbol to the TapeSpace:
 121             TapeSpace(TapePosition) := Tape_Read_Char;
 122             
 123          else
 124             
 125             -- Got an EOF instead of a symbol:
 126             EOF := True;
 127             if TapePosition /= TapeSpace'Length then
 128                Achtung("WARNING: Short Tape: Tapespace filled to position:" &
 129                          Peh_Tape_Range'Image(TapePosition) & " of" &
 130                          Peh_Tape_Range'Image(TapeSpace'Last) & ".");
 131             end if;
 132             
 133          end if;
 134          
 135          exit when EOF; -- When EOF, halt reading, and proceed to execution.
 136          
 137       end loop;
 138       
 139       -- Execute Peh over the given Tape, on Peh Machine with given dimensions:
 140       Verdict := Peh_Machine(Dimensions => PehDim,
 141                              Tape       => TapeSpace,
 142                              RNG        => RNG);
 143       
 144       -- A correctly-written Peh Tape is expected to produce a Verdict.
 145       -- On Unix, we will give it to the caller process via the usual means:
 146       case Verdict is
 147          
 148          -- Tape produced a Verdict of 'Yes' :
 149          when Yes =>
 150             Quit(Yes_Code);
 151             
 152          -- Tape produced a Verdict of 'No'  :
 153          when No =>
 154             Quit(No_Code);
 155             
 156             -- Tape ran to completion without producing any Verdict at all.
 157             -- Outside of simple test scenarios, noob explorations, etc.,
 158             -- this usually means that there is a logical mistake in the
 159             -- Tape somewhere, and we will warn the operator:
 160          when Mu =>
 161             Achtung("WARNING: Tape terminated without a Verdict.");
 162             Quit(Mu_Code);
 163             
 164       end case;
 165       
 166       -- If the Tape aborted on account of a fatal error condition (e.g. div0)
 167       -- Peh will Quit(Sad_Code) (see E(..) in ffa_calc.adb .)
 168       -- Therefore, Peh ALWAYS returns one of FOUR possible Unix return-codes:
 169       -- -2, -1, 0, 1. (see os.ads .)
 170       
 171    end;
 172    
 173 end Peh;