;
; Program: SHDEFINE
; Author: Richard Conn
; Version: 1.0
; Date: 5 Mar 84
;
version equ     10

;
;       SHDEFINE is used to define shell variables for the Shell SH.
; It makes entries into the file SH.VAR in the ROOT directory.
;

;
; Equates for Key Values
;
z3env   SET     0f400h  ;address of ZCPR3 environment
backup  equ     0       ;backup old file? 1 for yes, 0 for no
ctrlz   equ     'Z'-'@' ;^Z for EOF
fcb     equ     5ch
tbuff   equ     80h
cr      equ     0dh
lf      equ     0ah

;
; External Z3LIB and SYSLIB Routines
;
       ext     sctlfl,sout,sprint,scrlf,shldc
       ext     bbline,sksp,capine,fillb,cout,moveb,getfn1
       ext     initfcb,f$open,f$read,f$close,f$make,f$delete,f$write,f$rename
       ext     z3init,qprint,codend,hmovb,root,logud,getwhl,print

;
; Environment Definition
;
       if      z3env ne 0
;
; External ZCPR3 Environment Descriptor
;
       jmp     start
       db      'Z3ENV' ;This is a ZCPR3 Utility
       db      1       ;External Environment Descriptor
z3eadr:
       dw      z3env
start:
       lhld    z3eadr  ;pt to ZCPR3 environment
;
       else
;
; Internal ZCPR3 Environment Descriptor
;
       MACLIB  Z3BASE.LIB
       MACLIB  SYSENV.LIB
z3eadr:
       jmp     start
       SYSENV
start:
       lxi     h,z3eadr        ;pt to ZCPR3 environment
       endif

;
; Start of Program -- Initialize ZCPR3 Environment
;
       call    z3init  ;initialize the ZCPR3 Environment
       call    banner  ;print banner
;
; Check for Wheel
;
       call    getwhl  ;get wheel byte
       jnz     start0
       call    print
       db      cr,lf,' Not Wheel - Aborting',0
       ret
;
; Try to Load Variables
;
start0:
;
; Define File to Work With
;
       lxi     h,fcb+1 ;check for file name
       lxi     d,shvfcb+1      ;variable FCB
       mvi     b,11    ;11 chars
       mov     a,m     ;any name given?
       cpi     ' '     ;space if none
       jz      setdef  ;set default shell variable file name
;
; Define Passed Name as Shell Variable File
;
       call    moveb   ;set name
       lxi     h,deftype       ;set default type if none
       lxi     d,shvfcb+9      ;pt to type
       mvi     b,3     ;3 chars
       ldax    d               ;any chars
       cpi     ' '     ;if none, copy
       cz      moveb
       jmp     bakdef
;
; Define from Shell Variable File Name
;
setdef:
       call    getfn1  ;get name
       call    moveb   ;copy it
;
; Define $$$ and BAK Files
;
bakdef:
       lxi     h,shvfcb+1
       lxi     d,shvtmp+1      ;set $$$ name
       mvi     b,8             ;8 chars
       call    moveb
;
       if      backup
       lxi     d,shvbak+1      ;set BAK name
       call    moveb
       endif           ;backup
;
; Load Variables
;
       call    varload
       jnz     start1
;
; Initialize Shell Variables if File Not Found
;
       call    codend  ;pt to code end
       mvi     m,ctrlz ;place ^Z
;
; Process User Commands
;
start1:
       call    menu    ;use menu
       rz              ;abort
       call    varsave ;save new shell variables
       ret

;
; Input and Process User Commands
;       Return with Z if Abort
;
menu:
       call    print
       db      cr,lf
       db      cr,lf,' ** Shell Variable Editor **'
       db      cr,lf
       db      cr,lf,'Edit:    E. Edit (Add/Delete/Redefine) Shell Variables'
       db      cr,lf,' L. List Shell Variables on Console'
       db      cr,lf,' P. Print Shell Variables on Printer'
       db      cr,lf
       db      cr,lf,'Exit:    X. Exit and Update SH.VAR on Disk'
       db      cr,lf,' Q. Quit without Updating SH.VAR'
       db      cr,lf
       db      cr,lf,'Command: ',0
       call    capine  ;get command
       lxi     h,ctable        ;scan command table
       call    tscan
       call    print
       db      ' Invalid Command: ',0
       call    cout
       jmp     menu
