MODULE CharsTo; (***************************************************************************) (* Copyright (C) Olivetti 1989 *) (* All Rights reserved *) (* *) (* Use and copy of this software and preparation of derivative works based *) (* upon this software are permitted to any person, provided this same *) (* copyright notice and the following Olivetti warranty disclaimer are *) (* included in any copy of the software or any modification thereof or *) (* derivative work therefrom made by any person. *) (* *) (* This software is made available AS IS and Olivetti disclaims all *) (* warranties with respect to this software, whether expressed or implied *) (* under any law, including all implied warranties of merchantibility and *) (* fitness for any purpose. In no event shall Olivetti be liable for any *) (* damages whatsoever resulting from loss of use, data or profits or *) (* otherwise arising out of or in connection with the use or performance *) (* of this software. *) (***************************************************************************) IMPORT Text, Fmt; IMPORT CharType; PROCEDURE Card( READONLY chars: Chars; VAR c: CARDINAL; base: Fmt.Base := (*Fmt.*)Decimal) : BOOLEAN RAISES {} = VAR total := 0; limit := LAST(CARDINAL) DIV base; BEGIN IF NUMBER(chars) = 0 THEN RETURN FALSE END; FOR i := 0 TO LAST(chars) DO VAR ch := chars[i]; val: INTEGER; BEGIN IF '0' <= ch AND ch <= '9' THEN val := ORD(ch) - ORD('0'); ELSIF 'a' <= ch AND ch <= 'f' THEN val := ORD(ch) - ORD('a') + 10; ELSIF 'A' <= ch AND ch <= 'F' THEN val := ORD(ch) - ORD('A') + 10; ELSE RETURN FALSE; END; IF val >= base THEN RETURN FALSE END; IF total < limit OR total = limit AND val <= LAST(CARDINAL) MOD base THEN total := total * base + val; ELSE RETURN FALSE; END; END; END; c := total; RETURN TRUE; END Card; PROCEDURE CIEqual(READONLY chars: Chars; t: Text.T): BOOLEAN RAISES {}= VAR length := Text.Length(t); BEGIN IF NUMBER(chars) = length THEN FOR i := 0 TO length - 1 DO IF CharType.ToUpper(chars[i]) # Text.GetChar(t, i) THEN RETURN FALSE; END; END; (* for *) RETURN TRUE; ELSE RETURN FALSE; END; (* if *) END CIEqual; TYPE TextForEachBase = ARRAY Fmt.Base OF Text.T; PROCEDURE FirstInts(): TextForEachBase RAISES {}= VAR result: TextForEachBase; BEGIN FOR i := FIRST(Fmt.Base) TO LAST(Fmt.Base) DO VAR full := Fmt.Int(FIRST(INTEGER), i); BEGIN result[i] := Text.Sub(full, 1, Text.Length(full) - 1); END; END; RETURN result; END FirstInts; VAR firstInts_g := FirstInts(); (* Array of texts giving the digits for FIRST(INTEGER) for every base; the initial "-" is not included *) PROCEDURE InternalInt( READONLY chars: Chars; VAR i: INTEGER; base: Fmt.Base; neg: BOOLEAN) : BOOLEAN RAISES {}= VAR card: CARDINAL; BEGIN IF Card(chars, card, base) THEN IF neg THEN i := -card ELSE i := card END; RETURN TRUE; ELSE IF neg AND CIEqual(chars, firstInts_g[base]) THEN i := FIRST(INTEGER); RETURN TRUE; ELSE RETURN FALSE; END; END; END InternalInt; PROCEDURE Int( READONLY chars: Chars; VAR i: INTEGER; base: Fmt.Base := (*Fmt.*)Decimal) : BOOLEAN RAISES {} = VAR length := NUMBER(chars); BEGIN IF length > 0 THEN VAR ch := chars[0]; neg := (ch = '-'); c: CARDINAL; BEGIN IF neg OR ch = '+' THEN RETURN InternalInt(SUBARRAY(chars, 1, length - 1), i, base, neg); ELSE IF Card(chars, c, base) THEN i := c; RETURN TRUE; ELSE RETURN FALSE; END; END; (* if *) END; ELSE RETURN FALSE; END; END Int; PROCEDURE Bool(READONLY chars: Chars; VAR b: BOOLEAN): BOOLEAN RAISES {} = BEGIN IF CIEqual(chars, "TRUE") THEN b := TRUE; RETURN TRUE; ELSIF CIEqual(chars, "FALSE") THEN b := FALSE; RETURN TRUE; ELSE RETURN FALSE; END; END Bool; PROCEDURE BasedCard(READONLY chars: Chars; VAR c: CARDINAL): BOOLEAN RAISES {}= BEGIN FOR i := 0 TO LAST(chars) DO IF chars[i] = '_' THEN VAR base: CARDINAL; BEGIN RETURN Card(SUBARRAY(chars, 0, i), base) AND FIRST(Fmt.Base) <= base AND base <= LAST(Fmt.Base) AND Card(SUBARRAY(chars, i + 1, LAST(chars) - i), c, base); END; END; END; RETURN Card(chars, c); END BasedCard; PROCEDURE BasedInt(READONLY chars: Chars; VAR i: INTEGER): BOOLEAN RAISES {}= BEGIN FOR j := 0 TO LAST(chars) DO IF chars[j] = '_' THEN VAR iBase: INTEGER; BEGIN IF Int(SUBARRAY(chars, 0, j), iBase) AND iBase # FIRST(INTEGER) THEN VAR neg := iBase < 0; base: CARDINAL := ABS(iBase); BEGIN IF FIRST(Fmt.Base) <= base AND base <= LAST(Fmt.Base) THEN RETURN InternalInt( SUBARRAY(chars, j + 1, LAST(chars) - j), i, base, neg) END; END; END; END; RETURN FALSE; END; END; RETURN Int(chars, i); END BasedInt; <*INLINE*> PROCEDURE KorM(ch: CHAR): CARDINAL RAISES {}= BEGIN CASE ch OF | 'k', 'K' => RETURN 1024; | 'm', 'M' => RETURN 1024 * 1024; ELSE RETURN 1; END; (* case *) END KorM; PROCEDURE CheckedTimes( i: INTEGER; times: CARDINAL; VAR result: INTEGER) : BOOLEAN RAISES {}= BEGIN IF i > 0 THEN IF i > LAST(INTEGER) DIV times THEN RETURN FALSE END; ELSE VAR limit := FIRST(INTEGER) DIV times; BEGIN IF i < limit THEN RETURN FALSE END; IF i = limit AND FIRST(INTEGER) MOD times # 0 THEN RETURN FALSE END; END; END; result := i * times; RETURN TRUE; END CheckedTimes; PROCEDURE BigCard(READONLY chars: Chars; VAR c: CARDINAL): BOOLEAN RAISES {}= VAR last := LAST(chars); BEGIN IF last < 0 THEN RETURN FALSE END; VAR times := KorM(chars[last]); int: INTEGER; BEGIN IF times # 1 THEN IF BasedCard(SUBARRAY(chars, 0, last), c) AND CheckedTimes(c, times, int) THEN c := int; RETURN TRUE; ELSE RETURN FALSE; END; ELSE RETURN BasedCard(chars, c); END; END; END BigCard; PROCEDURE BigInt(READONLY chars: Chars; VAR i: INTEGER): BOOLEAN RAISES {}= VAR last := LAST(chars); BEGIN IF last < 0 THEN RETURN FALSE END; VAR times := KorM(chars[last]); BEGIN IF times # 1 THEN RETURN BasedInt(SUBARRAY(chars, 0, last), i) AND CheckedTimes(i, times, i); ELSE RETURN BasedInt(chars, i); END; END; END BigInt; BEGIN END CharsTo.