;***************************************************** ;* ;* Submit MP/M-86 ;* ;***************************************************** true equ 0ffh false equ 0 unknown equ 0 mpmint equ 224 ; int vec for mpm ent. mpm_conin equ 1 mpm_conout equ 2 mpm_conwrite equ 9 mpm_conread equ 10 mpm_constat equ 11 mpm_version equ 12 mpm_diskselect equ 14 mpm_openfile equ 15 mpm_readfile equ 20 mpm_getdefdisk equ 25 mpm_setdma equ 26 mpm_usercode equ 32 mpm_terminate equ 143 mpm_setprior equ 145 mpm_conattach equ 146 mpm_condetach equ 147 mpm_setdefcon equ 148 mpm_clicmd equ 150 mpm_parse equ 152 mpm_getdefcon equ 153 mpm_getpdadr equ 156 mpm_setdeflst equ 160 mpm_getdeflst equ 164 ; fcb offsets mode2 equ 6 ; 2nd open mode byte ftype equ 9 ; file type cr equ 32 ; offset of current record e_no_memory equ 3 ; cant find memory e_no_pd equ 12 ; no free pd's e_q_full equ 15 ; full queue e_badfname equ 24 ; illegal filename e_badftype equ 25 ; illegal filetype e_bad_load equ 28 ; bad ret. from BDOS load e_bad_read equ 29 ; bad ret. from BDOS read e_bad_open equ 30 ; bad ret. from BDOS open e_nullcmd equ 31 ; null command sent p_prior equ 05H ;process descriptor priority p_flag equ word ptr 06H ;flags p_name equ 08H ;name of process p_parent equ 1EH ;PD's parent pf_keep equ 02H ;keep flag pf_childabort equ 800H ;child aborted abnormally pf_ctlc equ 080H ;control c occured ;***************************************************** ;* ;* Submit Code ;* ;***************************************************** cseg org 0 jmps submit db 'COPYRIGHT (C) 1981,' db ' DIGITAL RESEARCH ' db '5 Oct 1981' db 13,10,0,'$' ;====== submit: ; PROGRAM MAIN - INITIALIZATION ;====== mov ax,ds pushf ! pop bx mov ss,ax mov sp,offset stacktop push bx ! popf mov cl,mpm_version call mpm cmp bh,11H jz okvers mov dx,offset wrongvers mov cl, mpm_conwrite ! call mpm mov cl,0 ! call mpm okvers: ; ;set priority better than parent ; mov cl,mpm_getpdadr call mpm ;get our PD address mov pdadr,bx ;save PD address mov sysdatseg,es ;and the system data area segment mov bx,es:p_parent[bx] ;get our parent's PD address cmp bx,0 ! jne psetpar ;see if parent exists mov dx,197 ! jmps setp ; oops, set to better than TMP psetpar:mov dx,es:p_prior[bx] ;our parent's priority dec dx ;we run at one better, cmp dx,64 ! jae setp mov dx,64 ;don't compete w/system setp: mov cl,mpm_setprior call mpm ;set our priority mov cl,mpm_setdma ;using default buffer at 80H for mov dx,offset dma ;command tail and argument expansion call mpm mov si,offset fcb mov byte ptr ftype[si],'S' ;look for file with type = SUB mov byte ptr ftype+1[si],'U' mov byte ptr ftype+2[si],'B' mov byte ptr cr[si],0 ;zero current record or byte ptr mode2[si],80h ;open in R/O mode mov dx,si call openfile cmp al,0ffh jnz exists mov dx,offset sopen_err call con_write jmp submitexit exists: mov al,fcb ;save disk number where command file is cmp al,0 ;default disk ? jnz save_disk_no mov cl,mpm_getdefdisk call mpm inc al save_disk_no: mov command_disk,al mov cl,mpm_usercode ;save user number of mov dl,0ffh call mpm ;command file mov command_user,al mov cx,mpm_getdefcon call mpm ;save console number this mov command_con,al ;program was run from ; ;deblank command tail ; mov si,offset cmdtail + 1 mov di,offset deblankbuf firstwhites: cmp byte ptr [si],' ' jnz tab jmps morewhites tab: cmp byte ptr [si],9 jnz deblank morewhites: inc si jmps firstwhites deblank: mov al,byte ptr [si] inc si cmp al,' ' jz skipwhite cmp al,9 ;tab jz skipwhite jmps copychar copychar: cmp al,0 ;end of of command tail ? jz putlastblank mov [di],al inc di jmps deblank putlastblank: mov byte ptr [di],' ' inc di mov [di],al ;ends with space and zero jmps dedone skipmore: inc si skipwhite: ;input = si points at tab or blank mov al,[si] cmp al,' ' jz skipmore cmp al,9 ;tab jz skipmore mov byte ptr [di],' ' inc di jmps deblank ;si points to non white char ;di is next char to copy dedone: ; ;fill argument tail ; mov bp,offset deblankbuf mov bx,offset argtable xor si,si ;pointer into deblankbuf mov di,si ;index into argtable nxtfill: mov al,byte ptr [bp + si] ;0th argument is '.sub' cmp al,0 jz filldone mov [bx + di],si inc di call skiparg ;skip over argument and blank jmps nxtfill skiparg: inc si cmp byte ptr [bp + si],' ' jnz skiparg inc si ;char after blank ret filldone: mov numargs,di call crlf ;get first command from SUB file mov cmdbuf,maxcmdlen ! mov dx,offset cmdbuf call readbuffer ;read from file to next crlf cmp bx,0 ! je topofcmdloop ;assume EOF if BX <> 0 ;jmp submitexit ;========== submitexit: ;========== mov cl,0 ! mov dx,0 ;jmp mpm ;=== mpm: ; INTERFACE ROUTINE FOR SYSTEM ENTRY POINTS ;=== int mpmint ! ret ;=========== topofcmdloop: ; LOOP FOREVER ;=========== ; ; check to see if control c was typed during last command ; mov bx,pdadr mov es,sysdatseg test es:p_flag[bx],pf_childabort jz gonext and es:p_flag[bx],not pf_childabort ;turn off child abort flg mov cl,11 ! mov si,offset fcb + 1 mov di, offset subfilename push ds ! pop es rep movs al,al mov dx,offset askabortmsg call con_write call charin and al,5fh ;make upper case cmp al,'Y' jnz gonext ;stop this submit and turn on ;pf_ctlc flag mov bx,pdadr ! mov es,sysdatseg or es:p_flag[bx],pf_ctlc submitexit1: jmp submitexit gonext: ; ; print CR,LF if we just sent a command ; cmp cmdsent,false ! je noclearline mov cmdsent,false call crlf noclearline: ; ; set up and print user prompt ; ; get current default disk mov cl,mpm_getdefdisk ! call mpm mov defdisk,al ; get current default user # ; this call should be made on every ; loop in case the 'USER' program ; has changed the default user number mov cl,mpm_usercode ! mov dl,0ffh call mpm mov defuser,al ;create user part of prompt string mov promptutens,13 mov promptuones,'0' cmp al,10 ! jb ones mov promptutens,'1' sub al,10 ones: add promptuones,al ; create disk part of prompt string mov al,'A' ! add al,defdisk mov promptdisk,al ; write user prompt mov dx,offset prompt cmp promptutens,13 ! jne writeprompt mov dx,offset promptutens writeprompt: mov cl,mpm_conwrite ! call mpm ; ; copy command to cli buffer, make upper case and ; expand command arguments ; mov si,offset cmd ;where command is mov bp,offset clicmd ;copy w/ expanded args here xor di,di ;index into cli command nextchar: mov al,[si] ;char from command inc si cmp al,'$' ;argument ? jz argmaybe noarg: call copyit jmps nextchar argmaybe: cmp byte ptr [si],'0' ;is next char after '$' a digit ? jb noarg cmp byte ptr [si],'9' ja noarg realarg: xor ax,ax ;copy argument throw out - '$' in al mov al,[si] sub al,'0' ;1st digit inc si cmp byte ptr [si],'0' ;is there a second digit ? jb onedigit cmp byte ptr [si],'9' ja onedigit mov dl,10 ;1st digit is tens in column mul dl mov dl,[si] ;2nd argument is ones column inc si sub dl,'0' add al,dl onedigit: mov bx,ax copyarg: cmp bx,numargs ; jb oknum ;numargs in range 1 to n jmps nextchar ;no such argument oknum: mov bl,argtable[bx] ;argument address rel to deblankbuf copymore: mov al,deblankbuf[bx] cmp al,' ' jz nextchar ;end of argument call copyit inc bx jmps copymore ;utility subroutine copyit: mov [bp + di],al ;mov to cli command buffer inc di cmp di,maxcmdlen ;cli buffer size jae donecopy testend: cmp al,0 jz donecopy ret donecopy: mov byte ptr [bp + di], '$' pop ax ;return is garbage ;jmps echocommand ;fall through to echocommand echocommand: ;print command after argument mov dx,offset clicmd ;substitution mov bx,dx ! cmp byte ptr [bx], '$' jnz writecommand inc dx ;skip '$' if line begins with '$' writecommand: call con_write ; ; echo newline ; call crlf ; ; make sure not a null command ; lea bx,cmd cmp blen,0 ! je gonextcmd cmp byte ptr [bx],';' ! je gonextcmd ; ; see if disk change - if 'X:' change def disk to X ; cmp blen,2 ! jne notdrive cmp byte ptr 1[bx],':' ! jne try_builtin ; change default disk mov dl,[bx] ;get disk name and dl,5fh ;make Upper Case sub dl,'A' ;make disk number ; check bounds cmp dl,0 ! jb subex cmp dl,15 ! jbe okdrive subex: jmp submitexit okdrive: ; select default disk mov cl,mpm_diskselect call mpm gonextcmd: jmp getnxtcmd notdrive: mov di,offset clicmd mov si, offset parseresult call parsefilename jcxz goodparse mov cl,126 mov di,offset clicmd mov al, ' ' push cs ! pop es repne scasb mov byte ptr[di], '$' jmp clierror goodparse: mov parseret,bx cmp parseresult,0 ! jz try_builtin jmp not_builtin try_builtin: mov di,offset usercmd mov si,offset parseresult ! inc si push ds ! pop es mov cx,4 ! repz cmpsw jnz notuser mov si,offset parseresult mov di,parseret ! cmp di,0 je pruser call parsefilename ; CX = 0 if ok cmp cx,0 ! jne pruser mov si,offset parseresult ! inc si mov dx,[si] call a_to_b cmp bl,15 ! ja usererr mov dl,bl ! call setuser jmp pruser usererr: mov dx,offset usererrmsg call con_write pruser: mov dx,offset usermsg call con_write call getuser mov dl,bl ! call prnum call crlf jmp getnxtcmd notuser: mov si,offset parseresult ! inc si mov di,offset printercmd push ds ! pop es mov cx,4 ! repz cmpsw jnz notprinter mov si,offset parseresult mov di,parseret ! test di,di jz prprinter call parsefilename ; CX = 0 if ok cmp cx,0 ! jne prprinter; no tail mov si,offset parseresult ! inc si mov dx,[si] call a_to_b cmp bl,0ffh ! je printererr mov dl,bl ! call setlist jcxz prprinter printererr: mov dx,offset printererrmsg call con_write prprinter: mov dx,offset printermsg call con_write call getlist mov dl,bl ! call prnum call crlf jmp getnxtcmd notprinter: ; check for '$include' option mov si,offset parseresult ! inc si mov di,offset includecmd push ds ! pop es mov cx,4 ! repz cmpsw jnz notinclude mov si,offset parseresult mov di,parseret ! test di,di jz notinclude call parsefilename ; CX = 0 if ok cmp cx,0 ! jne includerr; no tail mov si,pdadr add si,p_name mov di,offset clicmd mov cl,4 push ds ! pop es push ds ! mov ds,sysdatseg ; overwrite $include with rep movsw ; name of this program ; for recursive submits pop ds mov dx,offset includemsg call con_write jmps clicall ; send submit command includerr: mov dx,offset includerrmsg call con_write jmp submitexit notinclude: notbuiltin: ;======= clicall: ; SEND CLI COMMAND ;======= ; initialize Cli Control Block mov clicb_net,0 ; make cli call mov cmdsent,true lea dx,clicb ! mov cl,mpm_clicmd call mpm cmp bx,0 ! jne clierror ; ; more commands in sub file to process ? ; getnxtcmd: mov cmdbuf,maxcmdlen ! mov dx,offset cmdbuf call readbuffer ;read from file to next crlf cmp bx,0 ! je moretodo ;assume EOF if BX <> 0 jmp submitexit moretodo: mov cl,mpm_conattach ! call mpm jmp topofcmdloop ;======== clierror: ;======== ; Cli call unsuccesful, analyze and display error message ; input: CX = ERROR CODE ;null command? cmp cx,e_nullcmd ! jne not_nullcmd mov cmdsent,false jmp getnxtcmd not_nullcmd: ;no memory? cmp cx,e_no_memory ! jne memory_ok mov dx,offset memerr ! jmp showerr memory_ok: ;no pd in table? cmp cx,e_no_pd ! jne pd_ok mov dx,offset pderr ! jmp showerr pd_ok: ;illegal command name? cmp cx,e_badfname ! je fname_bad cmp cx,e_badftype ! jne fname_ok fname_bad: mov dx,offset fnameerr ! jmp showerr fname_ok: ;bad load? cmp cx,e_bad_load ! je load_bad cmp cx,e_bad_read ! jne load_ok load_bad: mov dx,offset loaderr ! jmp showerr load_ok: ;bad open? cmp cx,e_bad_open ! jne open_ok mov dx,offset openerr ! jmp showerr open_ok: ;RSP que full? cmp cx,e_q_full ! jne que_ok mov dx,offset qfullerr ! jmp showerr que_ok: ;some other error... mov dx,offset catcherr ;jmp showerr ;======= showerr: ;======= ; Print Error String ; input: DX = address of Error String call conwrite jmp submitexit ;========== readbuffer: ;========== ; Simulate Read Console buffer from a disk file. ; input: DX = buffer address ; output: BX <> 0 if EOF mov di,dx xor al,al mov 1[di],al ;no chars read cmp 0[di],al ;zero length buffer jnz buf_ok ;return no error - nop mov bx,0ffffh ret buf_ok: mov si,di ! inc si ! inc si ;si is next char read_another: mov al,1[di] cmp al,[di] jae done_ok ;full buffer push di call readchar ;fills [si] pop di cmp bx,0 ;non-zero or eof error jz not_error ret not_error: cmp byte ptr [si],0ah ! jne not_lf jmps done_ok not_lf: cmp byte ptr [si],0dh ! je done_ok inc byte ptr 1[di] ;not cr, inc buffer count inc si ;inc char position jmp read_another done_ok: cmp byte ptr 1[di],0 ;no characters read in buffer jz read_another ;skip leading cr's and lf's mov byte ptr [si],0 mov bx,0 ! ret ;======== readchar: ;======== ; Read a character from file. ; input = si is address of where to put character ; output = bx <> 0 if error ; xor bh,bh mov bl,buf_ptr ;char ptr in dma buffer cmp bl,128 jb no_read push si mov dl,command_user ;user of command file mov cl,mpm_usercode call mpm mov bx,offset fcb mov al,command_disk ;disk drive number of command file mov [bx],al ;re-open each time to allow deletion or byte ptr mode2[bx],80h ;of command file, open in R/O mode mov dx,bx call openfile cmp al,0ffh jz readerr mov dx,offset fcb call readfile ;read sequential cmp al,0 jnz readerr mov cl,mpm_usercode ;set user back to what the command mov dl,defuser ;file has set it to call mpm mov bx,0 pop si no_read: mov al,dma[bx] cmp al,1ah ;check for EOF jz eof mov [si],al inc bl mov buf_ptr,bl ;point to next char in disk buffer xor bx,bx ret readerr: pop si eof: mov bx,0ffffh ;error or eof ret ;***************************************************** ;* ;* SUBROUTINES ;* ;***************************************************** parsefilename: ;SI = fcb DI = string mov cx,mpm_parse mov bx,offset pcb mov [bx],di ! mov 2[bx],si mov dx,bx ! jmp mpm a_to_b: ;dl = 1st char, dh = 2nd char cmp dh,' ' ! jne atob2char mov dh,dl ! mov dl,'0' atob2char: cmp dh,'0' ! jb atoberr cmp dh,'9' ! ja atoberr cmp dl,'0' ! jb atoberr cmp dl,'9' ! ja atoberr sub dh,'0' ! sub dl,'0' mov ax,0 ! mov al,dl push dx ! mov cl,10 ! mul cl ! pop dx mov dl,dh ! mov dh,0 ! add ax,dx mov bx,ax ! ret atoberr: mov bl,0ffh ! ret prnum: ; dl = num (0-15) cmp dl,10 ! jb prnum_one push dx mov dl,'1' ! call prchar pop dx ! sub dl,10 prnum_one: add dl,'0' jmp prchar charin: mov cl,mpm_conin ! jmp mpm prchar: mov cl,mpm_conout ! jmp mpm getuser: mov dl,0ffh setuser: mov cl,mpm_usercode ! jmp mpm setconsole: mov cl,mpm_setdefcon ! jmp mpm setdisk: mov cl,mpm_diskselect ! jmp mpm getdisk: mov cl,mpm_getdefdisk ! jmp mpm setlist: mov cl,mpm_setdeflst ! jmp mpm getlist: mov cl,mpm_getdeflst ! jmp mpm attach: mov cl,mpm_conattach ! jmp mpm detach: mov cl,mpm_condetach ! jmp mpm conread: mov cl,mpm_conread ! jmp mpm crlf: mov dx,offset newline ;jmp con_write con_write: mov cl,mpm_conwrite jmp mpm openfile: mov cl,mpm_openfile jmp mpm readfile: mov cl,mpm_readfile jmp mpm ;***************************************************** ;* ;* Data Area ;* ;***************************************************** dseg org 05cH fcb rb 024H org 080h cmdtail rb 128 stack dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch dw 0cccch,0cccch,0cccch stacktop rw 0 maxcmdlen equ 128 ; the Read Console Buffer and the ; Cli Control Block share the same memory dma rb 128 numargs rw 1 argtable rb 64 ;address of arguments in cmdtail deblankbuf rb maxcmdlen + 1 cmdbuf rb 1 ;single command gets put here blen rb 1 cmd rb maxcmdlen + 1 clicb rb 0 ;command w/ expanded args goes here clicb_net db 0 clicmd rb maxcmdlen+1 command_user rb 1 command_disk rb 1 command_con rb 1 defdisk rb 1 defuser rb 1 buf_ptr db 128 ;force initial read ;in readchar routine prompt db 13 promptutens db '0' promptuones db '0' promptdisk db 'A' promptend db '>$' pcb dw offset clicmd dw offset parseresult parseret dw 0 parseresult rb 36 cmdsent db false pdadr rw 1 ;our pd address sysdatseg rw 1 ;the system data area's segment ;***************************************************** ;* ;* CONSTANTS ;* ;***************************************************** wrongvers db 'Requires MP/M-86' newline db 10,13,'$' askabortmsg db 13,10,10,'Terminate ' subfilename rb 11 db ' (Y/N) ? $' usercmd db 'USER ' printercmd db 'PRINTER ' includecmd db '$INCLUDE' usererrmsg db 13,10,'Invalid User Number, IGNORED',13,10,'$' usermsg db 13,10,'User Number = $' printererrmsg db 13,10,'Invalid Printer Number, IGNORED',13,10,'$' printermsg db 13,10,'Printer Number = $' includerrmsg db 13,10,'Include Error$' includemsg db '(submit)',10,13,'$' memerr db '?Not Enough Memory$' pderr db '?PD Table Full$' fnameerr db '?Illegal Command$' loaderr db '?Load Error$' openerr db '?Can''t Find Command$' catcherr db '?$' qfullerr db '?RSP Command Que Full$' ;SUBMIT error messages sopenerr db 'No ''SUB'' File Present$' argerr db 'Illegal Argument$' end