;
; Pack and Menu Exit
;       Return NZ
;
pack:
       call    codend  ;pack entries in table
       mov     d,h     ;HL=DE
       mov     e,l
;
; Check Next Entry
;
pack1:
       mov     a,m     ;get next char
       stax    d       ;put it
       cpi     ctrlz   ;done?
       jz      packx
       cpi     ' '     ;deleted?
       jz      pack3
;
; Copy Entry
;
pack2:
       mov     a,m     ;get char
       stax    d       ;put it
       inx     h       ;pt to next
       inx     d
       ora     a       ;done?
       jnz     pack2
       jmp     pack1   ;resume
;
; Skip Entry
;
pack3:
       mov     a,m     ;get char
       inx     h       ;pt to next
       ora     a       ;done?
       jnz     pack3
       jmp     pack1   ;resume
;
; Pack Complete
;
packx:
       xra     a       ;NZ
       dcr     a
       ret
;
; Menu Quit
;       Return Z
;
mquit:
       call    print
       db      cr,lf,' Do you really want to quit (Y/N)? ',0
       call    capine
       cpi     'Y'
       jnz     menu
       xra     a       ;Z
       ret
;
; List Names in Table on Printer
;
nprint:
       mvi     a,80H   ;select print
       jmp     nliste
;
; List Names in Table on Console
;
nlist:
       mvi     a,1     ;select console
nliste:
       sta     sctlfl  ;set flag
       call    pack    ;pack table
nlist0:
       call    sprint
       db      cr,lf,'List of Shell Variables',0
       lxi     d,0     ;set count
       call    codend  ;pt to list
;
; Main List Loop
;
nlist1:
       mov     a,m     ;get next variable
       cpi     ctrlz   ;done?
       jz      nlistx
;
; Print Next Element
;
       xchg            ;print number
       inx     h       ;increment count
       call    scrlf
       call    shldc   ;print
       xchg            ;DE contains count
       call    sprint
       db      ' Name: ',0
       mvi     b,8     ;8 chars in name
nlist2:
       mov     a,m     ;get char
       call    sout    ;print
       inx     h       ;pt to next
       dcr     b       ;count down
       jnz     nlist2
       call    sprint
       db      cr,lf,'      >',0
nlist3:
       mov     a,m     ;get char
       inx     h       ;pt to next
       ora     a       ;done?
       jz      nlist4  ;resume
       call    sout
       jmp     nlist3
nlist4:
       call    sprint
       db      '<',0
       jmp     nlist1
;
; Exit Listing
;
nlistx:
       call    scrlf   ;new line
       mov     a,d     ;check for none
       ora     e
       jnz     menu    ;resume menu
       call    sprint
       db      ' -- No Shell Variables Defined --',cr,lf,0
       jmp     menu

;
; Add Names to Table
;
nadd:
       call    print
       db      cr,lf,'Enter Shell Variable Name (RETURN to Quit): ',0
       mvi     a,0ffh  ;capitalize
       call    bbline
       call    sksp    ;skip to first non-blank
       ora     a       ;done?
       jz      menu    ;resume menu
;
; Copy Input Name into Shell Buffer SHVAR
;
       push    h       ;save ptr to name
       lxi     h,shvar ;init name buffer
       mvi     a,' '   ;space fill
       mvi     b,8     ;8 chars
       call    fillb
       xchg            ;pt to buffer in DE
       pop     h       ;pt to name
       mvi     b,8     ;8 chars max
nadd1:
       mov     a,m     ;get name char
       ora     a       ;done?
       jz      nadd2
       stax    d       ;store char
       inx     h       ;pt to next
       inx     d
       dcr     b       ;count down
       jnz     nadd1
