;  PROGRAM:  SAK (Strike Any Key)
;  AUTHOR:  Richard Conn
;  VERSION:  1.0
;  DATE:  18 April 1983
;  PREVIOUS VERSIONS:  None
vers    equ     10

;
;       SAK (Strike Any Key) is used for the following purposes:
;               1) to wait for user interaction before continuing
;                       and to allow the user to abort a Multiple
;                       Command Line
;               2) to command the user's attention by ringing the
;                       bell at his console
;
;       The SAK command line is:
;               SAK o...
;       SAK is invoked with the following options:
;               A     -- DO NOT Allow the User to Abort MCL
;               B     -- Ring Bell
;               Pnnnn -- Pause nnnn seconds and continue if no
;                        response by that time
;
       ext     print, condin, eval10, pause, cline, cout, phldc

tbuff   equ     80h     ;command line buffer
cr      equ     0dh
lf      equ     0ah
ctrlc   equ     'C'-'@'
ctrlg   equ     'G'-'@'

;
;       This program is Copyright (c) 1983 by Richard Conn
;       All Rights Reserved
;
;       ZCPR2 and its utilities, including this one, are released
; to the public domain.  Anyone who wishes to USE them may do so with
; no strings attached.  The author assumes no responsibility or
; liability for the use of ZCPR2 and its utilities.
;
;       The author, Richard Conn, has sole rights to this program.
; ZCPR2 and its utilities may not be sold without the express,
; written permission of the author.
;

;
;  Branch to Start of Program
;
       jmp     start

;
;******************************************************************
;
;  SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format
;
;       This data block precisely defines the data format for
; initial features of a ZCPR2 system which are required for proper
; initialization of the ZCPR2-Specific Routines in SYSLIB.
;

;
;  EXTERNAL PATH DATA
;
EPAVAIL:
       DB      0FFH    ; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES)
EPADR:
       DW      40H     ; ADDRESS OF EXTERNAL PATH IF AVAILABLE

;
;  INTERNAL PATH DATA
;
INTPATH:
       DB      0,0     ; DISK, USER FOR FIRST PATH ELEMENT
                       ; DISK = 1 FOR A, '$' FOR CURRENT
                       ; USER = NUMBER, '$' FOR CURRENT
       DB      0,0
       DB      0,0
       DB      0,0
       DB      0,0
       DB      0,0
       DB      0,0
       DB      0,0     ; DISK, USER FOR 8TH PATH ELEMENT
       DB      0       ; END OF PATH

;
;  MULTIPLE COMMAND LINE BUFFER DATA
;
MCAVAIL:
       DB      0FFH    ; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE?
MCADR:
       DW      0FF00H  ; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE

;
;  DISK/USER LIMITS
;
MDISK:
       DB      4       ; MAXIMUM NUMBER OF DISKS
MUSER:
       DB      31      ; MAXIMUM USER NUMBER

;
;  FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK
;
DOK:
       DB      0FFH    ; ALLOW DISK CHANGE? (0=NO, 0FFH=YES)
UOK:
       DB      0FFH    ; ALLOW USER CHANGE? (0=NO, 0FFH=YES)

;
;  PRIVILEGED USER DATA
;
PUSER:
       DB      10      ; BEGINNING OF PRIVILEGED USER AREAS
PPASS:
       DB      'chdir',0       ; PASSWORD FOR MOVING INTO PRIV USER AREAS
       DS      41-($-PPASS)    ; 40 CHARS MAX IN BUFFER + 1 for ending NULL

;
;  CURRENT USER/DISK INDICATOR
;
CINDIC:
       DB      '$'     ; USUAL VALUE (FOR PATH EXPRESSIONS)

;
;  DMA ADDRESS FOR DISK TRANSFERS
;
DMADR:
       DW      80H     ; TBUFF AREA

;
;  NAMED DIRECTORY INFORMATION
;
NDRADR:
       DW      00000H  ; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY
NDNAMES:
       DB      64      ; MAX NUMBER OF DIRECTORY NAMES
DNFILE:
       DB      'NAMES   '      ; NAME OF DISK NAME FILE
       DB      'DIR'           ; TYPE OF DISK NAME FILE

;
;  REQUIREMENTS FLAGS
;
EPREQD:
       DB      000H    ; EXTERNAL PATH?
MCREQD:
       DB      0FFH    ; MULTIPLE COMMAND LINE?
MXREQD:
       DB      000H    ; MAX USER/DISK?
UDREQD:
       DB      000H    ; ALLOW USER/DISK CHANGE?
PUREQD:
       DB      000H    ; PRIVILEGED USER?
CDREQD:
       DB      000H    ; CURRENT INDIC AND DMA?
NDREQD:
       DB      000H    ; NAMED DIRECTORIES?
Z2CLASS:
       DB      6       ; CLASS 6 (for Processor Speed)
       DB      'ZCPR2'
       DS      10      ; RESERVED

;
;  END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA
;
;******************************************************************
;

;
;  ZCPR2 Class 6 Constants
;
pspeed:
       db      4       ;Processor Speed in MHz
crtpage:
       db      24      ;CRT page Size

