C     RENBR(RSMPSW/MERGES PASSWORD AND STUDENT LISTS)
C
C     DONALD BARTH, YALE SCHOOL OF MANAGEMENT
C
C     The  RSMPSW  program  merges  a  list   of   possible
C     passwords  and  a  list of student names to produce a
C     file of assigned numbers and  passwords  for  use  by
C     either  the RESUME program or the JOBS program.  Each
C     line in the  resulting  file  contains  a  number,  a
C     password,  an  exclamation  point  and  the student's
C     name.
C
C     The file of student names must contain  only  1  name
C     per  line.   The  names are copied into the resulting
C     file in the same order as they appear in the original
C     file.   It  is suggested that these names should have
C     been sorted in alphabetical  order  before  they  are
C     processed by the RSMPSW program.
C
C     The file of possible passwords  can  have  the  words
C     wrapped  around  into  lines  of  up to 80 characters
C     each.  Any text file of reasonable length can be used
C     to  define  the passwords.  Only passwords containing
C     from 4 to 8 characters each are used.
C
C     The first approximately 200 passwords in the original
C     file  are stored in a hopper.  The passwords are then
C     selected from this hopper at random.  When the hopper
C     is  empty,  the  next  group  of  passwords  from the
C     orignal file are placed into the hopper.  Once all of
C     the  passwords  in  the original file have been used,
C     the hopper is filled with passwords from the start of
C     the  original  file  again.  Duplicates are discarded
C     each time the hopper is filled, but a password  in  1
C     filling  of  the  hopper  might  have  appeared  in a
C     previous filling of the hopper.
C
C     LTRSTR = ARRAY HOLDING MANY PASSWORDS EACH CONTAINING
C              MAXLTR LETTERS
C     LTRNAM = ARRAY INTO WHICH STUDENT NAMES ARE READ
C     LTRLIN = ARRAY HOLDING SINGLE LINE FROM PASSWORD FILE
      DIMENSION LTRSTR(2000),LTRNAM(40),LTRLIN(80)
C
C     FILE NAMES
      DOUBLE PRECISION FILONE,FILTWO,FILTHR,FILFOU
C
C     LTRABC = ARRAY CONTAINING UPPER CASE LETTERS A-Z
C     LWRABC = ARRAY CONTAINING LOWER CASE LETTERS A-Z
      DIMENSION LTRABC(26),LWRABC(26)
C
C     ARRAY CONTAINING UPPER CASE LETTERS A THROUGH Z
      DATA LTRABC /1HA,1HB,1HC,1HD,1HE,1HF,1HG,1HH,1HI,1HJ,
     1 1HK,1HL,1HM,1HN,1HO,1HP,1HQ,1HR,1HS,1HT,1HU,1HV,1HW,
     2 1HX,1HY,1HZ/
C
C     ARRAY CONTAINING LOWER CASE LETTERS A THROUGH Z
      DATA LWRABC /1Ha,1Hb,1Hc,1Hd,1He,1Hf,1Hg,1Hh,1Hi,1Hj,
     1 1Hk,1Hl,1Hm,1Hn,1Ho,1Hp,1Hq,1Hr,1Hs,1Ht,1Hu,1Hv,1Hw,
     2 1Hx,1Hy,1Hz/
C
C     MINLTR = MINIMUM NUMBER OF LETTERS IN SINGLE PASSWORD
C     MAXLTR = MAXIMUM NUMBER OF LETTERS IN SINGLE PASSWORD
      DATA MINLTR,MAXLTR/4,8/
C
C     UNIT NUMBERS
C     ITTY   = UNIT NUMBER FOR TERMINAL
C     IDISK  = UNIT NUMBER FROM WHICH READ STUDENT NAMES
C     JDISK  = UNIT NUMBER FROM WHICH READ TEXT CONTAINING
C              THE PASSWORDDS
C     KDISK  = UNIT NUMBER TO WHICH IS WRITTEN FILE TO BE
C              USED BY PASSWORD CHECKER IN JOBS OR RESUME
C              PROGRAM
C     LDISK  = UNIT NUMBER TO WHICH IS WRITTEN FILE TO BE
C              USED FOR SPLICING NAMES AND PASSWORDS INTO
C              FORM LETTERS USING FROFF WORD PROCESSOR
      DATA ITTY,IDISK,JDISK,KDISK,LDISK/5,1,20,21,22/
C
C     LMTSTR = TOTAL NUMBER OF LETTERS IN ALL PASSWORDS IN
C              HOPPER
C     LMTWID = NUMBER OF CHARACTERS IN SINGLE LINE IN TEXT
C              FILE
C     LMTNAM = NUMBER OF LETTERS IN A STUDENT NAME
      DATA LMTSTR,LMTWID,LMTNAM/2000,80,40/
