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.