Create a password generation program which will generate passwords containing random ASCII characters from the following groups:

         lower-case letters:  a ──► z
         upper-case letters:  A ──► Z
                     digits:  0 ──► 9
 other printable characters:  !"#$%&'()*+,-./:;<=>?@[]^_{|}~ 
 (the above character list excludes white-space, backslash and grave) 



The generated password(s) must include   at least one   (of each of the four groups):

   lower-case letter, 
   upper-case letter,
   digit  (numeral),   and 
   one  "other"  character. 



The user must be able to specify the password length and the number of passwords to generate.

The passwords should be displayed or written to a file, one per line.

The randomness should be from a system source or library.

The program should implement a help option or button which should describe the program and options when invoked.

You may also allow the user to specify a seed value, and give the option of excluding visually similar characters.

For example:            Il1     O0     5S     2Z            where the characters are:

   capital eye, lowercase ell, the digit one
   capital oh, the digit zero 
   the digit five, capital ess
   the digit two, capital zee


EnableExplicit
 
Procedure.b CheckPW(pw.s)
  Define flag.b=#True,
         tmp.b=#False,
         c.c,
         s.s,
         i.i  
  For c='a' To 'z'
    tmp=Bool(FindString(pw,Chr(c)))
    If tmp : Break : EndIf
  Next  
  flag & tmp
  tmp=#False  
  For c='A' To 'Z'
    tmp=Bool(FindString(pw,Chr(c)))
    If tmp : Break : EndIf
  Next  
  flag & tmp
  tmp=#False  
  For c='0' To '9'
    tmp=Bool(FindString(pw,Chr(c)))
    If tmp : Break : EndIf
  Next  
  flag & tmp
  tmp=#False  
  For c='!' To '/'
    s+Chr(c)
  Next  
  For c=':' To '@'
    s+Chr(c)
  Next  
  s+"[]^_{|}~"  
  For i=1 To Len(pw)
    tmp=Bool(FindString(s,Mid(pw,i,1)))
    If tmp : Break : EndIf
  Next    
  flag & tmp  
  ProcedureReturn flag
EndProcedure
 
Procedure.s InputHdl(prompt.s="")
  Define txt.s,
         s.s,
         r.i,
         hlp.s  
  Restore Help_01
  Read.s hlp  
  Print(prompt)       
  Repeat
    s=Inkey()    
    If s<>""
      If FindString("0123456789",s)
        txt+s
        Print(s)
      EndIf
      If s=Chr(27)
        txt="0"
        Break
      EndIf            
    ElseIf RawKey()
      r=RawKey()      
      If r=112
        PrintN("")
        PrintN(hlp)  
        Print(~"\n"+prompt)
      EndIf
    EndIf
    Delay(20)
  Until s=Chr(13)
  PrintN("")  
  ProcedureReturn txt
EndProcedure
 
NewList PasswordChar.c()
Define c.c,
       pwlen.i,
       n_of_pw.i, 
       pwstr.s,
       i.i
For c='!' To '~'
  If c<>'\' And c<>'`'
    AddElement(PasswordChar()) : PasswordChar()=c
  EndIf  
Next
OpenConsole("Password generator: F1=Help; Esc=End")
Repeat
  pwlen=Abs(Val(InputHdl("Length of the password (n>=4): ")))
  If pwlen=0 : Break : EndIf
  If pwlen<4 : Continue : EndIf
  n_of_pw=Abs(Val(InputHdl("Number of passwords (n>=1): ")))
  If n_of_pw=0 : Break : EndIf  
  For i=1 To n_of_pw    
    Repeat      
      pwstr=Mid(pwstr,2)
      RandomizeList(PasswordChar())
      ResetList(PasswordChar())      
      While NextElement(PasswordChar())
        pwstr+Chr(PasswordChar())      
        If Len(pwstr)>=pwlen : Break : EndIf
      Wend
    Until CheckPW(pwstr)
    PrintN(RSet(Str(i),Len(Str(n_of_pw))," ")+") "+pwstr)
    pwstr=""
  Next
  PrintN("")
ForEver
End
 
DataSection
  Help_01:
  Data.s ~"Help: Password generator\n"+
         ~"------------------------\n"+
         ~"Blabla bla blabla bla blablabla.\n"+
         ~"Blabla bla  blablabla.\n"+
         ~"Bla blabla bla blablabla bla.\n"+
         ~"Blabla bla blabla bla.\n"+
         ~"Bla blabla bla blablabla blablabla.\n"+
         ~"Blabla bla blabla bla blablabla.\n"+
         ~"Blabla blabla bla blablabla."
  EndOfHelp:
EndDataSection