language-Modula2-0.1: examples/Modula-2_Libraries/C.-Lins_Modula-2_Software_Component_Library/Vol1/UTILS/CHARUTIL.MOD
IMPLEMENTATION MODULE CharUtils;
(*====================================================================
Version : 1.0 Sat, Mar 4, 1989 C. Lins
Compiler : JPI TopSpeed Modula-2
Component: Tool- Primitive Utility - Character Utilities
INTRODUCTION
This module provides elementary character operations.
The JPI version was converted from the MacModula-2 version of
Alpha (V2.01), which was also by the same author.
REVISION HISTORY
v1.0 Sat, Mar 4, 1989 C. Lins
Initial JPI implementation.
LOCAL CONSTANTS
* LowercaseOffset
Numeric difference between the ordinal values of the lower-
and upper-case ASCII characters, such that when added to the
ordinal value of an uppercase character will yield the lowercase
letter equivalent.
INFORMATION HIDDEN
* Specifics related to the ASCII character set.
IMPLEMENTATION DESIGN NOTES
* The ASCII character set is assumed.
* Procedure call overhead in the MacMETH compiler is excessive for small
routines (few parameters, 0-4 bytes of locals, 1-4 lines of source code,
no procedure calls within the routine). It is much larger than for a
functionally equivalent assembly language version of the routine.
* In [2], using Ada, the operator IN can be used for membership tests on a
subtype or subrange, see sample usage on pg. 388.
To achieve the equivalent in Modula-2 one could:
* define a character set ADT module, since most M2 compilers
support SET types with a small maximum cardinality, (16 to
32 elements), when 128/256 elements are needed for the ASCII
characters. The problem is space: 8/16 words for each
character set variable plus the bit manipulation code to
implement IN (set membership test).
* hide within the implementation module tests to determine
whether a given character lies within the subrange bounds.
For efficiency reasons the second option was chosen.
* Routines that make a procedure call to another routine within
the module to accomplish a character test, should be transformed
to the in-line equivalent, in the interests of efficiency, which
(hopefully) will promote using the module.
The duplicate comparisons should not adversely effect the
maintainance effort for these reasons:
a. module is already specific to the ASCII characters;
b. the ASCII character definition is an ISO standard,
╘freezing╒ the specification and internal constraints;
c. no change to module functionality is anticipated.
d. statements are simple character comparisons against constant value(s).
REFERENCES and SUPPORTING DOCUMENTS
[1] Niklaus Wirth, Programming in Modula-2, 3rd ed., pg. 162,
Springer-Verlag Berlin Heidelberg, 1985.
[2] Grady Booch, Software Components in Ada, pp. 386-391,
Benjamin/Cummings Publishing Co, 1987.
PROPRIETARY NOTICES
CharUtils.MOD Copyright (C) 1989 Charles A. Lins.
====================================================================*)
CONST LowercaseOffset = VAL(INTEGER,MIN(LowercaseCharacter))
- VAL(INTEGER,MIN(UppercaseCharacter));
(*--------------------*)
PROCEDURE MakeUppercase (VAR theChar : CHAR (*-- inout *));
BEGIN
IF IsLowercase(theChar) THEN
(*-- Yes, convert to uppercase equivalent *)
theChar := CAP(theChar);
END (*--if*);
END MakeUppercase;
(*--------------------*)
PROCEDURE MakeLowercase (VAR theChar : CHAR (*-- inout *));
BEGIN
IF IsUppercase(theChar) THEN
(*-- Yes, convert to lowercase equivalent *)
theChar := CHR(ORD(theChar) + LowercaseOffset);
END (*--if*);
END MakeLowercase;
(*--------------------*)
PROCEDURE Uppercase ( theChar : CHAR (*-- in *))
: CHAR (*-- out *);
BEGIN
theChar := CAP(theChar);
RETURN theChar;
END Uppercase;
(*--------------------*)
PROCEDURE Lowercase ( theChar : CHAR (*-- in *))
: CHAR (*-- out *);
BEGIN
IF IsUppercase(theChar) THEN
(*-- Yes, convert to lowercase equivalent *)
theChar := CHR(ORD(theChar) + LowercaseOffset);
END (*--if*);
RETURN theChar;
END Lowercase;
(*--------------------*)
PROCEDURE IsAscii ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN (MIN(AsciiCharacter) <= theChar) & (theChar <= MAX(AsciiCharacter));
END IsAscii;
(*--------------------*)
PROCEDURE IsControl ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN (MIN(ControlCharacter) <= theChar) & (theChar <= MAX(ControlCharacter));
END IsControl;
(*--------------------*)
PROCEDURE IsGraphic ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN (MIN(GraphicCharacter) <= theChar) & (theChar <= MAX(GraphicCharacter));
END IsGraphic;
(*--------------------*)
PROCEDURE IsLowercase ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN (MIN(LowercaseCharacter) <= theChar) & (theChar <= MAX(LowercaseCharacter));
END IsLowercase;
(*--------------------*)
PROCEDURE IsUppercase ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN (MIN(UppercaseCharacter) <= theChar) & (theChar <= MAX(UppercaseCharacter));
END IsUppercase;
(*--------------------*)
PROCEDURE IsAlphabetic ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN IsLowercase(theChar) OR IsUppercase(theChar);
END IsAlphabetic;
(*--------------------*)
PROCEDURE IsDigit ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN (MIN(DigitCharacter) <= theChar) & (theChar <= MAX(DigitCharacter))
OR
(MIN(HexCharacter) <= theChar) & (theChar <= MAX(HexCharacter));
END IsDigit;
(*--------------------*)
PROCEDURE IsBinaryDigit ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN (MIN(BinaryCharacter) <= theChar) & (theChar <= MAX(BinaryCharacter));
END IsBinaryDigit;
(*--------------------*)
PROCEDURE IsOctalDigit ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN (MIN(OctalCharacter) <= theChar) & (theChar <= MAX(OctalCharacter));
END IsOctalDigit;
(*--------------------*)
PROCEDURE IsDecimalDigit ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN (MIN(DigitCharacter) <= theChar) & (theChar <= MAX(DigitCharacter));
END IsDecimalDigit;
(*--------------------*)
PROCEDURE IsHexDigit ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
MakeUppercase(theChar);
RETURN (MIN(HexCharacter) <= theChar) & (theChar <= MAX(HexCharacter));
END IsHexDigit;
(*--------------------*)
PROCEDURE IsAlphanumeric ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN IsDigit(theChar) OR IsLowercase(theChar) OR IsUppercase(theChar);
END IsAlphanumeric;
(*--------------------*)
PROCEDURE IsSpecial ( theChar : CHAR (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
RETURN ~(IsDigit(theChar) OR IsAlphabetic(theChar)) OR IsControl(theChar);
END IsSpecial;
(*--------------------*)
PROCEDURE ValueOf ( theChar : CHAR (*-- in *))
: Digit (*-- out *);
CONST MinDecCharValue = VAL(CARDINAL,MIN(DigitCharacter));
MinHexCharValue = VAL(CARDINAL,MIN(HexCharacter));
BEGIN
IF IsDecimalDigit(theChar) THEN
RETURN ORD(theChar) - MinDecCharValue;
ELSIF IsHexDigit(theChar) THEN
RETURN ORD(theChar) - MinHexCharValue + 10;
END (*--if*);
END ValueOf;
(*--------------------*)
PROCEDURE ImageOf ( theDigit: Digit (*-- in *))
: CHAR (*-- out *);
BEGIN
IF (theDigit <= VAL(Digit,MAX(DecimalDigit))) THEN
RETURN CHR(ORD(MIN(DigitCharacter)) + VAL(CARDINAL,theDigit));
ELSE
DEC(theDigit,MAX(DecimalDigit)+1);
RETURN CHR(ORD(MIN(HexCharacter)) + VAL(CARDINAL,theDigit));
END (*--if*);
END ImageOf;
(*--------------------*)
PROCEDURE IndexOf ( theChar : CHAR (*-- in *))
: Letter (*-- out *);
BEGIN
IF IsLowercase(theChar) THEN
RETURN ORD(theChar) - ORD(MIN(LowercaseCharacter)) + 1;
ELSIF IsUppercase(theChar) THEN
RETURN ORD(theChar) - ORD(MIN(UppercaseCharacter)) + 1;
END (*--if*);
END IndexOf;
(*--------------------*)
PROCEDURE UppercaseOf ( theLetter: Letter (*-- in *))
: CHAR (*-- out *);
BEGIN
RETURN CHR(ORD(MIN(UppercaseCharacter)) + VAL(CARDINAL,theLetter - 1) );
END UppercaseOf;
(*--------------------*)
PROCEDURE LowercaseOf ( theLetter: Letter (*-- in *))
: CHAR (*-- out *);
BEGIN
RETURN CHR(ORD(MIN(LowercaseCharacter)) + VAL(CARDINAL,theLetter - 1) );
END LowercaseOf;
(*--------------------*)
PROCEDURE IsEqual ( left : CHAR (*-- in *);
right : CHAR (*-- in *);
caseSensitive: BOOLEAN (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
IF caseSensitive THEN
RETURN (left = right);
END (*--if*);
RETURN (CAP(left) = CAP(right));
END IsEqual;
(*--------------------*)
PROCEDURE IsLessThan ( left : CHAR (*-- in *);
right : CHAR (*-- in *);
caseSensitive: BOOLEAN (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
IF caseSensitive THEN
RETURN (left < right);
END (*--if*);
RETURN (CAP(left) < CAP(right));
END IsLessThan;
(*--------------------*)
PROCEDURE IsGreaterThan ( left : CHAR (*-- in *);
right : CHAR (*-- in *);
caseSensitive: BOOLEAN (*-- in *))
: BOOLEAN (*-- out *);
BEGIN
IF caseSensitive THEN
RETURN (left > right);
END (*--if*);
RETURN (CAP(left) > CAP(right));
END IsGreaterThan;
(*--------------------*)
END CharUtils.