;
; Search for Name
;
nadd2:
       call    codend  ;pt to first element
;
; Check for End of Entries
;
nadd3:
       mov     a,m     ;get first char of next string
       cpi     ctrlz
       jz      addit   ;add name at HL
;
; Compare Names
;
       lxi     d,shvar ;pt to variable
       mvi     b,8     ;compare
       shld    curname ;save ptr to current name in case of delete
nadd4:
       ldax    d       ;check for duplicate
       cmp     m
       jnz     nadd5
       inx     h       ;pt to next
       inx     d
       dcr     b       ;count down
       jnz     nadd4
       jmp     nadd6
;
; No Match, so Skip Rest of String
;
nadd5:
       mov     a,m     ;skip to end of string
       inx     h       ;pt to next
       ora     a       ;done?
       jnz     nadd5
       jmp     nadd3   ;resume
;
; Match - Determine What User Wants to Do
;
nadd6:
       call    print
       db      cr,lf,' Shell Variable Name ',0
       call    prname  ;print name
       call    print
       db      ' Found -'
       db      cr,lf,' Delete It (D)'
       db      cr,lf,' Redefine It (R)'
       db      cr,lf,' No Change (anything else)'
       db      cr,lf,'Option: ',0
       call    capine
       cpi     'D'     ;delete?
       jz      delete
       cpi     'R'     ;redefine?
       jnz     nadd    ;restart if not
;
; Redefine Name
;
       lhld    curname ;pt to name in buffer
       mvi     b,8     ;space fill it
       mvi     a,' '
       call    fillb
       jmp     nadd3   ;resume in case another duplicate
;
; Delete Name
;
delete:
       lhld    curname ;pt to name in buffer
       mvi     b,8     ;space fill it
       mvi     a,' '
       call    fillb
       jmp     nadd    ;restart
;
; Add Name
;
addit:
       shld    curname ;save ptr to new name
       xchg            ;dest in DE
       lxi     h,shvar ;pt to name
       mvi     b,8     ;8 chars
       call    hmovb   ;copy name into buffer
       xchg            ;pt to after name with HL
       push    h       ;save ptr
       mvi     m,0     ;store ending 0 and ^Z in case of abort
       inx     h
       mvi     m,ctrlz ;store ^Z
       call    print
       db      cr,lf,' Definition of ',0
       call    prname  ;print name
       call    print
       db      ' (RETURN to Abort) -',cr,lf,'--> ',0
       mvi     a,0ffh  ;caps
       call    bbline
       pop     d       ;get destination
       mov     a,m     ;no input?
       ora     a       ;noadd if not
       jz      noadd
;
; Copy User Input into Buffer
;
addit1:
       mov     a,m     ;get char
       stax    d       ;put char
       inx     h       ;pt to next
       inx     d
       ora     a       ;done?
       jnz     addit1
       mvi     a,ctrlz ;mark end
       stax    d
       jmp     nadd

;
; Abort Add
;
noadd:
       lhld    curname ;pt to first char
       mvi     m,ctrlz ;mark end
       jmp     nadd

;
; Print Name of Shell Variable
;
prname:
       push    h       ;save regs
       push    b
       lxi     h,shvar ;pt to name
       mvi     b,8     ;8 chars
prn1:
       mov     a,m     ;get char
       call    cout
       inx     h       ;pt to next
       dcr     b       ;count down
       jnz     prn1
       pop     b       ;restore
       pop     h
       ret

;
; Command Table Scanner
;
tscan:
       mov     b,a     ;save char in B
tscan1:
       mov     a,m     ;end of table?
       ora     a
       mov     a,b     ;prep for return
       rz
       mov     a,m     ;get table char
       cmp     b       ;match?
       jz      tscan2
       inx     h       ;pt to next entry
       inx     h
       inx     h
       jmp     tscan1
;
; Command Found - Run It
;
tscan2:
       inx     h       ;get address
       mov     e,m
       inx     h
       mov     d,m
       xchg            ;address in HL
       pop     psw     ;clear stack
       pchl            ;"run" command
