3912 lines
148 KiB
Brainfuck
Executable File
3912 lines
148 KiB
Brainfuck
Executable File
*******************************************************************************
|
|
*
|
|
* uniVerse PI/open EDITOR
|
|
*
|
|
* Module %M% Version %I% Date %H%
|
|
*
|
|
* (c) Copyright 1998 Ardent Software Inc. - All Rights Reserved
|
|
* This is unpublished proprietary source code of Ardent Software Inc.
|
|
* The copyright notice above does not evidence any actual or intended
|
|
* publication of such source code.
|
|
*
|
|
*******************************************************************************
|
|
*
|
|
* Maintenance log - insert most recent change descriptions at top
|
|
*
|
|
* Date.... GTAR# WHO Description.........................................
|
|
* 10/14/98 23801 SAP Change copyrights.
|
|
* 07/30/96 18933 ALC Corrected fix below, it had quoting problems
|
|
* 06/10/96 18598 PEJ Modified create.file &ED& for NT
|
|
* 04/12/96 18194 KAM Disallow VOC Fptr changes if MODFPTRS tunable set
|
|
* 03/13/96 17797 AGM Replace 'SH -c' with OS.EXEC
|
|
* 10/27/95 17576 LDG If NLS on, check ^ mode display for invalid UTF.
|
|
* 06/28/95 16793 LDG Hide NLS functionality until after 8.3.3
|
|
* 05/18/95 15741 EAP Added error message for NLS write errors
|
|
* 05/16/95 15741 EAP Added error message for NLS unmappable Ids
|
|
* 05/03/95 16475 LDG Only display record ID in ^ mode if ^ or ^X is
|
|
* actually on if NLS is enabled.
|
|
* 04/28/95 16433 LDG Changed ^X handling of char 128 (SQL NULL)
|
|
* 04/26/95 16433 LDG Changed ^X handling of chars 248 thru 250.
|
|
* 03/09/95 13096 SAP Fixed problem with SPOOL command core dumping.
|
|
* 02/07/95 16092 LDG Added ^X for Unicode UP ARROW mode, plus ability to
|
|
* input all Unicode characters via ^X.
|
|
* 12/07/94 15420 PVW Fix error handling on opens
|
|
* 11/08/94 13738 JSM Change definition of non-printing characters to be
|
|
* compatible with release 6 editor
|
|
* 03/15/94 12299 LA Replaced calls to PRINTER.IO to reset terminal and/or
|
|
* printer with PRINTER CLOSE and PRINTER RESET
|
|
* statements to make sure printer buffer is flushed.
|
|
* 02/16/94 12267 FTW Allow nulls to be edited in all cases.
|
|
* 02/11/94 12101 FTW Fixed several lock releasing problems.
|
|
* 01/24/94 12516 KAM Fixed LOOP functionality for prestored commands.
|
|
* 11/05/93 11751 WLG Fixed to recognize difference between "" and no
|
|
* Record-id being supplied.
|
|
* 10/28/93 11751 WLG Fixed to allow null record-ids.
|
|
* 08/18/93 12082 PVW Changed message 970012 and added message 970013
|
|
* 07/07/93 11317 PVW Fix problem with SPOOL command
|
|
* 07/07/93 11762 PVW Save and Restore all COMMON variables
|
|
* 06/29/93 11742 PVW Handle SQL Integrity Constraint Violations
|
|
* 06/29/93 11762 PVW Clear COMMON variables before exiting ED
|
|
* 06/01/93 11645 PVW Remove DEVSYS.STRIPSTRS.MODE from code
|
|
* 03/18/93 11152 WLG Fixed non-existent error to use message 20141
|
|
* 02/23/93 11109 PVW Fix handling of sql null when inserting.
|
|
* 02/19/93 10797 PVW Check status() before writing out to another record
|
|
* for part files.
|
|
* 02/02/93 10955 PVW Fixed editor error messages if DICT file.
|
|
* 02/01/93 10966 PVW Allow SQL NULL as element in multivalued data.
|
|
* 01/25/93 10716 LPC Enforce data restrictions for partfiles.
|
|
* 01/21/93 10797 LPC Check for invalid partfiles
|
|
* 01/21/93 10908 PVW Fix problem with I types.
|
|
* 01/06/93 10826 PVW Change the way the LOOP handles start command.
|
|
* 01/06/93 10785 PVW Make 'FI file item' behave as 'FILE file item'
|
|
* 01/05/93 10812 PVW Fix problem when line = char(128) in ^ mode.
|
|
* 01/05/93 10757 PVW Correct permissions handling for the new editor
|
|
* 12/31/92 10793 PVW Set DEVSYS.STRIPSTRS.MODE to "Editor".
|
|
* 12/30/92 10757 PVW Changed handling for Pnn,"-",and "+".
|
|
* 12/18/92 10757 PVW Change special character handling.
|
|
* 12/17/92 10214 PVW Further changes to merge the two editors.
|
|
* 12/17/92 10692 PVW Show char 128 in up arrow mode.
|
|
* 12/11/92 10708 PVW Open and close DEVSYS.VOC.FILE within ED.
|
|
* 12/09/92 10214 PVW Help Message added.
|
|
* 12/07/92 10214 PVW More formatting problems.
|
|
* 12/03/92 10214 PVW Fixed miscellaneous problems regarding QA.
|
|
* 11/11/92 10214 PVW Port PI/open EDITOR to replace uniVerse EDITOR.
|
|
*
|
|
*******************************************************************************
|
|
|
|
$OPTIONS INFORMATION
|
|
|
|
$INCLUDE UNIVERSE.INCLUDE VERBINSERT.H
|
|
$INCLUDE UNIVERSE.INCLUDE UV.COM
|
|
$INCLUDE UNIVERSE.INCLUDE FORMAT.OPTS.H
|
|
$INCLUDE UNIVERSE.INCLUDE GETPU.H
|
|
$INCLUDE UNIVERSE.INCLUDE FILENAMES.H
|
|
$INCLUDE UNIVERSE.INCLUDE UVNLS.H
|
|
$INCLUDE UNIVERSE.INCLUDE MACHINE.NAME
|
|
|
|
*******************************************************************************
|
|
*
|
|
* The following lines of code are included to setup this program
|
|
* with then same input as the PI/open ED.B subroutine receives
|
|
* from the PI/open command line processor PERFORM.B.
|
|
*
|
|
* SUBROUTINE ED (SENTENCE, MAT SYMBOLS)
|
|
*
|
|
|
|
$INCLUDE UNIVERSE.INCLUDE SYMBOL.TBL.H
|
|
|
|
OPEN "VOC" TO DEVSYS.VOC.FILE ELSE
|
|
CALL *UVPRINTMSG(001752,"")
|
|
STOP
|
|
END
|
|
|
|
DIM SYMBOLS (VALSTART + MAXTOKENS)
|
|
|
|
MAT SYMBOLS = ''
|
|
|
|
SYMBOLS (NEXT.TKN.VALUE) = VALSTART
|
|
SYMBOLS (ORIGINAL.SENTENCE) = @SENTENCE
|
|
SENTENCE = TRIMF(@SENTENCE)
|
|
|
|
CHECK.TOKEN = FIELD(SENTENCE," ",1)
|
|
IF CHECK.TOKEN = "RUN" OR CHECK.TOKEN = "RAID" THEN
|
|
SENTENCE = FIELD(SENTENCE," ",2,9999)
|
|
SENTENCE = TRIMF(SENTENCE)
|
|
SENTENCE = FIELD(SENTENCE," ",2,9999)
|
|
END
|
|
|
|
*******************************************************************************
|
|
|
|
*
|
|
*---- EQU's and DIMensions.
|
|
EQU IntegrityViolation TO -3
|
|
EQU OBJ.FMC TO 19
|
|
EQU VOC.K.CODE.DICT TO 20
|
|
EQU LINES.PER.CELL TO 40 ; * LINES PER CELL OF MEMORY MATRIX
|
|
EQU STARS LIT 'STR("*", 5)'
|
|
|
|
SETPU = '!SETPU'
|
|
GETPU = '!GETPU'
|
|
MATBLOCK = '-MATBLOCK'
|
|
GET.FILE.NAME = '-GET.FILE.NAME' ; * To get file name from command line.
|
|
STRIPSTRINGS = '-STRIPSTRINGS'
|
|
FORMAT.BASIC = '-FORMAT.BASIC'
|
|
PERMISSIONS = '-PERMISSIONS'
|
|
SQLINTCHK = '-SQLINTCHK'
|
|
OpenError = '-OpenError'
|
|
|
|
*---- Define vital elements of blocked memory (see GET.LINE comments).
|
|
@SYSTEM.SET = 0
|
|
MEMORY.DIM = 100 ; * Initial size of memory matrix.
|
|
|
|
DIM MEMORY (MEMORY.DIM)
|
|
DIM LPC (MEMORY.DIM)
|
|
DIM PRIOR.MEMORY (MEMORY.DIM)
|
|
DIM PRIOR.LPC (MEMORY.DIM)
|
|
DIM SAVED.MEMORY (MEMORY.DIM)
|
|
DIM SAVED.LPC (MEMORY.DIM)
|
|
NEW.MEMORY.DIM = 20 ; * INITIAL SIZE OF NEW.MEMORY MATRICES
|
|
DIM NEW.MEMORY (NEW.MEMORY.DIM)
|
|
DIM NEW.LPC (NEW.MEMORY.DIM)
|
|
GOSUB CLEAR.NEW.MEMORY ; * CLEAR MATRICES AND INITIALIZE VARIABLES
|
|
DIM CMD.STACK (101), CMD.NAME (5)
|
|
MAT CMD.STACK = ''
|
|
DIM ED.CMD.STRING (1)
|
|
|
|
*---- Initialize for this EDIT session.
|
|
OVERFLOW.FLAG = 0 ; * SJE 23 Apr 84
|
|
ABORT.FLAG = ''
|
|
STACK.MODE = FALSE ; * indicates if stack processor mode
|
|
INPUT.MODE = FALSE ; * indicates if prompt is '=' or ':'
|
|
INPUT.LINE = ''
|
|
BLOCK.VERIFY.FLAG = TRUE
|
|
RECORD.NAME.LOCKED = FALSE
|
|
PROMPT ' ' ; AT.LIST = '' ; AT.SUB = '' ; HELP.RECORD = ''
|
|
X = '@FILE' ; Y = ''
|
|
GOSUB AT.INSERT
|
|
X = '@ID' ; Y = ''
|
|
GOSUB AT.INSERT
|
|
X = '@LINE' ; Y = ''
|
|
GOSUB AT.INSERT
|
|
X = '@IM' ; Y = @IM
|
|
GOSUB AT.INSERT
|
|
X = '@VM' ; Y = @VM
|
|
GOSUB AT.INSERT
|
|
X = '@SM' ; Y = @SM
|
|
GOSUB AT.INSERT
|
|
X = '@COMMAND' ; Y = @COMMAND
|
|
GOSUB AT.INSERT
|
|
X = '@PARASENTENCE' ; Y = @PARASENTENCE
|
|
GOSUB AT.INSERT
|
|
X = '@SENTENCE' ; Y = @SENTENCE
|
|
GOSUB AT.INSERT
|
|
X = '@LEVEL' ; Y = @LEVEL
|
|
GOSUB AT.INSERT
|
|
X = '@LOGNAME' ; Y = @LOGNAME
|
|
GOSUB AT.INSERT
|
|
X = '@WHO' ; Y = @WHO
|
|
GOSUB AT.INSERT
|
|
X = '@USERNO' ; Y = @USERNO
|
|
GOSUB AT.INSERT
|
|
X = '@TIME' ; Y = OCONV(@TIME, 'MTHS')
|
|
GOSUB AT.INSERT
|
|
X = '@DATE' ; Y = OCONV(@DATE, 'D4')
|
|
GOSUB AT.INSERT
|
|
X = '@MONTH' ; Y = @MONTH
|
|
GOSUB AT.INSERT
|
|
X = '@DAY' ; Y = @DAY
|
|
GOSUB AT.INSERT
|
|
X = '@YEAR' ; Y = @YEAR
|
|
GOSUB AT.INSERT
|
|
X = '@TM' ; Y = @TM ; * 007
|
|
GOSUB AT.INSERT ; * 007
|
|
LINES.MESSAGE = @SYS.BELL:'Number of lines to print must be a'
|
|
PRE.STORE = 'Pre-stored command'
|
|
REC = 'record'
|
|
UREC = 'Record'
|
|
ENABLED = 'enabled'
|
|
DISABLED = 'disabled'
|
|
UNICODE = '+Unicode' ;* NLS, for when ^X enabled, not just ^
|
|
IN.FILE = ' in file "'
|
|
DUMMY = @(0) ; * TURN OFF CRT PAGING ON DISPLAY
|
|
FIRST.RECORD = TRUE
|
|
APPEND = '' ; * APPEND STRING
|
|
CMD = '' ; * COMMAND LINE
|
|
CMD.STACK (1) = '$' ; * END OF STACK INDICATOR
|
|
CMD.STRING = '' ; * CMD STACK DUMPED INTO HERE BEFORE BEING SAVED (.S)
|
|
COMMA = FALSE ; * FOR ANALYZING SAVE (.S) COMMAND
|
|
CURR.CMD.NAME = '' ; * INIT VARIABLE
|
|
DELIM.STRING = '!"#$%&()*+,-./:=@[\]_`{|}':"'"
|
|
ED.CMD.STRING (1) = '$' ; * INIT END OF PRE-STORED COMMAND STRING INDICATOR
|
|
ED.CMD.STRING.ACTIVE = FALSE ; * FLAG TRUE IF A CMD STRING IS BEING EXECUTED
|
|
ED.CMD.STRING.SUSPENDED = FALSE ; * FLAG TRUE IF AN EXECUTING COMMAND STRING IS IN 'PAUSE' MODE
|
|
END.STACK = 1 ; * POINTER TO THE END OF STACK INDICATOR
|
|
L.SELECT.FLAG = FALSE ; * FLAG TRUE IF CMD STRING RECORD NAMES SELECTED FROM A FILE
|
|
LOOP.FLAG = FALSE ; * FLAG TRUE IF CMD STRING IS BEING REPEATED BY A 'LOOP' COMMAND
|
|
NULL.CTR = 0 ; * COUNTER FOR SUCCESSIVE NULL COMMANDS
|
|
STACK.LIMIT = 100 ; * MAX NR OF STACK COMMANDS IS 99
|
|
UNLOAD.FLAG = FALSE ; * FLAG TRUE IF USING STRING.WRITE SUBR TO UNLOAD LINES
|
|
UPCMD = '' ; * INIT VARIABLE
|
|
UPCMD4 = '' ; * INIT VARIABLE
|
|
ERROR.COND = CHAR(0):@IM:CHAR(0) ; * ERROR INDICATOR
|
|
FIND.STRING = '' ; * 'FIND' STRING
|
|
FLEN = 0 ; * LENGTH OF FIND.STRING
|
|
ST.COLUMN = 1 ; * STARTING COLUMN (FIND COMMAND)
|
|
LOCATE.STRING = '' ; * LOCATE SEARCH STRING
|
|
MATCH.STRING = '' ; * 'MATCH' STRING
|
|
OLD.CHANGE.CMD = '' ; * PREVIOUS CHANGE COMMAND
|
|
PNUM = @CRTHIGH - 2 ; * LAST NUMBER OF LINES PRINTED
|
|
REPLACE.STRING = '' ; * PREVIOUS REPLACE COMMAND STRING
|
|
UP.ARROW = '^' ; * DEFINE UP ARROW CHARACTER
|
|
UP.ARROW.FLAG = FALSE ; * DISPLAY SPECIAL CHAR AS !XXX, FLAG
|
|
UP.ARROW.UNIC = '^x' ; * NLS up arrow mode that uses Unicode
|
|
UP.ARROW.UNIC.UP = UPCASE(UP.ARROW.UNIC) ;* used frequently
|
|
LEN.UP.ARROW.UNIC = LEN(UP.ARROW.UNIC) ;* ...ditto
|
|
UP.ARROW.UNIC.FLAG = FALSE ; * (display chars as ^xhhhh) in hex
|
|
NLS.ON.FLAG = SYSTEM(NLS$ON) ; * Set to 1 if NLS support switched on
|
|
PP.LINES = 20 ; * Default line count for PP command.
|
|
PL.LINES = 20 ; * Default line count for PL command.
|
|
NUM.REMAINING = '' ; * to control null editing
|
|
*---- Get CRT line width for folding.
|
|
CRT.WIDTH = @CRTWIDE
|
|
IF CRT.WIDTH < 1 OR CRT.WIDTH > 132 THEN CRT.WIDTH = 80
|
|
*---- Parse command sentence for file and record names.
|
|
SENT = TRIMF(FIELD(SENTENCE, ' ', 2, 9999))
|
|
INPUT.FILENAME:
|
|
PROMPT.FOR.FILE = TRUE ; NO.SELECT.LIST = TRUE
|
|
SINGLE.FILE.ONLY = TRUE ; ONLY.ONE.RECORD.FLAG = FALSE
|
|
FILE.NAME = '' ; DICT = ''
|
|
CALL @GET.FILE.NAME (NO.SELECT.LIST, SENT, DICT, FILE.NAME,
|
|
PROMPT.FOR.FILE, SINGLE.FILE.ONLY)
|
|
IF DICT = '' THEN DICT.TEXT = '' ELSE DICT.TEXT = DICT:' '
|
|
IF LEN(FILE.NAME) = 0 OR FILE.NAME # FILE.NAME <1> THEN GOTO STOP
|
|
*
|
|
* Open the file to be edited. Carry on if partially successful open
|
|
* of distributed file.
|
|
*
|
|
TEMP.SENTENCE = ''
|
|
FILE.NAME.VALID = FALSE
|
|
LOOP
|
|
UNTIL FILE.NAME.VALID DO
|
|
IF FILE.NAME = '' THEN
|
|
CALL @GET.FILE.NAME(NO.SELECT.LIST,TEMP.SENTENCE,DICT,FILE.NAME,PROMPT.FOR.FILE,SINGLE.FILE.ONLY)
|
|
END
|
|
IF DICT = '' THEN DICT.TEXT = '' ELSE DICT.TEXT = DICT:' '
|
|
IF LEN(FILE.NAME) = 0 OR FILE.NAME # FILE.NAME<1> THEN GOTO STOP
|
|
|
|
OPENCHECK DICT, FILE.NAME TO EDIT.FILE THEN
|
|
FILE.TYPE = STATUS()
|
|
FILE.NAME.VALID = TRUE
|
|
EDIT.READ.ONLY = FALSE
|
|
EDIT.PERM.MODE = 1
|
|
EDIT.PERM.IN = 6
|
|
EDIT.PERM.OUT = ''
|
|
CALL @PERMISSIONS(EDIT.FILE,EDIT.PERM.MODE,EDIT.PERM.IN,EDIT.PERM.OUT)
|
|
IF NOT(EDIT.PERM.OUT) THEN
|
|
EDIT.READ.ONLY = TRUE
|
|
END
|
|
END ELSE
|
|
ErrorCode = STATUS()
|
|
READL FileRec FROM DEVSYS.VOC.FILE,FILE.NAME THEN
|
|
IF DICT = "" THEN
|
|
PathName = FileRec<2>
|
|
END ELSE
|
|
PathName = FileRec<3>
|
|
END
|
|
RELEASE DEVSYS.VOC.FILE,FILE.NAME
|
|
END ELSE
|
|
PathName = ""
|
|
END
|
|
IF DICT = "" THEN
|
|
FileName = FILE.NAME
|
|
END ELSE
|
|
FileName = "DICT,":FILE.NAME
|
|
END
|
|
CALL @OpenError(ErrorCode,FileName,PathName)
|
|
DICT = '' ; FILE.NAME = ''
|
|
END
|
|
REPEAT
|
|
|
|
X = '@FILE' ; Y = FILE.NAME ; GOSUB AT.INSERT
|
|
IF TRIM(SENT) = '""' OR TRIM(SENT) = "''" THEN
|
|
NULL.ID = TRUE
|
|
END ELSE NULL.ID = FALSE
|
|
IF INDEX(SENT, "'", 1) + INDEX(SENT, '"', 1) THEN
|
|
CALL @STRIPSTRINGS(SENT, MAT SYMBOLS)
|
|
END ELSE SENT = TRIM(SENT)
|
|
IF SENT = '*' THEN
|
|
CALL *UVPRINTMSG(001295,"")
|
|
SELECT EDIT.FILE
|
|
SENT = ''
|
|
END
|
|
|
|
SELECT.LIST.FLAG = FALSE
|
|
READLIST RECORD.LIST
|
|
THEN
|
|
CONVERT @IM TO @FM IN RECORD.LIST
|
|
SELECT.LIST.FLAG = TRUE
|
|
NUM.REMAINING=DCOUNT(RECORD.LIST,@FM)
|
|
END
|
|
ELSE
|
|
RECORD.LIST = ''
|
|
END
|
|
|
|
IF LEN(SENT) # 0 THEN
|
|
IF COUNT(SENT, ' ') = 0 AND NOT(SELECT.LIST.FLAG) THEN ONLY.ONE.RECORD.FLAG = TRUE
|
|
NUMSENT=COUNT(SENT,' ')+1
|
|
SENT.AVAIL=NUMSENT
|
|
NUM.REMAINING=NUMSENT
|
|
LOOP
|
|
RECORD.NAME = FIELD(SENT, ' ', 1)
|
|
IF RECORD.NAME [1, 1] = CHAR(LITERAL) THEN
|
|
RECORD.NAME = SYMBOLS(RECORD.NAME [2, 999])
|
|
END
|
|
SENT = SENT [COL2() + 1, 999999]
|
|
WHILE SENT.AVAIL GT 0
|
|
SENT.AVAIL=SENT.AVAIL-1
|
|
RECORD.LIST<NUMSENT-SENT.AVAIL>=RECORD.NAME
|
|
REPEAT
|
|
END
|
|
IF COUNT(RECORD.LIST, @FM) THEN SELECT.LIST.FLAG = TRUE
|
|
|
|
GET.NEXT.RECORD: ; * Get the next record.
|
|
GOSUB GET.RECORD
|
|
GOSUB OOPS.INITIAL.SAVE ; * SET UP FOR OOPS <====
|
|
|
|
GET.CMD: ; * Get next command from user.
|
|
* Set up to save record prior to change for 'OOPS'.
|
|
IF CHANGE.FLAG OR CHANGE.DURING.CMD.STRING THEN
|
|
IF NOT(ED.CMD.STRING.ACTIVE) THEN
|
|
GOSUB OOPS.AFTER.CHANGE.CMD ; * SET UP FOR OOPS <====
|
|
CHANGE.DURING.CMD.STRING = FALSE
|
|
END ELSE CHANGE.DURING.CMD.STRING = TRUE
|
|
END
|
|
|
|
GET.CMD.0:
|
|
IF CHANGE.FLAG THEN RECORD.CHANGE.FLAG = TRUE
|
|
IF BOT = 0 THEN LNUM = 0 ; * BOT=0 MEANS RECORD IS NULL
|
|
IF BOT THEN GOSUB GET.LINE ; * GET LINE IF RECORD IS NOT NULL
|
|
ELSE IF CHANGE.FLAG THEN CHANGE.FLAG = FALSE ; RECORD.CHANGE.FLAG = TRUE
|
|
IF NOT(ED.CMD.STRING.ACTIVE) THEN
|
|
IF LNUM => BOT AND BOT > 0 THEN
|
|
CALL *UVPRINTMSG(001209,BOT)
|
|
END
|
|
CALL *UVPRINTMSG(001210,"")
|
|
END ELSE
|
|
IF ED.CMD.STRING.SUSPENDED THEN
|
|
CALL *UVPRINTMSG(001242,"")
|
|
CALL *UVPRINTMSG(001210,"")
|
|
END
|
|
END
|
|
GOSUB INPUT.LINE
|
|
|
|
GET.CMD.1:
|
|
COMMAND.SUCCESSFUL = TRUE
|
|
STACK.MODE = FALSE
|
|
CMD = INPUT.LINE
|
|
ORIGINAL.CMD = CMD
|
|
IF CMD = '.?' THEN CMD = 'HELP .'
|
|
IF CMD # '?' AND CMD [LEN(CMD), 1] = '?' THEN
|
|
CMD = CMD [1, LEN(CMD) - 1] ; GOSUB STASH.IT ; GOTO GET.CMD
|
|
END
|
|
CMD = REPLACE(CMD, 1, 1, 1, TRIMF(CMD <1, 1, 1>))
|
|
GOSUB PUT.ON.STACK
|
|
|
|
GET.CMD.2:
|
|
IF LEN(CMD) = 0 THEN
|
|
IF BOT = 0 THEN GOTO GET.CMD ; * BOT = 0 MEANS RECORD IS NULL
|
|
LNUM = IF LNUM < BOT THEN LNUM + 1 ELSE 0
|
|
GOTO END.NOCHANGE
|
|
END
|
|
NULL.CTR = 0
|
|
IF NUM(CMD) THEN GOTO SET.LNUM
|
|
IF CMD = "-" OR CMD = "+" THEN GOTO END.NOCHANGE
|
|
|
|
*---- Convert lower case to upper case for command processing.
|
|
UPCMD = UPCASE(CMD) ;
|
|
|
|
*---- Look for 'OOPS' command to restore; else, save record if necessary.
|
|
IF UPCMD = 'OOPS' THEN
|
|
IF ED.CMD.STRING.ACTIVE THEN
|
|
J = 0 ; * KILL ACTIVE CMD STRING
|
|
ED.CMD.STRING.ACTIVE = FALSE
|
|
ED.CMD.STRING.SUSPENDED = FALSE
|
|
IF CHANGE.DURING.CMD.STRING THEN
|
|
GOSUB OOPS.AFTER.CHANGE.CMD
|
|
CHANGE.DURING.CMD.STRING = FALSE
|
|
END
|
|
END
|
|
IF LEN(SAVED.CMD) = 0 THEN
|
|
CALL *UVPRINTMSG(001249,"")
|
|
GOTO GET.CMD
|
|
END
|
|
J = 0 ; * KILL ANY ACTIVE EDIT CMD STRING
|
|
ED.CMD.STRING.ACTIVE = FALSE
|
|
GOSUB OOPS.RESTORE ; * SET UP FOR OOPS <====
|
|
GOTO END.CMD
|
|
END ELSE
|
|
IF NOT(ED.CMD.STRING.ACTIVE) THEN GOSUB OOPS.BEFORE.EACH.CMD ; * SET UP FOR OOPS <====
|
|
END
|
|
CMDN = 1
|
|
|
|
*---- Look for 1-letter commands.
|
|
IF LEN(UPCMD) = 1 THEN
|
|
CMDX = INDEX('ABCDFILMNPQRTX<>^?', UPCMD, 1)
|
|
ON CMDX + 1 GOTO CMD.ERR, A, B, C, D, F, I, L, M, N, P, QUIT, R,
|
|
T, X, MFROM, MTHRU, UP.ARROW.TOGGLE, QUESTION.MARK
|
|
END
|
|
|
|
*---- Look for a letter and a space, followed by any string.
|
|
IF UPCMD MATCHES '1A" "0X' THEN
|
|
ANY = CMD [3, 9999]
|
|
CMDX = INDEX('ABCFILMR', UPCMD [1, 1], 1)
|
|
ON CMDX + 1 GOTO CMD.ERR, A.ANY, B.ANY, C.ANY, F.ANY,
|
|
I.ANY, L.ANY, M.ANY, R.ANY
|
|
END
|
|
|
|
*---- Look for 'Fnnn' --- a column-restricted FIND.
|
|
IF UPCMD [1, 1] = "F" THEN
|
|
IF CMD [2, 9999] MATCHES '0N" "0X' THEN
|
|
ST.COLUMN = FIELD(CMD [2, 9999], " ", 1)
|
|
ANY = CMD [LEN(ST.COLUMN) + 3, 9999]
|
|
GO TO F.COL
|
|
END
|
|
END
|
|
|
|
*---- Look for a letter followed by a number.
|
|
IF UPCMD MATCHES '1A0N' THEN
|
|
CMDN = CMD [2, 99]
|
|
IF CMDN > BOT THEN CMDN = BOT
|
|
CMDX = INDEX('DGLP', UPCMD [1, 1], 1)
|
|
ON CMDX + 1 GOTO CMD.ERR, D, G.N, P.N, P.N
|
|
END
|
|
|
|
*---- Look for command words.
|
|
UPCMD1 = UPCMD [1, 1] ; UPCMD2 = UPCMD [1, 2]
|
|
UPCMD3 = UPCMD [1, 3] ; UPCMD4 = UPCMD [1, 4]
|
|
UPCMD5 = UPCMD [1, 5] ; UPCMD6 = UPCMD [1, 6]
|
|
UPCMD8 = UPCMD [1, 8]
|
|
IF UPCMD = 'ABORT' THEN GOTO ABORT:
|
|
IF UPCMD = 'BLOCK' THEN GOTO BLOCK.VERIFY:
|
|
IF UPCMD3 = 'CAT' THEN GOTO CAT.ANY:
|
|
IF UPCMD = 'COL' THEN GOTO COL:
|
|
IF UPCMD = 'COPY' THEN GOTO COPY:
|
|
IF UPCMD = 'DELETE' THEN GOTO DELETE:
|
|
IF UPCMD2 = 'DE' THEN GOTO DE.N:
|
|
IF UPCMD = 'DROP' THEN GOTO DROP:
|
|
IF UPCMD3 = 'DUP' THEN GOTO DUP.ANY:
|
|
IF UPCMD = 'EX' THEN GOTO QUIT:
|
|
IF UPCMD = 'FD' THEN GOTO DELETE:
|
|
IF UPCMD = 'FI' THEN GOTO FILE.ANY:
|
|
IF UPCMD = 'FILE' THEN GOTO FILE.ANY:
|
|
* GTAR 10785
|
|
* Fake editor into thich user typed 'FILE file record'
|
|
*
|
|
IF UPCMD3 = 'FI ' THEN
|
|
CMD = 'FILE ':CMD[4,9999]
|
|
UPCMD = UPCASE(CMD)
|
|
UPCMD3 = UPCMD[1,3]
|
|
UPCMD4 = UPCMD[1,4]
|
|
UPCMD5 = UPCMD[1,5]
|
|
UPCMD6 = UPCMD[1,6]
|
|
UPCMD7 = UPCMD[1,7]
|
|
UPCMD8 = UPCMD[1,8]
|
|
GOTO FILE.ANY
|
|
END
|
|
IF UPCMD5 = 'FILE ' THEN GOTO FILE.ANY:
|
|
IF UPCMD = 'FORMAT' THEN FORMAT.TYPE = TRUE ; GOTO FORMAT:
|
|
IF UPCMD = 'FANCY.FORMAT' THEN FORMAT.TYPE = FALSE ; GOTO FORMAT:
|
|
IF UPCMD = 'G<' THEN GOTO G.BEGIN.BLOCK:
|
|
IF UPCMD = 'G>' THEN GOTO G.END.BLOCK:
|
|
IF UPCMD4 = 'HELP' THEN GOTO HELP.ANY:
|
|
IF UPCMD2 = 'IB' THEN GOTO I.BEFORE
|
|
IF UPCMD5 = 'LOAD ' THEN GOTO LOAD.ANY:
|
|
IF UPCMD = 'MOVE' THEN GOTO MOVE:
|
|
IF UPCMD = 'PB' THEN GOTO PRINT.BLOCK:
|
|
IF UPCMD2 = 'PL' THEN GOTO PL.CMD:
|
|
IF UPCMD2 = 'PO' THEN GOTO PO.N:
|
|
IF UPCMD2 = 'PP' THEN GOTO PP.CMD:
|
|
IF UPCMD = 'QUIT' THEN GOTO QUIT:
|
|
IF UPCMD = 'RELEASE' THEN GOTO RELEASE:
|
|
IF UPCMD = 'SAVE' THEN GOTO SAVE.ANY:
|
|
IF UPCMD5 = 'SAVE ' THEN GOTO SAVE.ANY:
|
|
IF UPCMD3 = 'SEQ' THEN GOTO SEQ.ANY:
|
|
IF UPCMD = 'SIZE' THEN COMMAND.SUCCESSFUL = FALSE ; DISPLAY.CURRENT.LINE = FALSE ; GOTO SIZE:
|
|
IF UPCMD = 'SPOOLHELP' THEN GOTO SPOOL.HELP:
|
|
IF UPCMD5 = 'SPOOL' THEN GOTO SPOOL.N:
|
|
IF UPCMD5 = 'STAMP' THEN GOTO STAMP:
|
|
IF UPCMD6 = 'UNLOAD' THEN GOTO UNLOAD.ANY:
|
|
IF UPCMD4 = 'XEQ ' THEN GOTO XEQ.ANY:
|
|
IF UPCMD3 = 'PE ' THEN GOTO XEQ.ANY:
|
|
IF UPCMD8 = 'PERFORM ' THEN GOTO XEQ.ANY:
|
|
IF UPCMD = "<>" THEN GOTO MFROM:
|
|
IF UPCMD = UP.ARROW.UNIC.UP THEN GOTO UP.ARROW.TOGGLE ;* NLS Unicode ^x cmd
|
|
|
|
*---- Look for EDITOR STACK and STRING commands.
|
|
IF UPCMD1 = '.' OR UPCMD4 = 'LOOP' OR UPCMD5 = 'PAUSE' THEN GOTO STACK.PROCESSOR:
|
|
IF UPCMD1 = 'C' OR UPCMD1 = 'R' THEN GOTO C.ANY: ; * CHANGE command.
|
|
|
|
CMD.ERR:
|
|
UNLOAD.FLAG = FALSE ; * RESET FLAGS ON LOAD/UNLOAD ERROR CONDITIONS
|
|
L.SELECT.FLAG = FALSE
|
|
* IF UPCMD4 = 'LOOP' THEN ED.CMD.STRING.ACTIVE = FALSE
|
|
* ELSE
|
|
IF NOT(ED.CMD.STRING.SUSPENDED) AND ED.CMD.STRING.ACTIVE THEN
|
|
CALL *UVPRINTMSG(001272,J:@FM:ED.CMD.STRING (J))
|
|
CALL *UVPRINTMSG(001273,"")
|
|
ERROR.FORMAT = TRUE
|
|
GOSUB PRINT.CMD.STRING
|
|
MSG.TEXT = UVREADMSG(001274,"")
|
|
IF NOT(@SYS.BELL) THEN
|
|
MSG.TEXT = CONVERT(CHAR(07),"",MSG.TEXT)
|
|
END
|
|
PRINT MSG.TEXT<1>
|
|
PRINT
|
|
CALL *UVPRINTMSG(001275,"")
|
|
CALL *UVPRINTMSG(001276,"")
|
|
INPUT COMMAND ; ANS = COMMAND ; ANS = UPCASE(ANS)
|
|
IF ANS # 'Q' THEN
|
|
ED.CMD.STRING (J) = COMMAND
|
|
J -= 1
|
|
END ELSE ED.CMD.STRING.ACTIVE = FALSE
|
|
GOTO GET.CMD
|
|
END
|
|
* END
|
|
IF NOT(STACK.MODE) THEN CALL *UVPRINTMSG(001245,"")
|
|
GOTO GET.CMD
|
|
|
|
NUMBER.ERR:
|
|
PRINT 'A non-numeric parameter was encountered where a number was expected.'
|
|
GOTO CMD.ERR
|
|
|
|
END.NOCHANGE: ; * End of command that did not change record.
|
|
CHANGE.FLAG = FALSE
|
|
GOTO END.CMD
|
|
|
|
END.CHANGE: ; * End of command that changed record.
|
|
CHANGE.FLAG = TRUE
|
|
|
|
END.CMD: ; * Set up to save record prior to change for 'OOPS'.
|
|
IF CHANGE.FLAG OR CHANGE.DURING.CMD.STRING THEN
|
|
IF NOT(ED.CMD.STRING.ACTIVE) THEN
|
|
GOSUB OOPS.AFTER.CHANGE.CMD ; * SET UP FOR OOPS <====
|
|
CHANGE.DURING.CMD.STRING = FALSE
|
|
END ELSE CHANGE.DURING.CMD.STRING = TRUE
|
|
END
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD.0
|
|
|
|
DONE.WITH.RECORD:
|
|
IF RECORD.NAME.LOCKED THEN
|
|
RELEASE EDIT.FILE, RECORD.NAME ; * RELEASE RECORD LOCK
|
|
RECORD.NAME.LOCKED = FALSE
|
|
END
|
|
IF ONLY.ONE.RECORD.FLAG THEN GOTO STOP ELSE GOTO GET.NEXT.RECORD
|
|
|
|
!
|
|
* Command processing routines.
|
|
!
|
|
|
|
*---- Conventions used in command processors:
|
|
*
|
|
* 1. Entered from a 'GOTO' in the routine 'GET.CMD'.
|
|
*
|
|
* 2. Exit with a 'GOTO' to one of the following labels:
|
|
* A. 'GET.CMD', to get the next command.
|
|
* B. 'END.CMD', to print the current line before going to 'GET.CMD'.
|
|
* C. 'END.CHANGE' to set 'CHANGE.FLAG' to 'TRUE' after changing
|
|
* the record; control proceeds through 'END.CMD', to print
|
|
* the current line before going to 'GET.CMD'.
|
|
* D. 'CMD.ERR', to print standard error message.
|
|
*
|
|
* 3. Use these standard 'GOSUB' routines:
|
|
* A. 'GET.LINE', to get the line numbered 'LNUM' into 'LINE'.
|
|
* B. 'PRINT.LINE', to print the string in 'LINE'.
|
|
* C. 'INPUT.LINE', to input a line of text from the CRT.
|
|
*
|
|
* 4. Each processor should maintain these variables as necessary:
|
|
* A. 'MEMORY' matrix contains 'LPC' lines of record in each cell.
|
|
* B. 'LNUM' is the line number being displayed/processed.
|
|
* C. 'LINE' contains the current line from record at line 'LNUM'.
|
|
* D. 'LPC' matrix defines number of lines per cell in 'MEMORY'.
|
|
* E. 'CELL' is the cell number in 'MEMORY' containing line 'LNUM'.
|
|
* F. 'CELL.FIRST.LINE' is the real line number of the first
|
|
* line of the current cell.
|
|
* G. 'CHANGE.FLAG' must be set to 'TRUE' if record is changed.
|
|
* H. 'BOT' should be set to the bottom line number if
|
|
* the number of lines is changed.
|
|
|
|
A.ANY: ; * APPEND command.
|
|
APPEND = ANY
|
|
|
|
A:
|
|
IF LNUM < 1 THEN
|
|
CALL *UVPRINTMSG(970007,LNUM)
|
|
GOTO CMD.ERR
|
|
END
|
|
LINE := APPEND
|
|
MEMORY (CELL) = REPLACE(MEMORY (CELL), LNUM - CELL.FIRST.LINE + 1, 0, 0, LINE)
|
|
GOTO END.CHANGE
|
|
|
|
ABORT: ; * Toggle command ABORT flag.
|
|
ABORT.FLAG = NOT(ABORT.FLAG)
|
|
IF ABORT.FLAG THEN
|
|
CALL *UVPRINTMSG(001267,ENABLED)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001267,DISABLED)
|
|
END
|
|
GOTO END.NOCHANGE
|
|
|
|
BLOCK.VERIFY: ; * Toggle command BLOCK.VERIFY flag.
|
|
BLOCK.VERIFY.FLAG = NOT(BLOCK.VERIFY.FLAG)
|
|
IF BLOCK.VERIFY.FLAG THEN
|
|
CALL *UVPRINTMSG(001268,ENABLED)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001268,DISABLED)
|
|
END
|
|
GOTO END.NOCHANGE
|
|
|
|
B.ANY: ; * Break a line into two lines.
|
|
IF LNUM < 1 THEN
|
|
CALL *UVPRINTMSG(970008,LNUM)
|
|
GOTO CMD.ERR
|
|
END
|
|
X = INDEX(LINE, ANY, 1)
|
|
IF X = 0 THEN GOTO CMD.ERR
|
|
X += LEN(ANY)
|
|
MEMORY (CELL) = REPLACE(MEMORY (CELL), LNUM - CELL.FIRST.LINE + 1, 0, 0, LINE [1, X - 1]:@FM:LINE [X, 999999])
|
|
LPC (CELL) += 1 ; BOT += 1
|
|
BLOCK.TRACK.LNUM = LNUM + 1 ; BLOCK.TRACK.CHANGE = 1 ; GOSUB BLOCK.TRACK
|
|
GOTO END.CHANGE
|
|
|
|
B: ; * Go to BOTTOM of record.
|
|
LNUM = BOT ; GOTO END.NOCHANGE
|
|
|
|
CAT.ANY: ; * Catenate two lines together.
|
|
IF LNUM < 1 OR LNUM = BOT THEN
|
|
CALL *UVPRINTMSG(970006,LNUM)
|
|
GOTO CMD.ERR
|
|
END
|
|
LINEX = LINE
|
|
LNUM += 1
|
|
GOSUB GET.LINE ; * GET NEXT LINE
|
|
LINEY = LINE
|
|
NUM.OF.LINES.TO.DELETE = 1
|
|
GOSUB DELETE.MEMORY
|
|
MEMORY (CELL) = REPLACE(MEMORY (CELL), LNUM - CELL.FIRST.LINE + 1, 0, 0, LINEX:CMD [5, 99]:LINEY)
|
|
BLOCK.TRACK.LNUM = LNUM ; BLOCK.TRACK.CHANGE = -1 ; GOSUB BLOCK.TRACK
|
|
GOTO END.CHANGE
|
|
|
|
COL: ; * Column display command.
|
|
CALL *UVPRINTMSG(001212,"")
|
|
CALL *UVPRINTMSG(001213,"")
|
|
GOTO END.NOCHANGE
|
|
|
|
C: ; * Change command.
|
|
CMD = OLD.CHANGE.CMD
|
|
IF LEN(CMD) = 0 THEN
|
|
PRINT 'No previous CHANGE command in effect ; must have parameters.'
|
|
GOTO CMD.ERR
|
|
END
|
|
|
|
C.ANY: ; * Look for first non-space, non-alphanumeric character as delimiter.
|
|
X = 2
|
|
LOOP DELIM = CMD [X, 1] WHILE DELIM = ' ' DO X += 1 REPEAT
|
|
IF NOT(INDEX(DELIM.STRING, DELIM, 1)) THEN
|
|
PRINT 'Valid delimiters are ':DELIM.STRING
|
|
GOTO CMD.ERR
|
|
END
|
|
IF COUNT(CMD, DELIM) > 3 THEN
|
|
PRINT 'Too many delimiters (3 max.).' ; GOTO CMD.ERR
|
|
END
|
|
OLD.CHANGE.CMD = CMD
|
|
FROM.FIELD = FIELD(CMD, DELIM, 2)
|
|
LEN.FROM.FIELD = LEN(FROM.FIELD)
|
|
TO.FIELD = FIELD(CMD, DELIM, 3)
|
|
IF COL2() = 0 THEN
|
|
PRINT 'Missing required TO field (for "CHANGE/FROM/TO").'
|
|
GOTO CMD.ERR
|
|
END
|
|
GLOBAL = FIELD(CMD, DELIM, 4) ; GLOBAL = UPCASE(GLOBAL) ; GLOBAL.FLAG = FALSE
|
|
IF GLOBAL [1, 1] = 'G' THEN GLOBAL = GLOBAL [2, 99] ; GLOBAL.FLAG = TRUE
|
|
IF GLOBAL [LEN(GLOBAL), 1] = 'G' THEN GLOBAL = GLOBAL [1, LEN(GLOBAL) - 1] ; GLOBAL.FLAG = TRUE
|
|
BLOCK.LOGIC = FALSE
|
|
IF GLOBAL = 'B' THEN
|
|
IF MFROM # 0 AND MTHRU # 0 THEN LNUM = MFROM ; * IF BLOCK SET, MOVE LNUM TO FRONT OF BLOCK
|
|
GOSUB BLOCK.CHECK
|
|
BLOCK.LOGIC = TRUE
|
|
END
|
|
N = IF NUM(GLOBAL) AND GLOBAL => 1 THEN GLOBAL ELSE 1
|
|
IF LNUM <= 0 THEN LNUM = 1
|
|
IF BLOCK.LOGIC THEN LNUM = MFROM ; LEND = MTHRU ; N = LEND - LNUM + 1
|
|
ELSE LEND = LNUM + N - 1 ; IF LEND > BOT THEN LEND = BOT
|
|
X.CHANGE.FLAG = FALSE ; * RESET LOCAL CHANGE FLAG
|
|
FOR LNUM = LNUM TO LEND
|
|
GOSUB GET.LINE
|
|
IF LEN(FROM.FIELD) = 0 THEN LINE = TO.FIELD:LINE ; GOTO C.REPLACE.LINE
|
|
X = INDEX(LINE, FROM.FIELD, 1)
|
|
IF X = 0 THEN GOTO C.NEXT.LINE
|
|
NEW.LINE = ''
|
|
LOOP
|
|
NEW.LINE := LINE [1, X - 1] :TO.FIELD
|
|
LINE = LINE [X + LEN.FROM.FIELD, 999999]
|
|
X = INDEX(LINE, FROM.FIELD, 1)
|
|
WHILE GLOBAL.FLAG AND X DO REPEAT
|
|
LINE = NEW.LINE:LINE
|
|
|
|
C.REPLACE.LINE:
|
|
MEMORY (CELL) = REPLACE(MEMORY (CELL), LNUM - CELL.FIRST.LINE + 1, 0, 0, LINE)
|
|
GOSUB PRINT.LINE
|
|
CHANGE.FLAG = TRUE
|
|
X.CHANGE.FLAG = TRUE ; * SET LOCAL CHANGE FLAG
|
|
|
|
C.NEXT.LINE:
|
|
GOSUB ABORT.CHECK
|
|
IF ABORT = 'Q' THEN
|
|
CALL *UVPRINTMSG(001228,"")
|
|
GOTO C.ABORT
|
|
END
|
|
NEXT LNUM
|
|
|
|
C.ABORT:
|
|
IF LNUM = 0 THEN CALL *UVPRINTMSG(001190,"")
|
|
ELSE IF N > 1 AND LNUM # BOT THEN PRINT 'At line ':LNUM
|
|
CHANGE.FLAG = X.CHANGE.FLAG ; * SET UP FLAG FOR OOPS SINCE GET.LINE
|
|
; * COULD HAVE RESET IT AFTER LAST LINE ACTUALLY CHANGED
|
|
GOTO GET.CMD
|
|
|
|
COPY: ; * Copy a BLOCK (i.e., duplicate the lines).
|
|
MOVE.FLAG = FALSE ; GOTO MOVE.COPY
|
|
|
|
DELETE: ; * Delete the entire record from the file.
|
|
IF (NOT(SYSTEM(62)) AND (EDITING.VOC.FPTR))
|
|
THEN
|
|
CALL *UVPRINTMSG(020553,"")
|
|
GOTO GET.CMD
|
|
END
|
|
|
|
CALL *UVPRINTMSG(001214,"")
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS # 'Y' THEN CALL *UVPRINTMSG(001215,"") ; GOTO GET.CMD
|
|
DELETE EDIT.FILE, RECORD.NAME ELSE
|
|
|
|
* DELETEU EDIT.FILE, RECORD.NAME ON ERROR
|
|
PRINT @SYS.BELL:'Failed to delete "':DISPLAY.RECORD.NAME:'" from file "':DICT:FILE.NAME:'". STATUS = ':STATUS()
|
|
GOTO GET.CMD
|
|
END
|
|
CALL *UVPRINTMSG(001246,DISPLAY.RECORD.NAME)
|
|
CALL *UVPRINTMSG(001286,DICT.TEXT:FILE.NAME)
|
|
GOTO DONE.WITH.RECORD
|
|
|
|
DE.N: ; * Delete a line or lines.
|
|
CMDN = CMD [3, 99]
|
|
IF NOT(NUM(CMDN)) THEN
|
|
PRINT 'Command requires number of lines to DELETE.'
|
|
GOTO CMD.ERR
|
|
END
|
|
IF CMDN <= 0 THEN CMDN = 1
|
|
|
|
D:
|
|
IF LNUM <= 0 THEN LNUM = 1
|
|
IF CMDN > (BOT - LNUM + 1) THEN CMDN = BOT - LNUM + 1
|
|
NUM.OF.LINES.TO.DELETE = CMDN
|
|
GOSUB DELETE.MEMORY
|
|
BLOCK.TRACK.LNUM = LNUM ; BLOCK.TRACK.CHANGE = -CMDN ; GOSUB BLOCK.TRACK
|
|
GOTO GET.CMD
|
|
|
|
DROP: ; * Delete a BLOCK of lines.
|
|
IF MFROM # 0 AND MTHRU # 0 THEN LNUM = MFROM ; * IF BLOCK SET, MOVE LNUM TO FRONT OF BLOCK
|
|
GOSUB BLOCK.CHECK ; GOSUB GET.LINE
|
|
NUM.OF.LINES.TO.DELETE = MTHRU - MFROM + 1
|
|
GOSUB DELETE.MEMORY
|
|
MTHRU = 0 ; * KILL BLOCK POINTERS
|
|
MFROM = 0
|
|
GOTO END.CMD
|
|
|
|
DUP.ANY: ; * Duplicate the current line.
|
|
IF LNUM < 1 THEN
|
|
CALL *UVPRINTMSG(970009,LNUM)
|
|
GOTO CMD.ERR
|
|
END
|
|
CMDN = CMD [4, 99]
|
|
IF NOT(NUM(CMDN)) THEN
|
|
PRINT 'Command requires number of lines to DUPLICATE.'
|
|
GOTO CMD.ERR
|
|
END
|
|
IF CMDN <= 0 THEN CMDN = 1
|
|
IF CMDN = 1 THEN
|
|
* LNUM += 1
|
|
* MEMORY (CELL) = INSERT(MEMORY (CELL), LNUM - CELL.FIRST.LINE + 1, 0, 0, LINE)
|
|
* The following code replaces the above 2 lines, which fail when
|
|
* inserting data before the last field if the last field is null.
|
|
X = LNUM - CELL.FIRST.LINE
|
|
IF X < 0 THEN
|
|
IF LEN(MEMORY (CELL)) = 0 THEN MEMORY (CELL) = LINE
|
|
ELSE MEMORY (CELL) = LINE:@FM:MEMORY (CELL)
|
|
END ELSE
|
|
Y = FIELD(MEMORY (CELL), @FM, 1, X + 1):@FM:LINE
|
|
X = MEMORY (CELL) [COL2(), 99999999]
|
|
IF LEN(X) = 0 THEN MEMORY (CELL) = Y
|
|
ELSE MEMORY (CELL) = Y:X
|
|
END
|
|
LNUM += 1
|
|
*---- End of special code.
|
|
LPC (CELL) += 1 ; BOT += 1 ; CHANGE.FLAG = TRUE
|
|
END ELSE
|
|
NEW.MEMORY.LINE = LINE
|
|
FOR X = 1 TO CMDN ; * BUILD A BLOCK OF NEW LINES
|
|
GOSUB APPEND.NEW.MEMORY
|
|
IF OVERFLOW.FLAG THEN GOTO END.CMD ; * SJE 23 Apr 84
|
|
NEXT X
|
|
GOSUB INSERT.MEMORY ; * INSERT THE NEW BLOCK
|
|
IF OVERFLOW.FLAG THEN GOTO END.CMD ; * SJE 23 Apr 84
|
|
GOSUB CLEAR.NEW.MEMORY
|
|
LNUM += 1
|
|
END
|
|
BLOCK.TRACK.LNUM = LNUM ; BLOCK.TRACK.CHANGE = CMDN ; GOSUB BLOCK.TRACK
|
|
GOTO END.CMD
|
|
|
|
FILE.ANY: ; * File the record; finished with it.
|
|
GOSUB FILE.IT
|
|
IF WRITEERROR THEN GOTO END.NOCHANGE ; *026
|
|
GOTO DONE.WITH.RECORD
|
|
|
|
F.COL: ; * A column-restricted FIND.
|
|
FIND.STRING = ANY ; GO TO F
|
|
|
|
F.ANY: ; * Find a line starting with string 'any'.
|
|
FIND.STRING = ANY ; ST.COLUMN = 1
|
|
|
|
F:
|
|
FLEN = LEN(FIND.STRING) ; SEARCH.X = 1 ; GOTO L.AGAIN
|
|
|
|
FORMAT: ; * Format INFO/BASIC program.
|
|
DISPLAY.CURRENT.LINE = FALSE
|
|
COMMAND.SUCCESSFUL = FALSE
|
|
IF BOT = 0 THEN GOTO END.NOCHANGE ; * EXIT IF NO LINES TO FORMAT
|
|
*
|
|
* Move the current lines of the program into the PROGRAM array ready
|
|
* for formatting, 1 line per field.
|
|
*
|
|
PROGRAM = ''
|
|
FOR LNUM = 1 TO BOT
|
|
GOSUB GET.LINE ; PROGRAM<-1> = LINE
|
|
NEXT LNUM
|
|
BOTX = BOT ; * SAVE BOT
|
|
LNUM = 1
|
|
GOSUB GET.LINE
|
|
NUM.OF.LINES.TO.DELETE = BOT
|
|
GOSUB DELETE.MEMORY ; * CLEAR ALL OF MEMORY, RETURN DMR SPACE
|
|
BOT = BOTX ; * RESTORE BOT WHICH WAS RESET BY DELETE.MEMORY
|
|
*
|
|
* Now do the actual format of this record.
|
|
* Depending on the value of FORMAT.TYPE do a FORMAT or FANCY.FORMAT
|
|
*
|
|
IF FORMAT.TYPE THEN
|
|
MAT FORMAT.OPTIONS = '' ; * Initialize the default FORMAT
|
|
FORMAT.MARGIN = 6 ; * options.
|
|
FORMAT.INDENT = 3 ; *
|
|
FORMAT.CASE = 'MCU' ; * Treat all keywords in upper case
|
|
FORMAT.LABELS = 0 ; * Do not place labels on a separate line
|
|
FORMAT.COMMENT = 0 ; * Do not format comments
|
|
FORMAT.BRIEF = 0 ; * Indicate progess with *'s
|
|
FORMAT.SURROUND = 0 ; * Do not surround special characters
|
|
FORMAT.ALIGN = 0 ; * Do not align within statements
|
|
END ELSE
|
|
MAT FORMAT.OPTIONS = '' ; * Initialize the default FORMAT
|
|
FORMAT.MARGIN = 6 ; * options.
|
|
FORMAT.INDENT = 3 ; *
|
|
FORMAT.CASE = 'MCU' ; * Treat all keywords in upper case
|
|
FORMAT.LABELS = 1 ; * Do not place labels on a separate line
|
|
FORMAT.COMMENT = 1 ; * Do not format comments
|
|
FORMAT.BRIEF = 0 ; * Indicate progess with *'s
|
|
FORMAT.SURROUND = 1 ; * Do not surround special characters
|
|
FORMAT.ALIGN = 0 ; * Do not align within statements
|
|
END
|
|
CALL @FORMAT.BASIC(PROGRAM, BOT, MAT FORMAT.OPTIONS)
|
|
*
|
|
X = INT((BOT - 1) / LINES.PER.CELL) ; * DETERMINE NUMBER OF FULL CELLS
|
|
LNUM = 0
|
|
PROGRAM = PROGRAM ; * Reset remove pointer
|
|
FOR XX = 1 TO X
|
|
LPC (XX) = LINES.PER.CELL
|
|
LNUM += 1
|
|
PROGRAM.LINE = ''
|
|
LOOP
|
|
REMOVE LINE.SEGMENT FROM PROGRAM SETTING LINE.SEGMENT.MARK
|
|
UNTIL(LINE.SEGMENT.MARK = 2 OR LINE.SEGMENT.MARK = 0) DO
|
|
IF ISNULL(LINE.SEGMENT) THEN LINE.SEGMENT = @NULL.STR
|
|
PROGRAM.LINE := LINE.SEGMENT:CHAR(256 - LINE.SEGMENT.MARK)
|
|
REPEAT
|
|
IF ISNULL(LINE.SEGMENT) THEN LINE.SEGMENT = @NULL.STR
|
|
PROGRAM.LINE := LINE.SEGMENT
|
|
MEMORY (XX) = PROGRAM.LINE
|
|
FOR XXX = 2 TO LINES.PER.CELL ; * MOVE LINES INTO CELL
|
|
LNUM += 1
|
|
PROGRAM.LINE = ''
|
|
LOOP
|
|
REMOVE LINE.SEGMENT FROM PROGRAM SETTING LINE.SEGMENT.MARK
|
|
UNTIL(LINE.SEGMENT.MARK = 2 OR LINE.SEGMENT.MARK = 0) DO
|
|
IF ISNULL(LINE.SEGMENT) THEN LINE.SEGMENT = @NULL.STR
|
|
PROGRAM.LINE := LINE.SEGMENT:CHAR(256 - LINE.SEGMENT.MARK)
|
|
REPEAT
|
|
IF ISNULL(LINE.SEGMENT) THEN LINE.SEGMENT = @NULL.STR
|
|
PROGRAM.LINE := LINE.SEGMENT
|
|
MEMORY (XX) := @FM:PROGRAM.LINE
|
|
NEXT XXX
|
|
NEXT XX
|
|
XX = X + 1 ; * CELL NUMBER OF LAST CELL
|
|
X = MOD(BOT - 1, LINES.PER.CELL) + 1 ; * DETERMINE NUM OF LINES IN LAST CELL
|
|
IF X THEN
|
|
LPC (XX) = X
|
|
LNUM += 1
|
|
PROGRAM.LINE = ''
|
|
LOOP
|
|
REMOVE LINE.SEGMENT FROM PROGRAM SETTING LINE.SEGMENT.MARK
|
|
UNTIL(LINE.SEGMENT.MARK = 2 OR LINE.SEGMENT.MARK = 0) DO
|
|
IF ISNULL(LINE.SEGMENT) THEN LINE.SEGMENT = @NULL.STR
|
|
PROGRAM.LINE := LINE.SEGMENT:CHAR(256 - LINE.SEGMENT.MARK)
|
|
REPEAT
|
|
IF ISNULL(LINE.SEGMENT) THEN LINE.SEGMENT = @NULL.STR
|
|
PROGRAM.LINE := LINE.SEGMENT
|
|
MEMORY (XX) = PROGRAM.LINE
|
|
FOR XXX = 2 TO X ; * MOVE LINES INTO LAST CELL
|
|
LNUM += 1
|
|
PROGRAM.LINE = ''
|
|
LOOP
|
|
REMOVE LINE.SEGMENT FROM PROGRAM SETTING LINE.SEGMENT.MARK
|
|
UNTIL(LINE.SEGMENT.MARK = 2 OR LINE.SEGMENT.MARK = 0) DO
|
|
IF ISNULL(LINE.SEGMENT) THEN LINE.SEGMENT = @NULL.STR
|
|
PROGRAM.LINE := LINE.SEGMENT:CHAR(256 - LINE.SEGMENT.MARK)
|
|
REPEAT
|
|
IF ISNULL(LINE.SEGMENT) THEN LINE.SEGMENT = @NULL.STR
|
|
PROGRAM.LINE := LINE.SEGMENT
|
|
MEMORY (XX) := @FM:PROGRAM.LINE
|
|
NEXT XXX
|
|
END
|
|
LAST.CELL = XX
|
|
CELL.FIRST.LINE = 1 ; CELL = 1 ; LNUM = 0
|
|
PROGRAM = '' ; * RETURN DMR STRING SPACE
|
|
GOTO END.CHANGE
|
|
|
|
G.N: ; * Goto a line (by number).
|
|
LNUM = CMDN ; GOTO CK.NUM
|
|
|
|
G.BEGIN.BLOCK: ; * 'G<': goto beginning of a BLOCK.
|
|
IF MFROM = 0 THEN GOSUB BLOCK.CHECK
|
|
LNUM = MFROM ; GOTO END.NOCHANGE
|
|
|
|
G.END.BLOCK: ; * 'G>': goto end of a BLOCK.
|
|
IF MTHRU = 0 THEN GOSUB BLOCK.CHECK
|
|
LNUM = MTHRU ; GOTO END.NOCHANGE
|
|
|
|
HELP.ANY: ; * Display HELP information.
|
|
GOSUB READ.HELP.RECORD
|
|
ANY = UPCMD [5, 99]
|
|
IF LEN(ANY) = 0 THEN
|
|
CALL *UVPRINTMSG(001248,"")
|
|
GOSUB INPUT.LINE ; ANY = INPUT.LINE
|
|
END
|
|
|
|
*---- Upcase the keywords or letter.
|
|
ANY = TRIM(ANY) ; ANY = UPCASE(ANY) ; XX = 0 ; PRINT
|
|
HELP.COUNT = COUNT(HELP.RECORD, @FM) + 1
|
|
FOR X = 1 TO HELP.COUNT
|
|
LINEX = HELP.RECORD <X>
|
|
IF (IF LEN(ANY) # 1 THEN INDEX(LINEX, ANY, 1) ELSE LINEX [1, 1] = ANY) THEN
|
|
LOOP
|
|
REMOVE LINEXX FROM LINEX SETTING DELIM
|
|
PRINT LINEXX ; XX += 1
|
|
IF XX => (@CRTHIGH - 2) THEN
|
|
CALL *UVPRINTMSG(001142,"")
|
|
INPUT Q, 1 ; Q = UPCASE(Q)
|
|
IF Q = 'Q' THEN GOTO HELP.END
|
|
XX = 0 ; PRINT
|
|
END
|
|
WHILE DELIM
|
|
REPEAT
|
|
END
|
|
NEXT X
|
|
|
|
HELP.END:
|
|
LINEX = '' ; PRINT ; GOTO END.NOCHANGE
|
|
|
|
I.ANY: ; * Insert a new line of text.
|
|
IF ANY = ' ' THEN ANY = ' ' ; * ANY = ''
|
|
* LNUM += 1
|
|
* MEMORY (CELL) = INSERT(MEMORY (CELL), LNUM - CELL.FIRST.LINE + 1, 0, 0, ANY)
|
|
* The following code replaces the above 2 lines, which fail when
|
|
* inserting data before the last field if the last field is null.
|
|
X = LNUM - CELL.FIRST.LINE
|
|
IF X < 0 THEN
|
|
IF LEN(MEMORY (CELL)) = 0 THEN MEMORY (CELL) = ANY
|
|
ELSE MEMORY (CELL) = ANY:@FM:MEMORY (CELL)
|
|
END ELSE
|
|
Y = FIELD(MEMORY (CELL), @FM, 1, X + 1):@FM:ANY
|
|
X = MEMORY (CELL) [COL2(), 99999999]
|
|
IF LEN(X) = 0 THEN MEMORY (CELL) = Y
|
|
ELSE MEMORY (CELL) = Y:X
|
|
END
|
|
LNUM += 1
|
|
*---- End of special code.
|
|
LPC (CELL) += 1
|
|
IF BOT = 0 THEN LAST.CELL = 1
|
|
BOT += 1
|
|
BLOCK.TRACK.LNUM = LNUM ; BLOCK.TRACK.CHANGE = 1 ; GOSUB BLOCK.TRACK
|
|
CHANGE.FLAG = TRUE
|
|
GOTO END.CMD
|
|
|
|
I.BEFORE: ; * Insert before current line.
|
|
ANY = CMD [4, 9999]
|
|
LNUM -= 1 ; * Back up one line.
|
|
IF LNUM < 0 THEN LNUM = 0
|
|
IF ANY THEN GOTO I.ANY ELSE GOTO I
|
|
|
|
I: ; * Put editor into INPUT mode.
|
|
LNUM.INPUT = LNUM
|
|
LNUM += 1
|
|
PRINT STR('0', 4 - LEN(LNUM)):LNUM:'=':
|
|
LOOP
|
|
INPUT.MODE = TRUE
|
|
GOSUB INPUT.LINE
|
|
IF LEN(INPUT.LINE) = 0 THEN
|
|
LNUM = LNUM.INPUT
|
|
GOSUB INSERT.MEMORY
|
|
IF OVERFLOW.FLAG THEN GOTO GET.CMD ; * SJE 23 Apr 84
|
|
LNUM = LNUM.INPUT + NEW.BOT
|
|
BLOCK.TRACK.LNUM = LNUM ; BLOCK.TRACK.CHANGE = NEW.BOT ; GOSUB BLOCK.TRACK
|
|
GOSUB CLEAR.NEW.MEMORY
|
|
GOTO GET.CMD
|
|
END
|
|
LNUM += 1 ; * PRINT NEXT LINE NUM ASAP
|
|
PRINT STR('0', 4 - LEN(LNUM)):LNUM:'=':
|
|
IF INPUT.LINE = ' ' THEN INPUT.LINE = '' ; * INPUT A NULL LINE
|
|
NEW.MEMORY.LINE = INPUT.LINE
|
|
GOSUB APPEND.NEW.MEMORY
|
|
IF OVERFLOW.FLAG THEN GOTO GET.CMD ; * SJE 23 Apr 84
|
|
REPEAT
|
|
|
|
L.ANY: ; * Locate a line containing the string 'any'.
|
|
LOCATE.STRING = ANY
|
|
|
|
L:
|
|
SEARCH.X = 2
|
|
|
|
L.AGAIN:
|
|
IF LNUM => BOT THEN LNUM = 0
|
|
|
|
L.NEXT:
|
|
COMMAND.SUCCESSFUL = FALSE
|
|
GOSUB ABORT.CHECK
|
|
IF ABORT = 'Q' THEN
|
|
CALL *UVPRINTMSG(001228,"")
|
|
GOTO END.NOCHANGE
|
|
END
|
|
LNUM += 1
|
|
IF LNUM > BOT THEN LNUM = BOT ; GOTO END.NOCHANGE
|
|
GOSUB GET.LINE
|
|
ON SEARCH.X GOTO FINDX, LOCATEX, MATCHX
|
|
|
|
FINDX:
|
|
IF LINE [ST.COLUMN, FLEN] = FIND.STRING THEN
|
|
COMMAND.SUCCESSFUL = TRUE
|
|
GOTO END.NOCHANGE
|
|
END ELSE
|
|
GOTO L.NEXT
|
|
END
|
|
|
|
LOCATEX:
|
|
IF INDEX(LINE, LOCATE.STRING, 1) THEN
|
|
COMMAND.SUCCESSFUL = TRUE
|
|
GOTO END.NOCHANGE
|
|
END ELSE
|
|
GOTO L.NEXT
|
|
END
|
|
|
|
MATCHX:
|
|
IF LEN(LINE) => 188 THEN
|
|
PRINT 'Line ':LNUM:' is longer than 188 characters, MATCH NOT DONE, line skipped.'
|
|
GOTO L.NEXT
|
|
END
|
|
IF LINE MATCHES MATCH.STRING THEN
|
|
COMMAND.SUCCESSFUL = TRUE
|
|
GOTO END.NOCHANGE
|
|
END ELSE
|
|
GOTO L.NEXT
|
|
END
|
|
|
|
LOAD.ANY: ; * Load lines from another record.
|
|
IF UPCMD1 = '.' THEN SENT = TRIM(CMD [4, 99])
|
|
ELSE SENT = TRIM(CMD [6, 99])
|
|
IF COUNT(SENT, ' ') > 2 THEN
|
|
PRINT 'Too many parameters. Expected (at most) a file name and record name.'
|
|
GOTO CMD.ERR
|
|
END
|
|
IF COUNT(SENT, ' ') THEN
|
|
PROMPT.FOR.FILE = FALSE ; NO.SELECT.LIST = TRUE ; SINGLE.FILE.ONLY = TRUE
|
|
LOAD.FILE.NAME = '' ; LOAD.DICT = '' ; LOAD.DICT.TEXT = ''
|
|
CALL @GET.FILE.NAME (NO.SELECT.LIST, SENT, LOAD.DICT,
|
|
LOAD.FILE.NAME, PROMPT.FOR.FILE, SINGLE.FILE.ONLY)
|
|
IF LOAD.DICT = '' ELSE LOAD.DICT.TEXT = LOAD.DICT:' '
|
|
IF LEN(LOAD.FILE.NAME) = 0 OR LOAD.FILE.NAME # LOAD.FILE.NAME <1> THEN
|
|
PRINT 'Invalid file name (not found in VOC, or not FILE DEFINITION record).'
|
|
GOTO CMD.ERR
|
|
END
|
|
LOAD.REC.NAME = SENT
|
|
*
|
|
* Open file to load data from. Carry on if partially successful open
|
|
* of distributed file.
|
|
*
|
|
OPENCHECK LOAD.DICT, LOAD.FILE.NAME TO LOAD.FILE ELSE
|
|
ErrorCode = STATUS()
|
|
READL FileRec FROM DEVSYS.VOC.FILE,LOAD.FILE.NAME THEN
|
|
IF LOAD.DICT = "" THEN
|
|
PathName = FileRec<2>
|
|
END ELSE
|
|
PathName = FileRec<3>
|
|
END
|
|
RELEASE DEVSYS.VOC.FILE,LOAD.FILE.NAME
|
|
END ELSE
|
|
PathName = ""
|
|
END
|
|
IF LOAD.DICT = "" THEN
|
|
FileName = LOAD.FILE.NAME
|
|
END ELSE
|
|
FileName = "DICT,":LOAD.FILE.NAME
|
|
END
|
|
CALL @OpenError(ErrorCode,FileName,PathName)
|
|
GOTO CMD.ERR
|
|
END
|
|
END ELSE
|
|
LOAD.FILE.NAME = FILE.NAME ; LOAD.DICT = DICT ; LOAD.FILE = EDIT.FILE
|
|
LOAD.DICT.TEXT = DICT.TEXT
|
|
IF UPCMD1 = '.' THEN
|
|
IF L.SELECT.FLAG AND LEN(SENT) # 0 THEN
|
|
OPENCHECK '', SENT TO LOAD.FILE ELSE
|
|
ErrorCode = STATUS()
|
|
READL FileRec from DEVSYS.VOC.FILE,SENT THEN
|
|
PathName = FileRec<2>
|
|
RELEASE DEVSYS.VOC.FILE,SENT
|
|
END ELSE
|
|
PathName = ""
|
|
END
|
|
FileName = SENT
|
|
CALL @OpenError(ErrorCode,FileName,PathName)
|
|
GOTO CMD.ERR
|
|
END
|
|
LOAD.FILE.NAME = SENT ; GOTO SL.3
|
|
END
|
|
LOAD.FILE.NAME = '&ED&'
|
|
LOAD.DICT = '' ; LOAD.DICT.TEXT = ''
|
|
OPENCHECK LOAD.DICT,LOAD.FILE.NAME TO LOAD.FILE ELSE
|
|
ErrorCode = STATUS()
|
|
READL FileRec FROM DEVSYS.VOC.FILE,LOAD.FILE.NAME THEN
|
|
PathName = FileRec<2>
|
|
RELEASE DEVSYS.VOC.FILE,LOAD.FILE.NAME
|
|
END ELSE
|
|
PathName = ""
|
|
END
|
|
FileName = LOAD.FILE.NAME
|
|
CALL @OpenError(ErrorCode,FileName,PathName)
|
|
GOTO CMD.ERR
|
|
END
|
|
END
|
|
LOAD.REC.NAME = SENT
|
|
END
|
|
IF L.SELECT.FLAG THEN GOTO SL.3
|
|
IF LEN(SENT) = 0 THEN GOTO CMD.ERR
|
|
IF UPCMD1 = '.' THEN GOTO READ.1
|
|
IF ED.CMD.STRING.ACTIVE THEN
|
|
PRINT STARS:' Loading "':LOAD.DICT.TEXT:LOAD.FILE.NAME:'" "':LOAD.REC.NAME:'"':'.'
|
|
END
|
|
CALL *UVPRINTMSG(001193,"")
|
|
GOSUB INPUT.LINE ; START = INPUT.LINE
|
|
IF NOT(NUM(START)) THEN
|
|
PRINT 'Starting line/field must be numeric ; you entered "':START:'".'
|
|
GOTO CMD.ERR
|
|
END
|
|
IF START < 1 THEN
|
|
CALL *UVPRINTMSG(001231,"")
|
|
GOTO CMD.ERR
|
|
END
|
|
CALL *UVPRINTMSG(001195,"")
|
|
GOSUB INPUT.LINE ; ENDING = INPUT.LINE
|
|
IF NOT(NUM(ENDING)) THEN
|
|
PRINT 'Ending line/field must be numeric ; you entered "':ENDING:'".'
|
|
GOTO CMD.ERR
|
|
END
|
|
IF ENDING < START THEN
|
|
CALL *UVPRINTMSG(001233,ENDING:@FM:START)
|
|
GOTO CMD.ERR
|
|
END
|
|
|
|
READ.1:
|
|
READ BLOCK FROM LOAD.FILE, LOAD.REC.NAME
|
|
ELSE
|
|
* Record %s does not exist
|
|
|
|
IF STACK.MODE THEN
|
|
CALL *UVPRINTMSG(970004,LOAD.REC.NAME:@FM:LOAD.FILE.NAME)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001196,LOAD.REC.NAME)
|
|
END
|
|
GOTO CMD.ERR
|
|
END
|
|
IF UPCMD1 = '.' THEN GOTO GET.CMD.FROM.BLOCK
|
|
IF ENDING - START + 1 > 32767 THEN ; *015
|
|
FIELDS = 32767 ; *015
|
|
BLOCK1 = FIELD(BLOCK, @FM, START, FIELDS) ; *015
|
|
LOOP ; *015
|
|
START += 32767 ; *015
|
|
IF ENDING - START + 1 <= 32767 THEN ; *015
|
|
FIELDS = ENDING - START + 1 ; *015
|
|
END ; *015
|
|
WHILE FIELDS > 0 DO ; *015
|
|
TEMPBLOCK = FIELD(BLOCK, @FM, START, FIELDS) ; *015
|
|
IF TEMPBLOCK # '' THEN ; *015
|
|
BLOCK1 = BLOCK1:@FM:TEMPBLOCK ; *015
|
|
END ELSE ; *015
|
|
START = ENDING + 1 ; *015
|
|
END ; *015
|
|
REPEAT ; *015
|
|
BLOCK = BLOCK1 ; *015
|
|
END ELSE ; *015
|
|
BLOCK = FIELD(BLOCK, @FM, START, ENDING - START + 1)
|
|
END ; *015
|
|
LINES.READ = IF LEN(BLOCK) = 0 THEN 0 ELSE COUNT(BLOCK, @FM) + 1
|
|
IF LINES.READ = 0 THEN GOTO LOAD.3
|
|
X = INT((LINES.READ - 1) / LINES.PER.CELL) ; * DETERMINE NUM OF CELLS REQUIRED
|
|
IF X + 1 > NEW.MEMORY.DIM THEN
|
|
NEW.MEMORY.DIM = X + 10
|
|
DIM NEW.MEMORY (NEW.MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; GOTO END.CMD ; * SJE 23 Apr 84
|
|
DIM NEW.LPC (NEW.MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; GOTO END.CMD ; * SJE 23 Apr 84
|
|
END
|
|
|
|
*---- The following code sets up
|
|
* to make a BLOCK of each element of the array. The size of the
|
|
* BLOCK is defined by LINES.PER.CELL.
|
|
|
|
*** MATBLOCK NEW.MEMORY FROM BLOCK, @FM, LINES.PER.CELL
|
|
CALL @MATBLOCK(MAT NEW.MEMORY,BLOCK,@FM,LINES.PER.CELL)
|
|
FOR XX = 1 TO X
|
|
NEW.LPC (XX) = LINES.PER.CELL
|
|
NEXT XX
|
|
NEW.LAST.CELL = X + 1
|
|
NEW.LPC (NEW.LAST.CELL) = MOD(LINES.READ - 1, LINES.PER.CELL) + 1
|
|
NEW.BOT = LINES.READ
|
|
GOSUB INSERT.MEMORY
|
|
IF OVERFLOW.FLAG THEN GOTO END.CMD ; * SJE 23 Apr 84
|
|
GOSUB CLEAR.NEW.MEMORY
|
|
LNUM += 1
|
|
BLOCK = '' ; * RETURN STRING SPACE
|
|
|
|
LOAD.3:
|
|
* %i lines/fields loaded.
|
|
CALL *UVPRINTMSG(001280,LINES.READ)
|
|
BLOCK.TRACK.LNUM = LNUM + LINES.READ - 1
|
|
BLOCK.TRACK.CHANGE = LINES.READ ; GOSUB BLOCK.TRACK
|
|
GOTO END.CMD
|
|
|
|
M.ANY: ; * Locate a line that matches pattern 'any'.
|
|
MATCH.STRING = ANY
|
|
|
|
M:
|
|
SEARCH.X = 3 ; GOTO L.AGAIN
|
|
|
|
MOVE: ; * Move a BLOCK of lines (deleting source lines).
|
|
MOVE.FLAG = TRUE
|
|
|
|
MOVE.COPY:
|
|
GOSUB BLOCK.CHECK
|
|
INSERT.LNUM = LNUM ; * SAVE LNUM
|
|
FOR LNUM = MFROM TO MTHRU ; * COPY THE DESIRED LINES INTO NEW MEMORY
|
|
GOSUB GET.LINE
|
|
NEW.MEMORY.LINE = LINE
|
|
GOSUB APPEND.NEW.MEMORY
|
|
IF OVERFLOW.FLAG THEN GOTO END.CMD ; * SJE 23 Apr 84
|
|
NEXT LNUM
|
|
IF MOVE.FLAG THEN
|
|
LNUM = MFROM
|
|
GOSUB GET.LINE
|
|
NUM.OF.LINES.TO.DELETE = MTHRU - MFROM + 1
|
|
GOSUB DELETE.MEMORY ; * DELETE THE BLOCK IF CMD IS A MOVE
|
|
LNUM = INSERT.LNUM ; * RESTORE LNUM
|
|
IF LNUM => MTHRU THEN LNUM -= MTHRU - MFROM + 1
|
|
MTHRU += LNUM - MFROM + 1
|
|
MFROM = LNUM + 1
|
|
END ELSE
|
|
LNUM = INSERT.LNUM ; * RESTORE LNUM
|
|
IF LNUM < MFROM THEN
|
|
X = MTHRU - MFROM + 1 ; MTHRU += X ; MFROM += X
|
|
END
|
|
END
|
|
GOSUB INSERT.MEMORY
|
|
IF OVERFLOW.FLAG THEN GOTO END.CMD ; * SJE 23 Apr 84
|
|
GOSUB CLEAR.NEW.MEMORY
|
|
LNUM += 1
|
|
GOTO END.CMD
|
|
|
|
N: ; * Move on to next record (if SELECT list is active).
|
|
IF SELECT.LIST.FLAG THEN
|
|
IF NOT(RECORD.CHANGE.FLAG) THEN GOTO DONE.WITH.RECORD
|
|
* Record changed --- OK to go to next record (Y)
|
|
CALL *UVPRINTMSG(001222,"")
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS = 'Y' THEN GOTO DONE.WITH.RECORD
|
|
ELSE GOTO END.NOCHANGE
|
|
END ELSE GOTO X.2
|
|
|
|
P: ; * Print lines on the CRT.
|
|
CMDN = PNUM ; GOTO P.N.1
|
|
|
|
P.N:
|
|
CMDN = CMD [2, 99] ; * GET ORIGINAL NUMBER
|
|
|
|
P.N.1:
|
|
IF LNUM <= 0 THEN LNUM = 1
|
|
LINE1 = LNUM
|
|
IF CMDN > 1 AND UPCMD[1,1] = "P" THEN PNUM = CMDN
|
|
LINE2 = LNUM + CMDN - 1
|
|
IF LINE2 > BOT THEN LINE2 = BOT
|
|
GOSUB PRINT.GROUP
|
|
GOTO GET.CMD
|
|
|
|
PRINT.BLOCK: ; * Print BLOCK on the CRT.
|
|
IF MFROM = 0 OR MTHRU = 0 THEN
|
|
* BLOCK not set up.
|
|
CALL *UVPRINTMSG(001219,"")
|
|
GOTO CMD.ERR
|
|
END
|
|
IF MFROM > MTHRU THEN
|
|
* BLOCK from %i through %i is in the wrong order.
|
|
CALL *UVPRINTMSG(001201,MFROM:@FM:MTHRU)
|
|
GOTO CMD.ERR
|
|
END
|
|
LINE1 = MFROM ; LINE2 = MTHRU ; LNUMX = LNUM
|
|
GOSUB PRINT.GROUP
|
|
LNUM = LNUMX ; PRINT ; GOTO END.NOCHANGE
|
|
|
|
PRINT.GROUP: ; * GOSUB routine for above PRINT routines.
|
|
FOR LNUM = LINE1 TO LINE2
|
|
GOSUB GET.LINE ; GOSUB PRINT.LINE
|
|
GOSUB ABORT.CHECK
|
|
IF ABORT = 'Q' THEN
|
|
CALL *UVPRINTMSG(001228,"")
|
|
RETURN
|
|
END
|
|
NEXT LNUM
|
|
RETURN
|
|
|
|
PO.N: ; * Set line number pointer to line 'n'.
|
|
CMD = CMD [3, 99]
|
|
IF NOT(NUM(CMD)) THEN
|
|
PRINT 'A line number is required ; you entered ':CMD:'.'
|
|
GOTO CMD.ERR
|
|
END
|
|
GOTO SET.LNUM
|
|
|
|
QUIT: ; * Quit this edit session.
|
|
* IF SELECT.LIST.FLAG THEN
|
|
* CALL *UVPRINTMSG(001216,"")
|
|
* PRINT 'Use "X" to exit EDITOR or "N" to see next selected ':REC:'.'
|
|
* GOTO CMD.ERR
|
|
* END
|
|
IF NOT(RECORD.CHANGE.FLAG) THEN GOTO DONE.WITH.RECORD
|
|
* Record changed, OK to Quit (Y)
|
|
CALL *UVPRINTMSG(001218,"")
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS = 'Y' THEN GOTO DONE.WITH.RECORD
|
|
GOTO END.NOCHANGE
|
|
|
|
QUESTION.MARK: ; * '?': display current STATUS.
|
|
COMMAND.SUCCESSFUL = FALSE
|
|
DISPLAY.CURRENT.LINE = FALSE
|
|
CALL *UVPRINTMSG(970011,@ACCOUNT)
|
|
CALL *UVPRINTMSG(001262,"")
|
|
PRINT DICT.TEXT:FILE.NAME:
|
|
IF EDIT.READ.ONLY THEN CALL *UVPRINTMSG(001263,"")
|
|
PRINT
|
|
LINEX = DISPLAY.RECORD.NAME
|
|
IF NLS.ON.FLAG AND UP.ARROW.FLAG THEN ;* in NLS mode, only display ID
|
|
GOSUB CONV.LINEX.TO.UP.ARROW ;* as ^xxx if ^ mode is on
|
|
END
|
|
CALL *UVPRINTMSG(001264,LINEX) ;* record name = nnnnnn
|
|
CALL *UVPRINTMSG(001265,LNUM)
|
|
IF UP.ARROW.FLAG THEN
|
|
IF UP.ARROW.UNIC.FLAG THEN
|
|
CALL *UVPRINTMSG(001266,ENABLED:UNICODE) ;* NLS Unicode ^x mode on
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001266,ENABLED) ;* standard ^ mode on
|
|
END
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001266,DISABLED)
|
|
END
|
|
IF ABORT.FLAG THEN
|
|
CALL *UVPRINTMSG(001267,ENABLED)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001267,DISABLED)
|
|
END
|
|
IF BLOCK.VERIFY.FLAG THEN
|
|
CALL *UVPRINTMSG(001268,ENABLED)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001268,DISABLED)
|
|
END
|
|
IF MTHRU = 0 OR MFROM = 0 THEN
|
|
* No BLOCK currently defined.
|
|
CALL *UVPRINTMSG(001269,"")
|
|
IF MFROM # 0 THEN
|
|
* Block FROM set to line %i.
|
|
CALL *UVPRINTMSG(001226,MFROM)
|
|
END
|
|
IF MTHRU # 0 THEN
|
|
* Block THROUGH set to line %i.
|
|
CALL *UVPRINTMSG(001225,MTHRU)
|
|
END
|
|
END ELSE
|
|
* BLOCK is from line %i through %i.
|
|
CALL *UVPRINTMSG(001270,MFROM:@FM:MTHRU)
|
|
END
|
|
IF CURR.CMD.NAME THEN
|
|
PRINT 'Last Pre-store executed = "':CURR.CMD.NAME:'".':
|
|
IF ED.CMD.STRING.SUSPENDED THEN PRINT ' Command is at a PAUSE.'
|
|
ELSE PRINT ' Command is not active.'
|
|
END ELSE
|
|
PRINT 'No ':PRE.STORE:' has been executed this session.'
|
|
END
|
|
RESTORE.CMD = IF ED.CMD.STRING.ACTIVE AND CHANGE.DURING.CMD.STRING THEN PRIOR.CMD ELSE SAVED.CMD
|
|
IF RESTORE.CMD THEN
|
|
CALL *UVPRINTMSG(001271,RESTORE.CMD)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001249,"")
|
|
END
|
|
GOTO END.CMD
|
|
|
|
R.ANY: ; * Replace line with new text.
|
|
REPLACE.STRING = CMD [3, 999999]
|
|
|
|
R:
|
|
IF LNUM < 1 THEN
|
|
CALL *UVPRINTMSG(970010,LNUM)
|
|
GOTO CMD.ERR
|
|
END
|
|
MEMORY (CELL) = REPLACE(MEMORY (CELL), LNUM - CELL.FIRST.LINE + 1, 0, 0, REPLACE.STRING)
|
|
GOTO END.CHANGE
|
|
|
|
RELEASE: ; * Release record lock.
|
|
IF RECORD.NAME.LOCKED THEN
|
|
RELEASE EDIT.FILE, RECORD.NAME
|
|
RECORD.NAME.LOCKED = FALSE
|
|
CALL *UVPRINTMSG(001252,"")
|
|
END ELSE PRINT UREC:' was not locked.'
|
|
GOTO END.NOCHANGE
|
|
|
|
SAVE.ANY: ; * Save a copy of this record.
|
|
COMMAND.SUCCESSFUL = FALSE
|
|
DISPLAY.CURRENT.LINE = FALSE
|
|
IF RECORD.CHANGE.FLAG OR UPCMD # 'SAVE' THEN
|
|
GOSUB FILE.IT
|
|
IF NOT(WRITEERROR) THEN RECORD.CHANGE.FLAG = FALSE ; * RESET ;*026
|
|
END ELSE
|
|
PRINT UREC:' has not been changed, or you already have done a SAVE.'
|
|
END
|
|
GOTO END.NOCHANGE
|
|
|
|
SEQ.ANY: ; * Generate a sequential number.
|
|
X = 4
|
|
LOOP DELIM = CMD [X, 1] WHILE DELIM = ' ' DO X += 1 REPEAT
|
|
IF NOT(INDEX(DELIM.STRING, DELIM, 1)) THEN
|
|
PRINT 'Valid delimiters are ':DELIM.STRING
|
|
GOTO CMD.ERR
|
|
END
|
|
IF COUNT(CMD, DELIM) > 4 THEN
|
|
PRINT 'Too many delimiters (4 maximum).'
|
|
GOTO CMD.ERR
|
|
END
|
|
FROM.FIELD = FIELD(CMD, DELIM, 2)
|
|
LEN.FROM.FIELD = LEN(FROM.FIELD)
|
|
TO.FIELD = FIELD(CMD, DELIM, 3)
|
|
INC.FIELD = FIELD(CMD, DELIM, 5)
|
|
IF NOT(NUM(INC.FIELD)) OR LEN(TO.FIELD) = 0 OR NOT(NUM(TO.FIELD)) THEN
|
|
GOTO NUMBER.ERR
|
|
END
|
|
IF LEN(INC.FIELD) = 0 THEN INC.FIELD = 1
|
|
EXTEND = 0
|
|
N = FIELD(CMD, DELIM, 4)
|
|
N = UPCASE(N)
|
|
IF N = 'B' THEN
|
|
GOSUB BLOCK.CHECK ; LNUM = MFROM ; LEND = MTHRU
|
|
END ELSE
|
|
IF LEN(N) = 0 OR NOT(NUM(N)) THEN GOTO NUMBER.ERR
|
|
IF LNUM <= 0 THEN LNUM = 1
|
|
LEND = LNUM + N - 1
|
|
EXTEND = 0
|
|
IF FROM.FIELD THEN
|
|
IF LEND > BOT THEN LEND = BOT
|
|
END ELSE
|
|
IF LEND > BOT THEN EXTEND = LEND ; LEND = BOT
|
|
END
|
|
END
|
|
X.CHANGE.FLAG = FALSE ; * RESET LOCAL CHANGE FLAG
|
|
FOR LNUM = LNUM TO LEND
|
|
GOSUB GET.LINE
|
|
IF LEN(FROM.FIELD) = 0 THEN LINE = TO.FIELD:LINE ; GOTO S.REPLACE.LINE
|
|
X = INDEX(LINE, FROM.FIELD, 1)
|
|
IF X = 0 THEN GOTO S.NEXT.LINE
|
|
LINE = LINE [1, X - 1]:TO.FIELD:LINE [X + LEN.FROM.FIELD, 999999]
|
|
|
|
S.REPLACE.LINE:
|
|
MEMORY (CELL) = REPLACE(MEMORY (CELL), LNUM - CELL.FIRST.LINE + 1, 0, 0, LINE)
|
|
GOSUB PRINT.LINE
|
|
CHANGE.FLAG = TRUE
|
|
X.CHANGE.FLAG = TRUE ; * SET LOCAL CHANGE FLAG
|
|
TO.FIELD += INC.FIELD
|
|
|
|
S.NEXT.LINE:
|
|
NEXT LNUM
|
|
IF EXTEND THEN
|
|
FOR LNUM = BOT + 1 TO EXTEND
|
|
LINE = TO.FIELD
|
|
GOSUB PRINT.LINE
|
|
NEW.MEMORY.LINE = LINE
|
|
GOSUB APPEND.NEW.MEMORY
|
|
IF OVERFLOW.FLAG THEN GOTO GET.CMD ; * SJE 23 Apr 84
|
|
TO.FIELD += INC.FIELD
|
|
NEXT LNUM
|
|
LNUM = BOT
|
|
GOSUB INSERT.MEMORY
|
|
IF OVERFLOW.FLAG THEN GOTO GET.CMD ; * SJE 23 Apr 84
|
|
GOSUB CLEAR.NEW.MEMORY
|
|
LNUM = EXTEND
|
|
GOTO GET.CMD
|
|
END
|
|
CHANGE.FLAG = X.CHANGE.FLAG ; * SET UP FLAG FOR OOPS SINCE GET.LINE
|
|
; * COULD HAVE RESET IT AFTER LAST LINE ACTUALLY CHANGED
|
|
GOTO GET.CMD
|
|
|
|
SIZE: ; * Display information about SIZE of record.
|
|
LENGTH = 0
|
|
FOR X = 1 TO LAST.CELL
|
|
LENGTH += LEN(MEMORY (X)) ; * ADD LENGTH OF LINES
|
|
NEXT X
|
|
IF LAST.CELL > 1 THEN LENGTH += LAST.CELL - 1
|
|
CALL *UVPRINTMSG(001255,DISPLAY.RECORD.NAME:@FM:BOT:@FM:LENGTH)
|
|
GOTO END.NOCHANGE
|
|
|
|
SPOOL.HELP: ; * Spool the HELP file on line printer.
|
|
GOSUB READ.HELP.RECORD
|
|
PRINTER ON
|
|
HEADING 'EDITOR H E L P LIST OF COMMANDS ':TIMEDATE():"'LLL'"
|
|
LOOP
|
|
REMOVE LINEX FROM HELP.RECORD SETTING DELIM
|
|
PRINT LINEX ; PRINT ' '
|
|
WHILE DELIM REPEAT
|
|
PRINTER OFF
|
|
DUMMY = @(0) ; * TURN OFF CRT PAGING
|
|
PRINT 'HELP listing spooled to printer.'
|
|
GOTO HELP.END
|
|
|
|
SPOOL.N: ; * Spool the record on line printer.
|
|
CMDN = CMD [6, 99]
|
|
IF NOT(NUM(CMDN)) THEN GOTO NUMBER.ERR
|
|
IF CMDN > 0 THEN
|
|
IF LNUM <= 0 THEN LNUM = 1
|
|
IF LNUM + CMDN - 1 > BOT THEN CMDN = BOT - LNUM + 1
|
|
LEND = LNUM + CMDN - 1
|
|
END ELSE LNUM = 1 ; LEND = BOT
|
|
BREAK KEY OFF
|
|
PRINTER ON ;* send output to lptr 0 via channel 0.
|
|
LPTR.WIDTH = @LPTRWIDE
|
|
LPTR.MODE = 0 ; CODE = 0
|
|
CALL @GETPU(PU$MODE,0,LPTR.MODE,CODE)
|
|
IF LPTR.MODE # 3 THEN
|
|
* save banner
|
|
LPTR.BANNER = SPACE(32)
|
|
CODE = 0
|
|
CALL @GETPU(PU$BANNER,0,LPTR.BANNER,CODE)
|
|
* set banner
|
|
RECORD.BANNER = FMT(DISPLAY.RECORD.NAME, 'L#32')
|
|
CALL @SETPU(PU$BANNER,0,RECORD.BANNER,CODE)
|
|
END
|
|
HEADING UREC:' - ':DISPLAY.RECORD.NAME:' File - ':FILE.NAME:' Account - ':@ACCOUNT:' ':TIMEDATE():"'LL'"
|
|
LINE.LENGTH = LPTR.WIDTH - 7
|
|
FOR LNUM = LNUM TO LEND
|
|
GOSUB GET.LINE ; GOSUB PRINT.LINE
|
|
NEXT LNUM
|
|
PRINTER CLOSE ;* Flush printer buffer (GTAR 12556)
|
|
PRINTER OFF
|
|
PRINTER CLOSE
|
|
IF LPTR.MODE # 3 THEN
|
|
* reset banner
|
|
PRINTER ON
|
|
CALL @SETPU(PU$BANNER,0,LPTR.BANNER,CODE)
|
|
PRINTER CLOSE ;* Flush printer buffer (GTAR 12556)
|
|
PRINTER OFF
|
|
END
|
|
BREAK KEY ON
|
|
DUMMY = @(0) ; * TURN OFF CRT PAGING
|
|
LINE.LENGTH = CRT.WIDTH - 7
|
|
IF CMDN > 0 THEN PRINT 'Lines ':LEND - CMDN + 1:' to ':LEND:' of ':
|
|
PRINT '"':DISPLAY.RECORD.NAME:'" spooled to the printer.'
|
|
|
|
T: ; * Goto TOP of record.
|
|
LNUM = 0 ; GOTO END.NOCHANGE
|
|
|
|
STAMP:
|
|
CMD = 'I '
|
|
BEGIN CASE
|
|
CASE RECORD.NAME [4] = '.CBL' OR RECORD.NAME [6] = '.COBOL'
|
|
CMD := SPACE(6):'*'
|
|
CASE RECORD.NAME [4] = '.CPL'
|
|
CMD := '/*'
|
|
CASE RECORD.NAME [4] = '.F77' OR RECORD.NAME [4] = '.FTN'
|
|
CMD := 'C'
|
|
CASE RECORD.NAME [7] = '.PASCAL'
|
|
CMD := '{'
|
|
CASE RECORD.NAME [4] = '.PL1' OR RECORD.NAME [5] = '.PL1G' OR RECORD.NAME [4] = '.PLP' OR RECORD.NAME [4] = '.SPL'
|
|
CMD := '/*'
|
|
CASE RECORD.NAME [5] = '.RUNI'
|
|
CMD := '.*'
|
|
CASE TRUE
|
|
CMD := '*'
|
|
END CASE
|
|
CMD := ' Last updated by ':@WHO
|
|
IF @WHO # @LOGNAME THEN CMD := ' (':@LOGNAME:')'
|
|
CMD := ' at ':OCONV(TIME(), 'MTS')
|
|
CMD := ' on ':OCONV(DATE(), 'D4/'):'.'
|
|
BEGIN CASE
|
|
CASE RECORD.NAME [7] = '.PASCAL'
|
|
CMD := ' }'
|
|
CASE RECORD.NAME [4] = '.PL1' OR RECORD.NAME [5] = '.PL1G' OR RECORD.NAME [4] = '.PLP' OR RECORD.NAME [4] = '.SPL'
|
|
CMD := ' */'
|
|
CASE TRUE
|
|
NULL
|
|
END CASE
|
|
STACK.MODE = FALSE
|
|
GOTO GET.CMD.2
|
|
|
|
UNLOAD.ANY: ; * Unload lines to another record.
|
|
COMMAND.SUCCESSFUL = FALSE
|
|
DISPLAY.CURRENT.LINE = FALSE
|
|
SV.LNUM = LNUM ; UNLOAD.FLAG = TRUE
|
|
GOSUB STRING.WRITE
|
|
UNLOAD.FLAG = FALSE ; LNUM = SV.LNUM
|
|
GOTO END.NOCHANGE
|
|
|
|
SET.LNUM: ; * '+n', '-n', 'n': set line number.
|
|
IF CMD [1, 1] = '+' OR CMD [1, 1] = '-' THEN LNUM += INT(CMD)
|
|
ELSE LNUM = INT(CMD)
|
|
|
|
CK.NUM:
|
|
IF LNUM < 0 THEN LNUM = 0
|
|
IF LNUM > BOT THEN LNUM = BOT ; COMMAND.SUCCESSFUL = FALSE
|
|
GOTO END.NOCHANGE
|
|
|
|
MFROM: ; * '<': set BLOCK 'from' pointer.
|
|
COMMAND.SUCCESSFUL = FALSE
|
|
DISPLAY.CURRENT.LINE = FALSE
|
|
IF LNUM = 0 THEN
|
|
|
|
CLEAR.BLOCK:
|
|
MFROM = 0 ; MTHRU = 0
|
|
* The current BLOCK pointers have been cleared.
|
|
CALL *UVPRINTMSG(001224,"")
|
|
END ELSE
|
|
MFROM = LNUM
|
|
* Block FROM set to line %i.
|
|
CALL *UVPRINTMSG(001226,MFROM)
|
|
END
|
|
IF UPCMD # '<>' OR LNUM = 0 THEN GOTO END.NOCHANGE
|
|
|
|
MTHRU: ; * '>': set BLOCK 'to' pointer.
|
|
COMMAND.SUCCESSFUL = FALSE
|
|
DISPLAY.CURRENT.LINE = FALSE
|
|
IF LNUM = 0 THEN GOTO CLEAR.BLOCK
|
|
MTHRU = LNUM
|
|
* Block THROUGH set to line %i.
|
|
CALL *UVPRINTMSG(001225,MTHRU)
|
|
GOTO END.NOCHANGE
|
|
|
|
UP.ARROW.TOGGLE: ; * '^': Up arrow display mode toggle.
|
|
* Controls the display/printing of special characters.
|
|
* There are two modes:
|
|
* - Straight '^' mode, in which unprintable characters are displayed as
|
|
* ^ddd (3-digit decimals) (UP.ARROW.FLAG AND NOT(UP.ARROW.UNIC.FLAG))
|
|
* unless the characters is > 255, in which case same as ^X mode.
|
|
* - NLS '^X' mode, in which unprintable characters are displayed as
|
|
* ^hhhh (4-digit hex) (UP.ARROW.FLAG AND UP.ARROW.UNIC.FLAG).
|
|
|
|
IF UPCMD = UP.ARROW.UNIC.UP THEN
|
|
* ^X means force Unicode ^ mode on regardless of previous state, but
|
|
* is only recognized if Unicode (NLS) mode is on:
|
|
IF NOT(NLS.ON.FLAG) THEN
|
|
* 'The %s command is not allowed unless NLS support is ON.'
|
|
* CALL *UVPRINTMSG('970014',UP.ARROW.UNIC.UP)
|
|
GOSUB PRINT.INVALID.UP.ARROW ;* replace with line above after 8.3.3
|
|
GOTO END.NOCHANGE
|
|
END
|
|
UP.ARROW.UNIC.FLAG = TRUE
|
|
UP.ARROW.FLAG = TRUE
|
|
END ELSE
|
|
* ^ on its own toggles standard mode, always sets Unicode ^ mode off:
|
|
UP.ARROW.FLAG = NOT(UP.ARROW.FLAG)
|
|
UP.ARROW.UNIC.FLAG = FALSE
|
|
END
|
|
IF UP.ARROW.FLAG THEN
|
|
IF UP.ARROW.UNIC.FLAG THEN
|
|
CALL *UVPRINTMSG(001266,ENABLED:UNICODE) ;* NLS Unicode ^x mode on
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001266,ENABLED) ;* standard ^ mode on
|
|
END
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001266,DISABLED)
|
|
END
|
|
GOTO END.NOCHANGE
|
|
|
|
***********************************************************************
|
|
* exit edit session and close common VOC file.
|
|
*
|
|
STOP:
|
|
IF ASSIGNED(DEVSYS.VOC.FILE) THEN
|
|
CLOSE DEVSYS.VOC.FILE
|
|
END
|
|
DEVSYS.DICT.SWITCH = 0
|
|
IF ASSIGNED(DEVSYS.DICT.FILE) THEN
|
|
CLOSE DEVSYS.DICT.FILE
|
|
END
|
|
DEVSYS.DICT.FILE.NAME = ""
|
|
IF ASSIGNED(DEVSYS.DATA.FILE) THEN
|
|
CLOSE DEVSYS.DATA.FILE
|
|
END
|
|
DEVSYS.DATA.FILE.NAME = ""
|
|
IF ASSIGNED(DEVSYS.R.FILE) THEN
|
|
CLOSE DEVSYS.R.FILE
|
|
END
|
|
DEVSYS.R.FILE.NAME = ""
|
|
PRINT:
|
|
|
|
STOP.POP:
|
|
RETURN TO STOP.POP
|
|
|
|
X: ; * Exit from editor when SELECT list is active.
|
|
IF SELECT.LIST.FLAG THEN
|
|
*---- PCC was here 11/04/83. Now releases locked record before stoppping.
|
|
IF RECORD.CHANGE.FLAG THEN
|
|
*------- See if we want to file first.
|
|
* Record changed --- OK to EXIT (Y)
|
|
CALL *UVPRINTMSG(001223,"")
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS # 'Y' THEN GOTO END.NOCHANGE ; * file it maybe
|
|
END
|
|
*------- We're stopping, but first may need to release current record.
|
|
IF RECORD.NAME.LOCKED THEN
|
|
RELEASE EDIT.FILE, RECORD.NAME ; * RELEASE RECORD LOCK
|
|
RECORD.NAME.LOCKED = FALSE
|
|
END
|
|
GOTO STOP
|
|
END
|
|
|
|
X.2:
|
|
* This command can only be used when a SELECT list is active.
|
|
CALL *UVPRINTMSG(001221,"")
|
|
GOTO CMD.ERR
|
|
*
|
|
* 007 - This section of code has replaced the old section completely.
|
|
* Note: the @variable @LINE is a special case, as it is the current
|
|
* line being edited, and must be allocated dynamically as
|
|
* the xeq sentence is being 'parsed';
|
|
* Note: tokens are strings delimited by blanks, thus to pass a legal
|
|
* @variable name to xeq without replacing it, the sentence must
|
|
* be of the form:
|
|
* XEQ ..... '@variable' ..... or
|
|
* XEQ ..... "@variable" .....
|
|
*
|
|
* Note the blanks before and after the dots
|
|
*
|
|
XEQ.ANY: ; * 007 Execute any PERFORM statement.
|
|
NEW.XEQ=''
|
|
*
|
|
* Get the PERFORM sentence to execute
|
|
*
|
|
XEQ.POS = INDEX(CMD, ' ', 1)
|
|
XEQ = CMD[XEQ.POS+1, 999999]
|
|
*
|
|
BLK=' '
|
|
XEQ.LEN=LEN(XEQ)
|
|
IF XEQ.LEN > 0 THEN ; * if there is anything after XEQ
|
|
|
|
NT=COUNT(XEQ,BLK)+1 ; * COUNT NUMBER OF TOKENS(>0)
|
|
FOR I=1 TO NT
|
|
TOKEN=FIELD(XEQ,BLK,I) ; * EXTRACT CURRENT TOKEN
|
|
|
|
C1=TOKEN[1,1]
|
|
C2='' ; * 013
|
|
IF C1 = '*' OR C1 = '-' THEN ; * 013
|
|
C2=C1 ; * 013
|
|
TOKEN=TOKEN[2,999999] ; * 013
|
|
C1=TOKEN[1,1] ; * 013
|
|
END ; * 013
|
|
|
|
L.TOK=LEN(TOKEN)
|
|
CL=TOKEN[L.TOK,1]
|
|
IF C1 = '@' THEN ; * CHECK FOR LEGAL @VARIABLE NAME
|
|
|
|
LOCATE TOKEN IN AT.LIST <1> BY 'AL' SETTING AT.LOC ELSE AT.LOC=''
|
|
|
|
IF AT.LOC THEN ; * LEGAL NAME FOUND,SPEC.CASE FOR @LINE
|
|
|
|
IF TOKEN='@LINE' THEN AT.SUB=REPLACE(AT.SUB,AT.LOC,0,0,LINE)
|
|
TOKEN = AT.SUB <AT.LOC>
|
|
END
|
|
END
|
|
|
|
IF TOKEN = '@FM' THEN TOKEN = @FM ; * CONVERT @FM TO ~
|
|
*
|
|
* NOW PROCESS QUOTED STRINGS, CHECKING THAT DATA INSIDE QUOTES IS A LEGAL
|
|
* @ VARIABLE NAME. NOTE THAT WE DO NOT NEED A SPECIAL CASE FOR @LINE, BUT
|
|
* THAT WE DO NEED ONE FOR @FM AS IT IS NOT IN AT.SUB
|
|
* SUB.TOKEN IS TOKEN STRIPPED OF QUOTES
|
|
*
|
|
IF (C1=CHAR(34) OR C1=CHAR(39)) AND CL = C1 THEN
|
|
|
|
SUB.TOKEN = TOKEN[2,L.TOK-2]
|
|
LOCATE SUB.TOKEN IN AT.LIST <1> BY 'AL' SETTING AT.LOC ELSE AT.LOC=''
|
|
IF AT.LOC OR SUB.TOKEN='@FM' THEN TOKEN=SUB.TOKEN
|
|
END
|
|
*
|
|
*IN ALL CASES ADD WHATEVER IS IN TOKEN TO NEW.XEQ
|
|
*
|
|
NEW.XEQ=NEW.XEQ:C2:TOKEN:BLK ; * 013 ;* ADD TOKEN TO NEW.XEQ IN ALL CASES
|
|
NEXT I ; * END OF DO LOOP
|
|
END ; * END OF IF PRECEEDING DO LOOP
|
|
|
|
NEW.XEQ = NEW.XEQ[1,LEN(NEW.XEQ)-1] ; * 014 ;* 018
|
|
|
|
CALL *UVPRINTMSG(001259,NEW.XEQ)
|
|
*
|
|
* (GTAR 12556) Reset terminal using uniVerse PRINTER RESET
|
|
*
|
|
PFLAG = SYSTEM(1)
|
|
IF PFLAG THEN PRINTER OFF
|
|
PRINTER RESET
|
|
IF PFLAG THEN PRINTER ON
|
|
|
|
SAVE.DEVSYS.VOC.FILE = DEVSYS.VOC.FILE
|
|
SAVE.DEVSYS.DICT.SWITCH = DEVSYS.DICT.SWITCH
|
|
SAVE.DEVSYS.DICT.FILE = DEVSYS.DICT.FILE
|
|
SAVE.DEVSYS.DICT.FILE.NAME = DEVSYS.DICT.FILE.NAME
|
|
SAVE.DEVSYS.DATA.FILE = DEVSYS.DATA.FILE
|
|
SAVE.DEVSYS.DATA.FILE.NAME = DEVSYS.DATA.FILE.NAME
|
|
SAVE.DEVSYS.R.FILE = DEVSYS.R.FILE
|
|
SAVE.DEVSYS.R.FILE.NAME = DEVSYS.R.FILE.NAME
|
|
|
|
EXECUTE NEW.XEQ ; * EXECUTE THE COMMAND LINE
|
|
|
|
DEVSYS.VOC.FILE = SAVE.DEVSYS.VOC.FILE
|
|
DEVSYS.DICT.SWITCH = SAVE.DEVSYS.DICT.SWITCH
|
|
DEVSYS.DICT.FILE = SAVE.DEVSYS.DICT.FILE
|
|
DEVSYS.DICT.FILE.NAME = SAVE.DEVSYS.DICT.FILE.NAME
|
|
DEVSYS.DATA.FILE = SAVE.DEVSYS.DATA.FILE
|
|
DEVSYS.DATA.FILE.NAME = SAVE.DEVSYS.DATA.FILE.NAME
|
|
DEVSYS.R.FILE = SAVE.DEVSYS.R.FILE
|
|
DEVSYS.R.FILE.NAME = SAVE.DEVSYS.R.FILE.NAME
|
|
|
|
PRINTER CLOSE ;* Flush printer buffer (GTAR 12556)
|
|
DUMMY = @(0) ; * DISABLE CRT PAGING AGAIN
|
|
CALL *UVPRINTMSG(001260,"")
|
|
PROMPT ' '
|
|
GOTO END.NOCHANGE
|
|
!
|
|
* General GOSUB routines.
|
|
!
|
|
|
|
GET.LINE: ; * Get specified line from record. GOSUB routine.
|
|
*---- The record being editted is maintained in a matrix called MEMORY.
|
|
* Each element of the matrix contains NUMBER.LINES.PER.CELL of source
|
|
* lines when the record is originally read into MEMORY.
|
|
* The actual number of lines in each cell is kept in a parallel matrix
|
|
* called LPC (Lines Per Cell).
|
|
|
|
*---- As MEMORY is modified, LPC must also be changed to reflect the correct
|
|
* number of lines in the changed cells. The current line, called LNUM,
|
|
* is in the current cell called CELL. The effective line number of the
|
|
* first line in the current cell is called CELL.FIRST.LNUM. The last
|
|
* line number is called BOT (bottom) and is in the last active cell
|
|
* called LAST.CELL. The variable LNUM.SAVE is used to indicate the
|
|
* previous line number that was being pointed to.
|
|
|
|
*---- The primary goal of the MEMORY accessing is speed. It is necessary
|
|
* to know if the current cell has been changed (since this reset any
|
|
* REMOVE pointers). The variable CHANGE.FLAG must be set to TRUE by any
|
|
* routine that changes any cell of MEMORY. If a cell has been changed
|
|
* then the REMOVE pointers must be rescanned.
|
|
|
|
*---- When accessing a line, the logic will determine if the line LNUM is
|
|
* in the current cell. If so, then it determines if the remove pointers
|
|
* can be used or if they have to be reset. If the line is not in the
|
|
* current cell, then the logic determines the fastest access
|
|
* to one of the four possible quadrants of MEMORY by
|
|
* scanning LPC forward from the first cell or the current cell or by
|
|
* scanning LPC backward from the last cell or the current cell.
|
|
* Once the correct cell is located, the desired line is REMOVEd.
|
|
* Subsequent accesses to get the next sequential line will use the REMOVE
|
|
* pointers until either a line is changed or the next line is in the
|
|
* next cell.
|
|
|
|
*---- GET.LINE should not be called with LNUM <= 0 or LNUM > BOT, or when the memory
|
|
* matrix is null !!!
|
|
|
|
*---- BOT line number of the last line (bottom)
|
|
* CELL current cell of MEMORY containing line LNUM
|
|
* CELL.FIRST.LINE line number of first line in this cell
|
|
* CHANGE.FLAG set to TRUE whenever a routine changes MEMORY (set by user)
|
|
* LAST.CELL last cell (matrix element) used in MEMORY and LPC
|
|
* LINE text line from record at line number LNUM
|
|
* LNUM line number of current line (set by user)
|
|
* LNUM.SAVE line number of previously accessed line
|
|
* LPC matrix, number of Lines Per Cell in MEMORY (set by user)
|
|
* MEMORY matrix of record being editted, LPC lines in each cell (set by user)
|
|
|
|
IF CHANGE.FLAG THEN
|
|
CHANGE.FLAG = FALSE ; RECORD.CHANGE.FLAG = TRUE
|
|
END ELSE
|
|
IF LNUM = LNUM.SAVE + 1 THEN
|
|
IF LNUM < CELL.FIRST.LINE + LPC (CELL) THEN GOTO GET.LINE.7 ; * GET NEXT SEQUENTIAL LINE
|
|
ELSE GOTO GET.LINE.2 ; * MUST GOTO TO NEXT CELL
|
|
END
|
|
IF (LNUM => CELL.FIRST.LINE) AND (LNUM < LPC (CELL) + CELL.FIRST.LINE) THEN
|
|
IF LNUM = LNUM.SAVE THEN RETURN ; * ALREADY HAVE IT
|
|
IF LNUM > LNUM.SAVE THEN GOTO GET.LINE.6 ; * IN THIS CELL AFTER LNUM.SAVE
|
|
ELSE GOTO GET.LINE.5 ; * IN THIS CELL BEFORE LNUM.SAVE
|
|
END
|
|
END
|
|
|
|
*---- Not in current cell, or cell changed; find cell containing LNUM.
|
|
IF LNUM => CELL.FIRST.LINE THEN
|
|
IF LNUM > (CELL.FIRST.LINE + BOT) / 2 THEN GOTO GET.LINE.3 ; * SCAN BACK FROM BOT
|
|
ELSE GOTO GET.LINE.2 ; * SCAN UP FROM CELL
|
|
END ELSE
|
|
IF LNUM > CELL.FIRST.LINE / 2 THEN GOTO GET.LINE.4 ; * SCAN BACK FROM CELL
|
|
ELSE GOTO GET.LINE.1 ; * SCAN UP FROM START (TOP)
|
|
END
|
|
|
|
GET.LINE.1: ; * Initialize scan forward from first line.
|
|
CELL = 1 ; CELL.FIRST.LINE = 1
|
|
IF LNUM = 0 THEN
|
|
LINE = '' ; LNUM.SAVE = 0
|
|
MEMORY (CELL) = MEMORY (CELL) ; * RESET REMOVE POINTER, DO NOT REMOVE !!!
|
|
RETURN
|
|
END
|
|
|
|
GET.LINE.2: ; * Scan forward to locate desired cell containing line LNUM.
|
|
LOOP WHILE LNUM => CELL.FIRST.LINE + LPC (CELL)
|
|
CELL.FIRST.LINE += LPC (CELL)
|
|
MEMORY (CELL) = MEMORY (CELL) ; * RESET REMOVE POINTER, DO NOT REMOVE !!!
|
|
CELL += 1
|
|
REPEAT
|
|
GOTO GET.LINE.5:
|
|
|
|
GET.LINE.3: ; * Initialize to scan backward from last cell.
|
|
CELL = LAST.CELL
|
|
CELL.FIRST.LINE = BOT + 1 - LPC (CELL)
|
|
|
|
GET.LINE.4: ; * Scan backward to locate desired cell containing line LNUM.
|
|
LOOP WHILE LNUM < CELL.FIRST.LINE
|
|
MEMORY (CELL) = MEMORY (CELL) ; * RESET REMOVE POINTER, DO NOT REMOVE !!!
|
|
CELL -= 1 ; CELL.FIRST.LINE -= LPC (CELL)
|
|
REPEAT
|
|
|
|
GET.LINE.5: ; * Reset to start remove from first line of cell.
|
|
LNUM.SAVE = CELL.FIRST.LINE - 1
|
|
MEMORY (CELL) = MEMORY (CELL) ; * RESET REMOVE POINTER, KEEP THIS LINE !!!
|
|
|
|
GET.LINE.6: ; * Remove lines up to the line before the desired one.
|
|
FOR X = LNUM.SAVE TO LNUM - 2
|
|
LOOP
|
|
REMOVE LINE FROM MEMORY (CELL) SETTING DX
|
|
UNTIL DX = 2 OR DX = 0 REPEAT
|
|
NEXT X
|
|
|
|
GET.LINE.7: ; * Remove the desired line.
|
|
LNUM.SAVE = LNUM
|
|
REMOVE LINE FROM MEMORY (CELL) SETTING DX
|
|
IF ISNULL(LINE) THEN LINE = @NULL.STR
|
|
IF DX = 2 OR DX = 0 THEN RETURN
|
|
LOOP
|
|
LINE := CHAR(256 - DX)
|
|
REMOVE LX FROM MEMORY (CELL) SETTING DX
|
|
IF ISNULL(LX) THEN LX = @NULL.STR
|
|
LINE := LX
|
|
UNTIL DX = 2 OR DX = 0 REPEAT
|
|
RETURN
|
|
|
|
DELETE.MEMORY: ; * Delete 1 or more lines from record memory. GOSUB routine.
|
|
*---- This subroutine deletes lines from the blocked memory. It is assumed
|
|
* that GET.LINE has been called with LNUM set to the first line to be
|
|
* deleted (this sets up variables used here). Also, the variable
|
|
* NUM.OF.LINES.TO.DELETE should be set by the caller to the number of lines to
|
|
* be deleted.
|
|
* It is assumed that LNUM + NUM.OF.LINES.TO.DELETE - 1 is not greater than BOT.
|
|
* If during the deleting process, one or more cells of memory are
|
|
* completely cleared (LPC (CELL) = 0), then they will be squeezed out of
|
|
* the matrices MEMORY and LPC.
|
|
* The most probable delete case is to delete a single line. This case
|
|
* is optimized to be the fastest. When deleting lines out of a cell
|
|
* the logic will check to see if the entire cell will be cleared so that
|
|
* it may be squeezed out of the matrices. If two cells are partially
|
|
* deleted, they will not be recombined.
|
|
* The subroutine exits with MEMORY and LPC set up to reflect the new
|
|
* record content. CHANGE.FLAG will be set, LNUM will be backed up
|
|
* one line, and BOT and LAST.CELL will be properly adjusted.
|
|
* Two variables, CELLX and CELLY are used to count the cell to squeeze.
|
|
* CELLX points to the first cell that may be squeezable.
|
|
* CELLY points to the cell after the last one that may be squeezed.
|
|
|
|
*---- Initialize:
|
|
IF NUM.OF.LINES.TO.DELETE = 0 THEN RETURN
|
|
CHANGE.FLAG = TRUE
|
|
BOT -= NUM.OF.LINES.TO.DELETE
|
|
|
|
*---- Check if first cell will be totally deleted; if so, squeeze out cell.
|
|
IF LNUM = CELL.FIRST.LINE AND NUM.OF.LINES.TO.DELETE => LPC (CELL) THEN
|
|
CELLX = CELL ; GOTO DELETE.MEMORY.1
|
|
END
|
|
|
|
*---- Check if only one line (but not all of cell) to be deleted.
|
|
IF NUM.OF.LINES.TO.DELETE = 1 THEN
|
|
MEMORY (CELL) = DELETE(MEMORY (CELL), LNUM - CELL.FIRST.LINE + 1, 0, 0)
|
|
LPC (CELL) -= 1
|
|
GOTO DELETE.MEMORY.2
|
|
END
|
|
|
|
*---- Determine number of lines to delete from the first cell.
|
|
NUM.TO.DELETE = IF LNUM + NUM.OF.LINES.TO.DELETE > CELL.FIRST.LINE + LPC (CELL)
|
|
THEN LPC (CELL) - (LNUM-CELL.FIRST.LINE)
|
|
ELSE NUM.OF.LINES.TO.DELETE
|
|
|
|
*---- Delete some lines from the current cell.
|
|
SENT = FIELD(MEMORY (CELL), @FM, LNUM - CELL.FIRST.LINE + 1, NUM.TO.DELETE) ; * SET COL1() AND COL2()
|
|
SENT = '' ; * RETURN DMR SPACE
|
|
MEMORY (CELL) = MEMORY (CELL) [1, COL1() - 1]:MEMORY (CELL) [COL2() + IF COL1() THEN 0 ELSE 1, 999999]
|
|
LPC (CELL) -= NUM.TO.DELETE
|
|
|
|
*---- Check if all done; if not, go to next cell.
|
|
IF NUM.TO.DELETE = NUM.OF.LINES.TO.DELETE THEN GOTO DELETE.MEMORY.2
|
|
CELLX = CELL + 1
|
|
NUM.OF.LINES.TO.DELETE -= NUM.TO.DELETE
|
|
|
|
DELETE.MEMORY.1: ; * Scan cell line count to see if they can be squeezed.
|
|
CELLY = CELLX
|
|
LOOP WHILE IF CELLY <= LAST.CELL THEN NUM.OF.LINES.TO.DELETE => LPC (CELLY) ELSE 0
|
|
NUM.OF.LINES.TO.DELETE -= LPC (CELLY)
|
|
CELLY += 1 ; * ON EXIT, CELLY CONTAINS FIRST LINE AFTER DELETED BLOCK
|
|
REPEAT
|
|
|
|
*---- Calculate number of cells to shift and abandon.
|
|
XX = CELLY - CELLX ; * XX IS THE NUMBER OF CELLS TO SQUEEZE OUT
|
|
IF XX THEN
|
|
|
|
*---- Shift end of memory down unless there are no cells left to shift.
|
|
IF CELLY <= LAST.CELL THEN
|
|
FOR X = CELLX TO LAST.CELL-XX
|
|
MEMORY (X) = MEMORY (CELLY)
|
|
LPC (X) = LPC (CELLY)
|
|
CELLY += 1
|
|
NEXT X
|
|
END
|
|
LAST.CELL -= XX ; * SET UP LAST.CELL TO CORRECT FINAL VALUE
|
|
|
|
*---- Clear out abandoned cells.
|
|
FOR X = LAST.CELL + 1 TO LAST.CELL + XX
|
|
MEMORY (X) = '' ; LPC (X) = 0
|
|
NEXT X
|
|
END
|
|
|
|
*---- Delete unwanted lines from next cell, if any.
|
|
IF NUM.OF.LINES.TO.DELETE THEN
|
|
MEMORY (CELLX) = FIELD(MEMORY (CELLX), @FM, NUM.OF.LINES.TO.DELETE+1, 999999)
|
|
LPC (CELLX) -= NUM.OF.LINES.TO.DELETE
|
|
END
|
|
|
|
DELETE.MEMORY.2: ; * Exit with LNUM backed up one line.
|
|
IF LNUM = CELL.FIRST.LINE THEN
|
|
IF LNUM # 1 THEN
|
|
CELL -= 1 ; * BACKUP TO LAST LINE OF PREVIOUS CELL
|
|
CELL.FIRST.LINE -= LPC (CELL)
|
|
END
|
|
END
|
|
LNUM -= 1
|
|
RETURN
|
|
|
|
INSERT.MEMORY:
|
|
* Insert a new block into record memory. GOSUB routine.
|
|
* This subroutine inserts blocks of lines into the blocked record memory.
|
|
* New lines from NEW.MEMORY will be inserted after the current line LNUM.
|
|
* The block of new lines is contained in matrices called NEW.MEMORY
|
|
* and NEW.LPC in the same format as the main matrices MEMORY and LPC.
|
|
* They contain the number of lines specified by NEW.BOT (new bottom)
|
|
* and contain NEW.LAST.CELL active cells (matrix elements).
|
|
* The strategy of insertion is to push the new memory cells into the
|
|
* memory matrices without altering or combining any cells. If the
|
|
* insertion requires splitting the current cell (that is, the current
|
|
* line LNUM is not the last line of the cell) then that cell will
|
|
* be split into two cells and the new memory cells will be pushed
|
|
* in between.
|
|
* If LNUM=0 then insertion will be made in front of all lines.
|
|
* The new memory matrices and associated variables will not be altered.
|
|
* The subroutine exits with all key memory variables correctly set up.
|
|
IF NEW.BOT = 0 THEN RETURN
|
|
GOSUB GET.LINE ; * INITIALIZE POINTERS TO MEMORY FOR CURRENT LNUM
|
|
CHANGE.FLAG = TRUE
|
|
IF BOT = 0 THEN LAST.CELL = 0 ; * RESET IF RECORD IS NULL
|
|
BOT += NEW.BOT
|
|
|
|
*---- Check size of memory matrices & re-dimension if necessary.
|
|
IF NEW.LAST.CELL + LAST.CELL + 1 > MEMORY.DIM THEN
|
|
MEMORY.DIM = NEW.LAST.CELL + LAST.CELL + 20
|
|
DIM MEMORY (MEMORY.DIM) ; * RE-DIMEMSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM LPC (MEMORY.DIM) ; * RE-DIMEMSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM PRIOR.MEMORY (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM PRIOR.LPC (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM SAVED.MEMORY (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM SAVED.LPC (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
FOR X = LAST.CELL + 1 TO MEMORY.DIM
|
|
MEMORY (X) = '' ; * INITIALIZE MEMORY
|
|
LPC (X) = 0 ; * INITIALIZE LINES.PER.CELL MATRIX
|
|
PRIOR.MEMORY (X) = '' ; SAVED.LPC (X) = 0
|
|
PRIOR.LPC (X) = 0 ; SAVED.MEMORY (X) = ''
|
|
NEXT X
|
|
END
|
|
|
|
*---- Is insert at front (LNUM = 0).
|
|
IF LNUM = 0 THEN
|
|
START.CELL = 1
|
|
CELLX = LAST.CELL + NEW.LAST.CELL
|
|
GOTO INSERT.MEMORY.1
|
|
END
|
|
|
|
*---- Is insert after end (LNUM = BOT).
|
|
IF LNUM = BOT THEN
|
|
CELLX = LAST.CELL + NEW.LAST.CELL
|
|
GOTO INSERT.MEMORY.2
|
|
END
|
|
|
|
*---- Set up to insert after the current cell.
|
|
START.CELL = CELL + 1
|
|
|
|
*---- Allow 1 extra if splitting current cell (LNUM not at cell end
|
|
* and LNUM # 0).
|
|
CELLX = LAST.CELL + NEW.LAST.CELL + ((LNUM < CELL.FIRST.LINE + LPC (CELL) - 1) AND LNUM # 0)
|
|
|
|
INSERT.MEMORY.1: ; * Spread memory cells to allow for new cells.
|
|
CELLY = CELLX ; * SAVE NEW LAST.CELL
|
|
FOR X = LAST.CELL TO START.CELL STEP -1
|
|
MEMORY (CELLX) = MEMORY (X)
|
|
LPC (CELLX) = LPC (X)
|
|
CELLX -= 1
|
|
NEXT X
|
|
|
|
*---- Split cell into two if LNUM not at cell end and LNUM # 0.
|
|
IF LNUM THEN
|
|
X = LPC (CELL) - (LNUM - CELL.FIRST.LINE + 1)
|
|
IF X THEN
|
|
MEMORY (CELLX) = FIELD(MEMORY (CELL), @FM, LNUM - CELL.FIRST.LINE + 2, X)
|
|
LPC (CELLX) = X
|
|
MEMORY (CELL) = MEMORY (CELL) [1, COL1() - 1]
|
|
LPC (CELL) -= X
|
|
CELLX -= 1 ; * SKIP OVER EXTRA CELL
|
|
END
|
|
END
|
|
|
|
INSERT.MEMORY.2: ; * Insert the cells of the new memory blocks.
|
|
FOR X = NEW.LAST.CELL TO 1 STEP -1
|
|
MEMORY (CELLX) = NEW.MEMORY (X)
|
|
LPC (CELLX) = NEW.LPC (X)
|
|
CELLX -= 1
|
|
NEXT X
|
|
LAST.CELL = CELLY
|
|
RETURN
|
|
|
|
APPEND.NEW.MEMORY: ; * Append new line to memory.
|
|
* This routine will append the line in NEW.MEMORY.LINE to the end of
|
|
* the NEW.MEMORY matrix. This routine will leave all key new memory
|
|
* variables set up for a subsequent call to INSERT.MEMORY.
|
|
NEW.BOT += 1
|
|
NEW.LAST.CELL = INT((NEW.BOT - 1) / LINES.PER.CELL) + 1
|
|
IF NEW.LAST.CELL > NEW.MEMORY.DIM THEN
|
|
NEW.MEMORY.DIM += 10
|
|
DIM NEW.MEMORY (NEW.MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM NEW.LPC (NEW.MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
FOR Y = NEW.MEMORY.DIM-9 TO NEW.MEMORY.DIM
|
|
NEW.MEMORY (Y) = '' ; * CLEAR NEW MEMORY
|
|
NEW.LPC (Y) = 0
|
|
NEXT Y
|
|
END
|
|
NEW.MEMORY (NEW.LAST.CELL) := (IF NEW.LPC (NEW.LAST.CELL) THEN @FM ELSE '') :NEW.MEMORY.LINE
|
|
NEW.LPC (NEW.LAST.CELL) += 1
|
|
RETURN
|
|
|
|
CLEAR.NEW.MEMORY: ; * Clear out new memory variables.
|
|
MAT NEW.MEMORY = '' ; MAT NEW.LPC = 0
|
|
NEW.BOT = 0 ; NEW.LAST.CELL = 0
|
|
RETURN
|
|
|
|
OOPS.INITIAL.SAVE: ; * Memory restore routines: for OOPS command.
|
|
PRIOR.BLOCK.MFROM = MFROM ; PRIOR.BLOCK.MTHRU = MTHRU
|
|
PRIOR.BOT = BOT ; PRIOR.CELL = CELL
|
|
PRIOR.CELL.FIRST.LINE = CELL.FIRST.LINE
|
|
PRIOR.LAST.CELL = LAST.CELL ; PRIOR.LNUM = LNUM
|
|
MAT PRIOR.LPC = MAT LPC ; MAT PRIOR.MEMORY = MAT MEMORY
|
|
RETURN
|
|
|
|
OOPS.BEFORE.EACH.CMD:
|
|
PRIOR.BLOCK.MFROM = MFROM ; PRIOR.BLOCK.MTHRU = MTHRU
|
|
PRIOR.CELL = CELL ; PRIOR.CMD = CMD
|
|
IF CMD.STACK (1) = 'STAMP' THEN PRIOR.CMD = CMD.STACK (1)
|
|
PRIOR.CELL.FIRST.LINE = CELL.FIRST.LINE
|
|
PRIOR.LNUM = LNUM
|
|
RETURN
|
|
|
|
OOPS.AFTER.CHANGE.CMD:
|
|
SAVED.BLOCK.MFROM = PRIOR.BLOCK.MFROM
|
|
SAVED.BLOCK.MTHRU = PRIOR.BLOCK.MTHRU
|
|
SAVED.BOT = PRIOR.BOT ; SAVED.CELL = PRIOR.CELL
|
|
SAVED.CELL.FIRST.LINE = PRIOR.CELL.FIRST.LINE
|
|
SAVED.LAST.CELL = PRIOR.LAST.CELL
|
|
SAVED.LNUM = PRIOR.LNUM ; SAVED.CMD = PRIOR.CMD
|
|
MAT SAVED.LPC = MAT PRIOR.LPC
|
|
MAT SAVED.MEMORY = MAT PRIOR.MEMORY
|
|
PRIOR.BLOCK.MFROM = MFROM ; PRIOR.BLOCK.MTHRU = MTHRU
|
|
PRIOR.BOT = BOT ; PRIOR.LAST.CELL = LAST.CELL
|
|
MAT PRIOR.LPC = MAT LPC ; MAT PRIOR.MEMORY = MAT MEMORY
|
|
RETURN
|
|
|
|
OOPS.RESTORE:
|
|
MFROM = SAVED.BLOCK.MFROM ; MTHRU = SAVED.BLOCK.MTHRU
|
|
BOT = SAVED.BOT ; CELL = SAVED.CELL
|
|
CELL.FIRST.LINE = SAVED.CELL.FIRST.LINE
|
|
LAST.CELL = SAVED.LAST.CELL ; LNUM = SAVED.LNUM
|
|
MAT LPC = MAT SAVED.LPC ; MAT MEMORY = MAT SAVED.MEMORY
|
|
* Record restored to condition prior to Command %s.
|
|
OLD.LINEX = LINEX
|
|
LINEX = SAVED.CMD
|
|
GOSUB CONV.LINEX.TO.UP.ARROW
|
|
CALL *UVPRINTMSG(001250,LINEX)
|
|
LINEX = OLD.LINEX
|
|
PRIOR.CMD = '' ; CHANGE.FLAG = TRUE
|
|
RETURN
|
|
|
|
BLOCK.TRACK: ; * Move BLOCK pointers.
|
|
*---- Entered with the following variables set up:
|
|
* BLOCK.TRACK.LNUM (line before lines deleted, or last line inserted)
|
|
* BLOCK.TRACK.CHANGE (+lines inserted, or -lines deleted)
|
|
* Check if deletion crossed BLOCK pointer.
|
|
IF BLOCK.TRACK.CHANGE < 0 THEN
|
|
BLOCK.TRACK.END = BLOCK.TRACK.LNUM - BLOCK.TRACK.CHANGE
|
|
IF MFROM => BLOCK.TRACK.LNUM + 1 AND MFROM <= BLOCK.TRACK.END THEN GOTO BLOCK.KILL
|
|
IF MTHRU => BLOCK.TRACK.LNUM + 1 AND MTHRU <= BLOCK.TRACK.END THEN GOTO BLOCK.KILL
|
|
END
|
|
|
|
*---- If an INSERT, calculate line before doing inserts.
|
|
IF BLOCK.TRACK.CHANGE > 0 THEN BLOCK.TRACK.LNUM -= BLOCK.TRACK.CHANGE
|
|
|
|
*---- Check if change affects both pointers.
|
|
IF BLOCK.TRACK.LNUM < MFROM THEN
|
|
MFROM += BLOCK.TRACK.CHANGE ; MTHRU += BLOCK.TRACK.CHANGE
|
|
RETURN
|
|
END
|
|
|
|
*---- Check if change affects just MTHRU (change inside BLOCK).
|
|
IF BLOCK.TRACK.LNUM < MTHRU THEN
|
|
MTHRU += BLOCK.TRACK.CHANGE
|
|
RETURN
|
|
END
|
|
|
|
*---- Change must have been after BLOCK; no effect on pointers.
|
|
RETURN
|
|
|
|
BLOCK.KILL: ; * Kill BLOCK pointers.
|
|
MFROM = 0 ; MTHRU = 0 ; RETURN
|
|
|
|
BLOCK.CHECK: ; * Check BLOCK pointers ('<' and '>').
|
|
IF MFROM = 0 OR MTHRU = 0 THEN
|
|
* BLOCK not set up
|
|
CALL *UVPRINTMSG(001219,"")
|
|
RETURN TO CMD.ERR
|
|
END
|
|
IF UPCMD1 = "G" THEN RETURN ; * DO NOT DISPLAY MESSAGE ON 'G< OR G>' COMMAND
|
|
IF MTHRU < MFROM THEN
|
|
* BLOCK from %i through %i is in the wrong order.
|
|
CALL *UVPRINTMSG(001201,MFROM:@FM:MTHRU)
|
|
RETURN TO CMD.ERR
|
|
END
|
|
IF MFROM < LNUM AND LNUM < MTHRU THEN
|
|
PRINT ' encloses the destination line.'
|
|
RETURN TO CMD.ERR
|
|
END
|
|
IF MTHRU > BOT THEN
|
|
PRINT ' extends beyond the bottom.'
|
|
RETURN TO CMD.ERR
|
|
END
|
|
IF BLOCK.VERIFY.FLAG THEN
|
|
* BLOCK from %i through %i. OK (Y)
|
|
CALL *UVPRINTMSG(001202,MFROM:@FM:MTHRU)
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS # 'Y' THEN
|
|
* Command not done!^G\n\r
|
|
CALL *UVPRINTMSG(001203,"")
|
|
RETURN TO GET.CMD
|
|
END
|
|
END ELSE
|
|
* BLOCK from %i through %i.
|
|
CALL *UVPRINTMSG(001204,MFROM:@FM:MTHRU)
|
|
END
|
|
RETURN
|
|
|
|
INPUT.LINE: ; * Input a line, convert '^' to character.
|
|
IF ED.CMD.STRING.ACTIVE AND NOT(ED.CMD.STRING.SUSPENDED) THEN
|
|
GOSUB ABORT.CHECK
|
|
IF ABORT = 'Q' THEN
|
|
ED.CMD.STRING.ACTIVE = FALSE
|
|
J = 0
|
|
PRINT STARS:' Aborted ':PRE.STORE:' execution.'
|
|
PRINT
|
|
RETURN TO END.CMD
|
|
END
|
|
J += 1
|
|
IF ED.CMD.STRING (J) = '$' THEN
|
|
ED.CMD.STRING.ACTIVE = FALSE
|
|
J = 0
|
|
CALL *UVPRINTMSG(001227,"")
|
|
RETURN TO END.CMD
|
|
END
|
|
INPUT.LINE = ED.CMD.STRING (J)
|
|
END ELSE
|
|
IF INPUT.LINE = ERROR.COND THEN
|
|
PRINT STR('0',4 - LEN(LNUM)):LNUM:'=':
|
|
INPUT.LINE = ''
|
|
END
|
|
INPUT INPUT.LINE
|
|
END
|
|
GOSUB CONV.FROM.UP.ARROW
|
|
IF INPUT.LINE = ERROR.COND THEN GOTO INPUT.LINE
|
|
INPUT.MODE = FALSE
|
|
RETURN
|
|
|
|
CONV.FROM.UP.ARROW: ; * Convert 'INPUT.LINE' from '^' to the specified characters.
|
|
X = INDEX(INPUT.LINE, UP.ARROW, 1)
|
|
IF X = 0 THEN RETURN
|
|
IF LEN(INPUT.LINE) =< LEN.UP.ARROW.UNIC THEN
|
|
IF INPUT.LINE = UP.ARROW OR UPCASE(INPUT.LINE) = UP.ARROW.UNIC.UP THEN
|
|
* Allow ^ and ^X through if in command mode (for speed, don't
|
|
* UPCASE the line unless a possible match is there):
|
|
IF INPUT.MODE = TRUE THEN
|
|
GOSUB PRINT.INVALID.UP.ARROW ;* error message
|
|
INPUT.LINE = ERROR.COND
|
|
END
|
|
RETURN
|
|
END
|
|
END
|
|
II = INPUT.LINE [1, X - 1]
|
|
LOOP
|
|
X += 1
|
|
IF INPUT.LINE [X, 1] = UP.ARROW THEN
|
|
* ^^ replaced by single ^:
|
|
II := UP.ARROW
|
|
X += 1
|
|
END ELSE
|
|
IF UPCASE(INPUT.LINE[X - 1, 2]) = UP.ARROW.UNIC.UP THEN
|
|
* Attempt to enter 4-digit hex unicode string - check it's allowed:
|
|
IF NOT(NLS.ON.FLAG) THEN
|
|
* '%s UP ARROW mode is not allowed unless NLS support is ON.'
|
|
* CALL *UVPRINTMSG('970015',UP.ARROW.UNIC.UP)
|
|
GOSUB PRINT.INVALID.UP.ARROW ;* replace with line above after 8.3.3
|
|
GOTO CONV.FROM.UP.ARROW.ERR.EXIT
|
|
END
|
|
* Check 4 hex digits actually entered:
|
|
X += 1
|
|
CX = INPUT.LINE[X, 4]
|
|
DEC.CX = ICONV(CX, 'MX')
|
|
IF STATUS() # 0 OR LEN(CX) # 4 OR DEC.CX = UNI$FM THEN
|
|
* '%s must be followed by 4 hex digits.'
|
|
* Also, can't allow field mark though (equivalent to ^254).
|
|
CALL *UVPRINTMSG('970016',UP.ARROW.UNIC.UP)
|
|
GOTO CONV.FROM.UP.ARROW.ERR.EXIT
|
|
END
|
|
* Convert character to UTF and insert back into line:
|
|
II := UNICHAR(DEC.CX)
|
|
X += 4
|
|
END ELSE
|
|
CX = INPUT.LINE [X, 3]
|
|
*******************************************************************************
|
|
*
|
|
* Old code read as follows:
|
|
*---------- PCC. Make sure we get ALL numbers!
|
|
* IF NOT(NUM(CX)) OR CX<0 OR CX>255 OR CX = 254 OR LEN(CX) NE 3 THEN
|
|
* Changed to check for '3N' to not allow things like '^-001' to pass the
|
|
* NUM() test.
|
|
*******************************************************************************
|
|
IF NOT(CX MATCHES '3N') OR CX>255 OR CX = 254 THEN
|
|
GOSUB PRINT.INVALID.UP.ARROW
|
|
GOTO CONV.FROM.UP.ARROW.ERR.EXIT
|
|
END
|
|
* In NLS mode, note that ^248-^250 go in as the pseudo-mark
|
|
* characters below @TM, which is what CHAR(248) etc. returns.
|
|
* If you want to enter the Unicode characters with values
|
|
* >= 248 decimal, you must use ^X00F8 etc.
|
|
II := CHAR(CX)
|
|
X += 3
|
|
END
|
|
END
|
|
INPUT.LINE = INPUT.LINE [X, 999999]
|
|
X = INDEX(INPUT.LINE, UP.ARROW, 1)
|
|
IF X = 0 THEN
|
|
INPUT.LINE = II:INPUT.LINE
|
|
RETURN
|
|
END
|
|
II := INPUT.LINE [1, X - 1]
|
|
REPEAT
|
|
* Never falls through!
|
|
CONV.FROM.UP.ARROW.ERR.EXIT: ;* common way out of above routine with error
|
|
IF INPUT.MODE THEN
|
|
INPUT.LINE = ERROR.COND ; * SET ERROR CONDITIONS
|
|
END ELSE
|
|
INPUT.LINE = ''
|
|
RETURN TO CMD.ERR
|
|
END
|
|
RETURN
|
|
|
|
PRINT.INVALID.UP.ARROW: ;* Message about use of "^" command
|
|
* (Illegal up-arrow character code. )
|
|
* (Range is "000" through "255", excluding "254".)
|
|
MSG.TEXT = UVREADMSG(001192,"")
|
|
IF NOT(@SYS.BELL) THEN
|
|
MSG.TEXT = CONVERT(CHAR(7),"",MSG.TEXT)
|
|
END
|
|
PRINT MSG.TEXT<1>
|
|
PRINT MSG.TEXT<2>
|
|
RETURN
|
|
|
|
PRINT.LINE: ; * Print the current line.
|
|
LINEX = LINE
|
|
IF UP.ARROW.FLAG THEN GOSUB CONV.LINEX.TO.UP.ARROW
|
|
IF LEN(LINEX) <= LINE.LENGTH THEN
|
|
PRINT STR('0', 4 - LEN(LNUM)):LNUM:': ':LINEX
|
|
END ELSE
|
|
PRINT STR('0', 4 - LEN(LNUM)):LNUM:': ':
|
|
PRINT LINEX [1, LINE.LENGTH]
|
|
LOOP
|
|
LINEX = LINEX [LINE.LENGTH + 1, 999999]
|
|
UNTIL LEN(LINEX) = 0
|
|
PRINT ' ':LINEX [1, LINE.LENGTH]
|
|
REPEAT
|
|
END
|
|
RETURN
|
|
|
|
PL.CMD:
|
|
IF LEN(UPCMD) > 2 THEN
|
|
X = TRIM(UPCMD [3, 9999])
|
|
IF NOT(NUM(X)) THEN GOTO PL.ERROR
|
|
IF X # INT(X) THEN GOTO PL.ERROR
|
|
PL.LINES = X
|
|
END ELSE X = PL.LINES ; * Use last value for PL command.
|
|
IF X > 0 THEN
|
|
LINE1 = LNUM
|
|
LINE2 = LNUM + X
|
|
IF LINE2 > BOT THEN LINE2 = BOT
|
|
END ELSE
|
|
LINE1 = LNUM + X
|
|
IF LINE1 < 1 THEN LINE1 = 1
|
|
LINE2 = LNUM
|
|
END
|
|
LNUMX = LNUM
|
|
GOSUB PRINT.GROUP ; PRINT
|
|
LNUM = LNUMX
|
|
GOTO END.NOCHANGE
|
|
|
|
PL.ERROR:
|
|
PRINT LINES.MESSAGE:'n integer.'
|
|
GOTO END.NOCHANGE
|
|
|
|
PP.CMD: ; * Print a page enclosing current line.
|
|
IF LEN(UPCMD) > 2 THEN
|
|
X = TRIM(UPCMD [3, 9999])
|
|
IF NOT(NUM(X)) THEN GOTO PP.ERROR
|
|
IF X # INT(X) THEN GOTO PP.ERROR
|
|
IF X < 1 THEN GOTO PP.ERROR
|
|
PP.LINES = X
|
|
END ELSE X = PP.LINES ; * Use last value for PP command.
|
|
IF MOD(X, 2) # 0 THEN X += 1
|
|
LINE1 = LNUM - (X / 2)
|
|
IF LINE1 < 1 THEN LINE1 = 1
|
|
LINE2 = LNUM + (X / 2)
|
|
IF LINE2 > BOT THEN LINE2 = BOT
|
|
LNUMX = LNUM
|
|
GOSUB PRINT.GROUP ; PRINT
|
|
LNUM = LNUMX
|
|
GOTO END.NOCHANGE
|
|
|
|
PP.ERROR:
|
|
PRINT LINES.MESSAGE:' positive integer.'
|
|
GOTO END.NOCHANGE
|
|
|
|
CONV.LINEX.TO.UP.ARROW: ; * Convert 'LINEX' to '^' format.
|
|
LL = '' ; X = 0
|
|
|
|
* In NLS mode, check all characters on line are valid UTF, otherwise
|
|
* you can't trust the ^nnnn output (usually see ^x0000 for bad UTF):
|
|
IF NLS.ON.FLAG THEN
|
|
BAD.CHARS.IN.LINEX = FALSE
|
|
DUMMY = OCONV(LINEX, 'NLSUTF8')
|
|
IF STATUS() # 0 THEN
|
|
* WARNING: Line has invalid internal characters, and may
|
|
* display incorrectly.
|
|
CALL *UVPRINTMSG(970017,'')
|
|
BAD.CHARS.IN.LINEX = TRUE
|
|
END
|
|
END
|
|
|
|
IF LINEX = @NULL.STR THEN
|
|
* Print line as ^128 on its own:
|
|
LINEX = UP.ARROW:SEQ(@NULL.STR)
|
|
END ELSE
|
|
LOOP
|
|
X += 1
|
|
CX = LINEX [X, 1]
|
|
UNTIL LEN(CX) = 0 AND NOT(ISNULL(CX)) DO
|
|
IF NLS.ON.FLAG THEN
|
|
* Don't convert unless ^ mode is actually set - may be displayable:
|
|
IF NOT(UP.ARROW.FLAG)
|
|
THEN RETURN
|
|
* In NLS mode:
|
|
* - The "^" character and the marks 248-255 always print as ^ddd.
|
|
* - If Unicode ^x mode is on, all non-ASCII-printable chars
|
|
* (127 upwards) will print as ^xhhhh.
|
|
* - If Unicode ^x mode is off, 127-247 print as ^ddd,
|
|
* 248 upwards print as ^xhhhh (but note that single-byte
|
|
* marks 248-255 are still printed as ^xxx).
|
|
* Note that a null line already got printed as ^128 above.
|
|
BEGIN CASE
|
|
CASE CX = UP.ARROW ;* "^"
|
|
GOSUB PRINT.UP.ARROW.DEC
|
|
CASE UNISEQ(CX) = UNI$SQLNULL OR (UNISEQ(CX) >= UNI$SYSDEL AND UNISEQ(CX) =< UNI$IM) ;* 128, 248-255
|
|
* Check whether it's really a mark, or the Unicode value
|
|
* that UNISEQ returns for a mark - note we can't use SEQ()
|
|
* for this, as it may give a runtime warning with NLS on:
|
|
IF BYTELEN(CX) = 1 THEN
|
|
GOSUB PRINT.UP.ARROW.DEC ;* genuinely a mark
|
|
END ELSE
|
|
GOSUB PRINT.UP.ARROW.HEX ;* actually Unicode F8Fx char
|
|
END
|
|
CASE UNISEQ(CX) < 32 OR UNISEQ(CX) > 126 ;* non-ASCII-printing chars
|
|
BAD.CHAR.IN.LINEX.FOUND = FALSE
|
|
IF BAD.CHARS.IN.LINEX THEN
|
|
* NLS mode - check if we got an invalid character here,
|
|
* which SEQ() cannot print - display something else instead:
|
|
DUMMY = OCONV(CX, 'NLSUTF8')
|
|
IF STATUS() # 0
|
|
THEN BAD.CHAR.IN.LINEX.FOUND = TRUE
|
|
END
|
|
BEGIN CASE
|
|
CASE BAD.CHAR.IN.LINEX.FOUND
|
|
GOSUB PRINT.UP.ARROW.BAD.UTF
|
|
CASE UP.ARROW.UNIC.FLAG OR UNISEQ(CX) > 247
|
|
GOSUB PRINT.UP.ARROW.HEX
|
|
CASE 1
|
|
GOSUB PRINT.UP.ARROW.DEC
|
|
END CASE
|
|
END CASE
|
|
END ELSE
|
|
|
|
***************************************************************************
|
|
*
|
|
* THIS WAS THE OLD DEFINITION OF NON-PRINTING CHARACTERS UNDER PI
|
|
*
|
|
* A non-printing char is defined as:
|
|
* - char in C0 set excluding the 5 chars where the displaced
|
|
* graphics (clashed with the mark chars) are mapped to.
|
|
* ( CX < CHAR(28) AND CX # CHAR(26))
|
|
* - the DEL char ( CHAR(127) ) or chars in C1 set.
|
|
* ( CX > CHAR(126) AND CX < CHAR(160) )
|
|
* - the 5 mark chars or the up arrow
|
|
* ( CX >= @TM )
|
|
*
|
|
* NON.PRINTING = ((CX < CHAR(28) AND CX # CHAR(26)) OR (CX >= @TM) OR (CX = UP.ARROW) OR (CX > CHAR(126) AND CX < CHAR(160)))
|
|
*
|
|
***************************************************************************
|
|
*
|
|
* THIS HAS BEEN CHANGED TO BE COMPATIBLE WITH THE RELEASE 6
|
|
* VERSION OF THE UNIVERSE EDITOR
|
|
* (Change was agreed to by Len Greenwood and Jim T.)
|
|
*
|
|
* A non-printing character is defined as:
|
|
* - CHAR(0) thru CHAR(31)
|
|
* - CHAR(127) thru CHAR(255), but not CHAR(254) or UP.ARROW
|
|
*
|
|
* NON.PRINTING = (CX < CHAR(32)) OR (CX > CHAR(126))
|
|
* Note: don't compare CHARs, since may be localized - use SEQs instead.
|
|
*
|
|
***************************************************************************
|
|
NON.PRINTING = (SEQ(CX) < 32) OR (SEQ(CX) > 126) OR (CX = UP.ARROW)
|
|
IF NON.PRINTING THEN
|
|
GOSUB PRINT.UP.ARROW.DEC
|
|
END
|
|
END
|
|
REPEAT
|
|
LINEX = LL:LINEX
|
|
END
|
|
RETURN
|
|
|
|
PRINT.UP.ARROW.BAD.UTF:
|
|
* No input: always print a recognizable string for a "bad" utf character:
|
|
LL := LINEX[1, X - 1]:UP.ARROW:'!!!!'
|
|
LINEX = LINEX [X + 1, 999999]
|
|
X = 0
|
|
RETURN
|
|
|
|
PRINT.UP.ARROW.DEC:
|
|
* Input: CX is character to be printed
|
|
CX = SEQ(CX)
|
|
LL := LINEX [1, X - 1] :UP.ARROW:STR('0', 3 - LEN(CX)) :CX
|
|
LINEX = LINEX [X + 1, 999999]
|
|
X = 0
|
|
RETURN
|
|
|
|
PRINT.UP.ARROW.HEX:
|
|
* Input: CX is character to be printed
|
|
HEX.CX = OCONV(UNISEQ(CX), 'MX')
|
|
LL := LINEX [1, X - 1] :UP.ARROW.UNIC:STR('0', 4 - LEN(HEX.CX)) :HEX.CX
|
|
LINEX = LINEX [X + 1, 999999]
|
|
X = 0
|
|
RETURN
|
|
|
|
GET.RECORD: ; * Get record name and read the record.
|
|
RECORD.NAME = RECORD.LIST <1>
|
|
RECORD.LIST = DELETE(RECORD.LIST, 1, 0, 0)
|
|
IF RECORD.NAME = '' AND NUM.REMAINING NE '' AND NUM.REMAINING GT 0 THEN NULL.ID.INLIST=TRUE ELSE NULL.ID.INLIST=FALSE
|
|
IF NUM.REMAINING # '' THEN NUM.REMAINING=NUM.REMAINING-1
|
|
IF (LEN(RECORD.NAME) # 0 OR (NULL.ID.INLIST) OR (FIRST.RECORD AND (NULL.ID OR SELECT.LIST.FLAG))) THEN
|
|
LINEX = RECORD.NAME
|
|
GOSUB CONV.LINEX.TO.UP.ARROW
|
|
DISPLAY.RECORD.NAME = LINEX
|
|
IF SELECT.LIST.FLAG AND NOT(ONLY.ONE.RECORD.FLAG) THEN
|
|
CALL *UVPRINTMSG(001291,DISPLAY.RECORD.NAME)
|
|
END
|
|
GOTO INITIALIZE
|
|
END
|
|
SELECT.LIST.FLAG = FALSE
|
|
ONLY.ONE.RECORD.FLAG = FALSE
|
|
ED.CMD.STRING.ACTIVE = FALSE
|
|
ED.CMD.STRING.SUSPENDED = FALSE
|
|
J = 0
|
|
IF NOT(FIRST.RECORD) THEN
|
|
PRINT
|
|
CALL *UVPRINTMSG(001018,"")
|
|
PRINT DICT.TEXT:FILE.NAME
|
|
END
|
|
FIRST.RECORD = FALSE
|
|
CALL *UVPRINTMSG(001290,"")
|
|
GOSUB INPUT.LINE
|
|
FIRST.CHAR = INPUT.LINE [1, 1]
|
|
IF FIRST.CHAR = '"' OR FIRST.CHAR = "'" THEN
|
|
INPUT.LINE = INPUT.LINE [2, INDEX(INPUT.LINE, FIRST.CHAR, 2) - 2]
|
|
END ELSE
|
|
INPUT.LINE = TRIM(INPUT.LINE)
|
|
END
|
|
RECORD.NAME = INPUT.LINE
|
|
LINEX = RECORD.NAME
|
|
GOSUB CONV.LINEX.TO.UP.ARROW
|
|
DISPLAY.RECORD.NAME = LINEX
|
|
IF LEN(RECORD.NAME) = 0 THEN GOTO STOP
|
|
|
|
INITIALIZE: ; * Initialize for each record.
|
|
FIRST.RECORD = FALSE
|
|
X = '@ID' ; Y = RECORD.NAME ; GOSUB AT.INSERT
|
|
BLOCK.LOGIC = FALSE ; * BLOCK LOGIC FLAG
|
|
BOT = 0 ; * BOTTOM LINE NUMBER
|
|
CELL = 1 ; * CURRENT CELL OF MEMORY
|
|
CELL.FIRST.LINE = 1 ; * LINE NUM OF 1ST LINE IN CURRENT CELL
|
|
CHANGE.FLAG = FALSE ; * RECORD CHANGED FLAG
|
|
CHANGE.DURING.CMD.STRING = FALSE ; * RECORD CHANGED DURING CMD STRING XEQ
|
|
LAST.CELL = 0 ; * LAST ACTIVE CELL IN MEMORY
|
|
LINE = '' ; * CURRENT LINE
|
|
LINE.LENGTH = CRT.WIDTH - 7 ; * LENGTH OF LINE TO FOLD ON
|
|
LNUM = 0 ; * CURRENT LINE NUMBER
|
|
LNUM.SAVE = 0 ; * SAVE OF LNUM
|
|
MAT LPC = 0 ; * MATRIX OF LINES PER CELL OF MEMORY
|
|
MAT MEMORY = '' ; * BLOCKED MEMORY OF RECORD BEING EDITTED
|
|
MAT PRIOR.MEMORY = '' ; * OOPS MEMORY
|
|
MAT PRIOR.LPC = 0 ; * OOPS MEMORY
|
|
MAT SAVED.MEMORY = '' ; * OOPS MEMORY
|
|
MAT SAVED.LPC = 0 ; * OOPS MEMORY
|
|
MFROM = 0 ; * BLOCK 'FROM' POINTER
|
|
MTHRU = 0 ; * BLOCK 'THRU' POINTER
|
|
RECORD.CHANGE.FLAG = FALSE ; * SET TO TRUE IF RECORD CHANGED
|
|
SAVED.CMD = '' ; * LAST CMD THAT CHANGED THE RECORD
|
|
GOSUB CLEAR.NEW.MEMORY ; * CLEAR NEW MEMORY AND KEY VARIABLES
|
|
I.TYPE.EXPR = ''
|
|
|
|
READ.2: ; * Try to read record from file.
|
|
RECORD.NAME.LOCKED = TRUE
|
|
EDITING.VOC.FPTR = FALSE
|
|
READU RECORD FROM EDIT.FILE, RECORD.NAME
|
|
* ON ERROR
|
|
* CALL *UVPRINTMSG(STATUS(),"")
|
|
* RETURN TO DONE.WITH.RECORD
|
|
* END
|
|
LOCKED
|
|
RECORD.NAME.LOCKED = FALSE
|
|
CALL *UVPRINTMSG(001191,"")
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS = 'Y' THEN GOTO READ.2 ELSE RETURN TO DONE.WITH.RECORD
|
|
END
|
|
THEN
|
|
IF EDIT.READ.ONLY THEN
|
|
CALL *UVPRINTMSG(001398,DICT.TEXT:FILE.NAME)
|
|
END
|
|
ELSE IF ((FILE.NAME = 'VOC') AND (RECORD[1,1]='F' OR RECORD[1,1]='f'))
|
|
THEN
|
|
EDITING.VOC.FPTR = TRUE
|
|
END
|
|
END
|
|
ELSE
|
|
DF.ERROR = STATUS()
|
|
IF DF.ERROR = 1 OR DF.ERROR = 2 THEN
|
|
STATUS TEMP.INFO FROM EDIT.FILE ELSE TEMP.INFO = ""
|
|
IF TEMP.INFO<21> = 27 THEN
|
|
CALL *UVPRINTMSG(970013,RECORD.NAME)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(970012,RECORD.NAME)
|
|
END
|
|
RETURN TO DONE.WITH.RECORD
|
|
END
|
|
ELSE IF DF.ERROR = 3 THEN
|
|
CALL *UVPRINTMSG(47007,RECORD.NAME)
|
|
RETURN TO DONE.WITH.RECORD
|
|
END
|
|
ELSE IF DF.ERROR = 4 THEN
|
|
* Warning message already issued - no need to repeat ourselves
|
|
* CALL *UVPRINTMSG(47006,RECORD.NAME)
|
|
RETURN TO DONE.WITH.RECORD
|
|
END
|
|
|
|
IF EDIT.READ.ONLY THEN
|
|
CALL *UVPRINTMSG(001396,DICT.TEXT:FILE.NAME:@FM:RECORD.NAME)
|
|
RETURN TO DONE.WITH.RECORD
|
|
END ELSE
|
|
GOTO NEW.RECORD
|
|
END
|
|
END
|
|
|
|
*---- Check if reading an I-TYPE record from a DICTIONARY.
|
|
IF DICT AND RECORD [1, 1] = 'I' THEN
|
|
I.TYPE.EXPR = RECORD <2>
|
|
I.TYPE.DATE = OCONV(RECORD <OBJ.FMC - 2>, 'D2/')
|
|
IF LEN(I.TYPE.DATE) # 0 THEN
|
|
PRINT 'This is a Type "I" Descriptor last compiled on ':
|
|
PRINT I.TYPE.DATE:' at ':OCONV(RECORD <OBJ.FMC - 1>, 'MT:'):'.'
|
|
END ELSE PRINT 'This Type "I" Descriptor must be compiled before use.'
|
|
END
|
|
|
|
*---- Record already exists.
|
|
BOT = IF LEN(RECORD) = 0 THEN 0 ELSE COUNT(RECORD, @FM) + 1
|
|
X = INT((BOT - 1) / LINES.PER.CELL) ; * DETERMINE NUM OF FULL CELLS REQUIRED
|
|
IF X + 1 > MEMORY.DIM THEN
|
|
MEMORY.DIM = X + 20
|
|
DIM MEMORY (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN RECORD = '' ; GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM LPC (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN RECORD = '' ; GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM PRIOR.MEMORY (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN RECORD = '' ; GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM PRIOR.LPC (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN RECORD = '' ; GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM SAVED.MEMORY (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN RECORD = '' ; GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
DIM SAVED.LPC (MEMORY.DIM) ; * RE-DIMENSION
|
|
IF INMAT() THEN RECORD = '' ; GOSUB OVERFLOW ; RETURN ; * SJE 23 Apr 84
|
|
FOR XX = MEMORY.DIM - 19 TO MEMORY.DIM
|
|
SAVED.LPC (XX) = 0 ; MEMORY (XX) = '' ;
|
|
LPC (XX) = 0 ; PRIOR.LPC (XX) = 0
|
|
PRIOR.MEMORY (XX) = '' ; SAVED.MEMORY (XX) = ''
|
|
NEXT XX
|
|
END
|
|
|
|
*---- The following code sets up
|
|
* to make a BLOCK of each element of the array. The size of the
|
|
* BLOCK is defined by LINES.PER.CELL.
|
|
|
|
*** MATBLOCK MEMORY FROM RECORD, @FM, LINES.PER.CELL
|
|
CALL @MATBLOCK(MAT MEMORY,RECORD,@FM,LINES.PER.CELL)
|
|
FOR XX = 1 TO X
|
|
LPC (XX) = LINES.PER.CELL
|
|
NEXT XX
|
|
LAST.CELL = X + (BOT > 0) ; * =0 IF BOT = 0
|
|
IF LAST.CELL > 0 THEN
|
|
LPC (LAST.CELL) = MOD(BOT - 1, LINES.PER.CELL) + 1
|
|
END
|
|
RECORD = '' ; * RETURN DMR SPACE
|
|
* %i lines long
|
|
CALL *UVPRINTMSG(001207,BOT)
|
|
RETURN
|
|
|
|
NEW.RECORD:
|
|
* New record.
|
|
CALL *UVPRINTMSG(001206,"")
|
|
RETURN
|
|
|
|
FILE.IT: ; * File the record. GOSUB routine.
|
|
WRITEERROR = FALSE ; *026
|
|
OUT.DICT = DICT ; OUT.FILE.NAME = FILE.NAME ; OUT.FILE = EDIT.FILE
|
|
|
|
IF (NOT(SYSTEM(62)) AND (EDITING.VOC.FPTR))
|
|
THEN
|
|
CALL *UVPRINTMSG(020553,"")
|
|
RETURN TO GET.CMD
|
|
END
|
|
|
|
************************************************************************
|
|
* 'READU LOCK.AGAIN FROM EDIT.FILE,RECORD.NAME THEN NULL' BELOW IS DONE
|
|
* TO RESET READLOCK INITIALLY SET BY FIRST TCL EDIT. THIS IS IN PLACE TO
|
|
* FIX PROBLEM OF LOCK BEING RELEASED WHEN ACTIVE FILE VARIABLE 'OUT.FILE'
|
|
* GETS REASSIGNED MULTIPLE TIMES (ABOVE).
|
|
************************************************************************
|
|
READU LOCK.AGAIN FROM EDIT.FILE,RECORD.NAME
|
|
* ON ERROR
|
|
* CALL *UVPRINTMSG(STATUS(),"")
|
|
* RETURN TO GET.CMD
|
|
* END
|
|
THEN
|
|
NULL ;*SEE ABOVE
|
|
END
|
|
OUT.DICT.TEXT = DICT.TEXT
|
|
IF LEN(CMD [6, 99]) = 0 THEN
|
|
OUT.REC.NAME = RECORD.NAME
|
|
IF EDIT.READ.ONLY THEN
|
|
CALL *UVPRINTMSG(001398,OUT.DICT.TEXT:OUT.FILE.NAME)
|
|
RETURN TO GET.CMD
|
|
END
|
|
END ELSE
|
|
SENT = TRIM(CMD [6,99])
|
|
IF COUNT(SENT, ' ') > 2 THEN RETURN TO CMD.ERR
|
|
IF COUNT(SENT, ' ') THEN
|
|
PROMPT.FOR.FILE = FALSE ; NO.SELECT.LIST = TRUE
|
|
OUT.FILE.NAME = '' ; OUT.DICT = '' ; OUT.DICT.TEXT = ''
|
|
SINGLE.FILE.ONLY = TRUE
|
|
CALL @GET.FILE.NAME (NO.SELECT.LIST, SENT, OUT.DICT,
|
|
OUT.FILE.NAME, PROMPT.FOR.FILE, SINGLE.FILE.ONLY)
|
|
IF OUT.DICT = '' ELSE OUT.DICT.TEXT = OUT.DICT:' '
|
|
IF LEN(OUT.FILE.NAME) = 0 THEN RETURN TO CMD.ERR
|
|
IF OUT.FILE.NAME # OUT.FILE.NAME <1> THEN RETURN TO CMD.ERR
|
|
OUT.REC.NAME = SENT
|
|
OPENCHECK OUT.DICT, OUT.FILE.NAME TO OUT.FILE ELSE
|
|
ErrorCode = STATUS()
|
|
READL FileRec FROM DEVSYS.VOC.FILE,OUT.FILE.NAME THEN
|
|
IF OUT.DICT = "" THEN
|
|
PathName = FileRec<2>
|
|
END ELSE
|
|
PathName = FileRec<3>
|
|
END
|
|
RELEASE DEVSYS.VOC.FILE,OUT.FILE.NAME
|
|
END ELSE
|
|
PathName = ""
|
|
END
|
|
IF OUT.DICT = "" THEN
|
|
FileName = OUT.FILE.NAME
|
|
END ELSE
|
|
FileName = "DICT,":OUT.FILE.NAME
|
|
END
|
|
CALL @OpenError(ErrorCode,FileName,PathName)
|
|
RETURN TO CMD.ERR
|
|
END
|
|
END ELSE OUT.REC.NAME = FIELD(SENT, ' ', 1)
|
|
IF LEN(OUT.REC.NAME) = 0 THEN
|
|
PRINT 'Too many parameters. Expected (at most) a file name and record name.'
|
|
RETURN TO CMD.ERR
|
|
END
|
|
|
|
READ.3:
|
|
OUT.PERM.MODE = 1
|
|
OUT.PERM.IN = 6
|
|
OUT.PERM.OUT = ''
|
|
CALL @PERMISSIONS(OUT.FILE,OUT.PERM.MODE,OUT.PERM.IN,OUT.PERM.OUT)
|
|
IF NOT(OUT.PERM.OUT) THEN
|
|
CALL *UVPRINTMSG(001398,OUT.DICT.TEXT:OUT.FILE.NAME)
|
|
RETURN TO GET.CMD
|
|
END
|
|
|
|
READU SENT FROM OUT.FILE, OUT.REC.NAME
|
|
* ON ERROR
|
|
* CALL *UVPRINTMSG(STATUS(),"")
|
|
* GOTO GET.CMD
|
|
* END
|
|
LOCKED
|
|
CALL *UVPRINTMSG(001191,"")
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS = 'Y' THEN GOTO READ.3 ELSE GOTO GET.CMD
|
|
END ELSE
|
|
DF.ERROR = STATUS()
|
|
IF DF.ERROR = 1 OR DF.ERROR = 2 THEN
|
|
STATUS TEMP.INFO FROM OUT.FILE ELSE TEMP.INFO = ""
|
|
IF TEMP.INFO<21> = 27 THEN
|
|
CALL *UVPRINTMSG(970013,OUT.REC.NAME)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(970012,OUT.REC.NAME)
|
|
END
|
|
GOTO GET.CMD
|
|
END
|
|
ELSE IF DF.ERROR = 3 THEN
|
|
CALL *UVPRINTMSG(47007,OUT.REC.NAME)
|
|
GOTO GET.CMD
|
|
END
|
|
ELSE IF DF.ERROR = 4 THEN
|
|
* Warning message already issued - no need to repeat ourselves
|
|
* CALL *UVPRINTMSG(47006,OUT.REC.NAME)
|
|
GOTO GET.CMD
|
|
END
|
|
GOTO FILE.IT.2
|
|
END
|
|
SENT = '' ; * RETURN DMR STRING SPACE
|
|
* already exists
|
|
IF STACK.MODE THEN
|
|
CALL *UVPRINTMSG(001197,"")
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001110,"")
|
|
END
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS # 'Y' THEN
|
|
CALL *UVPRINTMSG(001220,"")
|
|
GOSUB RELEASE.IF.OK
|
|
RETURN TO GET.CMD
|
|
END
|
|
END
|
|
|
|
FILE.IT.2:
|
|
LNUMX = LNUM ; * SAVE LNUM
|
|
LINE1 = '' ; LINE2 = '' ; LINE.OBJ.FMC = ''
|
|
IF BOT => 1 THEN
|
|
LNUM = 1 ; GOSUB GET.LINE ; LINE1 = LINE
|
|
END
|
|
IF BOT => 2 THEN
|
|
LNUM = 2 ; GOSUB GET.LINE ; LINE2 = LINE
|
|
END
|
|
IF BOT => OBJ.FMC THEN
|
|
LNUM = OBJ.FMC ; GOSUB GET.LINE ; LINE.OBJ.FMC = LINE
|
|
END
|
|
IF OUT.DICT AND LINE1 [1, 1] = 'I' AND (I.TYPE.EXPR # LINE2 OR LEN(LINE.OBJ.FMC) = 0) THEN
|
|
IF BOT => OBJ.FMC - 4 THEN
|
|
LNUM = OBJ.FMC - 4 ; * DELETE EXPRESSION OBJECT CODE
|
|
GOSUB GET.LINE
|
|
NUM.OF.LINES.TO.DELETE = BOT - LNUM + 1
|
|
GOSUB DELETE.MEMORY
|
|
END
|
|
PRINT 'This Type "I" Descriptor must be compiled before use.'
|
|
END
|
|
|
|
SQL.ERROR = FALSE
|
|
NLS.ERROR = FALSE
|
|
MATWRITEU MEMORY ON OUT.FILE, OUT.REC.NAME ON ERROR
|
|
WRITEERROR = TRUE
|
|
STATUS.CODE = STATUS()
|
|
IF STATUS.CODE = 47006 OR STATUS.CODE = 47007 THEN
|
|
CALL *UVPRINTMSG(STATUS.CODE,OUT.REC.NAME)
|
|
NLS.ERROR = TRUE
|
|
END
|
|
|
|
END
|
|
ELSE
|
|
WRITEERROR = TRUE ;
|
|
STATUS.CODE = STATUS()
|
|
IF STATUS.CODE = IntegrityViolation THEN
|
|
SQL.ERROR = TRUE
|
|
IO.VAR = 2
|
|
MATBUILD DYN.ARRAY FROM MEMORY
|
|
CALL @SQLINTCHK(DYN.ARRAY,OUT.FILE,OUT.REC.NAME,OUT.DICT.TEXT:OUT.FILE.NAME,IO.VAR)
|
|
END
|
|
END
|
|
IF NOT(WRITEERROR) AND (UPCMD4 <> 'SAVE' OR LEN(CMD [6, 99]) <> 0) THEN ; *026
|
|
GOSUB RELEASE.IF.OK ; *REPLACED *026 UNCONDITIONAL RELEASE
|
|
*
|
|
* Convert numeric string to character to prevent the problem
|
|
* when the key string is 15+ byte numeric.
|
|
*
|
|
TEMP.OUT.REC.NAME = 'N':OUT.REC.NAME
|
|
TEMP.RECORD.NAME = 'N':RECORD.NAME
|
|
IF TEMP.OUT.REC.NAME = TEMP.RECORD.NAME THEN RECORD.NAME.LOCKED = FALSE
|
|
*
|
|
END ; *026
|
|
LINEX = OUT.REC.NAME
|
|
GOSUB CONV.LINEX.TO.UP.ARROW
|
|
|
|
IF WRITEERROR THEN ; *026
|
|
IF NOT(SQL.ERROR) AND NOT(NLS.ERROR) THEN
|
|
PRINT @SYS.BELL:'Failed to file "':LINEX:'"':IN.FILE:OUT.DICT.TEXT:OUT.FILE.NAME:'". STATUS = ':STATUS.CODE
|
|
END
|
|
END ELSE ; *026
|
|
CALL *UVPRINTMSG(001238,LINEX)
|
|
CALL *UVPRINTMSG(001286,OUT.DICT.TEXT:OUT.FILE.NAME)
|
|
END ; *026
|
|
LNUM = LNUMX ; * RESTORE LNUM
|
|
RETURN
|
|
|
|
RELEASE.IF.OK:
|
|
IF UPCMD5 = 'SAVE ' AND (OUT.REC.NAME = RECORD.NAME) AND (OUT.DICT = DICT) THEN
|
|
REL.OUTREC=0
|
|
IF OUT.FILE.NAME # '' AND OUT.FILE.NAME # FILE.NAME THEN
|
|
STATUS OUTFLSTAT FROM OUT.FILE THEN
|
|
STATUS ORIGFLSTAT FROM EDIT.FILE THEN
|
|
IF (OUTFLSTAT<10> = ORIGFLSTAT<10>) AND (OUTFLSTAT<11> = ORIGFLSTAT<11>) THEN NULL ELSE REL.OUTREC=1
|
|
END
|
|
END
|
|
END
|
|
IF REL.OUTREC THEN RELEASE OUT.FILE, OUT.REC.NAME
|
|
END ELSE
|
|
RELEASE OUT.FILE, OUT.REC.NAME
|
|
END
|
|
RETURN
|
|
|
|
!
|
|
* Command stack and pre-stored command routines.
|
|
!
|
|
|
|
STACK.PROCESSOR:
|
|
STACK.MODE = TRUE
|
|
SV.CMD = CMD
|
|
CMD = TRIM(CMD)
|
|
IF UPCMD3 = '.XK' OR UPCMD3 = '.XR' THEN GOTO STACK.EXECUTE
|
|
IF UPCMD4 = 'LOOP' THEN GOTO STRING.LOOP
|
|
IF UPCMD5 = 'PAUSE' THEN GOTO STRING.PAUSE
|
|
TOKEN1 = FIELD(CMD, ' ', 2)
|
|
TOKEN2 = FIELD(CMD, ' ', 3)
|
|
TOKEN3 = FIELD(CMD, ' ', 4)
|
|
TOKEN4 = FIELD(CMD, ' ', 5)
|
|
GOSUB SET.UP.NN
|
|
IF UPCMD2 = '.A' THEN GOTO STACK.APPEND
|
|
IF UPCMD2 = '.C' THEN GOTO STACK.CHANGE
|
|
IF UPCMD2 = '.D' THEN GOTO STACK.DELETE
|
|
IF UPCMD2 = '.X' THEN GOTO STACK.EXECUTE
|
|
IF UPCMD2 = '.I' THEN GOTO STACK.INSERT
|
|
IF UPCMD2 = '.L' THEN GOTO STACK.LIST
|
|
IF UPCMD2 = '.R' THEN GOTO STACK.RECALL
|
|
IF UPCMD2 = '.S' THEN GOTO STACK.SAVE
|
|
IF UPCMD2 = '.U' THEN GOTO STACK.UPCASE
|
|
GOTO CMD.ERR
|
|
|
|
DISPLAY.CURRENT.LINE:
|
|
IF UNASSIGNED(DISPLAY.CURRENT.LINE) THEN DISPLAY.CURRENT.LINE = TRUE
|
|
IF UNASSIGNED(COMMAND.SUCCESSFUL) THEN COMMAND.SUCCESSFUL = TRUE
|
|
IF DISPLAY.CURRENT.LINE OR COMMAND.SUCCESSFUL THEN
|
|
IF LNUM = 0 THEN
|
|
CALL *UVPRINTMSG(001190,"")
|
|
END ELSE
|
|
IF BOT THEN
|
|
GOSUB GET.LINE
|
|
IF COMMAND.SUCCESSFUL THEN
|
|
GOSUB PRINT.LINE
|
|
END
|
|
END
|
|
END
|
|
END
|
|
DISPLAY.CURRENT.LINE = TRUE
|
|
COMMAND.SUCCESSFUL = TRUE
|
|
RETURN
|
|
|
|
STACK.APPEND: ; * '.A': append to a stack command.
|
|
CMD.STACK (NN) := SV.CMD [INDEX(SV.CMD, ' ', 1) + 1, 9999]
|
|
PRINT NN "R%2":" ":CMD.STACK (NN)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD
|
|
|
|
STACK.CHANGE: ; * '.C': change a stack command.
|
|
DELIM = CMD [LEN(NN) + 3, 1]
|
|
FROM.STRING = FIELD(SV.CMD [2, 9999], DELIM, 2)
|
|
LEN.FROM = LEN(FROM.STRING)
|
|
TO.STRING = FIELD(SV.CMD [2, 9999], DELIM, 3)
|
|
IF COL2() = 0 THEN
|
|
PRINT 'Missing required TO field (for "CHANGE/FROM/TO").'
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO CMD.ERR
|
|
END
|
|
IF LEN(FROM.STRING) = 0 THEN
|
|
CMD.STACK (NN) = TO.STRING:CMD.STACK (NN)
|
|
PRINT NN "R%2":" ":CMD.STACK (NN)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD
|
|
END
|
|
GLOBAL = FIELD(SV.CMD[2,9999], DELIM, 4) ; GLOBAL = UPCASE(GLOBAL) ; GLOBAL.FLAG = FALSE
|
|
IF GLOBAL[1,1] = "G" THEN GLOBAL = GLOBAL[2,99] ; GLOBAL.FLAG = TRUE
|
|
STACK.CHANGED = FALSE
|
|
STACK.CHANGE.1:
|
|
START.POS = INDEX(CMD.STACK (NN), FROM.STRING, 1)
|
|
IF START.POS NE 0 THEN
|
|
STACK.CHANGED = TRUE
|
|
CMD.STACK (NN) [START.POS, LEN.FROM] = ''
|
|
CMD.STACK (NN) = CMD.STACK (NN) [1, START.POS - 1]:TO.STRING:CMD.STACK (NN) [START.POS + LEN.FROM, 9999]
|
|
IF GLOBAL.FLAG THEN GOTO STACK.CHANGE.1
|
|
END
|
|
IF STACK.CHANGED THEN
|
|
PRINT NN "R%2":" ":CMD.STACK (NN)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
END
|
|
GOTO GET.CMD
|
|
|
|
STACK.DELETE: ; * '.D': delete a stack command or a pre-stored command string.
|
|
IF TOKEN1 THEN GOTO STRING.DELETE
|
|
CALL *UVPRINTMSG(001077,NN)
|
|
PRINT
|
|
NN -= 1
|
|
GOSUB PUSH.DOWN
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD
|
|
|
|
STRING.DELETE:
|
|
GOSUB STRING.WRITE
|
|
|
|
SD.1:
|
|
IF REC.TYPE.CODE # 'E' THEN
|
|
CALL *UVPRINTMSG(001108,WRITE.REC.NAME)
|
|
GOTO CMD.ERR
|
|
END
|
|
DELETE WRITE.FILE, WRITE.REC.NAME
|
|
CALL *UVPRINTMSG(970003,WRITE.REC.NAME:@FM:WRITE.FILE.DICT:WRITE.FILE.NAME)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD
|
|
|
|
STACK.EXECUTE: ; * '.X': execute one stack command, or load (not into the stack) and
|
|
* execute a pre-stored string.
|
|
IF UPCMD3 = '.XK' THEN
|
|
IF NOT(ED.CMD.STRING.ACTIVE) THEN GOTO CMD.ERR
|
|
ED.CMD.STRING.ACTIVE = FALSE
|
|
ED.CMD.STRING.SUSPENDED = FALSE
|
|
J = 0
|
|
ED.CMD.STRING (1) = '$'
|
|
GOTO GET.CMD
|
|
END
|
|
IF UPCMD3 = '.XR' THEN
|
|
IF ED.CMD.STRING.SUSPENDED THEN
|
|
ED.CMD.STRING.SUSPENDED = FALSE
|
|
GOTO GET.CMD
|
|
END ELSE GOTO CMD.ERR
|
|
END
|
|
IF TOKEN1 THEN GOTO STRING.EXECUTE
|
|
PRINT NN "R%2":" ":CMD.STACK (NN + 1)
|
|
INPUT.LINE = CMD.STACK (NN + 1)
|
|
IF NN = 1 THEN
|
|
FOR IJ = 1 TO 2
|
|
NN = 0
|
|
GOSUB PUSH.DOWN
|
|
NEXT IJ
|
|
END ELSE
|
|
NN = 0
|
|
GOSUB PUSH.DOWN
|
|
END
|
|
GOTO GET.CMD.1
|
|
|
|
STRING.EXECUTE:
|
|
J = 0
|
|
IF ED.CMD.STRING.SUSPENDED THEN
|
|
IF CHANGE.DURING.CMD.STRING THEN
|
|
GOSUB OOPS.AFTER.CHANGE.CMD
|
|
CHANGE.DURING.CMD.STRING = FALSE
|
|
END
|
|
GOSUB OOPS.BEFORE.EACH.CMD
|
|
ED.CMD.STRING.SUSPENDED = FALSE
|
|
END
|
|
MAT ED.CMD.STRING = '$'
|
|
GOTO LOAD.ANY
|
|
|
|
STACK.INSERT: ; * '.I': insert one or more commands into the stack.
|
|
IF TOKEN1 OR LEN(SV.CMD) > 4 THEN GOTO SI.3
|
|
NUM.CMDS = 0 ; NEW.CMD = ''
|
|
|
|
SI.1:
|
|
PRINT ' =':
|
|
GOSUB INPUT.LINE
|
|
ED.CMD = INPUT.LINE
|
|
IF LEN(ED.CMD) = 0 THEN GOTO SI.2
|
|
IF ED.CMD = ' ' THEN ED.CMD = ''
|
|
NEW.CMD := ED.CMD:@FM
|
|
NUM.CMDS += 1
|
|
IF NN + NUM.CMDS => STACK.LIMIT THEN
|
|
PRINT @SYS.BELL:'Can only accept 99 commands.'
|
|
GOTO SI.2
|
|
END
|
|
GOTO SI.1
|
|
|
|
SI.2:
|
|
BLOCK.END = NN
|
|
GOSUB POP.UP
|
|
FIELD.CTR = 1
|
|
FOR I = NN + NUM.CMDS - 1 TO NN STEP -1
|
|
CMD.STACK (I) = FIELD(NEW.CMD, @FM, FIELD.CTR)
|
|
FIELD.CTR += 1
|
|
NEXT I
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD
|
|
|
|
SI.3:
|
|
BLOCK.END = NN
|
|
NUM.CMDS = 1
|
|
GOSUB POP.UP
|
|
IF LEN(TOKEN1) = 0 THEN
|
|
IF SV.CMD [LEN(NN) + 4, 9999] = ' ' THEN
|
|
CMD.STACK (NN) = ''
|
|
END ELSE
|
|
CMD.STACK (NN) = SV.CMD [LEN(NN) + 4, 9999]
|
|
END
|
|
END ELSE CMD.STACK (NN) = SV.CMD [INDEX(SV.CMD, ' ', 1) + 1, 9999]
|
|
PRINT NN "R%2":" ":CMD.STACK(NN)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD
|
|
|
|
STACK.LIST: ; * '.L': list all or part of the stack, pre-stored string, or
|
|
* pre-stored record names.
|
|
IF TOKEN1 THEN GOTO STRING.LIST
|
|
IF NN => END.STACK THEN NN = END.STACK - 1
|
|
NUM.LINES = 0
|
|
FOR I = NN TO 1 STEP -1
|
|
PRINT I "R%2":" ":CMD.STACK (I)
|
|
GOSUB PN.1
|
|
NEXT I
|
|
PRINT
|
|
GOTO END.NOCHANGE
|
|
|
|
STRING.LIST:
|
|
LEN.CMD = LEN(CMD)
|
|
IF CMD [LEN.CMD - 1, 2] = ' *' THEN GOTO SL.2
|
|
GOTO LOAD.ANY
|
|
|
|
SL.1:
|
|
PRINT
|
|
PRINT SPACE(5):LOAD.REC.NAME
|
|
ERROR.FORMAT = FALSE
|
|
GOSUB PRINT.CMD.STRING
|
|
PRINT
|
|
GOTO END.NOCHANGE
|
|
|
|
SL.2:
|
|
L.SELECT.FLAG = TRUE
|
|
CMD = CMD [1, LEN.CMD - 2]
|
|
GOTO LOAD.ANY
|
|
|
|
SL.3:
|
|
L.SELECT.FLAG = FALSE
|
|
MAT CMD.NAME = ''
|
|
SELECT LOAD.FILE
|
|
NUM.LINES = 0
|
|
PRINT ; PRINT 'File is "':DICT:LOAD.FILE.NAME:'".' ; PRINT
|
|
|
|
SL.3A:
|
|
FOR K = 1 TO 5
|
|
|
|
SL.3B:
|
|
READNEXT CMD.NAME (K) ELSE GOTO SL.4
|
|
READ COMMAND.RECORD FROM LOAD.FILE, CMD.NAME (K) ELSE
|
|
PRINT 'Selected ':REC:' "':CMD.NAME (K):'"':IN.FILE:DICT:LOAD.FILE.NAME:'" not found.'
|
|
GOTO SL.3B
|
|
END
|
|
IF COMMAND.RECORD <1> [1, 1] # 'E' THEN GOTO SL.3B
|
|
NEXT K
|
|
GOSUB PRINT.NAMES
|
|
GOTO SL.3A
|
|
|
|
SL.4:
|
|
GOSUB PRINT.NAMES ; GOTO END.NOCHANGE
|
|
|
|
STACK.RECALL: ; * '.R': recall a stack command to the bottom of the stack.
|
|
; * or load a pre-stored string into the stack.
|
|
IF TOKEN1 THEN GOTO LOAD.ANY
|
|
IF END.STACK = 1 THEN
|
|
CALL *UVPRINTMSG(001071,1)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO CMD.ERR
|
|
END
|
|
BLOCK.END = 1 ; NUM.CMDS = 1
|
|
GOSUB POP.UP
|
|
CMD.STACK (1) = CMD.STACK (NN + 1)
|
|
PRINT NN "R%2":" ":CMD.STACK (1)
|
|
** retain copy of command
|
|
** GOSUB PUSH.DOWN
|
|
PRINT
|
|
GOTO END.NOCHANGE
|
|
|
|
SR.1:
|
|
FWD.PTR = 1 ; BLOCK.END = 1
|
|
NUM.CMDS = BOT.STRING - 2
|
|
GOSUB POP.UP
|
|
FOR I = NUM.CMDS TO 1 STEP -1
|
|
CMD.STACK (I) = ED.CMD.STRING (FWD.PTR)
|
|
FWD.PTR += 1
|
|
NEXT I
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD
|
|
|
|
STACK.SAVE: ; * '.S': save one or more commands as a pre-stored string.
|
|
IF LEN(CMD) = 2 THEN
|
|
CALL *UVPRINTMSG(020072,"")
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO CMD.ERR
|
|
END
|
|
IF END.STACK = 1 THEN
|
|
CALL *UVPRINTMSG(001071,1)
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO CMD.ERR
|
|
END
|
|
COMMA = INDEX(CMD, ',', 1)
|
|
IF COMMA THEN
|
|
IF COUNT(CMD, ' ') < 2 THEN
|
|
CALL *UVPRINTMSG(020073,"")
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO CMD.ERR
|
|
END
|
|
FIRST.CMD = CMD [COMMA-2, 2]
|
|
IF NOT(NUM(FIRST.CMD)) THEN
|
|
CALL *UVPRINTMSG(020073,"")
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO CMD.ERR
|
|
END
|
|
LAST.CMD = CMD [COMMA + 1, 2]
|
|
IF NOT(NUM(LAST.CMD)) THEN
|
|
CALL *UVPRINTMSG(020073,"")
|
|
GOTO CMD.ERR
|
|
END
|
|
IF FIRST.CMD < LAST.CMD THEN
|
|
SWAP.CMD = FIRST.CMD
|
|
FIRST.CMD = LAST.CMD
|
|
LAST.CMD = SWAP.CMD
|
|
END
|
|
CMD = CMD [1, COMMA-3]
|
|
END ELSE FIRST.CMD = NN ; LAST.CMD = 1
|
|
GOSUB STRING.WRITE
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD
|
|
|
|
STACK.UPCASE:
|
|
CMD.STACK (NN) = UPCASE( CMD.STACK (NN) )
|
|
PRINT NN "R%2":" ":CMD.STACK (NN)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
GOTO GET.CMD
|
|
|
|
STRING.LOOP: ; * LOOP: loop within a pre-stored command string.
|
|
IF NOT(ED.CMD.STRING.ACTIVE) THEN GOTO CMD.ERR ; * DON'T TAKE 'LOOP' FROM KEYBOARD
|
|
IF LOOP.FLAG THEN GOTO TEST.LOOP.CTR
|
|
|
|
SETUP.LOOP:
|
|
SAVE.J = J
|
|
LOOP.FLAG = TRUE
|
|
STMT.NR = FIELD(TRIM(UPCMD), ' ', 2)
|
|
IF STMT.NR = '' THEN STMT.NR = 1
|
|
IF NOT(NUM(STMT.NR)) THEN
|
|
LOOP.FLAG = FALSE
|
|
GOTO CMD.ERR
|
|
END
|
|
STMT.NR = STMT.NR - 1
|
|
IF STMT.NR < 0 OR STMT.NR > SAVE.J - 1 THEN
|
|
LOOP.FLAG = FALSE
|
|
GOTO CMD.ERR
|
|
END
|
|
NR.TIMES = FIELD(TRIM(UPCMD), ' ', 3)
|
|
IF NR.TIMES = '' THEN NR.TIMES = 1
|
|
IF NOT(NUM(NR.TIMES)) THEN
|
|
LOOP.FLAG = FALSE
|
|
GOTO CMD.ERR
|
|
END
|
|
IF NR.TIMES < 1 THEN NR.TIMES = 1
|
|
IF STMT.NR > 0 THEN STMT.NR = STMT.NR - 1
|
|
J = STMT.NR
|
|
GOTO GET.CMD
|
|
|
|
TEST.LOOP.CTR:
|
|
NR.TIMES -= 1
|
|
IF NR.TIMES = 0 THEN
|
|
LOOP.FLAG = FALSE ; J = SAVE.J ; GOTO GET.CMD
|
|
END
|
|
J = STMT.NR
|
|
GOTO GET.CMD
|
|
|
|
STRING.PAUSE: ; * PAUSE: suspend execution of a pre-stored command string.
|
|
IF ED.CMD.STRING (1) = '$' THEN GOSUB SP.2 ; GOTO END.CMD
|
|
IF NOT(ED.CMD.STRING.ACTIVE) THEN GOTO CMD.ERR
|
|
ED.CMD.STRING.SUSPENDED = TRUE
|
|
CALL *UVPRINTMSG(001261,J)
|
|
GOTO END.CMD
|
|
|
|
!
|
|
* Command stack and pre-stored command subroutines.
|
|
!
|
|
|
|
GET.CMD.FROM.BLOCK: ; * Get pre-stored commands from record block into string.
|
|
IF BLOCK <1> [1, 1] = 'E' AND UPCMD2 # '.L' THEN
|
|
BLOCK = DELETE(BLOCK, 1, 0, 0)
|
|
END ELSE
|
|
IF UPCMD2 # '.L' THEN
|
|
CALL *UVPRINTMSG(001108,LOAD.REC.NAME)
|
|
GOTO CMD.ERR
|
|
END
|
|
END
|
|
DIM.SIZE = COUNT(BLOCK, @FM)
|
|
DIM ED.CMD.STRING (DIM.SIZE + 2)
|
|
IF INMAT() THEN GOSUB OVERFLOW ; GOTO GET.CMD ; * SJE 23 Apr 84
|
|
MATPARSE ED.CMD.STRING FROM BLOCK, @FM
|
|
ED.CMD.STRING (INMAT() + 1) = '$'
|
|
BOT.STRING = INMAT() + 2
|
|
BLOCK = ''
|
|
IF UPCMD2 = '.L' THEN GOTO SL.1
|
|
IF INMAT() > 99 THEN
|
|
PRINT 'This ':PRE.STORE:' string exceeds 99 commands.'
|
|
GOTO CMD.ERR
|
|
END
|
|
IF UPCMD2 = '.R' THEN
|
|
PRINT ; PRINT STARS:' Loaded ':INMAT():' command(s).' ; PRINT
|
|
GOTO SR.1
|
|
END
|
|
CURR.CMD.NAME = LOAD.REC.NAME
|
|
ED.CMD.STRING.ACTIVE = TRUE
|
|
GOTO GET.CMD
|
|
|
|
POP.UP: ; * Move stack commands up a given number of slots.
|
|
IF END.STACK + NUM.CMDS > 100 THEN
|
|
END.STACK = 100
|
|
ES = 101-NUM.CMDS
|
|
CMD.STACK (END.STACK) = '$'
|
|
END ELSE
|
|
ES = END.STACK
|
|
END.STACK = END.STACK + NUM.CMDS
|
|
END
|
|
FOR I = ES TO BLOCK.END STEP -1
|
|
CMD.STACK (I + NUM.CMDS) = CMD.STACK (I)
|
|
NEXT I
|
|
RETURN
|
|
|
|
PRINT.CMD.STRING: ; * Print a pre-stored string on the CRT.
|
|
JJ = 1 ; KK = 20
|
|
|
|
SP.1:
|
|
FOR INDEX = JJ TO KK UNTIL ED.CMD.STRING (INDEX) = '$'
|
|
IF ERROR.FORMAT THEN
|
|
PRINT " ":INDEX "R%2":": ":ED.CMD.STRING(INDEX)
|
|
END ELSE
|
|
PRINT FMT(INDEX, 'R%3'):' ':ED.CMD.STRING (INDEX)
|
|
END
|
|
NEXT INDEX
|
|
IF ED.CMD.STRING (1) # '$' THEN GOTO SP.3
|
|
|
|
SP.2: ; * NOTE: 'SP.2' also used via GOSUB.
|
|
PRINT STARS:'The ':PRE.STORE:' string is empty.'
|
|
RETURN
|
|
|
|
SP.3:
|
|
IF ED.CMD.STRING (INDEX) = '$' THEN
|
|
RETURN
|
|
END
|
|
JJ += 20 ; KK += 20
|
|
CALL *UVPRINTMSG(001142,"")
|
|
INPUT Q, 1 ; Q = UPCASE(Q)
|
|
IF Q = 'Q' THEN RETURN
|
|
GOTO SP.1
|
|
|
|
PRINT.NAMES: ; * Print pre-stored record names in a given file.
|
|
PRINT CMD.NAME (1), CMD.NAME (2), CMD.NAME (3), CMD.NAME (4), CMD.NAME (5)
|
|
MAT CMD.NAME = ''
|
|
|
|
PN.1:
|
|
NUM.LINES += 1
|
|
IF NUM.LINES > (@CRTHIGH - 4) THEN
|
|
NUM.LINES = 0
|
|
CALL *UVPRINTMSG(001142,"")
|
|
INPUT Q, 1 ; Q = UPCASE(Q)
|
|
IF Q = 'Q' THEN RETURN TO END.NOCHANGE
|
|
END
|
|
RETURN
|
|
|
|
PUSH.DOWN: ; * Push stack commands down a given number of slots.
|
|
FOR I = NN + 1 TO END.STACK
|
|
CMD.STACK (I) = CMD.STACK (I + 1)
|
|
NEXT I
|
|
END.STACK -= 1
|
|
RETURN
|
|
|
|
PUT.ON.STACK: ; * Put commands onto the command stack.
|
|
IF LEN(CMD) = 0 AND NULL.CTR THEN
|
|
NULL.CTR += 1
|
|
CMD.STACK (1) = '+':NULL.CTR
|
|
RETURN
|
|
END
|
|
IF UPCASE(CMD [1, 3]) = '.XR' THEN RETURN
|
|
IF UPCASE(CMD [1, 3]) = '.XK' THEN RETURN
|
|
IF UPCASE(CMD [1, 2]) = '.X' THEN GOTO STASH.IT
|
|
IF UPCASE(CMD [1, 4]) = 'HELP' THEN RETURN
|
|
IF CMD [1, 1] = '.' THEN RETURN
|
|
IF CMD [1, 1] = '?' THEN RETURN
|
|
IF ED.CMD.STRING.ACTIVE AND NOT(ED.CMD.STRING.SUSPENDED) THEN RETURN
|
|
|
|
STASH.IT:
|
|
NUM.CMDS = 1 ; BLOCK.END = 1
|
|
GOSUB POP.UP
|
|
IF LEN(CMD) = 0 THEN NULL.CTR = 1 ; CMD.STACK (1) = '+':1
|
|
ELSE CMD.STACK (1) = ORIGINAL.CMD
|
|
RETURN
|
|
|
|
SET.UP.NN: ; * Find which stack command is to be operated on.
|
|
MATCH.CHAR = MATCHFIELD(UPCMD [3, 1], '1N', 1)
|
|
IF LEN(MATCH.CHAR) # 0 THEN
|
|
NN = UPCMD [3, 1]
|
|
MATCH.CHAR = MATCHFIELD(UPCMD [4, 1], '1N', 1)
|
|
IF LEN(MATCH.CHAR) # 0 THEN
|
|
NN := UPCMD [4, 1]
|
|
MATCH.CHAR = MATCHFIELD(UPCMD [5, 1], '1N', 1)
|
|
IF LEN(MATCH.CHAR) # 0 THEN NN := UPCMD [5, 1]
|
|
END
|
|
END ELSE
|
|
IF UPCMD2 # '.C' THEN
|
|
IF CMD [3, 1] # ' ' AND LEN(CMD [3, 1]) # 0 THEN RETURN TO CMD.ERR
|
|
END
|
|
IF UPCMD2 = '.L' THEN NN = 9 ELSE NN = 1
|
|
IF UPCMD2 = '.C' THEN CMD = CMD [1, 2]:1:CMD [3, 9999]
|
|
IF UPCMD2 = '.I' THEN SV.CMD = SV.CMD [1, 2]:1:SV.CMD [3, 9999]
|
|
IF END.STACK = 1 THEN
|
|
IF UPCMD2 = '.D' AND TOKEN1 THEN RETURN
|
|
IF UPCMD2 = '.I' OR UPCMD2 = '.R' OR UPCMD2 = '.X' THEN RETURN
|
|
END
|
|
END
|
|
IF NN = 0 THEN RETURN TO CMD.ERR
|
|
IF NN => END.STACK - 1 AND UPCMD2 = '.X' AND NOT(TOKEN1) THEN
|
|
CALL *UVPRINTMSG(001071,NN)
|
|
PRINT
|
|
NN = 0
|
|
GOSUB PUSH.DOWN
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
RETURN TO CMD.ERR
|
|
END
|
|
IF NN = STACK.LIMIT AND UPCMD2 # '.L' THEN RETURN TO CMD.ERR
|
|
IF NN = END.STACK AND UPCMD2 = '.I' THEN RETURN
|
|
IF NN => END.STACK AND UPCMD2 # '.L' THEN
|
|
CALL *UVPRINTMSG(001071,NN)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
RETURN TO CMD.ERR
|
|
END
|
|
RETURN
|
|
|
|
STRING.WRITE: ; * Write stack to a pre-stored command record, or unload lines.
|
|
WRITE.FILE.DICT = ''
|
|
IF NOT(COUNT(CMD, ' ')) THEN RETURN TO CMD.ERR
|
|
SENT = TRIM(CMD [INDEX(CMD, ' ', 1) + 1, 99])
|
|
IF COUNT(SENT, ' ') > 2 THEN RETURN TO CMD.ERR
|
|
IF COUNT(SENT, ' ') THEN
|
|
PROMPT.FOR.FILE = FALSE ; NO.SELECT.LIST = TRUE
|
|
WRITE.FILE.NAME = '' ; WRITE.FILE.DICT = ''
|
|
SINGLE.FILE.ONLY = TRUE
|
|
CALL @GET.FILE.NAME (NO.SELECT.LIST, SENT, WRITE.FILE.DICT,
|
|
WRITE.FILE.NAME, PROMPT.FOR.FILE, SINGLE.FILE.ONLY)
|
|
IF LEN(WRITE.FILE.NAME) = 0 THEN RETURN TO CMD.ERR
|
|
IF WRITE.FILE.NAME # WRITE.FILE.NAME <1> THEN RETURN TO CMD.ERR
|
|
LOAD.REC.NAME = SENT
|
|
OPENCHECK WRITE.FILE.DICT, WRITE.FILE.NAME TO WRITE.FILE ELSE
|
|
ErrorCode = STATUS()
|
|
READL FileRec FROM DEVSYS.VOC.FILE,WRITE.FILE.NAME THEN
|
|
IF WRITE.FILE.DICT = "" THEN
|
|
PathName = FileRec<2>
|
|
END ELSE
|
|
PathName = FileRec<3>
|
|
END
|
|
RELEASE DEVSYS.VOC.FILE,WRITE.FILE.NAME
|
|
END ELSE
|
|
PathName = ""
|
|
END
|
|
IF WRITE.FILE.DICT = "" THEN
|
|
FileName = WRITE.FILE.NAME
|
|
END ELSE
|
|
FileName = "DICT,":WRITE.FILE.NAME
|
|
END
|
|
CALL @OpenError(ErrorCode,FileName,PathName)
|
|
RETURN TO CMD.ERR
|
|
END
|
|
WRITE.REC.NAME = SENT
|
|
END ELSE
|
|
IF UNLOAD.FLAG THEN
|
|
WRITE.FILE.NAME = FILE.NAME ; WRITE.FILE.DICT = DICT
|
|
WRITE.FILE = EDIT.FILE
|
|
END ELSE
|
|
WRITE.FILE.NAME = '&ED&' ; WRITE.FILE.DICT = ''
|
|
OPENCHECK WRITE.FILE.DICT, WRITE.FILE.NAME TO WRITE.FILE ELSE
|
|
ErrorCode = STATUS()
|
|
READL FileRec FROM DEVSYS.VOC.FILE,WRITE.FILE.NAME THEN
|
|
PathName = FileRec<2>
|
|
RELEASE DEVSYS.VOC.FILE,WRITE.FILE.NAME
|
|
END ELSE
|
|
IF ErrorCode = -1 THEN
|
|
AcctFlavor = SYSTEM(1001)
|
|
IF AcctFlavor = 2 OR AcctFlavor = 8 OR AcctFlavor = 16 THEN
|
|
CreateArgs = "1,1,3 1,1,1"
|
|
END ELSE
|
|
CreateArgs ="1 0 0"
|
|
END
|
|
EXECUTE "CREATE-FILE &ED& ":CreateArgs
|
|
|
|
OPENCHECK WRITE.FILE.DICT, WRITE.FILE.NAME TO WRITE.FILE THEN
|
|
GOTO WRITE.OKAY
|
|
END ELSE
|
|
ErrorCode = STATUS()
|
|
READL FileRec FROM DEVSYS.VOC.FILE,WRITE.FILE.NAME THEN
|
|
PathName = FileRec<2>
|
|
RELEASE DEVSYS.VOC.FILE,WRITE.FILE.NAME
|
|
END ELSE
|
|
PathName = ""
|
|
END
|
|
END
|
|
END ELSE
|
|
PathName = ""
|
|
END
|
|
END
|
|
FileName = WRITE.FILE.NAME
|
|
CALL @OpenError(ErrorCode,FileName,PathName)
|
|
RETURN TO CMD.ERR
|
|
END
|
|
END
|
|
WRITE.OKAY:
|
|
WRITE.REC.NAME = FIELD(SENT, ' ', 1)
|
|
END
|
|
IF LEN(SENT) = 0 THEN RETURN TO CMD.ERR
|
|
IF LEN(WRITE.REC.NAME) = 0 THEN RETURN TO CMD.ERR
|
|
IF UNLOAD.FLAG THEN
|
|
* Starting line/field number -
|
|
CALL *UVPRINTMSG(001193,"")
|
|
GOSUB INPUT.LINE
|
|
START = INPUT.LINE
|
|
IF NOT(NUM(START)) THEN
|
|
PRINT 'Starting line/field must be numeric ; you entered "':START:'".'
|
|
RETURN TO CMD.ERR
|
|
END
|
|
IF START < 1 THEN
|
|
CALL *UVPRINTMSG(001231,"")
|
|
RETURN TO CMD.ERR
|
|
END
|
|
IF START > BOT THEN
|
|
CALL *UVPRINTMSG(001230,BOT:@FM:START)
|
|
RETURN TO CMD.ERR
|
|
END
|
|
* Ending line/field number -
|
|
CALL *UVPRINTMSG(001195,"")
|
|
GOSUB INPUT.LINE
|
|
ENDING = INPUT.LINE
|
|
IF NOT(NUM(ENDING)) THEN
|
|
PRINT 'Ending line/field must be numeric ; you entered "':ENDING:'".'
|
|
RETURN TO CMD.ERR
|
|
END
|
|
IF ENDING < START THEN
|
|
CALL *UVPRINTMSG(001233,ENDING:@FM:START)
|
|
RETURN TO CMD.ERR
|
|
END
|
|
END
|
|
|
|
CHECK.FOR.LOCK:
|
|
READU COMMAND.RECORD FROM WRITE.FILE, WRITE.REC.NAME
|
|
* ON ERROR
|
|
* CALL *UVPRINTMSG(STATUS(),"")
|
|
* RETURN TO GET.CMD
|
|
* END
|
|
LOCKED
|
|
CALL *UVPRINTMSG(001191,"")
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS = 'Y' THEN GOTO CHECK.FOR.LOCK ELSE RETURN TO GET.CMD
|
|
END ELSE
|
|
IF UPCMD2 = '.D' THEN
|
|
CALL *UVPRINTMSG(970004,WRITE.REC.NAME:@FM:WRITE.FILE.DICT:WRITE.FILE.NAME)
|
|
PRINT
|
|
GOSUB DISPLAY.CURRENT.LINE
|
|
RETURN TO GET.CMD
|
|
END
|
|
DF.ERROR = STATUS()
|
|
IF DF.ERROR = 1 OR DF.ERROR = 2 THEN
|
|
STATUS TEMP.INFO FROM WRITE.FILE ELSE TEMP.INFO = ""
|
|
IF TEMP.INFO<21> = 27 THEN
|
|
CALL *UVPRINTMSG(970013,WRITE.REC.NAME)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(970012,WRITE.REC.NAME)
|
|
END
|
|
RETURN TO GET.CMD
|
|
END
|
|
ELSE IF DF.ERROR = 3 THEN
|
|
CALL *UVPRINTMSG(47007,WRITE.REC.NAME)
|
|
RETURN TO GET.CMD
|
|
END
|
|
ELSE IF DF.ERROR = 4 THEN
|
|
* Warning message already issued - no need to repeat ourselves
|
|
* CALL *UVPRINTMSG(47006,WRITE.REC.NAME)
|
|
RETURN TO GET.CMD
|
|
END
|
|
GOTO WRITE.IT.OUT
|
|
END
|
|
REC.TYPE.CODE = COMMAND.RECORD <1> [1, 1]
|
|
COMMAND.RECORD = '' ; * RETURN STRING SPACE
|
|
IF UPCMD2 = '.D' THEN RETURN TO SD.1
|
|
* already exists overwrite
|
|
IF STACK.MODE THEN
|
|
CALL *UVPRINTMSG(001110,"")
|
|
CALL *UVPRINTMSG(001200,"")
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001197,"")
|
|
END
|
|
GOSUB INPUT.LINE ; ANS = INPUT.LINE ; ANS = UPCASE(ANS)
|
|
IF ANS # 'Y' THEN
|
|
IF STACK.MODE THEN
|
|
CALL *UVPRINTMSG(001111,WRITE.REC.NAME)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001198,"")
|
|
DISPLAY.CURRENT.LINE = FALSE
|
|
END
|
|
RETURN
|
|
END
|
|
|
|
WRITE.IT.OUT:
|
|
|
|
WRITE.PERM.MODE = 1
|
|
WRITE.PERM.IN = 2
|
|
WRITE.PERM.OUT = ''
|
|
CALL @PERMISSIONS(WRITE.FILE,WRITE.PERM.MODE,WRITE.PERM.IN,WRITE.PERM.OUT)
|
|
IF NOT(WRITE.PERM.OUT) THEN
|
|
CALL *UVPRINTMSG(001398,WRITE.FILE.DICT:WRITE.FILE.NAME)
|
|
RETURN TO GET.CMD
|
|
END
|
|
|
|
IF UNLOAD.FLAG THEN GOTO UNLOAD
|
|
CMD.STRING = UVREADMSG(010239,"")
|
|
CMD.STRING = 'E':CMD.STRING:TIMEDATE():@FM
|
|
IF NN = 1 AND NOT(COMMA) THEN LAST.CMD = 1
|
|
ELSE
|
|
IF CMD.STACK (FIRST.CMD) [1, 1] = 'E' THEN CMD.STRING = '' ; * USER PUT OWN 'E' FIELD
|
|
FOR JJ = FIRST.CMD TO LAST.CMD + 1 STEP -1
|
|
CMD.STRING := CMD.STACK (JJ):@FM
|
|
NEXT JJ
|
|
END
|
|
CMD.STRING := CMD.STACK (LAST.CMD)
|
|
WRITE CMD.STRING TO WRITE.FILE, WRITE.REC.NAME ELSE
|
|
WRITE.STATUS = STATUS()
|
|
IF WRITE.STATUS = IntegrityViolation THEN
|
|
IO.VAR = 2
|
|
CALL @SQLINTCHK(CMD.STRING,WRITE.FILE,WRITE.REC.NAME,WRITE.FILE.DICT:" ":WRITE.FILE.NAME,IO.VAR)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001236,WRITE.STATUS)
|
|
END
|
|
END
|
|
IF STACK.MODE THEN
|
|
CALL *UVPRINTMSG(970005,WRITE.REC.NAME:@FM:WRITE.FILE.DICT:WRITE.FILE.NAME)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001112,WRITE.REC.NAME)
|
|
END
|
|
RETURN
|
|
|
|
UNLOAD:
|
|
IF ENDING > BOT THEN ENDING = BOT
|
|
UN.RECORD = ''
|
|
FOR LNUM = START TO ENDING - 1
|
|
GOSUB GET.LINE
|
|
UN.RECORD := LINE:@FM
|
|
NEXT LNUM
|
|
LNUM = ENDING
|
|
GOSUB GET.LINE
|
|
UN.RECORD := LINE
|
|
WRITE UN.RECORD TO WRITE.FILE, WRITE.REC.NAME
|
|
ELSE
|
|
WRITE.STATUS = STATUS()
|
|
IF WRITE.STATUS = IntegrityViolation THEN
|
|
IO.VAR = 2
|
|
CALL @SQLINTCHK(UN.RECORD,WRITE.FILE,WRITE.REC.NAME,WRITE.FILE.DICT:" ":WRITE.FILE.NAME,IO.VAR)
|
|
END ELSE
|
|
CALL *UVPRINTMSG(001236,WRITE.STATUS)
|
|
END
|
|
RETURN
|
|
END
|
|
* IF STACK.MODE THEN
|
|
* CALL *UVPRINTMSG(970005,WRITE.REC.NAME:@FM:WRITE.FILE.DICT:WRITE.FILE.NAME)
|
|
* END
|
|
UN.RECORD = ''
|
|
* %i lines/fields unloaded.
|
|
CALL *UVPRINTMSG(001199,ENDING - START + 1)
|
|
DISPLAY.CURRENT.LINE = FALSE
|
|
RETURN
|
|
|
|
READ.HELP.RECORD:
|
|
IF LEN(HELP.RECORD) = 0 THEN
|
|
READ HELP.RECORD FROM SYS.MESSAGE,970000 ELSE
|
|
CALL *UVPRINTMSG(970002,"")
|
|
RETURN TO HELP.END
|
|
END
|
|
READ HELP.RECORD.2 FROM SYS.MESSAGE,970001 ELSE
|
|
CALL *UVPRINTMSG(970002,"")
|
|
RETURN TO HELP.END
|
|
END
|
|
HELP.RECORD = HELP.RECORD:@FM:HELP.RECORD.2
|
|
HELP.RECORD = CHANGE(HELP.RECORD,'_':@FM,@VM)
|
|
|
|
* Ignore standard header (top three lines) of help file.
|
|
* HELP.RECORD = FIELD(HELP.RECORD, @FM, 4, 9999) ;* not on uniVerse!
|
|
|
|
* Following code to be removed post-8.3.3.
|
|
* Remove references to NLS and Unicode functionality if NLS mode is off.
|
|
NUM.HELP.LINES = DCOUNT(HELP.RECORD, @FM)
|
|
HELP.RECORD.ORIG = HELP.RECORD
|
|
HELP.RECORD = ''
|
|
SKIP.HELP.LINE = @FALSE
|
|
FOR N = 1 TO NUM.HELP.LINES
|
|
HELP.LINE = HELP.RECORD.ORIG<N>
|
|
IF NLS.ON.FLAG THEN ;* just remove the NLS marker lines
|
|
IF HELP.LINE[1,3] # 'NLS'
|
|
THEN HELP.RECORD<-1> = HELP.LINE
|
|
END ELSE ;* remove all lines between as well
|
|
BEGIN CASE
|
|
CASE HELP.LINE = 'NLSBEGIN'
|
|
SKIP.HELP.LINE = @TRUE
|
|
CASE HELP.LINE = 'NLSEND'
|
|
SKIP.HELP.LINE = @FALSE
|
|
CASE SKIP.HELP.LINE = @FALSE
|
|
HELP.RECORD<-1> = HELP.LINE
|
|
END CASE
|
|
END
|
|
NEXT N
|
|
* End 8.3.3 special - remove NLSBEGIN/NLSEND lines from messages 970000/970001
|
|
END
|
|
RETURN
|
|
|
|
ABORT.CHECK:
|
|
ABORT = FALSE
|
|
IF NOT(ABORT.FLAG) THEN RETURN
|
|
INPUT ABORT, -1
|
|
IF NOT(ABORT) THEN RETURN
|
|
INPUT ABORT, 1
|
|
ABORT = UPCASE(ABORT)
|
|
IF ABORT = 'Q' THEN RETURN
|
|
* Stopped at line %i
|
|
CALL *UVPRINTMSG(001229,LNUM)
|
|
INPUT ABORT, 1
|
|
ABORT = UPCASE(ABORT)
|
|
IF ABORT = 'Q' THEN RETURN
|
|
ABORT = FALSE
|
|
RETURN
|
|
|
|
AT.INSERT:
|
|
LOCATE X IN AT.LIST <1> BY 'AL' SETTING AT.LOC ELSE
|
|
AT.LIST = INSERT(AT.LIST, AT.LOC, 0, 0, X)
|
|
AT.SUB = INSERT(AT.SUB, AT.LOC, 0, 0, Y)
|
|
RETURN
|
|
END
|
|
AT.SUB = REPLACE(AT.SUB, AT.LOC, 0, 0, Y)
|
|
RETURN
|
|
|
|
* SJE SPARs 3002891 and 3004396 23 Apr 84
|
|
* Give warning message and return to caller who will return to GET.CMD ASAP.
|
|
OVERFLOW:
|
|
PRINT
|
|
PRINT @SYS.BELL:'Memory overflow, one line of data may be lost. FILE as soon'
|
|
PRINT 'as possible to prevent further loss and re-EDit.'
|
|
OVERFLOW.FLAG = 1
|
|
RETURN
|
|
*
|
|
|
|
END
|