C
C     VARIOUS SINGLE CHARACTERS
C     LTRSPA = THE SPACE OR BLANK
C     LTREQU = THE EQUAL SIGN
C     LTREXC = THE EXCLAMATION POINT
C     LTRMIN = THE MINUS OR HYPHEN
C     LTRAPO = THE APOSTROPHE
      DATA LTRSPA,LTREQU,LTREXC,LTRMIN,LTRAPO/
     1 1H ,1H=,1H!,1H-,1H'/
C
C     TELL USER WHAT PROGRAM THIS IS
      WRITE(ITTY,1)
    1 FORMAT(' RSMPSW'/
     1' Merges password list and student name list'/)
C
C     OPEN FILE CONTAINING STUDENT NAMES
    2 WRITE(ITTY,3)
    3 FORMAT(' File containing list of student names? ',$)
      READ(ITTY,4)FILONE
    4 FORMAT(1A10)
      OPEN(UNIT=IDISK,FILE=FILONE,ACCESS='SEQIN',ERR=5)
      GO TO 7
    5 WRITE(ITTY,6)
    6 FORMAT(' Cannot open file')
      GO TO 2
    7 CONTINUE
C
C     OPEN FILE CONTAINING PASSWORDS
    8 WRITE(ITTY,9)
    9 FORMAT(' File containing list of passwords? ',$)
      READ(ITTY,10)FILTWO
   10 FORMAT(1A10)
      OPEN(UNIT=JDISK,FILE=FILTWO,ACCESS='SEQIN',ERR=11)
      GO TO 13
   11 WRITE(ITTY,12)
   12 FORMAT(' Cannot open file')
      GO TO 8
   13 CONTINUE
C
C     OPEN OUTPUT FILE TO BE READ BY JOBS OR RESUME PROGRAM
   14 WRITE(ITTY,15)
   15 FORMAT(' Output file for password checker? ',$)
      READ(ITTY,16)FILTHR
   16 FORMAT(1A10)
      OPEN(UNIT=KDISK,FILE=FILTHR,ACCESS='SEQOUT',ERR=17)
      GO TO 19
   17 WRITE(ITTY,18)
   18 FORMAT(' Cannot open file')
      GO TO 14
   19 CONTINUE
C
C     OPEN OUTPUT FILE TO BE USED FOR FORM LETTERS
   20 WRITE(ITTY,21)
   21 FORMAT(' Output file for word processor? ',$)
      READ(ITTY,22)FILFOU
   22 FORMAT(1A10)
      OPEN(UNIT=LDISK,FILE=FILFOU,ACCESS='SEQOUT',ERR=23)
      GO TO 25
   23 WRITE(ITTY,24)
   24 FORMAT(' Cannot open file')
      GO TO 20
   25 CONTINUE
C
C     GET KERNEL FOR RANDOM NUMBER GENERATOR
      WRITE(ITTY,26)
   26 FORMAT(' Kernel for random numbers? ',$)
      READ(ITTY,27)KERNEL
   27 FORMAT(I)
C
C     FIND OUT HOW MANY INITIAL PASSWORDS TO REJECT
      WRITE(ITTY,28)
   28 FORMAT(' Discard how many initial passwords? ',$)
      READ(ITTY,27)IREJCT
C
C     FIND OUT WHAT FRACTION OF PASSWORDS TO USE
      WRITE(ITTY,29)
   29 FORMAT(' On average, Use 1 password out of how many? ',$)
      READ(ITTY,27)JREJCT
C
C     FIND OUT FIRST STUDENT NUMBER AND INCREMENT
      WRITE(ITTY,30)
   30 FORMAT(' Number to assign to first student? ',$)
      READ(ITTY,27)INITAL
      IF(INITAL.LT.0)INITAL=0
      WRITE(ITTY,31)
   31 FORMAT(' Increment each student number how much? ',$)
      READ(ITTY,27)INCRMT
      IF(INCRMT.LE.0)INCRMT=1
C
C     INITIALIZE RANDOM NUMBER SEQUENCE
      CALL SETRAN(KERNEL)
C
C     SET INITIAL CONDITIONS
C     KNTNAM = TOTAL NUMBER OF STUDENT NAMES PROCESSED
C     KNTWRD = NUMBER OF PASSWORDS NOW IN HOPPER
C     KNTTTL = TOTAL NUMBER OF PASSWORDS EVER PLACED IN
C              HOPPER
C     LMTWRD = MAXIMIM NUMBER OF PASSWORDS IN HOPPER
C     LMTSTR = MAXIMUM NUMBER OF CHARACTERS IN HOPPER
C     MAXLTR = MAXIMUM LENGTH OF ANY ONE PASSWORD
C     MAXWRD = LOCATION OF RIGHT END OF LAST WORD FROM TEXT
C              FILE
C     KNTOPN = NUMBER OF TIMES TEXT FILE WAS READ
C     NEEDED = NUMBER OF PASSWORDS WHICH COULD NOT BE
C              REJECTED AT END OF LAST HOPPER
      KNTNAM=0
      KNTWRD=0
      KNTTTL=0
      LMTWRD=LMTSTR/MAXLTR
      MAXWRD=LMTWID
      KNTOPN=1
      NEEDED=0
