60 lines
2.1 KiB
Text
60 lines
2.1 KiB
Text
MODULE Cusip; (* validate CUSIP codes *)
|
|
IMPORT Strings, Out;
|
|
|
|
CONST cusipBase = 39;
|
|
cusipLength = 9;
|
|
VAR cusipDigits : ARRAY cusipBase + 1 OF CHAR; (* 39 digits + trailing nul *)
|
|
|
|
(* returns TRUE if cusip is a valid CUSIP code, FALSE otherwise *)
|
|
PROCEDURE isCusip( cusip : ARRAY OF CHAR ) : BOOLEAN;
|
|
VAR sum, digit, cPos, checkDigit : INTEGER;
|
|
isValid : BOOLEAN;
|
|
|
|
(* returns the base 39 digit corresponding to a character of a CUSIP code *)
|
|
PROCEDURE cusipDigit( cChar : CHAR ) : INTEGER;
|
|
VAR digit, dPos : INTEGER;
|
|
BEGIN
|
|
digit := -999;
|
|
dPos := 0;
|
|
WHILE ( dPos <= cusipBase ) & ( digit < 0 ) DO
|
|
IF cusipDigits[ dPos ] = cChar THEN digit := dPos END;
|
|
INC( dPos )
|
|
END
|
|
RETURN digit
|
|
END cusipDigit ;
|
|
|
|
BEGIN
|
|
IF Strings.Length( cusip ) # cusipLength THEN
|
|
isValid := FALSE (* invalid length code *)
|
|
ELSE
|
|
(* CUSIP code has the correct length *)
|
|
sum := 0;
|
|
checkDigit := cusipDigit( cusip[ cusipLength - 1 ] );
|
|
FOR cPos := 0 TO cusipLength - 2 DO
|
|
digit := cusipDigit( cusip[ cPos ] );
|
|
IF ODD( cPos ) THEN digit := digit * 2 END;
|
|
INC( sum, ( digit DIV 10 ) + ( digit MOD 10 ) )
|
|
END;
|
|
isValid := ( 10 - ( sum MOD 10 ) ) MOD 10 = checkDigit
|
|
END
|
|
RETURN isValid
|
|
END isCusip ;
|
|
|
|
PROCEDURE testCusip( cusip : ARRAY OF CHAR ) ;
|
|
BEGIN
|
|
Out.String( cusip );
|
|
IF isCusip( cusip ) THEN Out.String( " valid" ) ELSE Out.String( " invalid" ) END;
|
|
Out.Ln
|
|
END testCusip;
|
|
|
|
BEGIN
|
|
|
|
cusipDigits := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*@#";
|
|
|
|
testCusip( "037833100" );
|
|
testCusip( "17275R102" );
|
|
testCusip( "38259P508" );
|
|
testCusip( "594918104" );
|
|
testCusip( "68389X106" );
|
|
testCusip( "68389X105" )
|
|
END Cusip.
|