*
* Check one or more ISINs specified as command line arguments
*

       PROGRAM VALIDATE_ISIN
       IMPLICIT NONE

       CHARACTER*13 ISIN
       INTEGER      I
       LOGICAL      IS_ISIN

       DO I = 1, IARGC()
           CALL GETARG(I, ISIN)
           IF (IS_ISIN(ISIN)) THEN
               PRINT *, 'ISIN ''', ISIN, ''' is valid'
           ELSE
               PRINT *, 'ISIN ''', ISIN, ''' is invalid'
           ENDIF
       ENDDO

       STOP
       END

*
* Checks whether an ISIN is valid
*

       LOGICAL FUNCTION IS_ISIN(ISIN)
       CHARACTER*13 ISIN

       INTEGER      I
       INTEGER      NEWSUM, OLDSUM
       INTEGER      D1
       INTEGER      D2
       LOGICAL      MULTIPLY
       LOGICAL      IS_DIGIT
       LOGICAL      IS_UPPER

       IF (LEN_TRIM(ISIN) .NE. 12) THEN
           IS_ISIN = .FALSE.
           RETURN
       ENDIF

       IF (IS_DIGIT(ISIN(12:12)) .EQV. .FALSE.) THEN
           IS_ISIN = .FALSE.
           RETURN
       ENDIF

       NEWSUM = 0
       MULTIPLY = .TRUE.

       DO I = 11, 1, -1
           IF (I .EQ. 0 .OR. I .EQ. 1) THEN
               IF (IS_UPPER(ISIN(I:I))) THEN
                   D1 = IACHAR(ISIN(I:I)) - IACHAR('A') + 10
               ELSE
                   IS_ISIN = .FALSE.
                   RETURN
               ENDIF
           ELSE
               IF (IS_UPPER(ISIN(I:I))) THEN
                   D1 = IACHAR(ISIN(I:I)) - IACHAR('A') + 10
               ELSE IF (IS_DIGIT(ISIN(I:I))) THEN
                   D1 = IACHAR(ISIN(I:I)) - IACHAR('0')
               ELSE
                   IS_ISIN = .FALSE.
                   RETURN
               ENDIF
           ENDIF

           IF (D1 .LT. 10) THEN
               IF (MULTIPLY) THEN
                   D1 = D1 * 2
               ENDIF
               MULTIPLY = .NOT. MULTIPLY
           ELSE
               D2 = D1 / 10
               D1 = MOD(D1, 10)
               IF (MULTIPLY) THEN
                   D1 = D1 * 2
               ELSE
                   D2 = D2 * 2
               ENDIF
               NEWSUM = NEWSUM + MOD(D2, 10) + (D2 / 10)
           ENDIF
           NEWSUM = NEWSUM + MOD(D1, 10) + (D1 / 10)
       ENDDO

       NEWSUM = MOD(NEWSUM, 10)
       NEWSUM = 10 - NEWSUM
       NEWSUM = MOD(NEWSUM, 10)

       OLDSUM = IACHAR(ISIN(12:12)) - IACHAR('0')

       IF (OLDSUM .NE. NEWSUM) THEN
           IS_ISIN = .FALSE.
           RETURN
       ENDIF

       IS_ISIN = .TRUE.

       RETURN
       END

*
* Checks whether a character is a digit
*

       LOGICAL FUNCTION IS_DIGIT(C)
       CHARACTER*1  C

       CHARACTER*10 DIGIT
       INTEGER      INDX

       DIGIT = '0123456789'
       INDX = INDEX(DIGIT, C)
       IF (INDX .NE. 0) THEN
           IS_DIGIT = .TRUE.
       ELSE
           IS_DIGIT = .FALSE.
       ENDIF

       RETURN
       END

*
* Checks whether a character is an uppercase letter
*

       LOGICAL FUNCTION IS_UPPER(C)
       CHARACTER*1  C

       CHARACTER*26 UPPER
       INTEGER      INDX

       UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
       INDX = INDEX(UPPER, C)
       IF (INDX .NE. 0) THEN
           IS_UPPER = .TRUE.
       ELSE
           IS_UPPER = .FALSE.
       ENDIF

       RETURN
       END
