Acho que conseguÃ, com certeza ainda pode ser enxugado o código, mas acredito que está funcionando bem para CNHs e PGUs:
PARAMETERS xCnh
IF xCnh=NIL
? "Falta parametro"
QUIT
ELSE
xCnh:=SO_NUMEROS(xCnh)
ENDIF
IF VER_PGU(xCnh) .or. VER_CNH(xCnh)
? "CNH OK"
ELSE
? "CNH INCORRETO"
ENDIF
FUNCTION VER_PGU(cPgu)
Result := .F.
if !(len(alltrim(cPgu)) = 9)
Return Result
endif
PGU_Forn := substr(cPgu,1,8)
Dig_Forn := substr(cPgu,9,1)
Soma := 0
Mult := 2
for j := 1 to 8
Soma := Soma + (val(substr(PGU_Forn,j,1)) * Mult)
Mult := Mult + 1
next
Digito := int(mod(Soma,11))
if Digito > 9
Digito := 0
endif
Dig_Enc := alltrim(Str(Digito))
if Dig_Forn = Dig_enc
Result := .T.
endif
if Dig_Forn <> Dig_enc
Result := .F.
endif
Return Result
FUNCTION VER_CNH(cCnh)
Result := .F.
if !(len(alltrim(cCnh))) = 11
Return Result
endif
CNH_Forn := substr(cCnh,1,9)
Dig_Forn := substr(cCnh,10,2)
Incr_Dig2 := 0
Soma := 0
Mult := 9
for j := 1 to 9
Soma := Soma + (val(substr(CNH_Forn,j,1)) * Mult)
Mult := Mult - 1
next
Digito1 := int(mod(Soma,11))
if Digito1 = 10
Incr_Dig2 := -2
endif
if Digito1 > 9
Digito1 := 0
endif
Soma := 0
Mult := 1
for j := 1 to 9
Soma := Soma + (val(substr(CNH_Forn,j,1)) * Mult)
Mult := Mult + 1
next
if int(mod(Soma,11)) + Incr_Dig2 < 0
Digito2 := 11 + int(mod(Soma,11)) + Incr_Dig2
endif
if int(mod(Soma,11)) + Incr_Dig2 >= 0
Digito2 := int(mod(Soma,11)) + Incr_Dig2
endif
if Digito2 > 9
Digito2 := 0
endif
Dig_Enc := alltrim(str(Digito1))+alltrim(str(Digito2))
if Dig_Forn = Dig_enc
Result := .T.
endif
if !(Dig_Forn = Dig_enc)
Result := .F.
endif
Return Result
FUNCTION SO_NUMEROS(xCnh)
cNums:=""
for u=1 to len(xCnh)
if isdigit(substr(xCnh,u,1))
cNums:=cNums+substr(xCnh,u,1)
endif
next
Return cNums
É bom conhecer outras linguagens de programação, o Delphi não deixa de ser Pascal (muito parecido a Clipper, tem bastante de C e algo de Java) o que me facilitou a comprensão. Bom espero que o código seja bastante útil, eu o único que fiz é adapta-lo.