.;	FILE:	SORT.CMD
.;
.;	AUTHOR:	ROGER JENKINS
.;		WYCLIFFE BIBLE TRANSLATORS
.;		HUNTINGTON BEACH, CA 92647
.;		(714)536-9346
.;
.;	DATE:	25-JAN-82
.;
.;
.; This command file will create a sort specification file based on
.; user input to various questions.  The overall flow of the command file is:
.;
.;	GET FILE-SPEC.
.;
.;	GET HEADER DATA:
.;	    SORT TYPE
.;	    NORMAL SORT SEQUENCE
.;	    COLLATING SEQUENCE
.;	    ARE KEYS TO BE STRIPPED FROM THE OUTPUT DATA
.;	    OUTPUT RECORD LENGTH.
.;
.;	IF COLLATING SEQUENCE IS "X", GET ALTERNATE SEQUENCE DATA:
.;	    UNTIL <RETURN> GET ALTSEQ CHARACTER PAIR.
.;
.;	UNTIL NO MORE ARE WANTED, GET RECORD TYPE SPECIFICATION DATA:
.;	    INCLUSION, OMISSION OR SPECIAL INCLUSION
.;	    IF NOT FIRST, GET CONTINUATION TYPE ("AND" OR "OR")
.;	    FIELD MODE
.;	    FACTOR 1 STARTING COLUMN
.;	    FACTOR 1 ENDING COLUMN
.;	    FACTOR 2 TYPE (FIELD OR CONSTANT)
.;	    RELATIONSHIP BETWEEN FACTOR 1 AND FACTOR 2
.;	    IF FACTOR 2 TYPE IS CONSTANT:
.;		GET FACTOR 2 CONSTANT.
.;	    ELSE:
.;		GET FACTOR 2 STARTING AND ENDING POINTS.
.;
.;	UNTIL NO MORE ARE WANTED, GET FIELD SPECIFICATION DATA:
.;	    RECORD TYPE (N, O, F OR D)
.;	    FIELD MODE
.;	    KEY STARTING COLUMN
.;	    KEY ENDING COLUMN
.;	    IF RECORD TYPE EQ "F":
.;		GET TRIGGER CHARACTER
.;		GET REPLACEMENT CHARACTER
.;		GET CONTINUATION
.;
.;	REREAD GENERATED FILE AND FILL IN KEY DATA IN HEADER.
.;	END.
.;
	;
	; This command file will create a sort specification file based on
	; user input to various questions.
	;
	; Press ESC for help in answering any question.
	;
	.ENABLE SUBSTITUTION
	.ENABLE ESCAPE
.;
.; INITIALIZE SOME VARIABLES AND CONSTANTS
.;
	.SETS ZERO "0"
	.SETS NINE "9"
	.SETN MAXKEY 0.
	.SETS DOT "."
	.SETS LAST ""
	.SETS MORRTS ""
	.SETS FSMORE ""
	.SETS LINE "00"				! INITIALIZE LINE NUMBER
	.SETS PAGE "00"				! INITIALIZE PAGE NUMBER
.;
.; GET SPECIFICATION FILE NAME
.;
	.GOTO ASK01
.HELP01:
	;
	;
	; The specification file offers a variety of controls for the sorting
	; process.  These controls are entered in a format consisting of up to
	; four types of records or lines in the specification file.  This
	; command file will ask you various questions and based on your
	; answers, will create the specification file for you.  You need
	; to tell us what name you want the specification file to have.
	; The default file name is SORT.SPC.  If you omit the file type,
	; the default file type will be ".SPC"
	;
.ASK01:	.ASKS FILNAM Enter sort specification file name [D: SORT.SPC]
	.IFT <ESCAPE> .GOTO HELP01
	.GOSUB PARSE			! PARSE THE FILE NAME
	.IF DEV EQ "" .SETS DEV "SY:"	! SET DEFAULT DEVICE
	.IF NAM EQ "" .SETS NAM "SORT"	! SET DEFAULT NAME
	.IF TYP EQ "" .SETS TYP ".SPC"	! SET DEFAULT FILE TYPE
	.SETS SPCFIL DEV+UIC+NAM+TYP	! GET IT ALL TOGETHER
.;
.; NOW LET''S OPEN THE SPECIFICATION FILE
.;
	.OPEN 'SPCFIL'
.;
.; SEE IF THEY WANT THE LONG DIALOGUE
.;
	.GOTO ASK02
.HELP02:
	;
	;
	; If you want a plain vanilla flavored specification file, we can make
	; a lot of assumptions and skip many questions.  The following are the
	; assumptions that we will make during the short dialogue but will ask
	; you for during the full dialogue.
	;
	; HEADER:
	; Sort type = TAG		Normal sort sequence = ASCENDING
	; Collating sequence = ASCII	STRIP key fields
	;
	; ALTSEQ:
	; None
	;
	; RECORD TYPE SPECIFICATION:
	; NO Omits	Field mode = C	Factor 2 = CONSTANT
	;
	; FIELD SPECIFICAIONS (KEYS)
	; Field type = N	Field mode = C
	;
.ASK02:	.ASK LONG Do you want the full (long) dialogue
	.IFT <ESCAPE> .GOTO HELP02
	;
.;
.;
.;
.;		1. HEADER RECORD SPECIFICATION
.;
.;
.;
.; GET INFO FOR HEADER RECORD
.;
	.GOTO ASK11
.HELP11:
	;
	;
	; There are four types of sorts:  Record sort, Tag sort, Address
	; routing sort and Index sort.  The default sort is Record sort.
	; Each process has its particular input requirements, processing
	; methods and resultant output files.  Each has it own advantages
	; and disadvantages.  Please see the SORT-11 manual, page 1-8 for
	; a more complete description of each type of sort.
	;
	; Type at least the first letter of the type of sort you want.
	; The default is Tag sort.
	;
.ASK11:
	.IFT LONG .ASKS STYPE Which type of sort do you want [D: TAG SORT]
	.IFT <ESCAPE> .GOTO HELP11
	.IFF LONG .SETS STYPE ""		! IF NOT LONG DIALOGUE.
	.IF STYPE EQ "" .SETS STYPE "T"		! DEFAULT SORT TYPE
	.SETS STYPE STYPE[1:1]			! WE ONLY WANT 1 LETTER
.;
.; MAKE SURE STYPE IS VALID
.;
	.IF STYPE EQ "R" .OR .IF STYPE EQ "T" .GOTO OK
	.IF STYPE EQ "A" .OR .IF STYPE EQ "I" .GOTO OK
	;
	; ILLEGAL SORT TYPE.
	; TRY AGAIN.
	;
	.GOTO ASK11
.OK:	.;
.;
.; GET NORMAL SORT ORDER SEQUENCE
.;
	.GOTO ASK12
.HELP12:
	;
	;
	; You may define the "normal" sort sequence as Ascending or
	; Descending.  Later, you may specify whether a particular key is
	; to be sorted in "normal" or "opposite" sequence.
	;
	; Type either "A" or "D".  Default is "A"
	;
.ASK12:
.IFT LONG .ASKS SRTSEQ Is the normal sort Ascending or Descending [D: A]
	.IFT <ESCAPE> .GOTO HELP12
	.IFF LONG .SETS SRTSEQ ""			! IF NOT LONG DIALOGUE.
	.IF SRTSEQ EQ "" .SETS SRTSEQ "A"		! DEFAULT SEQUENCE
	.SETS SRTSEQ SRTSEQ[1:1]			! WE ONLY WANT 1 CHAR
	.IF SRTSEQ EQ "D" .OR .IF SRTSEQ EQ "A" .GOTO OK ! MAKE SURE ITS VALID
	;
	; YOU MUST ANSWER WITH EITHER "ASCENDING" OR "DESCENDING".
	; TRY AGAIN.
	;
	.GOTO ASK12