C
C     GET NEXT STUDENT NAME
   32 READ(IDISK,33,END=65)LTRNAM
   33 FORMAT(40A1)
      MAXNAM=LMTNAM+1
   34 MAXNAM=MAXNAM-1
      IF(MAXNAM.LE.0)GO TO 32
      IF(LTRNAM(MAXNAM).EQ.LTRSPA)GO TO 34
      IF(MAXNAM.NE.1)GO TO 35
      IF(LTRNAM(1).EQ.LTREQU)GO TO 65
   35 KNTNAM=KNTNAM+1
C
C     GET NEXT LINE OF PASSWORDS
      IF(KNTWRD.NE.0)GO TO 58
      GO TO 40
   36 READ(JDISK,37,END=39)LTRLIN
   37 FORMAT(80A1)
      MAXWRD=0
C
C     TEST FOR LINE CONTAINING ONLY = MARKING END OF FILE
      IF(LTRLIN(1).NE.LTREQU)GO TO 40
      ITEST=1
   38 ITEST=ITEST+1
      IF(ITEST.GT.LMTWID)GO TO 39
      IF(LTRLIN(ITEST).EQ.LTRSPA)GO TO 38
      GO TO 40
C
C     END OF PASSWORD FILE ENCOUNTERED
   39 MAXWRD=LMTWID
      CLOSE(UNIT=JDISK)
      IF(KNTTTL.EQ.0)GO TO 69
      IF(LMTWRD.GT.KNTTTL)LMTWRD=KNTTTL
      KNTOPN=KNTOPN+1
      OPEN(UNIT=JDISK,FILE=FILTWO,ACCESS='SEQIN')
      IF(KNTWRD.LT.LMTWRD)GO TO 36
      GO TO 58
C
C     FIND FIRST LETTER OF PASSWORD
   40 MINWRD=MAXWRD
      KREJCT=0
   41 MINWRD=MINWRD+1
      IF(MINWRD.GT.LMTWID)GO TO 36
      LTRNOW=LTRLIN(MINWRD)
      IF(LTRNOW.EQ.LTRSPA)GO TO 41
      DO 42 LETTER=1,26
      IF(LTRNOW.EQ.LTRABC(LETTER))GO TO 44
      IF(LTRNOW.NE.LWRABC(LETTER))GO TO 42
      LTRLIN(MINWRD)=LTRABC(LETTER)
      GO TO 44
   42 CONTINUE
      IF(LTRNOW.EQ.LTRMIN)GO TO 43
      IF(LTRNOW.EQ.LTRAPO)GO TO 43
      GO TO 41
   43 KREJCT=1
   44 CONTINUE
C
C     FIND FINAL LETTER OF PASSWORD
      MAXWRD=MINWRD
   45 MAXWRD=MAXWRD+1
      IF(MAXWRD.GT.LMTWID)GO TO 48
      LTRNOW=LTRLIN(MAXWRD)
      IF(LTRNOW.EQ.LTRSPA)GO TO 48
      DO 46 LETTER=1,26
      IF(LTRNOW.EQ.LTRABC(LETTER))GO TO 45
      IF(LTRNOW.NE.LWRABC(LETTER))GO TO 46
      LTRLIN(MAXWRD)=LTRABC(LETTER)
      GO TO 45
   46 CONTINUE
      IF(LTRNOW.EQ.LTRMIN)GO TO 47
      IF(LTRNOW.EQ.LTRAPO)GO TO 47
      GO TO 48
   47 KREJCT=1
      GO TO 45
   48 LENGTH=MAXWRD-MINWRD
      MAXWRD=MAXWRD-1
      IF(LENGTH.LT.MINLTR)GO TO 40
      IF(LENGTH.GT.MAXLTR)GO TO 40
      IF(KREJCT.NE.0)GO TO 40
C
C     EXCLUDE DUPLICATE PASSWORDS
      IF(KNTWRD.EQ.0)GO TO 53
      KTEST=0
      DO 52 I=1,KNTWRD
      ITEST=MINWRD
      JTEST=KTEST
      KTEST=KTEST+MAXLTR
      DO 50 J=1,MAXLTR
      JTEST=JTEST+1
      IF(ITEST.LE.MAXWRD)GO TO 49
      IF(LTRSTR(JTEST).NE.LTRSPA)GO TO 52
      GO TO 51
   49 IF(LTRSTR(JTEST).NE.LTRLIN(ITEST))GO TO 52
      ITEST=ITEST+1
   50 CONTINUE
   51 GO TO 40
   52 CONTINUE
   53 CONTINUE
