PROGRAM castin;
 {$nomain}

{ 
  File:[22,310]CASTIN.PAS
  Author: Phil Hannay 14-Jan-87  (patterned after CASTWO.PAS)

  Last Edit: 23-JUN-1988 22:05:43 

  History:
	 23-JUN-1988 21:55:32  - JMB PA3UTL upgrade.

}

 {$NOLIST}
 {[a+,b+,l-,k+,r+] Pasmat }
 %INCLUDE 'PAS$EXT:General.typ';
 %INCLUDE 'PAS$EXT:Error.ext';
 %INCLUDE 'PAS$EXT:CASTWO.EXT';
 {$LIST}


  PROCEDURE Castin(VAR asc: PACKED ARRAY [lo..hi: integer] OF char;
                   VAR Int: integer;
                   VAR pos: integer);
    EXTERNAL;

{*USER*

Pascal-3 procedure which converts an input string of ASCII characters in ASC
to an integer INT (signed binary word) using a decimal (base 10) radix. 
POS specifies starting point in the string (array).  Upon exit from this
procedure, POS will be left pointing to the position of the terminating
character or the end of the string, whichever comes first.
Leading space or tab character(s)
are ignored.  The number will be considered negative if a leading "-" minus
sign is encountered, and the number will be considered positive is a leading
"+" plus sign or no sign at all is encountered.  The plus or minus sign
needs to preceed the first ascii digit, but can be separated from that first
digit by any number of (ignored) space or tab characters.  

Any non-digit following the first valid digit will terminate the conversion.
This includes a period (decimal point), a comma, a blank, 
or any other non digit.
In any case, POS will be left pointing at this terminating character,
so you may use it to go on to the next number.  Thus you can parse
strings like "34,+55,+ 45,  -834,,3".  Where no valid digit is
encountered before the next terminator (such as the ",," in the example),
a value of zero will be returned.  Likewise a number like "345.344" could
be parsed into two integers, the first representing the number before the
decimal point, the second the number after the decimal.  

Remember that this routine handles arrays using the string conventions.
The length of a type 0 string is determined by the 0 element of the array,
and the length of a type 1 string is determined by the first null character
in the string.  Be careful if you use strings made up of left justified
numbers with extra blank padding to the right of the number.  The first
blank encountered will act as the terminator.  If you keep POS where it
is and call CASTIN again, the remaining blanks will be read as another
number and give you a zero.  This is nice in that an all blank string
like "    " will return a value of zero.  It does also mean that a
string like "34    " will return a value of 34, the first time you call
CASTIN, and if you do not alter POS, will return a 0, the second time you
call CASTIN.

Integer overflow (greater than +32767 or less than -32768) is indicated
by a negative POS value.  No error messages are issued on integer overflow,
so caller must check POS if overflow possiblity exists.  On the other hand,
this also permits the caller to use this routine to validate input to insure
that the ascii string represents a valid integer.  

}
{*WIZARD*

The input string is converted to a signed word in INT.  The radix is
assumed to be decimal.  Thus the range that the ascii string can represent
is +32767 down thru -32768.  If overflow occurs, and error
message is output, and INT retains the last valid value, and POS is set
negative.  A leading plus (+) or minus (-) sign will be recognized,
with a minus sign overriding a positive sign in the unlikely event that
the two are used together.  After the occurance of a valid digit, the
plus and minus signs are considered valid terminating characters.
Periods (decimal points) and commas are considered valid terminating 
characters.

Note: This routine will handle type 1 strings, type 0 strings, and
ordinary packed arrays.  There is some differences in behavior that
need to be understood.  The upper limit of the variable ASC will be
determined by the byte integer value in ASC[0] in type 0 strings.  However,
in type 1 strings and ordinary packed arrays, there is not clear definition
of the upper limit.  A type 1 string upper limit is defined by the
the occurance of a <NULL> character in the string.  But an ordinary
packed array could also have a null, without any intention of being a
type 1 string.  For this reason, we use the upper limit of the array
for ASC variables that are not type 0 strings, and treat type 1 strings
as if they were ordinary packed arrays.  The action of this conversion
routine is the same for all types of ASC, but they are not handled
the same internally in this procedure.

}


  PROCEDURE Castin;

    LABEL
      999; { used for premature exit on error }

    CONST
      Debug = false;

    VAR
      Bpos, Limit : integer;
      Bin, Max : Word;
      Positive: boolean; {set true if number is positive}


    BEGIN
      {Initialize some stuff.}
      Positive := true; {assume positve number}
      Int := 0; {assume zero - if no ascii digits found, will return zero}

      IF ((lo = 0) AND (pos < 1)) OR (pos > hi) THEN
        BEGIN
        error(4, warning_err, 'CASTIN -- Illegal postition:', pos);
        GOTO 999
        END;

      if lo = 0 then limit:= ord(asc[0]) else limit:= hi;

      { skip leading spaces,tabs,zeros,plus sign or minus signs }
      Bpos := pos;
      WHILE (Bpos < Limit) AND
            (ord(asc[Bpos]) IN [40B, 11B, 60B, 53B, 55B]) DO
        BEGIN
        { If minus sign encountered, set postive false to indicate 
          negative number }
        IF ord(asc[Bpos]) IN [55B] THEN Positive := false;
        Bpos := Bpos + 1;
        END;

      IF (Bpos = Limit) AND (ord(asc[Bpos]) IN [40B, 11B, 60B, 53B, 55B])
        THEN BEGIN { zero or nothing to convert }
        IF Debug THEN writeln('no bpos found');
        pos := Limit;
        GOTO 999
        END;

      { Now convert the number using CASTWO radix 10 }
      Pos:= Bpos;
      CASTWO(Asc, Bin, Pos, 10);
      if positive then max:= 77777B else max:= 100000B;
      if debug then writeln ('max=',max:-6,' bin=',bin:-6);
      if Bin > max 
        then begin
          { overflow }
          Pos:= pos * (-1);
          GOTO 999;
          end
        else begin
          { okay, assign pos or neg}
          Int:= Loophole (integer, Bin);
          if not(positive) then Int:= Int * (-1);
          end;

    999:
    END;