.OK:	.;
.;
.; SEE WHAT COLLATING SEQUENCE THEY WANT (ASCII, EBSDIC OR MODIFIED ASCII)
.;
	.GOTO ASK13
.HELP13:
	;
	;
	; This field identifies the sort order for fields identified as
	; alphanumeric in the field specification record.  If X is entered
	; here, then you will have to enter ALTSEQ records.  Standard
	; ASCII is assumed for forced key field specifications and this field
	; cannot be used to ammend that assumption.  
	;
	; Sort does not perform file transliteration.  FILES THAT ARE NOT
	; ALREADY IN STANDARD ASCII CHARACTERS MUST BE TRANSLITERATED BEFORE 
	; THE SORT.  The EBCDIC option specifies ASCII characters sorted into
	; EBCDIC sequence.
	;
	; Answer with a space (for ASCII), E (for EBCDIC) or X (for user-
	; modified ASCII).  Default is a space, ASCII)
	;
.ASK13:
.IFT LONG .ASKS COLSEQ Enter collating sequence (space, E or X) [D: space]
	.IFT <ESCAPE> .GOTO HELP13
	.IFF LONG .SETS COLSEQ ""			! IF NOT LONG DIALOGUE
	.IF COLSEQ EQ "" .SETS COLSEQ " "		! DEFAULT IS A SPACE
	.SETS COLSEQ COLSEQ[1:1]			! WE ONLY WANT 1 CHAR
	.IF COLSEQ EQ " " .OR .IF COLSEQ EQ "E" .OR .IF COLSEQ EQ "X" .GOTO OK
	;
	; ANSWER MUST BE SPACE, "E" OR "X".
	; TRY AGAIN.
	;
	.GOTO ASK13
.OK:	.;
.;
.; SEE IF THEY WANT THE KEY FIELD STRIPPED FROM THE OUTPUT RECORD.
.;
	.GOTO ASK14
.HELP14:
	;
	;
	; If key fields are not stripped from the output record, the key fields
	; may be treated as data fields and moved to the output record as any
	; other data fields would be, whether relocated within the output
	; record with respect to the input record or not.
	;
	; Note that the usual way we do it is to strip the key fields from the
	; output record then define the output record as the entire input
	; record.
	;
	; Answer Yes to leave the keys in the output record or No to have them
	; stripped from the output record.  Default is No.
	;
.ASK14:	.IFT LONG .ASK YN Do you want the key fields left in the output records
	.IFT <ESCAPE> .GOTO HELP14
	.IFF LONG .SETF YN		! IF NOT LONG DIALOGUE
	.IFT YN .SETS STRIP " "		! Y: LEAVE KEY FIELDS
	.IFF YN .SETS STRIP "X"		! N: STRIP KEY FIELDS
.;
.; GET THE OUTPUT RECORD LENGTH
.;
	.IF STYPE EQ "R" .OR .IF STYPE EQ "T" .GOTO ASK15
.;
.; INITIALIZE THE NAME OF THE TIPE OF SORT FOR THE FOLLOWING MESSAGE
.;
	.IF STYPE EQ "A" .SETS S "Address Routing"
	.IF STYPE EQ "I" .SETS S "Index"
	;
	; Since you selected an 'S' sort, the output record length
	; field is not necessary and will be left blank.
	;
	.SETS OUTLEN "    "
	.GOTO WRITE
.HELP15:
	;
	;
	; Enter a decimal number equal to the number of bytes in the largest
	; output record.
	;
	; If the output record is to be the entire input record, then you 
	; should enter the number of bytes in the largest input record.
	;
	; If the output is not the entire input record, then you should add the
	; sizes of all the output data fields in the field specification
.IFT YN	; plus the sizes of the key fields, since they are to be included
	; for the largest output record in the file.
	;
.ASK15:	.ASKN [::80.] N Enter the output record length
	.IFT <ESCAPE> .GOTO HELP15
	.SETS OUTLEN "0000'N'"			! PUT ON PLENTY OF LEADING 0''S
	.TEST OUTLEN				! FIND OUT HOW LONG VAR IS
	.SETS OUTLEN OUTLEN[<STRLEN>-3:<STRLEN>] ! CHOP TO LAST 4 CHARS
.;
.; WRITE HEADER RECORD
.;
.WRITE:	.GOSUB PCOUNT				! INCREMENT AND FORMAT PAGE #
	.GOSUB LCOUNT				! INCREMENT AND FORMAT LINE #
.DATA 'PAGE''LINE' HSORT'STYPE' 00000'SRTSEQ'       'COLSEQ' 'STRIP''OUTLEN'
	;
.;
.;
.;
.; 		2. ALTSEQ RECORD SPECIFICATION
.;
.;
.;
.; SEE IF THEY NEED ALTSEQ RECORDS
.;
	.IF COLSEQ NE "X" .GOTO SELREC
.;
.; SET UP ASCII TRANSLATION TABLES AND START FIRST ALTSEQ RECORD.
.; THESE TABLES ARE USED BY THE SUBROUTINE "ASQCNV"
.;
	.SETS ASCII1 " ! #$%&'()*+,-./0123456789:;<=>?"
	.SETS ASCII2 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_"
	.SETS ASCII3 "`abcdefghijklmnopqrstuvwxyz{|}~"
	.SETS ALTREC "ALTSEQ  "			! INITIALIZE FIRST DATA RECORD
.;
.; GET ONE PAIR AND CONVERT TO OCTAL
.;
	.GOTO ASK21