C
C     STORE PASSWORD IN HOPPER
      KNTTTL=KNTTTL+1
      KNTWRD=KNTWRD+1
      ISTORE=MAXLTR*KNTWRD-MAXLTR+1
      DO 54 I=1,MAXLTR
      LTRSTR(ISTORE)=LTRSPA
      IF(MINWRD.LE.MAXWRD)LTRSTR(ISTORE)=LTRLIN(MINWRD)
      ISTORE=ISTORE+1
      MINWRD=MINWRD+1
   54 CONTINUE
      IF(KNTWRD.LT.LMTWRD)GO TO 40
C
C     DISCARD INITIAL PASSWORDS IF NECESSARY
      IF(IREJCT.LE.0)GO TO 57
      KREJCT=IREJCT
      IF(KREJCT.GT.KNTWRD)KREJCT=KNTWRD
      IREJCT=IREJCT-KREJCT
      IMOVE=MAXLTR*KNTWRD
      KNTWRD=KNTWRD-KREJCT
      JMOVE=0
      KMOVE=MAXLTR*KREJCT
   55 JMOVE=JMOVE+1
      KMOVE=KMOVE+1
      IF(KMOVE.GT.IMOVE)GO TO 56
      LTRSTR(JMOVE)=LTRSTR(KMOVE)
      GO TO 55
   56 GO TO 40
   57 CONTINUE
C
C     PICK PASSWORD AT RANDOM FROM HOPPER
C     RAN RETURNS RANDOM VALUE IN RANGE 0.0 THROUGH 1.0
   58 IRANDM=1.0+(RAN(0)*FLOAT(KNTWRD))
      IF(IRANDM.LE.0)IRANDM=1
      IF(IRANDM.GT.KNTWRD)IRANDM=KNTWRD
      IFINAL=MAXLTR*IRANDM
      IFIRST=IFINAL-MAXLTR+1
      IF(INITAL.GT.999999)INITAL=0
      WRITE(KDISK,59)INITAL,(LTRSTR(I),I=IFIRST,IFINAL),
     1 LTREXC,(LTRNAM(I),I=1,MAXNAM)
   59 FORMAT(1I6,1X,100A1)
      WRITE(LDISK,60)(LTRNAM(I),I=1,MAXNAM)
   60 FORMAT(100A1)
      WRITE(LDISK,61)INITAL,(LTRSTR(I),I=IFIRST,IFINAL)
   61 FORMAT(1I6,1X,100A1)
      INITAL=INITAL+INCRMT
C
C     STORE THE TOP PASSWORD IN PLACE OF THE ONE USED
      NEEDED=NEEDED+JREJCT
   62 KNTWRD=KNTWRD-1
      NEEDED=NEEDED-1
      IF(KNTWRD.EQ.0)GO TO 64
      JMOVE=(IRANDM*MAXLTR)-MAXLTR+1
      KMOVE=(KNTWRD*MAXLTR)+1
      DO 63 IMOVE=1,MAXLTR
      LTRSTR(JMOVE)=LTRSTR(KMOVE)
      JMOVE=JMOVE+1
      KMOVE=KMOVE+1
   63 CONTINUE
C
C     REJECT FRACTION OF PASSWORDS IN HOPPER
      IF(NEEDED.LE.0)GO TO 64
      IRANDM=1.0+(RAN(0)*FLOAT(KNTWRD))
      IF(IRANDM.LE.0)IRANDM=1
      IF(IRANDM.GT.KNTWRD)IRANDM=KNTWRD
      GO TO 62
   64 GO TO 32
C
C     MARK THE END OF THE OUTPUT FILES
   65 WRITE(KDISK,66)
   66 FORMAT('=')
      CLOSE(UNIT=KDISK)
      WRITE(LDISK,67)
   67 FORMAT('.END FILE')
      CLOSE(UNIT=LDISK)
C
C     TYPE FINAL SUMMARY ON TERMINAL
      WRITE(ITTY,68)KNTNAM,LMTWRD,KNTTTL,KNTWRD,KNTOPN
   68 FORMAT(
     1' Number of students:      ',1I5/
     2' Hopper size:             ',1I5/
     3' Total passwords scanned: ',1I5/
     4' Passwords left in hopper:',1I5/
     5' Times text file read:    ',1I5)
      GO TO 71
   69 WRITE(ITTY,70)
   70 FORMAT(' File does not contain any passwords that ',
     1'can be used')
      GO TO 71
   71 STOP
      END