;
;  Other Buffers
;
abortf:
       ds      1       ;abort flag
bell:
       ds      1       ;bell flag
delay:
       ds      2       ;delay constant

;
;  Start of Program
;
start:

;
;  Print Banner
;
       call    print
       db      'SAK, Version '
       db      (vers/10)+'0','.',(vers mod 10)+'0',0
;
;  Init Options and Parse and Interpret Command Line
;
       xra     a       ;turn options off
       sta     bell    ;turn off bell
       sta     delay   ;turn off delay (pause)
       sta     delay+1
       mvi     a,0ffh  ;turn options on
       sta     abortf  ;turn on abort
       lxi     h,tbuff ;save command line
       call    cline
opt:
       mov     a,m     ;get option letter
       inx     h       ;pt to next
       ora     a       ;done?
       jz      optdone
       cpi     ' '     ;skip spaces
       jz      opt
       cpi     'A'     ;abort?
       jz      optabort
       cpi     'B'     ;bell?
       jz      optbell
       cpi     'P'     ;pause?
       jz      optpause
       call    print
       db      cr,lf,'SAK is invoked by a command line of the following form:'
       db      cr,lf,' SAK o...'
       db      cr,lf,'where "o..." is zero or more options combined in any '
       db      'order.'
       db      cr,lf,'The options are:'
       db      cr,lf,' A     -- DO NOT Allow the User to Abort and Clear the '
       db      'MCL Buffer'
       db      cr,lf,' B     -- Ring the Bell'
       db      cr,lf,' Pnnnn -- Pause nnnn seconds and then resume '
       db      'automatically'
       db      cr,lf,'SAK allows the user to strike ^C to abort and clear the'
       db      cr,lf,'multiple command line buffer (if there is one) or any'
       db      cr,lf,'other key to continue execution'
       db      cr,lf,0
       ret
;
;  Process A option (Abort MCL)
;
optabort:
       xra     a       ;turn off abort
       sta     abortf
       jmp     opt
;
;  Process B option (Ring Bell)
;
optbell:
       mvi     a,0ffh  ;turn on bell
       sta     bell
       jmp     opt
;
;  Process Pnnnn option (Pause nnnn seconds)
;
optpause:
       call    eval10  ;convert argument to decimal value in DE
       xchg            ;HL contains value
       shld    delay
       call    print
       db      cr,lf,'Pause Selected: ',0
       call    phldc   ;print in decimal
       call    print
       db      ' Second Delay before Resuming',0
       xchg            ;HL pts to next char
       jmp     opt
;
;  Continue Command Processing
;
optdone:
       lhld    delay   ;get delay count in HL
       lda     abortf  ;abort allowed?
       ora     a       ;0=no
       jz      noabort
       call    print
       db      cr,lf,'Please Strike ^C to Abort, Any Other Key to '
       db      'Continue - ',0
       jmp     sakloop
noabort:
       call    print
       db      cr,lf,'Please Strike Any Key to Continue - ',0
;
;  Main Delay Loop
;
sakloop:
;
;  Ring Bell if Option Selected
;
       lda     bell    ;get flag
       ora     a       ;set zero flag
       cnz     bout    ;ring bell and delay
;
;  Get character if one is available
;
       call    condin  ;optionally get character
       jnz     gotchar ;process character
;
;  Loop if No Delay
;
       mov     a,h     ;check for no delay
       ora     l
       jz      sakloop
;
;  Delay and test for input
;
       push    h       ;save second counter
       lxi     h,10    ;1 full second delay
       lda     pspeed  ;get processor speed
       mov     b,a     ;... in B
       call    pause   ;delay 1 sec
       pop     h       ;get second counter
       dcx     h       ;count down
       mov     a,h     ;done?
       ora     l
       jnz     sakloop
;
;  Process Input Character
;       If no input and timout instead, A=0 for continuation character
;
gotchar:
       cpi     ctrlc   ;abort?
       jz      abort
resume:
       call    print
       db      cr,lf,'Resuming ...',0
       ret
;
;  Abort Multiple Command Line if there is one
;
abort:
       lda     abortf  ;abort allowed?
       ora     a       ;0=no
       jz      resume
       lda     mcavail ;multiple command line available?
       ora     a       ;0=no
       jz      abort1
       lhld    mcadr   ;get address of buffer
       lxi     d,4     ;add 4
       xchg
       dad     d       ;HL=MC+4, DE=MC
       mvi     m,0     ;set no further command
       xchg            ;HL=MC, DE=MC+4 (next command char ptr)
       mov     m,e     ;store ptr to next command
       inx     h
       mov     m,d
abort1:
       call    print
       db      cr,lf,'Aborting ...',0
       ret
;
;  Ring Bell and Delay Briefly
;
bout:
       mvi     a,ctrlg ;ring bell
       call    cout
       push    h       ;save HL
       lhld    delay   ;do not delay if pause already invoked
       mov     a,h     ;zero delay?
       ora     l
       jnz     bout1   ;skip delay
       lxi     h,4     ;0.4 sec delay
       lda     pspeed  ;get processor speed
       mov     b,a     ;... in B
       call    pause   ;delay
bout1:
       pop     h
       ret

       end