RosettaCodeData/Task/Password-generator/OoRexx/password-generator.rexx
2023-07-01 13:44:08 -04:00

98 lines
6.4 KiB
Rexx

/*REXX program generates a random password according to the Rosetta Code task's rules.*/
parse arg L N seed xxx dbg /*obtain optional arguments from the CL*/
casl= 'abcdefghijklmnopqrstuvwxyz' /*define lowercase alphabet. */
casu= translate(casle) /*define uppercase alphabet. */
digs= '0123456789' /*define digits. */
/* avoiding the ambiguous characters Il1 o0 5S */
casl= 'abcdefghijkmnpqrtuvwxy' /*define lowercase alphabet. */
casu= translate(casl) /*define uppercase alphabet. */
digs= '0123456789' /*define digits. */
spec= '''!"#$%&()+,-./:;<=>?@[]^{|}~' /*define a bunch of special characters.*/
if L='?' then call help /*does user want documentation shown? */
if L='' | L="," then L=8 /*Not specified? Then use the default.*/
If N='' | N="," then N=1 /* " " " " " " */
If xxx=''| xxx="," then xxx='1lI0O2Z5S' /* " " " " " " */
if seed>'' &,
seed<>',' then Do
if \datatype(seed,'W')then call ser "seed is not an integer:" seed
Call random ,,seed /*the seed for repeatable RANDOM BIF #s*/
End
casl=remove(xxx,casl)
casu=remove(xxx,casu)
digs=remove(xxx,digs)
Say 'casl='casl
Say 'casu='casu
Say 'digs='digs
Say 'spec='spec
if \datatype(L, 'W') then call ser "password length, it isn't an integer: " L
if L<4 then call ser "password length, it's too small: " L
if L>80 then call ser "password length, it's too large: " L
if \datatype(N, 'W') then call ser "number of passwords, it isn't an integer: " N
if N<0 then call ser "number of passwords, it's too small: " N
do g=1 for N /*generate N passwords (default is 1)*/
pw=letterL()||letterU()||numeral()||special()/*generate 4 random PW constituents.*/
do k=5 to L; z=random(1, 4) /* [?] flush out PW with more parts. */
if z==1 then pw=pw || letterL() /*maybe append random lowercase letter.*/
if z==2 then pw=pw || letterU() /* " " " uppercase " */
if z==3 then pw=pw || numeral() /* " " " numeral */
if z==4 then pw=pw || special() /* " " " special character*/
end /*k*/ /* [?] code below randomizes PW chars.*/
t=length(pw) /*the length of the password (in bytes)*/
do L+L /*perform a random number of char swaps*/
a=random(1,t); x=substr(pw,a,1) /*A: 1st char location; X is the char.*/
b=random(1,t); y=substr(pw,b,1) /*B: 2nd " " Y " " " */
pw=overlay(x,pw,b); pw=overlay(y,pw,a) /* swap the two chars. */
end /*swaps*/ /* [?] perform extra swap to be sure. */
say right(g,length(N)) 'password is: ' pw counts() /*display the Nth password */
end /*g*/
exit /*stick a fork in it, we're all done. */
/*--------------------------------------------------------------------------------------*/
ser: say; say '***error*** invalid' arg(1); exit 13 /*display an error message*/
letterL: return substr(casl, random(1, length(casl)), 1) /*return random lowercase.*/
letterU: return substr(casu, random(1, length(casu)), 1) /* " " uppercase.*/
numeral: return substr(digs, random(1, length(digs)), 1) /* " " numeral. */
special: return substr(spec, random(1, length(spec)), 1) /* " " special char*/
remove: Procedure
Parse arg nono,s
Return space(translate(s,'',nono),0)
/*--------------------------------------------------------------------------------------*/
counts:
If dbg>'' Then Do
cnt.=0
str.=''
Do j=1 To length(pw)
c=substr(pw,j,1)
If pos(c,casL)>0 Then Do; cnt.0casL=cnt.0casL+1; str.0casL=str.0casL||c; End
If pos(c,casU)>0 Then Do; cnt.0casU=cnt.0casU+1; str.0casU=str.0casU||c; End
If pos(c,digs)>0 Then Do; cnt.0digs=cnt.0digs+1; str.0digs=str.0digs||c; End
If pos(c,spec)>0 Then Do; cnt.0spec=cnt.0spec+1; str.0spec=str.0spec||c; End
End
txt=cnt.0casL cnt.0casU cnt.0digs cnt.0spec
If pos(' 0 ',txt)>0 Then
txt=txt 'error'
Return txt str.0casL str.0casU str.0digs str.0spec
End
Else
txt=''
Return txt
help: signal .; .: do j=sigL+2 to sourceline()-1; say sourceline(j); end; exit 0
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~ documentation begins on next line.~~~~~~~~~~~~~~~~~~~~~~~~~
+-----------------------------------------------------------------------------+
¦ Documentation for the GENPW program: ¦
¦ ¦
¦ Rexx genpwd <length|,> <howmany|,> <seed|,> <xxx|,> <dbg> ¦
¦ 8 1 n '1lI0O2Z5S' none Defaults ¦
¦ ¦
¦--- where: ¦
¦ length is the length of the passwords to be generated. ¦
¦ The default is 8. ¦
¦ If a comma (,) is specified, the default is used. ¦
¦ The minimum is 4, the maximum is 80. ¦
¦ ¦
¦ howMany is the number of passwords to be generated. ¦
¦ The default is 1. ¦
¦ xxx Characters NOT to be used in generated passwords ¦
¦ dbg Schow count of characters in the 4 groups ¦
+-----------------------------------------------------------------------------+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~documentation ends on the previous line.~~~~~~~~~~~~~~~~~~~*/