.HELP21:
	;
	;
	; ALTSEQ records allow you to change the order in which a character or
	; characters are sorted.  You can use these records to:
	;
	; 1) Move certain records to the front or back of a file.
	; 2) Group them in one place within the file.
	; 2) Change the order in which records appear in a given sequence
	;    within the file.
	;
	; You must specify two ASCII characters:  the character being sorted
	; out of sequence and the character that corresponds to its new
	; position in the sorting sequence.  Separate the two characters by a
	; comma.  If instead of typing an ASCII character, you type three
	; octal digits, the octal equivalent will be used instead of an ASCII
	; character.
	;
	; For example, the correct entry to cause an ASCII space to be sorted
	; as an ASCII zero would be either " ,0" or "040,060".
	;
	; Note that control characters and the quote character (") must be
	; entered in octal.
	;
.ASK21:
	.ASKS ASQGRP Enter ALTSEQ character pair. Press <RETURN> when done.
	.IFT <ESCAPE> .GOTO HELP21
	.IF ASQGRP EQ "" .GOTO ENDASQ
.;
.; CONVERT 2 ASCII CHARACTERS
.;
	.PARSE ASQGRP "," ASQCHR CHR2	! SPLIT THE CHRS APART
	.GOSUB ASQCVT			! CONVERT FIRST ONE
	.IFT ASQERR .GOTO ASK21		! CHECK FOR CONVERSION ERRORS
	.SETS CHR1 ASQCHR		! COPY CONVERTED NUM BACK TO RIGHT VAR
.;
	.SETS ASQCHR CHR2		! COPY 2ND NUMBER TO SUB INPUT VAR
	.GOSUB ASQCVT			! CONVERT 2ND NUMBER
	.IFT ASQERR .GOTO ASK21		! CHECK FOR CONVERSION ERRORS
	.SETS CHR2 ASQCHR		! COPY CONVERTED NUM BACK TO RIGHT VAR
.;
.; PLACE THE 2 OCTAL DIGITS ON THE END OF THE ALTSEQ RECORD
.;
	.TEST ALTREC				! IF ALTSEQ REC IS FULL, WRITE.
	.IF <STRLEN> GT 75. .DATA 'ALTREC'
	.IF <STRLEN> GT 75. .SETS ALTREC "ALTSEQ  " ! SET UP NEW ALTSEQ REC
	.SETS ALTREC ALTREC+CHR1+CHR2		! ADD NEW PAIR TO CURRENT REC
	.GOTO ASK21				! DO ANOTHER ONE
.;
.; WRITE LAST RECORD OUT
.;
.ENDASQ: .TEST ALTREC				! LETS MAKE SURE WE HAVE DATA
	.IF <STRLEN> GT 7. .DATA 'ALTREC'
	;
.;
.;
.;
.; 		3. RECORD TYPE SPECIFICATION
.;
.;
.; SEE IF THEY WANT TO INCLUDE A RECORD TYPE SPECIFICATION.
.;
.SELREC:
	.SETT FRSTIO				! THIS IS FIRST IO RECORD
	.SETF DATREC				! NO DATA FIELDS YET
	.SETS FSTYPE ""				! RESET FOR NEW PAGE
	.GOSUB PCOUNT				! INCREMENT AND FORMAT PAGE #
	.GOTO ASK31
.HELP31:
	;
	;
	; Record type specifications control input record selection and allow
	; SORT to work with variable record formats.
	;
	; If all the records in the input file are to be included in the sorted
	; output file and they all have the same format or you are using the
	; entire record as the key, then no record type specification is
	; necessary.  If all the records have the same format and some are to
	; be omitted, then only one record type specification is needed.  If
	; several different formats of records are to be sorted, then there
	; must be a record type specification for each.  Each record type
	; specification used should be followed by its appropriate field 
	; specifications.
	;
.ASK31:
	.ASK RTS Do you want to include any'MORRTS' record type specifications
	.IFT <ESCAPE> .GOTO HELP31
	.SETS MORRTS " more"			! SET VAR FOR NEXT ASK31
.;
.; CHECK OUT POSSIBILITIES:
.;
.;	IF MORE RTS, GET GET ONE
.;	IF NO MORE:
.;	   IF LAST REC WAS FIELD SPEC THEN STOP
.;	   IF LAST WAS RTS "I" GO TO GET FIELD
.;	   IF LAST WAS RTS "O" ERROR (CAN'T STOP ON OMIT)
.;
	.IFT RTS .GOTO GETIO		! MORE RTS. GET REST.
	.IF LAST EQ "F" .GOTO PASS2	! END OF SPEC FILE.
	.IF LAST EQ ""  .GOTO GETFS	! NO RTS RECS AT ALL.
	.IF IO EQ "I" .GOTO GETFS	! END OF RTS RECORDS. GET FIELD SPEC.
	;
	; SPECIFICATION FILE CAN NOT END WITH AN OMISSION RECORD.

	; TRY AGAIN.
	;
	.GOTO ASK31
.;
.; GET INCLUSION OR OMISSION CHARACTER
.;
.GETIO:	.SETS LAST "R"				! LAST (THIS) REC IS RTS
	.GOTO ASK32
.HELP32:
	;
	;
	; This field determines whether the described records will be included
	; or omitted from the output file.
	;
	; If inclusion is specified and the rest of this record specification
	; record is blank, then all input records not previously described will
	; be included in the sort output.  Records that are not described with
	; "Include" specification records will be ignored.  Because SORT
	; processes Include and Omit lines sequentially, you should be very
	; careful to get your lines in the right order, particularly if any
	; records are described on more than one line.  The last record before
	; a Field Specification record must be an Include line.  If you type 
	; "S", then a special include record will be generated for your last
	; record specification record that will include all records not
	; previously described.
	;
	; Note:  Omit records are a little messy to work with, and can usually
	; be avoided by Including all records that would be Omitted.
	;
	; Default is Include.
	;
.ASK32:
.IFT LONG .ASKS IO Is this an Inclusion or Omission specification record [D: I]
	.IFT <ESCAPE> .GOTO HELP32
	.IFF LONG .SETS IO ""			! IF NOT LONG DIALOGUE
	.IF IO EQ "" .SETS IO "I"		! DEFAULT IT "I"
	.SETS IO IO[1:1]			! WE ONLY WANT 1ST CHAR
	.IF IO EQ "I" .OR .IF IO EQ "O" .OR .IF IO EQ "S" .GOTO OK     ! VALID?
	;
	; YOU MAY ONLY ENTER "I", "O" OR "S".
	; TRY AGAIN.
	;
	.GOTO ASK32
.;
.; IF SPECIAL RECORD, SET UP EVERYTHING ELSE FOR THAT.
.;
.OK:	.IF IO NE "S" .GOTO NEXT	! IS THIS THE SPECIAL INCLUDE RECORD?
	.SETS IO "I"			! YES - MAKE IT "INCLUDE"
	.SETS AO ""			! MAKE EVERYTHING ELSE BLANK
	.SETS FLDMOD ""
	.SETS F1SP ""
	.SETS F1EP ""
	.SETS FRELAT ""
	.SETS FC ""
	.SETS F2SP ""
	.SETS F2EP ""
	.GOTO WRTSEL

.; GET CONTINUATION CHARACTER (FOR CONTINUATIONS ONLY)
.;
.NEXT:	.IFT FRSTIO .SETS AO " " ! INITIALIZE AO FOR FIRST TIME THRU
	.IFT FRSTIO .GOTO ASK34	 ! WE DON''T NEED CONTINUATION ON 1ST REC
	.GOTO ASK33
.HELP33:
	;
	;
	; The continuation character allows for cases in which several
	; conditions define a single record type.  Multiple AND and OR lines
	; are permissible, but the series will be processed strictly in
	; sequence, each line ANDed or ORed to the accumulated Boolean
	; expression in turn.
	;
	; See the SORT-11 manual, page 3-13 for examples.
	;
	; Type an "A" if this specification is to be ANDed with the previous.
	; Type an "O" if this specification is to be ORed with the previous.
	;
	; There is no default.
	;
.ASK33:
	.ASKS AO Enter continuation character ("A" or "O")
	.IFT <ESCAPE> .GOTO HELP33
	.SETS AO AO[1:1]			! ONLY WANT 1ST CHAR
	.IF AO EQ "A" .OR .IF AO EQ "O" .GOTO OK ! CHECK FOR VALID ENTRIES
	;
	; "A" AND "O" ARE THE ONLY LEGAL ENTRIES.
	; TRY AGAIN.
	;
	.GOTO ASK33
.OK:	.;
.;
.; GET FIELD MODE (DATA TYPE)
.;
	.GOTO ASK34
.HELP34:
	;
	;
	; The field mode defines the type of data described on this
	; specification record.  The following table defines the valid entries:
	;
	; Value	  Description
	;   B	  Binary
	;   C	  Alphanumeric
	;   D	  ASCII Numeric
	;   F	  Binary Floating Point in 2 to 4 words
	;   I	  Numeric with leading and separate sign
	;   J	  Numeric with trailing and separate sign
	;   K	  Numeric with sigh leading and overpunched in first byte
	;   P	  Packed decimal
	;   Z	  Zone, see SORT-11 manual, Appendix B, table B-2
	;
	; You must enter one of the letters from the "Value" column.
	; "C" is the default.
	;
.ASK34:
	.IFT LONG .ASKS FLDMOD Enter the field mode [D: C]
	.IFT <ESCAPE> .GOTO HELP34
	.IFF LONG .SETS FLDMOD ""		! IF NOT LONG DIALOGUE
	.IF FLDMOD EQ "" .SETS FLDMOD "C"	! SET DEFAULT TO "C"
	.SETS FLDMOD FLDMOD[1:1]		! WE ONLY WANT 1ST CHAR
	.IF FLDMOD EQ "B" .GOTO OK		! CHECK FOR VALID ENTRIES
	.IF FLDMOD EQ "C" .GOTO OK		! ETC
	.IF FLDMOD EQ "D" .GOTO OK		! ETC
	.IF FLDMOD EQ "F" .GOTO OK		! AD NAUSEUM...
	.IF FLDMOD EQ "I" .GOTO OK
	.IF FLDMOD EQ "J" .GOTO OK
	.IF FLDMOD EQ "K" .GOTO OK
	.IF FLDMOD EQ "P" .GOTO OK
	.IF FLDMOD EQ "Z" .GOTO OK
	;
	; ILLEGAL FIELD MODE. PRESS <ESCAPE> FOR HELP
	; TRY AGAIN.
	;
	.GOTO ASK34
.OK:	.SETF FRSTIO		! SO WE CAN GET CONTINUATION CHR NEXT TIME
.;
.; GET FACTOR 1
.;
	.GOTO ASK35
.HELP35:
	;
	;
	; In order to select or describe a type of input record, the record
	; must be identifiable.  Factor 1 describes a field on the record
	; that will be compared to Factor 2 (another field or constant).
	;
	; You must identify the starting column of Factor 1 at this time. If
	; you wish, you may enter both the starting column and length at this
	; one time by entering ssss.lll  where "ssss" is the starting column
	; and "lll" is the length.  If you do not enter the length at this
	; time, you will be asked to specify the ending column or length of
	; factor 1 at a later time.
	;
	; The first byte of the record is counted as byte number 1.
	;
.ASK35:
	.ASKS F1SP Enter the starting column and .length of Factor 1.
	.IFT <ESCAPE> .GOTO HELP35
	.PARSE F1SP "." F1SP F1EP		! SPLIT ON "."
	.IF F1EP NE "" .SETS F1EP "."+F1EP	! MAKE F1EP LOOK LIKE LENGTH
	.SETS CKNINP F1SP	! COPY VALUE TO SUBROUTINE INPUT PARAMETER
	.GOSUB CHKNUM		! CHECK NUMBER
	.IFT CKNFLG .GOTO OK	! ANY ERRORS?
	;
	; YOU MAY ONLY ENTER UP TO 4 DIGITS FOR FACTOR 1 STARTING POINT.
	; TRY AGAIN.
	;
	.GOTO ASK35
.OK:	.;
.;
.; GET FACTOR 1 END POINT (IF DONT ALREADY HAVE IT FROM PREVIOUS QUESTION).
.;
	.GOTO ASK36
.HELP36:
	;
	;
	; Enter the end point of factor 1 as a number of up to 4 digits.  If
	; you prefer, instead of entering the column number of the end point,
	; you may enter the length of the field.  If you choose to enter the
	; length, then place a decimal point (.) in front of the number so that
	; the command file will know that you are entering a length.  The
	; command file will convert the length to the ending column number and
	; use that in the sort specification file.
	;
	; NOTE:  The end point of Factor 1 cannot exceed the record length of
	; the input records.
	;
.ASK36:
	.IF F1EP EQ "" .ASKS F1EP Enter the endpoint or .length of factor 1
	.IFT <ESCAPE> .GOTO HELP36
	.SETF F1LFLG				! ASSUME LENGTH
	.TEST F1EP				! HOW LONG IS IT?
	.IF DOT NE F1EP[1:1] .GOTO NODOT	! IF NO DOT, JUMP
	.SETT F1LFLG				! SET LENGTH FLAG TRUE
	.SETS F1EP F1EP[2:<STRLEN>]		! REMOVE DOT FROM NUMBER
.NODOT:.TEST F1EP				! HOW LONG IS F1EP?
	.IF <STRLEN> LE 4 .GOTO OK		! WE MIGHT BE TOO LONG
	;
	; YOU MAY ONLY ENTER UP TO 4 DIGITS OR A DECIMAL POINT AND 4 DIGITS.
	; TRY AGAIN.
	;
	.SETS F1EP ""
	.GOTO ASK36
.OK:	.SETS CKNINP F1EP			! COPY NUMBER TO SUB PARAMETER
	.GOSUB CHKNUM				! CHECK OUT NUMBER
	.IFT CKNFLG .GOTO OK			! ANY ERRORS?
	;
	; YOU MAY ONLY ENTER A DECIMAL POINT AND NUMERIC DIGITS FOR 
	; THE END POINT OR LENGTH OF FACTOR 1.
	; TRY AGAIN.
	;
	.GOTO ASK36
.OK:	.IFT F1LFLG .SETN N 'F1SP'.+'F1EP'.-1.	! COMPUTE END POINT FROM LENGTH
	.IFT F1LFLG .SETS F1EP "'N'"		! CONVERT END POINT TO STRING
.;	
.; PAD F1SP AND F1EP WITH LEADING ZEROS IF NECESSARY TO MAKE THEM 4 DIGITS
.;
	.SETS F1SP "000"+F1SP			! ADD LOTS OF LEADING ZEROS
	.TEST F1SP				! HOW LONG IS VAR NOW?
	.SETS F1SP F1SP[<STRLEN>-3:<STRLEN>]	! SAVE LAST 4 CHARS
.;
	.SETS F1EP "000"+F1EP			! ADD LOGS OF LEADING ZEROS
	.TEST F1EP				! HOW LONG IS VAR NOW?
	.SETS F1EP F1EP[<STRLEN>-3:<STRLEN>]	! SAVE LAST 4 CHARS
.;
.; MAKE SURE THE STARTING POINT IS LE THE ENDING POINT
.;
	.IF F1EP GE F1SP .GOTO OK		! SP CANT BE GREATER THAN EP
	;
	; THE END POINT ('F1EP') CANNOT BE LESS THAN THE 
	; STARTING POINT ('F1SP').  TRY AGAIN.
	;
	.GOTO ASK35
.OK:	.;
.;
.; FIND OUT WHAT FACTOR 2 WILL BE
.;
	.GOTO ASK37
.HELP37:
	;
	;
	; In order to specify a record type, we will compare Factor 1 (a field
	; on the input record) to Factor 2 (either a different field on the
	; input record or a constant in the specification file).  You must
	; indicate whether Factor 2 will be a Field or a Constant.  Enter at
	; least an "F" or "C".
	;
	; Default is "C".
	;
.ASK37:
	.IFT LONG .ASKS FC Will Factor 2 be a Field or a Constant [D: C]
	.IFT <ESCAPE> .GOTO HELP37
	.IFF LONG .SETS FC ""				! IF NOT LONG DIALOGUE
	.IF FC EQ "" .SETS FC "C"			! SET DEFAULT
	.SETS FC FC[1:1]				! SAVE ONLY 1ST CHAR
	.IF FC EQ "F" .OR .IF FC EQ "C" .GOTO OK	! CHECK FOR VALID ENTRY
	;
	; YOU MAY ONLY ENTER "F" OR "C".
	; TRY AGAIN.
	;
	.GOTO ASK37
.OK:	.;
.;
.; GET RELATIONSHIP BETWEEN FACTOR 1 AND FACTOR 2
.;
	.GOTO ASK38
.HELP38:
	;
	;
	; The relationship between Factor 1 and Factor 2 describes how the two
	; fields will be compared.  Enter one of the two letter relationships
	; from the following table.
	;
	; EQ - Equal to
	; NE - Not equal to
	; LT - Less than  (EG. Factor 1 LT Factor 2)
	; GT - Greater than
	; LE - Less than or equal to
	; GE - Greater than or equal to
	;
.ASK38:
.ASKS [2:2] FRELAT Enter the 2 letter relationship code for Factors 1 and 2
	.IFT <ESCAPE> .GOTO HELP38
	.IF FRELAT EQ "EQ" .GOTO OK	! MAKE SURE ENTRY WAS VALID
	.IF FRELAT EQ "NE" .GOTO OK	! ETC....
	.IF FRELAT EQ "LT" .GOTO OK
	.IF FRELAT EQ "GT" .GOTO OK
	.IF FRELAT EQ "LE" .GOTO OK
	.IF FRELAT EQ "GE" .GOTO OK
	;
	; ILLEGAL RELATIONSHIP.
	; TRY AGAIN.
	;
	.GOTO ASK38
.OK:	.;
.;
.; GET FACTOR 2 AS A CONSTANT
.;
	.IF FC EQ "F" .GOTO ASK3A      ! HE WANTS FACTOR TO TO BE A FIELD. SKIP
.;
	.IF FLDMOD EQ "B" .SETN LEN 'F1EP'.-'F1SP'.+1.	! SET LENGTHS OF EACH
	.IF FLDMOD EQ "C" .SETN LEN 'F1EP'.-'F1SP'.+1.	!  TYPE OF CONSTANT.
	.IF FLDMOD EQ "D" .SETN LEN 'F1EP'.-'F1SP'.+1.	!   MOST ARE THE SAME
	.IF FLDMOD EQ "F" .SETN LEN 8.			!    LENGTH AS FACTOR 1
	.IF FLDMOD EQ "I" .SETN LEN 5.
	.IF FLDMOD EQ "J" .SETN LEN 'F1EP'.-'F1SP'.+1.
	.IF FLDMOD EQ "K" .SETN LEN 'F1EP'.-'F1SP'.+1.
	.IF FLDMOD EQ "P" .SETN LEN 'F1EP'.-'F1SP'.+1.
	.IF LEN GT 20. .SETN LEN 20.			! CAN''T BE TOO LONG
	.GOTO ASK39
.HELP39:
	;
	;
	; Earlier you specified that Factor 2 would be a constant in the sort
	; specification file.  You must enter that constant at this time.  This
	; constant must match the data type of Factor 1 (binary, alphanumeric,
	; etc.).  Also, after conversion to the internal value (if conversion
	; is necessary), the length must be the same as Factor 1.  You may
	; enter up to 'LEN' characters for the constant.
	;
.ASK39:	.ASKS [1.:'LEN'.] F2SP Enter Factor 2 constant
	.IFT <ESCAPE> .GOTO HELP39
	.SETS F2SP F2SP+"                    "	! PAD FACTOR 2 WITH BLANKS
	.SETS F2SP F2SP[1.:20.]			! ONLY USE 1ST 20 CHARS.
	.SETS F2EP ""				! EP IS BLANK FOR CONSTANTS
	.GOTO WRTSEL				! DONE WITH THIS RECORD.
.;
.; GET FACTOR 2 STARTING COLUMN (NOT A CONSTANT)
.;
	.GOTO ASK3A
.HELP3A:
	;
	;
	; Earlier you specified that Factor 2 would be a field on the input
	; record.  Now you must specify the starting column and length of 
	; Factor 2.  You must enter Factor 2 just like you entered Factor 1:
	; Starting column and length as "ssss.lll".  If you don't enter the
	; length, you will be asked to enter the ending column or length later.
	;
	; The first byte of the record is counted as byte number 1.
	;
.ASK3A:
	.ASKS F2SP Enter the starting column and .length of Factor 2
	.IFT <ESCAPE> .GOTO HELP3A
	.PARSE F2SP "." F2SP F2EP		! SPLIT ON "."
	.IF F2EP NE "" .SETS F2EP "."+F2EP	! MAKE F2EP LOOK LIKE LENGTH
	.SETS CKNINP F2SP		! COPY NUMBER TO SUB INPUT VARIABLE
	.GOSUB CHKNUM			! CHECK OUT NUMBER
	.IFT CKNFLG .GOTO OK		! ANY ERRORS?
	;
	; YOU MAY ONLY ENTER UP TO 4 NUMERIC DIGITS FOR FACTOR 2.
	; TRY AGAIN.
	;
	.GOTO ASK3A
.OK:	.;
.;
.; GET FACTOR 2 END POINT (IF WE DONT ALREADY HAVE IT).
.;
	.GOTO ASK3B
.HELP3B:
	;
	;
	; Enter the end point of Factor 2 as a number of up to 4 digits.  If
	; you prefer, instead of entering the column number of the end point,
	; you may enter the length of the field.  If you choose to enter the
	; length, then place a decimal point (.) in front of the number so that
	; the command file will know that you are entering a length.  The
	; command file will convert the length to the ending column number and
	; use that in the sort specification file.
	;
.ASK3B:
	.IF F2EP EQ "" .ASKS F2EP Enter the endpoint or .length of factor 2
	.IFT <ESCAPE> .GOTO HELP3B
	.SETF F2LFLG				! ASSUME NOT LENGTH
	.TEST F2EP				! HOW LONG IS IT?
	.IF DOT NE F2EP[1:1] .GOTO NODOT	! IF DOT, IT IS A LENGTH
	.SETT F2LFLG				! SET LENGTH FLAG TRUE
	.SETS F2EP F2EP[2:<STRLEN>]		! CHOP OFF DOT
.NODOT:.SETS CKNINP F2EP			! COPY NUMBER TO SUB INPUT PARM
	.GOSUB CHKNUM				! CHECK OUT NUMBER
	.IFT CKNFLG .GOTO OK			! ANY ERRORS?
	;
	; YOU MAY ONLY ENTER A DECIMAL POINT AND NUMERIC DIGITS FOR 
	; THE END POINT OR LENGTH OF FACTOR 2.
	; TRY AGAIN.
	;
	.GOTO ASK3B
.OK:	.IFT F2LFLG .SETN N 'F2SP'.+'F2EP'.-1.	! IF LENGTH, COMPUTE END POINT
	.IFT F2LFLG .SETS F2EP "'N'"		! CONVERT EP FROM NUMB TO CHAR
.;	
.; PAD F2SP AND F2EP WITH LEADING ZEROS IF NECESSARY TO MAKE THEM 4 DIGITS
.;
	.SETS F2SP "000"+F2SP			! ADD LOTS OF LEADING ZEROS
	.TEST F2SP				! SEE HOW LONG IT IS
	.SETS F2SP F2SP[<STRLEN>-3:<STRLEN>]	! SAVE LAST 4 CHARACTERS
.;
	.SETS F2EP "000"+F2EP			! ADD LOTS OF LEADING ZEROS
	.TEST F2EP				! SEE HOW LONG IT IS
	.SETS F2EP F2EP[<STRLEN>-3:<STRLEN>]	! SAVE LAST 4 CHARACTERS
.;
.; MAKE SURE THE STARTING POINT IS LE THE ENDING POINT
.;
	.IF F2EP GE F2SP .GOTO OK		! SP CANT BE GREATER THAN EP
	;
	; THE END POINT ('F2EP') CANNOT BE LESS THAN THE 
	; STARTING POINT ('F2SP').  TRY AGAIN.
	;
	.GOTO ASK3A
.OK:	.;
.;
.; PUT RECORD TYPE SPECIFICATION RECORD TOGETHER NOW
.;
.WRTSEL:
	.GOSUB LCOUNT			! CONVERT AND INCREMENT LINE NUMBER
	.DATA 'PAGE''LINE' 'IO''AO''FLDMOD''F1SP''F1EP''FRELAT''FC''F2SP''F2EP'
	;
	.GOTO ASK31		! GET ANOTHER RECORD TYPE SPECIFICATION
.;
.;
.;
.;		4 - FIELD SPECIFICATION RECORD
.;
.;
.;
.; SEE IF THEY WANT ANOTHER FIELD RECORD
.; 
.GETFS:
	.GOTO ASK40
.HELP40:
	;
	;
	; There are normally a set of field specifications following each
	; record type specification in the specification file set.  If there
	; are no record type specifications, any appropriate field
	; specifications follow the header (or ALTSEQ) record.
	;
	; Field specifications have two main jobs:
	; 1) to determine, for each record type, the keys on which the sort is
	;    to be based
	; 2) to describe the output file format.
	;
	; List the key field specifications first, in order of decreasing
	; significance.  Then, if the sorting process is SORTR or SORTT, add
	; the data field spcifications to put out any portions of the original
	; input record.
	;
	; List the Key and Data field specification lines in the same order as
	; the required output record format.  The SORT creates the output
	; record according to the order, size, and contents of the key and data
	; specifications.  