;
; Command Table
;
ctable:
       db      'E'     ;enter
       dw      nadd
       db      'L'     ;list
       dw      nlist
       db      'P'     ;print
       dw      nprint
       db      'X'     ;exit
       dw      pack
       db      'Q'     ;quit
       dw      mquit
       db      0       ;end of table

;
; Print Banner
;
banner:
       call    qprint
       db      'SHDEFINE, Version '
       db      (version/10)+'0','.',(version mod 10)+'0'
       db      0
       ret
;
; Save Shell Variable List
;       Return with Z if Error
;
varsave:
       call    print
       db      cr,lf,' Writing Shell Variables to Disk',0
       lxi     d,shvtmp        ;open temp
       call    initfcb
       call    f$delete        ;delete if any exists
       call    f$make          ;create new file
       inr     a               ;error?
       rz
       call    codend          ;pt to scratch area
;
; Save Loop
;
vars1:
       lxi     d,tbuff         ;copy into buffer
       mvi     b,128           ;128 bytes
       call    hmovb
       lxi     d,shvtmp        ;write block
       call    f$write
       jnz     werr            ;write error
       lxi     d,tbuff         ;check for done
       mvi     b,128           ;128 bytes
;
; Check for Done
;
vars2:
       ldax    d               ;look for ^Z
       cpi     ctrlz
       jz      varsx
       inx     d               ;pt to next
       dcr     b               ;count down
       jnz     vars2
       jmp     vars1
;
; Done
;
varsx:
       lxi     d,shvtmp        ;close temp file
       call    f$close
;
; Delete Old Backup File SH.BAK
;
       if      backup
;
       lxi     d,shvbak        ;delete any old backups
       call    initfcb
       call    f$delete
;
; Create New Backup File SH.BAK=SH.VAR
;
       lxi     h,shvbak        ;new name
       lxi     d,shvfcb        ;old name
       call    f$rename        ;create backup file
;
       else
;
; Erase Original File
;
       lxi     d,shvfcb        ;delete file
       call    initfcb
       call    f$delete
;
       endif           ;backup
;
; Create New Shell Variable File SH.VAR=SH.$$$
;
       lxi     h,shvfcb        ;new name
       lxi     d,shvtmp        ;old name
       call    f$rename        ;create new file
       xra     a               ;return OK
       dcr     a               ;NZ
       ret
;
; File Write Error
;
werr:
       call    print
       db      cr,lf,'Error in Writing File - Aborting',0
       xra     a               ;error code
       ret

;
; Load Shell Variable List
;       Return with Z if Error
;
varload:
;
; Look for Variable File
;
       call    root            ;determine DU of root
       call    logud           ;goto root
       call    codend          ;pt to scratch area
       mvi     m,ctrlz         ;prep for no file
       lxi     d,shvfcb        ;try to open file
       call    initfcb         ;init FCB
       call    f$open
       rnz                     ;file not found
;
; Read in Variable File
;
varl1:
       lxi     d,shvfcb        ;read in file
       call    f$read
       jnz     varl2
       lxi     d,tbuff         ;pt to data
       xchg                    ;copy into memory
       mvi     b,128           ;128 bytes
       call    hmovb
       xchg
       jmp     varl1
varl2:
       lxi     d,shvfcb        ;close file
       call    f$close
;
; Say List is Already Loaded
;
       xra     a               ;return NZ for OK
       dcr     a
       ret

;
; Buffers
;
curname:
       ds      2               ;ptr to current variable name
shvar:
       ds      8               ;shell variable name
deftype:
       db      'VAR'           ;default file type
;
       if      backup
shvbak:
       db      0
       db      'SH      '      ;name of shell variable file
       db      'BAK'
       ds      24              ;36 bytes total
       endif           ;backup
;
shvtmp:
       db      0
       db      'SH      '      ;name of shell variable file
       db      '$$$'
       ds      24              ;36 bytes total
shvfcb:
       db      0
       db      'SH      '      ;name of shell variable file
       db      'VAR'
       ds      24              ;36 bytes total

       end