.IF STRIP EQ " " .GOTO SKIP 	! IF NOT STRIPPING, SKIP REST OF MESSAGE
	;
	; Since you indicated in the header that you wanted the key fields
	; stripped from the output records, you will have to include a data
	; field specification that includes the keys if you want them in the
	; output records.
.SKIP:	;
.ASK40:	.ASK FSFLG Do you want to enter any'FSMORE' field specifications
	.IFT <ESCAPE> .GOTO HELP40
	.SETS FSMORE " more"
	.IFT FSFLG .GOTO GETFT		! GET FIELDS FOR FS RECORD
	.IF LAST EQ "F" .GOTO SKIP	! NO MORE FS RECORDS, GO BACK FOR RTS
	;
	; YOU MUST ENTER EITHER AT LEAST ONE FIELD SPECIFICATION RECORD.
	; TRY AGAIN.
	;
	.GOTO GETFS
.;
.SKIP:	.IFT DATREC .OR .IF STRIP NE "X" .GOTO SELREC
	;
	; YOU MUST ENTER AT LEAST ONE DATA FIELD SPECIFICATION RECORD.
	; TRY AGAIN.
	;
	.GOTO GETFS
.;
.; GET FIELD TYPE
.;
.GETFT:	.SETS LAST "F"			! LAST (THIS) RECORD IS "FIELD"
	.SETS LFSTYP FSTYPE		! IF NOT 1ST TIME, SAVE LAST FS TYPE
	.GOTO ASK41
.HELP41:
	;
	;
	; The Field Type tells SORT-11 what it is to do with this specification
	; record.  If you are describing a key field, you may select whether
	; the key is to be in the normal order, which you specified earlier as
	.SETS S "ascending"
	.IF SRTSEQ EQ "D" .SETS S "descending"
	; 'S' or you may specify that one or more key fields are to be sorted
	; in opposite sequence from the normal order.
	;
	; Enter one of the following letters to describe the field type you
	; want.  Note that key fields must be in order of decreasing 
	; significance and must preceed data fields.
	;
	; N - Key field, Normal sort sequence.
	; O - Key field, Opposite sort sequence.
	; F - Forced key field.  (Forced keys allow you to force one particular
	;     key to be sorted out of the normal sequence.  See SORT-11 manual,
	;     pages 3-16 thru 3-17.
	; D - Data field.
	;
	; Default field type is Normal.
	;
.ASK41:
	.ASKS FSTYPE Enter field specification record type [D: N]
	.IFT <ESCAPE> .GOTO HELP41
	.IF FSTYPE EQ "" .SETS FSTYPE "N"	! SET DEFAULT
	.IF FSTYPE EQ "N" .GOTO OK		! CHECK FOR VALID ENTRIES
	.IF FSTYPE EQ "O" .GOTO OK
	.IF FSTYPE EQ "F" .GOTO OK
	.IF FSTYPE EQ "D" .GOTO OK
	;
	; ILLEGAL FIELD TYPE.
	; TRY AGAIN.
	;
	.GOTO ASK41
.OK:	.IF LFSTYP NE "D" .OR .IF FSTYPE EQ "D" .GOTO OK    ! SEE MESSAGE BELOW
	;
	; AN "'FSTYPE'" FIELD RECORD CANNOT FOLLOW A "D" FIELD RECORD.
	; TRY AGAIN.
	;
	.GOTO ASK41
.OK:	.IF FSTYPE EQ "D" .SETT DATREC
.;
.; GET FIELD DATA TYPE.
.; FOR FIELD TYPE OF "F" OR "D", SET DATA TYPE TO "C".
.;
	.IF FSTYPE EQ "N" .OR .IF FSTYPE EQ "O" .GOTO ASK42
	.SETS FSMODE "C"
	.GOTO ASK43
.HELP42:
	;
	;
	; The field mode defines the type of data described on this
	; Field type record.  The following table defines the valid entries:
	;
	; Value	  Description
	;   B	  Binary
	;   C	  Alphanumeric
	;   D	  ASCII Numeric
	;   F	  Binary Floating Point in 2 to 4 words
	;   I	  Numeric with leading and separate sign
	;   J	  Numeric with trailing and separate sign
	;   K	  Numeric with sigh leading and overpunched in first byte
	;   P	  Packed decimal
	;   Z	  Zone, see SORT-11 manual, Appendix B, table B-2
	;
	; You must enter one of the letters from the "Value" column.
	; "C" is the default.
	;
.ASK42:
	.IFT LONG .ASKS FSMODE Enter the field mode [D: C]
	.IFT <ESCAPE> .GOTO HELP42
	.IFF LONG .SETS FSMODE ""		! IF NOT LONG DIALOGUE
	.IF FSMODE EQ "" .SETS FSMODE "C"	! DEFAULT IS "C"
	.SETS FSMODE FSMODE[1:1]		! WE ONLY WANT 1ST CHARACTER
	.IF FSMODE EQ "B" .GOTO OK		! MAKE SURE ENTRY IS VALID
	.IF FSMODE EQ "C" .GOTO OK
	.IF FSMODE EQ "D" .GOTO OK
	.IF FSMODE EQ "F" .GOTO OK
	.IF FSMODE EQ "I" .GOTO OK
	.IF FSMODE EQ "J" .GOTO OK
	.IF FSMODE EQ "K" .GOTO OK
	.IF FSMODE EQ "P" .GOTO OK
	.IF FSMODE EQ "Z" .GOTO OK
	;
	; ILLEGAL FIELD MODE. PRESS <ESCAPE> FOR HELP
	; TRY AGAIN.
	;
	.GOTO ASK42
.OK:	.;
.;
.; GET STARTING COLUMN OF FIELD LOCATION
.;
	.GOTO ASK43
.HELP43:
	;
	;
	; You must identify the columns in which the key is found.  Specify the
	; starting column and length as ssss.lll where "ssss" is the starting
	; column and "lll" is the length.  The first column on the input record
	; is number as column 1.  If you do not enter then length, later you
	; will be asked to enter the ending column or length.
	;
	.IF FSTYPE NE "F" .GOTO ASK43
	; Note, however, that for forced key fields, the length will be forced
	; to be one byte, regardless of what you enter.
	;
.ASK43:
.ASKS FLSP Enter the starting column and length of the key or data field
	.IFT <ESCAPE> .GOTO HELP43
	.PARSE FLSP "." FLSP FLEP		! SPLIT ON "."
	.IF FLEP NE "" .SETS FLEP "."+FLEP	! MAKE FLEP LOOK LIKE LENGTH
	.SETS CKNINP FLSP	! COPY NUMBER TO INPUT PARAMETER
	.GOSUB CHKNUM		! CHECK NUMBER FOR VALIDITY
	.IFT CKNFLG .GOTO OK	! ANY ERRORS?
	;
	; YOU MAY ONLY ENTER UP TO 4 NUMERIC DIGITS FOR THE KEY OR DATA
	; FIELD.  TRY AGAIN.
	;
	.GOTO ASK43
.OK:	.;
.;
.; GET KEY OR DATA FIELD END POINT (IF WE DONT ALREADY HAVE IT).
.; NOTE THAT FOR "F" FIELDS, WE ONLY PERMIT 1 BYTE KEYS.
.;
	.IF FSTYPE NE "F" .GOTO ASK44	! IF FORCED FIELD...
	.SETS FLEP FLSP			!  MAKE IT A ONE BYTE FIELD.
.HELP44:
	;
	;
	; Enter the end point of the field as a number of up to 4 digits.  If
	; you prefer, instead of entering the column number of the end point,
	; you may enter the length of the field.  If you choose to enter the
	; length, then place a decimal point (.) in front of the number so that
	; the command file will know that you are entering a length.  The
	; command file will convert the length to the ending column number and
	; use that in the sort specification file.
	;
.ASK44:
.IF FLEP EQ "" .ASKS FLEP Enter end or .length of the key or data field
	.IFT <ESCAPE> .GOTO HELP44
	.SETF FLFLG				! ASSUME NOT LENGTH
	.TEST FLEP				! HOW LONG IS IT?
	.IF DOT NE FLEP[1:1] .GOTO NODOT	! IF DOT, THEN WE HAVE LENGTH
	.SETT FLFLG				! SET LENGTH FLAG TRUE
	.SETS FLEP FLEP[2:<STRLEN>]		! CHOP OFF DOT
.NODOT:.SETS CKNINP FLEP			! COPY NUMBER TO INPUT PARM
	.GOSUB CHKNUM				! CHECK NUMBER FOR VALIDITY
	.IFT CKNFLG .GOTO OK			! ANY ERRORS?
	;
	; YOU MAY ONLY ENTER A DECIMAL POINT AND UP TO 4 NUMERIC DIGITS FOR 
	; THE END POINT OR LENGTH OF THE KEY OR DATA FIELD.
	; TRY AGAIN.
	;
	.GOTO ASK44
.OK:	.IFT FLFLG .SETN N 'FLSP'.+'FLEP'.-1.	! IF LENGTH, COMPUTE END POINT
	.IFT FLFLG .SETS FLEP "'N'"		! CONVERT EP FROM NUM TO STRING
.;	
.; PAD FLSP AND FLEP WITH LEADING ZEROS IF NECESSARY TO MAKE THEM 4 DIGITS
.;
	.SETS FLSP "000"+FLSP			! ADD LOTS OF LEADING ZEROS
	.TEST FLSP				! HOW LONG IS IT NOW?
	.SETS FLSP FLSP[<STRLEN>-3:<STRLEN>]	! ONLY USE LAST 4 CHARACTERS
.;
	.SETS FLEP "000"+FLEP			! YOU''VE SEEN IT BEFORE.
	.TEST FLEP
	.SETS FLEP FLEP[<STRLEN>-3:<STRLEN>]
.;
.; MAKE SURE THE STARTING POINT IS LE THE ENDING POINT
.;
	.IF FLEP GE FLSP .GOTO OK		! SP CANT BE GREATER THAN EP
	;
	; THE END POINT ('FLEP') CANNOT BE LESS THAN THE 
	; STARTING POINT ('FLSP').  TRY AGAIN.
	;
	.GOTO ASK43
.OK:	.;
.;
.; GET FORCED KEY FIELDS IF THIS IS A FORCED KEY
.;
	.IF FSTYPE EQ "F" .GOTO SKIP		! IF NOT FORCED FIELD,...
	.SETS TRGCHR " "			!  INITIALIZE FORCED FIELD...
	.SETS REPCHR " "			!   STUFF.
	.SETS CONCHR " "			!
	.GOTO WRTFS				! WE CAN WRITE THE RECORD NOW
.;
.; GET TRIGGER CHARACTER
.;
.SKIP:	.GOTO ASK45
.HELP45:
	;
	;
	; The trigger character identifies the character needed to trigger the
	; force.  The force occurs only if this character is found.  Use this
	; and the following field to change the contents of a 1 character key,
	; thereby changing the sorting sequence.  The original data will still
	; appear on the output record, since only the key will be changed.  
	;
	; See pages 3-16 through 3-17 of the SORT-11 manual.
	;
.ASK45:	.ASKS [1:1] TRGCHR Enter forced key field trigger character
	.IFT <ESCAPE> .GOTO HELP45
.;
.; GET REPLACEMENT CHARACTER
.;
	.GOTO ASK46
.HELP46:
	;
	;
	; SORT will compare the trigger character to the specified column on
	; the input record.  If the trigger character is found, then the
	; replacement character is used as the key instead of what ever is
	; found in the input record.  The original data will still appear on
	; the output record, since only the key will be changed.
	;
	; See pages 3-16 through 3-17 of the SORT-11 manual.
	;
.ASK46:	.ASKS [1:1] REPCHR Enter forced key field replacement character
	.IFT <ESCAPE> .GOTO HELP46
.;
.; SEE IF THIS IS A CONTINUATION OF THE PREVIOUS KEY
.;
	.SETS CONCHR " "		! IN CASE THIS IS THE FIRST KEY
	.IF FSMORE EQ "" .GOTO WRTFS	! IF THIS IS 1ST KEY, WE CANT CONTINUE
	.GOTO ASK47
.HELP47:
	;
	;
	; If this is a continuation of the previous key, SORT will only modify
	; the same key byte as the previous key.  This makes it possible to
	; combine several conditions within the same key, such as arranging an
	; output file in the order 4, 2, 3, 1, rather than 1, 2, 3, 4, or 4, 3,
	; 2, 1.
	;
	; Note that if this is a continuation, then the key columns must be the
	; same as the key columns of the previous key
	;
.ASK47:	.ASK YN Is this a continuation of the previous key
	.IFT <ESCAPE> .GOTO HELP47
	.IFT YN .SETS CONCHR "X"	! SET UP THE CONTINUATION CHARACTER
.;
.;
.; WRITE THIS RECORD TO THE FILE
.;
.WRTFS:
	.GOSUB LCOUNT			! FORMAT AND INCREMENT LINE NUMBER
.DATA 'PAGE''LINE' F'FSTYPE''FSMODE''FLSP''FLEP''TRGCHR''REPCHR''CONCHR'
	;
	.SETS FSMORE " more"		! SET UP "MORE" MESSAGE
	.IF FSTYPE NE "D" .SETN MAXKEY MAXKEY+'FLEP'.-'FLSP'.+1. ! TOTAL KEYS
	.GOTO GETFS			! GET NEXT FIELD SPEC RECORD
.;
.;
.;
.;		5 - PASS 2
.;
.;
.; NOW THAT WE KNOW EVERYTHING, FIX UP HEADER RECORD.
.; READ, MODIFY AND REPLACE HEADER.
.;
.PASS2:	.CLOSE			! CLOSE CURRENT SPECIFICATION OUTPUT FILE
	.OPENR #0 'SPCFIL'
	.OPEN  #1 'SPCFIL'
	.READ #0 HEADER		! GET THE OLD (INCOMPLETE) HEADER
	.SETS M "0000'MAXKEY'"	! CONVERT MAX KEY TO CHAR WITH LEADING ZEROS
	.TEST M			! HOW LONG IS M?
	.SETS M M[<STRLEN>-4:<STRLEN>]	! GET LAST 5 CHARACTERS
	.SETS HEADER HEADER[1.:12.]+M+HEADER[18.:80.]	! PUT IN TOTAL KEY LENG
	.DATA #1 'HEADER'
.;
.; COPY REST OF SPEC FILE
.;
.LOOP:
	.READ #0 RECORD		! READ A RECORD
	.IFT <EOF> .GOTO CLOSE	! STOP IF EOF
	.DATA #1 'RECORD'
	.GOTO LOOP		! GET ANOTHER RECORD
.;
.; CLOSE FILES
.;
.CLOSE:	.CLOSE #0		! CLOSE INPUT FILE.
	.CLOSE #1		! CLOSE OUTPUT FILE.
	.ENABLE QUIET		! SO NO ONE KNOWS WHAT WE ARE DOING.
	PIP 'SPCFIL'/PU		! PURGE ALL BUT OUTPUT FILE.
	.DISABLE QUIET		! THEY CAN WATCH NOW.
.;
.;
.; STOP HERE
.;
.;
	.EXIT

.;
.;
.;
.; 		SUBROUTINES
.;
.;
.;
.; ASQCVT - CONVERT ALTERNATE SEQUENCE CHARACTERS TO OCTAL
.;
.; PARAMETERS:
.;    ASQCHR - INPUT AS ASCII OR OCTAL, OUTPUT AS OCTAL
.;    ASQERR - TRUE IF ERROR DETECTED, FALSE IF NOT.
.;
.ASQCVT:
	.SETF ASQERR
	.TEST ASQCHR
	.IF <STRLEN> EQ 1 .GOTO ASQASC
	.IF <STRLEN> EQ 3 .GOTO ASQOCT
	;
	; INCORRECT NUMBER OF CHARACTERS ENCOUNTERED BEFORE
	; OR AFTER THE COMMA.
	; TRY AGAIN.
	;
	.SETT ASQERR
	.GOTO ASQRTN
.;
.; MAKE SURE ALL THREE DIGITS ARE OCTAL
.;
.ASQOCT:.SETN I 1
	.SETS ZERO "0"
	.SETS SEVEN "7"
.ASQOCL:
.IF ZERO GT ASQCHR['I':'I'] .OR .IF SEVEN LT ASQCHR['I':'I'] .GOTO ASQNOC
	.INC I
	.IF I LE 3 .GOTO ASQOCL
.;
.; MAKE SURE OCTAL NUMBER IS NOT GREATER THAN 177
	.SETN I 'ASQCHR'
	.IF I LE 177 .GOTO ASQRTN
	.SETT ASQERR
	;
	; OCTAL NUMBERS MAY NOT BE GREATER THAN 177.
	; TRY AGAIN.
	;
	.GOTO ASQRTN
.;
.; BAD OCTAL DIGIT FOUND
.;
.ASQNOC:;
	; EXPECTING AN OCTAL DIGIT, BUT NON-OCTAL DIGIT WAS FOUND.
	; TRY AGAIN.
	;
	.SETT ASQERR
	.GOTO ASQRTN
.;
.; CONVERT ASCII CHARACTERS TO OCTAL
.;
.ASQASC:.;
.;
.; FIND CHARACTER IN ASCII TABLE
.;
	.SETN T 1
	.SETN I 1
.ASQLAS:
	.IF ASQCHR EQ ASCII'T'['I':'I'] .GOTO ASQFOU
	.INC I
	.IF I LE 40 .GOTO ASQLAS
	.INC T
	.SETN I 1
	.IF T LE 3 .GOTO ASQLAS
	;
	; WE CANNOT CONVERT THAT CHARACTER.  PLEASE ENTER IT IN OCTAL.
	; TRY AGAIN.
	;
	.SETT ASQERR
	.GOTO ASQRTN
.;
.; SEND BACK OCTAL EQUIVALENT OF CHARACTER
.;
.ASQFOU:.SETN I (I-1)+(40*T)
	.SETS ASQCHR "'I'"
	.IF I LT 100 .SETS ASQCHR "0"+ASQCHR
	.IF I LT 10  .SETS ASQCHR "0"+ASQCHR
.;
.; RETURN FROM HERE
.;
.ASQRTN: .RETURN
.;
.;
.;
.;  LCOUNT - LINE COUNTER, CONVERTER AND INCREMENTER SUBROUTINE
.;
.;  PARAMETER:	LINE - FORMATED LINE NUMBER
.;
.LCOUNT:
	 .SETN N 'LINE'.		! GET LINE NUMBER AS A NUMBER
	.INC N				! INCREMENT IT.
	.SETS LINE "'N'"		! CONVERT BACK TO A STRING.
	.IF N LT 10. .SETS LINE "0"+LINE ! ADD LEADING ZERO IF NECESSARY.
	.RETURN				! RETURN TO CALLER.
.;
.;
.;
.;  PCOUNT - PAGE COUNTER, CONVERTER AND INCREMENTER SUBROUTINE
.;
.;  PARAMETER:	PAGE - FORMATED PAGE NUMBER
.;
.PCOUNT:
	 .SETN N 'PAGE'.		! GET PAGE NUMBER AS A NUMBER
	.INC N				! INCREMENT IT.
	.SETS PAGE "'N'"		! CONVERT BACK TO A STRING.
	.IF N LT 10. .SETS PAGE "0"+PAGE ! ADD LEADING ZERO IF NECESSARY.
	.SETS LINE "00"
	.RETURN				! RETURN TO CALLER.
.;
.;
.;
.;  CHKNUM - CHECK A STRING VARIABLE TO MAKE SURE THAT IS IT ALL DIGITS AND
.;	     NOT MORE THAN 4 DIGITS.
.;
.;  PARAMETERS:  IN: CKNINP - STRING TO BE CHECKED.
.;		 OUT: CKNFLG - TRUE IF ALL DIGITS, F IF NOT.
.;
.CHKNUM:
	.SETF CKNFLG
	.TEST CKNINP
	.IF <STRLEN> GT 4 .GOTO RETURN
	.SETN I 1.
.CKNL:
	.IF ZERO GT CKNINP[I:I] .OR .IF NINE LT CKNINP[I:I] .GOTO RETURN
	.INC I
	.IF I LE <STRLEN> .GOTO CKNL
	.SETT CKNFLG
.RETURN:.RETURN
.;
.;
.;
.;  PARSE - PARSE A FILE NAME INTO ITS COMPONENTS
.;
.;  PARAMETERS:	IN: FILNAM - THE UNPARSED FILE NAME. 
.;		    EG: DB0:[200,200]PGM4004.DAT;1
.;		OUT: DEV - THE DEVICE. EG: DB0:
.;		     UIC - THE UIC.    EG: [200,200]
.;		     NAM - THE NAME.   EG: PGM4004
.;		     TYP - THE TYPE.   EG: .DAT
.;		     VER - THE VERSION.EG: ;1
.;
.; IF AN OUTPUT PARAMETER IS EQUAL TO "", THEN NONE WAS SPECIFIED.
.; FILNAM WILL BE LEFT UNCHANGED.
.;
.PARSE:
.;
.; COPY FILE NAME.
.;
	.SETS F FILNAM
.;
.; PARSE DEVICE
.;
	.PARSE F ":" DEV F			! SPLIT DEVICE FROM REST
	.IF F NE "" .GOTO GOTDEV		! IF WE HAVE DEV, JUMP
	.SETS F DEV				! COPY F TO RIGHT VARIABLE
	.SETS DEV ""				! NO DEVICE SPECIFIED
.GOTDEV:.IF DEV NE "" .SETS DEV DEV+":"		! PUT COLON BACK ON GOOD DEV
.;
.; PARSE UIC
.;
	.PARSE F "]" UIC F			! SPLIT UIC FROM REST
	.IF F NE "" .GOTO GOTUIC		! IF WE HAVE UIC, JUMP
	.SETS F UIC				! COPY REST TO RIGHT VARIABLE
	.SETS UIC ""				! NO UIC SPECIFIED
.GOTUIC:.IF UIC NE "" .SETS UIC UIC+"]"		! PUT "]" BACK ON GOOD UIC
.;
.; PARSE FILE NAME TYPE AND VERSION
.;
	.PARSE F ";" F VER			! SPLIT VERSION FROM THE REST
	.PARSE F "." NAM TYP			! SPLIT NAME FROM TYPE
	.IF TYP NE "" .SETS TYP "."+TYP		! PUT "." BACK ON GOOD TYPE
	.IF VER NE "" .SETS VER ";"+VER		! PUT ";" BACK ON GOOD VERSION 
	.RETURN
