gno/bin/gsh/builtin.asm
tribby e586eeefeb Changes for gsh version 2.0d9:
Added additional optional debug code. A version of gsh with the memory
checking debug code turned on is available as an exe file.

Lock and unlock the hash mutual exclusion key in when disposing of the
hash table.

Allow five digits rather than four when printing the process number in
the ps command.

Piping the output of a command into a non-executable file no longer
causes gsh to hang.
1999-01-14 17:44:25 +00:00

1970 lines
33 KiB
NASM

************************************************************************
*
* The GNO Shell Project
*
* Developed by:
* Jawaid Bazyar
* Tim Meekins
*
* $Id: builtin.asm,v 1.10 1999/01/14 17:44:22 tribby Exp $
*
**************************************************************************
*
* BUILTIN.ASM
* By Tim Meekins
* Modified by Dave Tribby for GNO 2.0.6
*
* Builtin command searching and execution.
*
* Note: text set up for tabs at col 16, 22, 41, 49, 57, 65
* | | | | | |
* ^ ^ ^ ^ ^ ^
**************************************************************************
*
* Interfaces defined in this file:
*
* builtin subroutine (2:argc,4:argv)
* Returns completion status in Accumulator
*
* IsBuiltin subroutine (4:name)
* return 2:tbl
*
* Remainder are interfaces to builtin commands with interface
* subroutine (4:argv,2:argc)
* returns status in accumulator
* cd (chdir is entry as an alternate name)
* clear
* echo
* pwd
* which
* prefix
* rehash (unhash is entry as an alternate name)
* exit
* setdebug
* psbi (command name is "ps")
* hashbi (command name is "hash")
* source
* cmdbi (command name is "commands")
*
**************************************************************************
mcopy /obj/gno/bin/gsh/builtin.mac
dummybuiltin start ; ends up in .root
end
setcom 60
p_next gequ 0 ;next in global proclist
p_friends gequ p_next+4 ;next in job list
p_flags gequ p_friends+4 ;various job status flags
p_reason gequ p_flags+2 ;reason for entering this state
p_index gequ p_reason+2 ;job index
p_pid gequ p_index+2 ;process id
p_jobid gequ p_pid+2 ;process id of job leader
p_command gequ p_jobid+2 ;command (how job invoked)
p_space gequ p_command+4 ;space for structure
**************************************************************************
*
* Find and execute a builtin command
*
**************************************************************************
builtin START
using BuiltinData
val equ 1
file equ val+2
tbl equ file+4
space equ tbl+4
argv equ space+3
argc equ argv+4
end equ argc+2
; subroutine (2:argc,4:argv),space
tsc
sec
sbc #space-1
tcs
phd
tcd
ldy #2
lda [argv]
sta file
lda [argv],y
sta file+2
ld4 builtintbl,tbl
ld2 -1,val
lda argc
beq done
loop ldy #2
lda [tbl]
ora [tbl],y
beq done
lda [tbl],y
pha
lda [tbl]
pha
pei (file+2)
pei (file)
jsr cmpcstr
beq foundit
bpl done
add2 tbl,#10,tbl
bra loop
;
; Found the command handler address. Since we don't have a "jsl [tbl],y"
; instruction, after pushing parameters on the stack we will push the
; return address, then the command's address - 1 (2 bytes only, since it's
; in the current bank). An rts will take us to the command handler, and a
; rtl at the end of the handler will bring us back.
;
foundit anop
pei (argv+2) Push parameters (3 words)
pei (argv)
pei (argc)
phk Push return address (high byte)
per return-1 Push return address (low bytes)
ldy #4 Get address of builtin handler
lda [tbl],y (16 bytes; assume in this bank)
dec a subtract 1 so rts will take us there
pha
rts Go to builtin handler routine.
;
; Return from handler to this location
;
return sta val Save return status.
;
; Free the argv array
;
ph4 #0 (no path)
pei (argc)
pei (argv+2)
pei (argv)
jsl argfree
done ldy val Y-reg = return value.
lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
tya Accumulator = return value.
rtl
END
**************************************************************************
*
* Is it a built-in?
*
* Return value is: -1 if not a built-in, 0 if forked built-in,
* 1 if non-forked built-in.
*
**************************************************************************
IsBuiltin START
using BuiltinData
tbl equ 0
space equ tbl+4
subroutine (4:name),space
ld4 builtintbl,tbl
builtinloop ldy #2
lda [tbl]
ora [tbl],y
beq nofile
lda [tbl],y
pha
lda [tbl]
pha
pei (name+2)
pei (name)
jsr cmpcstr
beq foundit
bpl nofile
add2 tbl,#10,tbl
bra builtinloop
foundit ldy #8 Get the fork/nofork flag
lda [tbl],y and use it as return value.
bra foundbuiltin
nofile lda #-1 Set not-found return value.
foundbuiltin sta tbl
return 2:tbl
END
**************************************************************************
*
* Builtin data
*
**************************************************************************
BuiltinData DATA
;
; First address is a pointer to the name, the second is a pointer to the
; command. Third value is fork flag (0 to fork, 1 for no fork).
; TABLE MUST BE SORTED BY COMMAND NAME.
;
builtintbl dc a4'aliasname,alias',i2'0'
dc a4'bgname,bg',i2'1'
dc a4'bindkeyname,bindkey',i2'0'
dc a4'cdname,cd',i2'1'
dc a4'chdirname,chdir',i2'1'
dc a4'clearname,clear',i2'1' Changed to unforked
dc a4'cmdname,cmdbi',i2'0'
dc a4'dirsname,dirs',i2'0'
dc a4'echoname,echo',i2'0'
dc a4'editname,edit',i2'1'
dc a4'exitname,exit',i2'1'
dc a4'exportname,export',i2'1'
dc a4'fgname,fg',i2'1'
dc a4'hashname,hashbi',i2'0'
dc a4'hname,PrintHistory',i2'0'
dc a4'jobsname,jobs',i2'1'
dc a4'killname,kill',i2'1'
dc a4'popdname,popd',i2'1'
dc a4'pfxname,prefix',i2'1'
dc a4'psname,psbi',i2'0'
dc a4'pushdname,pushd',i2'1'
dc a4'pwdname,pwd',i2'1'
dc a4'rehashname,rehash',i2'1'
dc a4'setname,set',i2'0'
dc a4'setbugname,setdebug',i2'0'
dc a4'setenvname,setenv',i2'0'
dc a4'sourcename,source',i2'1' Changed to unforked
dc a4'stopname,stop',i2'1'
dc a4'tsetname,tset',i2'1'
dc a4'unaliasname,unalias',i2'1'
dc a4'unhashname,unhash',i2'1'
dc a4'unsetname,unset',i2'1'
dc a4'whichname,which',i2'0'
dc i4'0,0'
aliasname dc c'alias',h'00'
bgname dc c'bg',h'00'
bindkeyname dc c'bindkey',h'00'
chdirname dc c'chdir',h'00'
cdname dc c'cd',h'00'
clearname dc c'clear',h'00'
cmdname dc c'commands',h'00'
dirsname dc c'dirs',h'00'
echoname dc c'echo',h'00'
editname dc c'edit',h'00'
exitname dc c'exit',h'00'
exportname dc c'export',h'00'
fgname dc c'fg',h'00'
hashname dc c'hash',h'00'
hname dc c'history',h'00'
jobsname dc c'jobs',h'00'
killname dc c'kill',h'00'
pfxname dc c'prefix',h'00'
popdname dc c'popd',h'00'
psname dc c'ps',h'00'
pushdname dc c'pushd',h'00'
pwdname dc c'pwd',h'00'
rehashname dc c'rehash',h'00'
setbugname dc c'setdebug',h'00'
setname dc c'set',h'00'
setenvname dc c'setenv',h'00'
sourcename dc c'source',h'00'
stopname dc c'stop',h'00'
tsetname dc c'tset',h'00'
unaliasname dc c'unalias',h'00'
unhashname dc c'unhash',h'00'
unsetname dc c'unset',h'00'
whichname dc c'which',h'00'
END
**************************************************************************
*
* CD: builtin command
* syntax: cd [pathname]
*
* Changes the current prefix to pathname. If no pathname then set to $HOME
*
**************************************************************************
cd START
chdir ENTRY
dpg equ 1 Direct page pointer.
buf equ dpg+4 Buffer address to be freed.
status equ buf+4 Status returned from command.
space equ status+2
argc equ space+3
argv equ argc+2
end equ argv+4
; subroutine (4:argv,2:argc),space
tsc
sec
sbc #space-1
tcs
phd
tcd
lock cdmutex
stz buf Clear the pointer to
stz buf+2 allocated buffer.
stz status Assume good status.
lda argc Number of parameters
dec a determines type of cd...
beq cdhome either to $HOME
dec a or to the directory
jeq paramcd on the command line.
;
; Illegal parameters: print usage string
;
showusage inc status Return status = 1.
lda [argv]
tax
ldy #2
lda [argv],y
stx argv
sta argv+2
lda [argv],y
and #$FF
beq cdusage
ldx #^Usage2 Print chdir usage
lda #Usage2
jsr errputs
jmp exit
cdusage ldx #^Usage Print cd usage
lda #Usage
jsr errputs
jmp exit
;
; Set prefix to $home
;
cdhome anop
ph4 #home Get value of $HOME
jsl getenv
sta buf If GS/OS result buffer
stx buf+2 wasn't allocated,
ora buf+2
jeq exit there's no more to do.
clc Calculate address
lda buf of GS/OS input string
adc #2 (2 bytes from start of
sta PRecPath result buffer).
sta GRecPath
lda buf+2
adc #0
sta PRecPath+2
sta GRecPath+2
bra getinfo
;
; Set prefix to path specified on command line
;
paramcd anop
ldy #4
lda [argv],y
sta dpg
iny2
lda [argv],y
sta dpg+2
lda [dpg]
and #$FF
if2 @a,ne,#'-',setprefix
jmp showusage
setprefix pei (dpg+2)
pei (dpg)
jsr c2gsstr
sta PRecPath
sta GRecPath
sta buf
stx PRecPath+2
stx GRecPath+2
stx buf+2
;
; Get file information to determine whether target is a valid directory
;
getinfo GetFileInfo GRec
bcc ok
ohshit sta ErrError
ErrorGS Err
inc status Return status = 1.
bra done
ok if2 GRecFT,eq,#$F,ok2
ldx dpg+2
lda dpg
jsr errputs
ldx #^direrr
lda #direrr
jsr errputs
inc status Return status = 1.
bra done
;
; Everything looks OK. Set prefix 0 to the indicated value
;
ok2 SetPrefix PRec
bcs ohshit
;
; Deallocate buffer (if necessary), unlock mutex, cleanup stack, and leave
;
done ph4 buf
jsl nullfree
exit unlock cdmutex
ldy status Put return status in Y-reg
lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
tya Put return status in Accumulator.
rtl
cdmutex key Mutual exclusion key
; Parameter block for GS/OS SetPrefix call
PRec dc i'2' pCount
dc i'0' prefixNum (0 = current directory)
PRecPath ds 4 Pointer to input prefix path
; Parameter block for GS/OS GetFileInfo call
GRec dc i'3' pCount
GRecPath ds 4 Pointer to input pathname
GRecAcc ds 2 access (result)
GRecFT ds 2 fileType (result)
home gsstr 'home' Env variable name
; Parameter block for shell ErrorGS call (p 393 in ORCA/M manual)
Err dc i2'1' pCount
ErrError ds 2 Error number
Usage dc c'Usage: cd [pathname]',h'0d00'
Usage2 dc c'Usage: chdir [pathname]',h'0d00'
dirErr dc c': Not a directory',h'0d00'
END
**************************************************************************
*
* CLEAR: builtin command
* syntax: clear
*
* clears the screen
*
**************************************************************************
clear START
space equ 1
argc equ space+3
argv equ argc+2
end equ argv+4
; subroutine (4:argv,2:argc),space
tsc
phd
tcd
lda argc
dec a
beq clearit
ldx #^Usage
lda #Usage
jsr errputs
ldy #1 Return status = 1.
bra exit
clearit jsr clearscrn
jsr flush
ldy #0 Return status = 0.
exit lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
tya
rtl
Usage dc c'Usage: clear',h'0d00'
END
**************************************************************************
*
* ECHO: builtin command
* syntax: echo [-n] [text][...]
*
* Echo displays to stdout what is on the command (except -n).
*
* If '-n' specified then don't print newline.
*
**************************************************************************
echo START
val equ 1
nl equ val+2 flag: was -n option set?
ptr equ nl+2
status equ ptr+4
space equ status+2
argc equ space+3
argv equ argc+2
end equ argv+4
; subroutine (4:argv,2:argc),space
* Add space on stack for local variables
tsc
sec
sbc #space-1
tcs
phd
tcd
stz status Clear return status.
stz nl Clear the -n flag.
dec argc Decrement argument counter.
jeq done Done if no more arguments.
ldy #4
lda [argv],y Set ptr to
sta ptr point to the
iny2 text of the
lda [argv],y first
sta ptr+2 argument.
ldy #1
lda [ptr] Get first
and #$FF character.
if2 @a,ne,#'-',loop If != '-', handle as regular param.
; First argument begins with "-"; only legal value is -n
lda [ptr],y Get second
and #$FF character.
if2 @a,eq,#'n',gotn If != 'n', it's a bad one.
showusage ldx #^Usage Incorrect parameter usage:
lda #Usage display the usage string.
jsr errputs
inc status Return status = 1.
jmp exit
gotn iny
lda [ptr],y Get third
and #$FF character.
bne showusage If != 0, it's a bad one.
inc nl Set the -n flag.
add2 argv,#4,argv Bump argument pointer.
dec argc Decrement argument counter.
jeq done Done if no more arguments.
;
; Beginning of main processing loop of echo parameters.
;
loop add2 argv,#4,argv Bump argument pointer.
ldy #2
lda [argv],y Set ptr to argv (next argument)
sta ptr+2
lda [argv]
sta ptr
putloop lda [ptr] Get first
and #$FF character.
cmp #0 If 0,
jeq doneput done with this argument.
cmp #'\' If != "\"
jne putit go save in print buffer.
incad ptr Escape character found; point
lda [ptr] to the next
and #$FF character.
beq doneput If 0, done with this argument.
if2 @a,ne,#'b',esc02 Check for escape codes: "b"
ldx #1
jsr moveleft moveleft
bra didit
esc02 if2 @a,ne,#'f',esc03 "f"
jsr clearscrn clearscreen
bra didit
esc03 if2 @a,ne,#'n',esc04 "n"
lda #13 print newline
bra putit
esc04 if2 @a,ne,#'r',esc05 "r"
lda #13 print newline
bra putit
esc05 if2 @a,ne,#'t',esc06 "t"
lda #9 print tab
bra putit
esc06 if2 @a,ne,#'0',putit "0"
stz val decode numeric value
ldy #1
escloop lda [ptr],y
and #$FF
beq putval
if2 @a,cc,#'0',putval
if2 @a,cs,#'9'+1,putval
sub2 @a,#'0',@a
pha
lda val
asl2 a
adc val
asl a
adc 1,s
sta val
pla
incad ptr
bra escloop
putval lda val Get numeric escape code.
putit jsr putchar Save character in accumulator.
didit incad ptr Point to next char in arg
jmp putloop and go process it.
doneput dec argc Decrement argument counter.
beq done Done if no more arguments.
bmi done (or if there were no arguments!)
lda #' ' Add a blank
jsr putchar between arguments.
jmp loop Get next argument.
done lda nl If "-n" flag isn't set,
bne exit
jsr newline add a newline.
exit jsr flush Print the buffer.
ldy status
* Clear parameters from stack and return from subroutine.
lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
tya
rtl
Usage dc c'Usage: echo [-n] [strings...]',h'0d00'
END
**************************************************************************
*
* PWD: builtin command
* syntax: pwd
*
* print the working directory.
*
**************************************************************************
pwd START
ptr equ 1
space equ ptr+4
argc equ space+3
argv equ argc+2
end equ argv+4
; subroutine (4:argv,2:argc),space
tsc
sec
sbc #space-1
tcs
phd
tcd
dec argc If an argument was provided,
beq wait
ldx #^Usage print the usage string.
lda #Usage
jsr errputs
ldy #1 Return status = 1.
bra exit
wait pea 0
jsl getpfxstr Get value of prefix 0.
sta ptr
stx ptr+2
ora ptr+2 If NULL pointer returned,
beq done an error was reported.
ldy #2 If length of returned
lda [ptr],y GS/OS string is 0,
beq freebuf an error was reported.
lda ptr X/A = address of
clc text (four bytes
adc #4 beyond start).
bcc doputs
inx
doputs jsr puts Print the c-string
jsr newline and add a newline.
freebuf ph4 ptr Free the buffer.
jsl nullfree
done ldy #0 Return status = 0.
exit lda space Deallocate stack space
sta end-3 and return to the caller.
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
tya Return status.
rtl
Usage dc c'Usage: pwd',h'0d00'
END
**************************************************************************
*
* WHICH: builtin command
* syntax: which [command ...]
*
* displays the location of command
*
**************************************************************************
which START
using hashdata
ptr equ 1
sptr equ ptr+4
file equ sptr+4
status equ file+4
space equ status+2
argc equ space+3
argv equ argc+2
end equ argv+4
; subroutine (4:argv,2:argc),space
tsc
sec
sbc #space-1
tcs
phd
tcd
stz status Clear return status.
;
; Display usage if no argument
;
if2 argc,ge,#2,loop
ldx #^whicherr
lda #whicherr
jsr errputs
inc status Return status = 1
jmp exit
;
; loop through each argument
;
loop add2 argv,#4,argv
dec argc
jeq exit
lda [argv]
sta file
ldy #2
lda [argv],y
sta file+2
;
; see if it's an alias
;
pei (file+2)
pei (file)
jsl findalias
sta ptr
stx ptr+2
ora ptr+2
beq chkbuiltin
ldx #^aliasstr
lda #aliasstr
jsr puts
ldx ptr+2
lda ptr
jsr puts
jmp nextarg
;
; was it a built-in?
;
chkbuiltin pei (file+2)
pei (file)
jsl IsBuiltin
cmp #-1
beq tryhash
foundbuiltin ldx #^builtstr
lda #builtstr
jsr puts
jmp nextarg
;
; See if it was hashed
;
tryhash pei (file+2)
pei (file)
ph4 hash_table
ph4 #hash_paths
jsl search
cmp #0
bne foundhash
cpx #0
beq thispfx
;
; It was hashed, so say so.
;
foundhash sta sptr
stx sptr+2
jsr puts
pei (sptr+2) Free memory allocated
pei (sptr) by search to hold full path.
jsl nullfree
jmp nextarg
;
; It must be in the current prefix, so check it out.
;
thispfx lock whichmutex
;
; check for existence of file
;
pei (file+2)
pei (file)
jsr c2gsstr
sta GRecPath
stx GRecPath+2
sta ptr
stx ptr+2
GetFileInfo GRec
bcs nofile
;
; we found the file, so display the cwd
;
showcwd pei (ptr+2)
pei (ptr)
jsl nullfree
pea 0
jsl getpfxstr Get value of prefix 0.
sta ptr
stx ptr+2
ora ptr+2 If NULL pointer returned,
beq donecwd an error was reported.
ldy #2 If length of returned
lda [ptr],y GS/OS string is 0,
beq freebuf an error was reported.
lda ptr X/A = address of
clc text (four bytes
adc #4 beyond start).
bcc doputs
inx
doputs jsr puts Print the directory name.
ldx file+2 Print the file name.
lda file
jsr puts
freebuf ph4 ptr Free the buffer.
jsl nullfree
stz ptr
stz ptr+2
bra donecwd
;
; No such command
;
nofile ldx #^cantdoit
lda #cantdoit
jsr puts
donecwd unlock whichmutex
pei (ptr+2)
pei (ptr)
jsl nullfree
;
; Go try the next file.
;
nextarg jsr newline
jmp loop
exit ldy status
lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
tya
rtl
whicherr dc c'Usage: which [file ...]',h'0d00'
builtstr dc c'Shell Built-in Command',h'00'
cantdoit dc c'Command Not Found',h'00'
aliasstr dc c'Aliased as ',h'00'
whichmutex key
GRec dc i'4'
GRecPath ds 4
ds 2
GRecFileType ds 2
GRecAuxType ds 4
END
**************************************************************************
*
* PREFIX: builtin command
* syntax: prefix [num [prefix]]
*
* sets prefix number num to prefix or print list of all prefixes
*
**************************************************************************
prefix START
dir equ 1
numstr equ dir+4
pfxnum equ numstr+4
status equ pfxnum+2
space equ status+2
argc equ space+3
argv equ argc+2
end equ argv+4
; subroutine (4:argv,2:argc),space
tsc
sec
sbc #space-1
tcs
phd
tcd
lock prefixmutex
stz status Clear return status.
lda argc Get number of arguments.
dec a
beq showall If no parameters, show all prefixes.
dec a
jeq showone If one, show one.
dec a
jeq setprefix If two, set a prefix.
ldx #^usage
lda #usage
jsr errputs
jmp badstat
; -------------------------------------------------------------------
;
; No parameters provided: show all the prefixes
;
showall anop
lda #$FFFF
sta pfxnum First prefix # will be 0.
pha Get the boot volume string.
jsl getpfxstr
sta dir
stx dir+2
ora dir+2 If NULL pointer returned,
beq bumppfx an error was reported.
ldx #^bootstr
lda #bootstr
bra printid Jump into the loop
allloop lda pfxnum
pha
jsl getpfxstr
sta dir
stx dir+2
ora dir+2 If NULL pointer returned,
beq bumppfx an error was reported.
ldy #2 Get length word.
lda [dir],y
beq nextall If zero, do the next prefix.
Int2Dec (pfxnum,#pfxstr,#2,#0)
ldx #^pfxstr
lda #pfxstr
printid jsr puts
ldx dir+2
lda dir X/A = address of
clc text (four bytes
adc #4 beyond start).
bcc doputs2
inx
doputs2 jsr puts Print the directory name
jsr newline
nextall ph4 dir Free the GS/OS result buffer
jsl nullfree allocated for pathname.
bumppfx inc pfxnum Bump the prefix number.
if2 pfxnum,cc,#32,allloop
jmp done
; -------------------------------------------------------------------
;
; One parameter provided: show a single prefix
;
showone ldy #1*4+2 Put pointer to
lda [argv],y first command
sta numstr+2 argument in
pha numstr, and
dey2 also on stack
lda [argv],y as parameter.
sta numstr
pha
jsr cstrlen Get length of argument.
tax
Dec2Int (numstr,@x,#0),@a Convert to integer.
cmp #32 If prefix num >= 32,
bcc getpfx
jsr newline just print blank line.
jmp done
getpfx pha Get that prefix value.
jsl getpfxstr
sta dir
stx dir+2
ora dir+2 If NULL pointer returned,
jeq done an error was reported.
Int2Dec (pfxnum,#pfxstr,#2,#0)
ldy #2 Get length word.
lda [dir],y
beq donewline If zero, just print newline.
ldx dir+2
lda dir X/A = address of
clc text (four bytes
adc #4 beyond start).
bcc doputs3
inx
doputs3 jsr puts Print the directory name
donewline jsr newline
ph4 dir Free the GS/OS result buffer
jsl nullfree allocated for pathname.
jmp done
; -------------------------------------------------------------------
;
; Two parameters provided: set a prefix
;
setprefix ldy #1*4+2 Put pointer to
lda [argv],y first command
sta numstr+2 argument (prefix
pha num) in numstr, and
dey2 also on stack
lda [argv],y as parameter.
sta numstr
pha
jsr cstrlen Get length of argument.
tax
Dec2Int (numstr,@x,#0),PRecNum Convert to integer string.
lda PRecNum
cmp #32 If prefix num >= 32,
bcs done nothing to do.
ldy #2*4+2 Put pointer to
lda [argv],y second command
pha argument (value)
dey2 on stack as parameter.
lda [argv],y
pha
jsr c2gsstr Convert to GS string.
sta GRecPath Store in GetFileInfo
stx GRecPath+2 parameter block and
sta PRecPath SetPrefix p.b.
stx PRecPath+2
;
; Get file information to determine whether target is a valid directory
;
GetFileInfo GRec
bcc ok
sta ErrError
ErrorGS Err
bra done
ok if2 GRecFT,eq,#$F,ok2 If filetype != $F,
ldx #^direrr print error message
lda #direrr 'Not a directory'
jsr errputs
badstat inc status Return status = 1.
bra done
ok2 SetPrefix PRec Set the prefix.
bcc finish If error flag set,
ldx #^errorstr print error message
lda #errorstr 'could not set prefix,
jsr errputs pathname may not exist.'
inc status Return status = 1.
; -------------------------------------------------------------------
;
; All done: cleanup and return
;
finish ph4 PRecPath Free the name string buffer.
jsl nullfree
;
; Exit through here if PRecPath wasn't used
;
done unlock prefixmutex
ldy status
lda space
sta end-3
lda space+1
sta end-2
pld
tsc
clc
adc #end-4
tcs
tya
rtl
prefixmutex key
errorstr dc c'prefix: could not set prefix, pathname may not exist.'
dc h'0d00'
usage dc c'Usage: prefix prefixnum prefixname',h'0d00'
bootstr dc c' *: ',h'00'
pfxstr dc c'00: ',h'00'
dirErr dc c'prefix: Not a directory',h'0d00'
;
; Parameter block for GS/OS GetFileInfo call
;
GRec dc i'3' pCount
GRecPath ds 4 Pointer to input pathname
GRecAcc ds 2 access (result)
GRecFT ds 2 fileType (result)
;
; Parameter buffer for SetPrefix GS/OS call
;
PRec dc i'2' pCount
PRecNum dc i'0' prefix number
PRecPath ds 4 pointer to GS/OS string with value
;
; Parameter block for shell ErrorGS call (p 393 in ORCA/M manual)
;
Err dc i2'1' pCount
ErrError ds 2 Error number
END
**************************************************************************
*
* REHASH: builtin command
* syntax: rehash
*
* rehashes the path
*
**************************************************************************
*
* UNHASH: builtin command
* syntax: unhash
*
* turns off command hashing
*
**************************************************************************
rehash START
unhash ENTRY
status equ 0
space equ status+2
subroutine (4:argv,2:argc),space
stz status
lda argc
dec a
beq doit
ldx #^Usage
lda #Usage
jsr errputs
ldy #2
lda [argv],y
tax
lda [argv]
jsr errputs
lda #13
jsr errputchar
inc status Return status = 1.
bra exit
doit jsr dispose_hash ;remove old table
lda [argv]
tax
ldy #2
lda [argv],y
sta argv+2
stx argv
lda [argv]
and #$FF
jsr tolower
if2 @a,eq,#'u',exit ;if 'rehash' do the hashing.
jsl hashpath ;hash the path
exit return 2:status
Usage dc c'Usage: ',h'00'
END
**************************************************************************
*
* EXIT: builtin command
* syntax: exit
*
* exit gsh
*
**************************************************************************
exit START
using global
space equ 0
subroutine (4:argv,2:argc),space
inc exit_requested
return 2:#0
END
**************************************************************************
*
* SETDEBUG: builtin command
* syntax: setdebug (val | [+|-]flag)
*
* sets debugging in kernel
*
**************************************************************************
setdebug START
arg equ 0
newdebug equ arg+4
mode equ newdebug+2
status equ mode+2
space equ status+2
subroutine (4:argv,2:argc),space
stz status
lda argc
dec a
bne ok
showusage ldx #^usage
lda #usage
jsr errputs
inc status Return status = 1.
jmp return
ok stz mode
mv2 globaldebug,newdebug
dec argc
add2 argv,#4,argv
loop lda [argv]
sta arg
ldy #2
lda [argv],y
sta arg+2
lda [arg]
and #$FF
if2 @a,eq,#'-',turnoff
if2 @a,eq,#'+',turnon
ldx mode
bne showusage
ldx argc
dex
bne showusage
if2 @a,cc,#'0',showusage
if2 @a,cs,#'9'+1,showusage
pei (arg+2)
pei (arg)
jsr cstrlen
tax
Dec2Int (arg,@x,#0),@a
sta newdebug
jmp done
turnoff jsr findflag
eor #$FFFF
and newdebug
bra turnnext
turnon jsr findflag
ora newdebug
turnnext sta newdebug
ld2 1,mode
add2 argv,#4,argv
dec argc
beq done
jmp loop
done setdebug newdebug
mv2 newdebug,globaldebug
return return 2:status
findflag incad arg
ldy #0
findloop phy
lda nametbl,y
ora nametbl+2,y
beq nofind
lda nametbl+2,y
pha
lda nametbl,y
pha
pei (arg+2)
pei (arg)
jsr cmpcstr
beq foundit
pla
add2 @a,#4,@y
bra findloop
foundit pla
lsr a
tax
lda bittbl,x
rts
nofind pla
ldx arg+2
lda arg
jsr errputs
ldx #^errstr
lda #errstr
jsr errputs
lda #-1
pla ;rts address
jmp showusage
usage dc c'Usage: setdebug (value | [+|-]flag ... )',h'0d0d'
dc c'Flags: gsostrace - Trace GS/OS calls',h'0d'
dc c' gsosblocks - Trace GS/OS parameter blocks',h'0d'
dc c' gsoserrors - Trace GS/OS errors',h'0d'
dc c' pathtrace - Trace GS/OS pathnames',h'0d'
dc c' sigtrace - Trace signals',h'0d'
dc c' systrace - Trace system calls',h'0d'
* >> Next line is temporary
dc c' breakpoint - Coded brk instructions',h'0d'
dc h'00'
errstr dc c': Unknown flag',h'0d0d00'
nametbl dc a4'str01,str02,str03,str04,str05,str06,str07,0'
str01 dc c'gsostrace',h'00'
str02 dc c'pathtrace',h'00'
str03 dc c'gsoserrors',h'00'
str04 dc c'sigtrace',h'00'
str05 dc c'systrace',h'00'
str06 dc c'gsosblocks',h'00'
* >> Next line is temporary; Also: remove str07 in nametbl
str07 dc c'breakpoint',h'00'
bittbl dc i2'%000001'
dc i2'%000010'
dc i2'%000100'
dc i2'%001000'
dc i2'%010000'
dc i2'%100000'
* >> Next line is temporary
dc i2'%10000000'
* >> Next line is temporary
check4debug ENTRY
globaldebug dc i2'0'
END
**************************************************************************
*
* PS: builtin command
* syntax: ps
*
* display process status
*
**************************************************************************
psbi START
using pdata
myuid equ 0
t equ myuid+2
ps2 equ t+4
pr2 equ ps2+4
pr equ pr2+4
ps equ pr+4
status equ ps+4
space equ status+2
subroutine (4:argv,2:argc),space
stz status
lda argc
dec a
beq ok
showusage ldx #^usage
lda #usage
jsr errputs
inc status Return status = 1.
jmp return
ok getuid
sta myuid
kvm_open
sta ps
stx ps+2
ora2 @a,ps+2,@a
bne ok2
ldx #^kvmerrstr
lda #kvmerrstr
jsr errputs
inc status Return status = 1.
jmp done
ok2 ldx #^header
lda #header
jsr puts
loop kvmnextproc ps
sta pr
stx pr+2
ora2 @a,pr+2,@a
jeq done
ldy #94 ;ps->p_uid
lda [pr],y
cmp myuid
jne skip
ldy #2
lda [ps],y ;ps->pid
Int2Dec (@a,#pidstr,#5,#0)
ldx #^pidstr
lda #pidstr
jsr puts
ldy #2
lda [pr],y ;pr->processState
cmp #9
bcc okstate
lda #9
okstate asl a
asl a
asl a
tax
ldy #8
putstate lda statetbl,x
phx
phy
jsr putchar
ply
plx
inx
dey
bne putstate
ldy #6
lda [pr],y ;pr->ttyID
beq ttnul
cmp #3
bne ttnum
lda #'c'
jsr putchar
lda #'o'
bra showuser
ttnul lda #'n'
jsr putchar
lda #'u'
bra showuser
ttnum ldy #0
ttnumlup cmp #10
bcc ttnum0
sec
sbc #10
iny
bra ttnumlup
ttnum0 pha
tya
clc
adc #'0'
jsr putchar
pla
clc
adc #'0'
showuser jsr putchar
ldy #4
lda [pr],y ;pr->userID
Int2Hex (@a,#userstr+1,#4)
ldx #^userstr
lda #userstr
jsr puts
ldy #94
lda [pr],y ;pr->puid
Int2Hex (@a,#puidstr,#4)
ldx #^puidstr
lda #puidstr
jsr puts
ldy #50
lda [pr],y ;pr->ticks
tax
iny2
lda [pr],y
LongDivide (@ax,#60),(@ax,@yy)
LongDivide (@xa,#60),(t,@ax)
Long2Dec (@xa,#timestr+4,#2,#0)
Long2Dec (t,#timestr,#3,#0)
lda timestr+4
and #$FF
cmp #' '
bne time0
short a
lda #'0'
sta timestr+4
long a
time0 ldx #^timestr
lda #timestr
jsr puts
ldy #34
lda [pr],y ;pr->args
tax
iny2
lda [pr],y
jne goodcmd
cpx #0
jne goodcmd
lda pjoblist ;check for name in job list
ldx pjoblist+2
jobloop sta pr2
stx pr2+2
ora pr2+2
beq childof
ldy #p_pid
lda [pr2],y
ldy #2
cmp [ps],y ;ps->pid
bne loop2
ldy #p_command+2
lda [pr2],y
tax
ldy #p_command
lda [pr2],y
jsr puts
bra next
loop2 ldy #p_next+2
lda [pr2],y
tax
ldy #p_next
lda [pr2],y
bra jobloop
childof ldx #^forkstr
lda #forkstr
jsr puts
kvm_open
sta ps2
stx ps2+2
lda [pr]
tay
kvmgetproc (ps2,@y)
sta pr2
stx pr2+2
kvm_close ps2
ldy #34
lda [pr2],y ;pr2->args
tax
iny2
lda [pr2],y
bne goodcmd
cpx #0
bne goodcmd
ldx #^forkstr2
lda #forkstr2
jsr puts
bra next
goodcmd tay
txa
tyx
clc
adc #8
jsr puts
next jsr newline
skip jmp loop
done kvm_close ps
return return 2:status
usage dc c'Usage: ps',h'0d00'
kvmerrstr dc c'ps: error in kvm_open()',h'0d00'
header dc c' ID STATE TT MMID UID TIME COMMAND',h'0d00'
pidstr dc c'00000 ',h'00'
userstr dc c' 0000 ',h'00'
puidstr dc c'0000 ',h'00'
timestr dc c'000:00 ',h'00'
forkstr dc c'forked child of ',h'00'
forkstr2 dc c'an unknown process',h'00'
test1 dc c'getuid = $'
test1a dc c'0000',h'0d00'
statetbl dc c'defunct '
dc c'running '
dc c'ready '
dc c'blocked '
dc c'ready '
dc c'suspend '
dc c'waiting '
dc c'waiting '
dc c'paused '
dc c'unknown '
END
**************************************************************************
*
* HASH: builtin command
* syntax: hash
*
* display hashed commands
*
**************************************************************************
hashbi START
using hashdata
sv equ 0
q equ sv+4
p equ q+4
status equ p+4
space equ status+2
subroutine (4:argv,2:argc),space
stz status
lda argc
dec a
beq dohash
ldx #^Usage
lda #Usage
jsr errputs
inc status Return status = 1.
bra exit
dohash ph2 t_size Get size of hash table.
jsl sv_alloc Allocate a string vector array.
sta sv
stx sv+2
lda hash_table If no hash table
ora hash_table+2 has been allocated,
beq exit exit.
mv4 hash_table,p Move address to dir pg variable.
lda hash_numexe Get the number of executable files.
beq doneadd Done if 0.
;
; loop through every hashed file and add it the string vector
;
ldy #0 Y is index into the next entry.
ldx t_size X is the number of entries left.
beq doneadd
addloop lda [p],y Get next hash table entry.
sta q
iny
iny
lda [p],y
sta q+2
iny
iny
ora q If this entry isn't used,
beq skip skip to the next one.
phy Hold the Y and X regs on stack.
phx
pei (sv+2) Insert string in table entry
pei (sv) into the string vector.
clc
lda q
adc #2 (Note: tn_name in hash.asm == 2)
tax
lda q+2
adc #0
pha
phx
pea 1 (allocflag: 1 = allocate memory)
jsl sv_add
plx Restore X and Y regs from stack.
ply
skip dex
bne addloop
;
; Files have all been added to the string vector
;
doneadd anop
pei (sv+2)
pei (sv)
jsl sv_sort Sort the string vector.
pei (sv+2)
pei (sv)
jsl sv_colprint Print the string vector in columns.
pei (sv+2)
pei (sv)
jsl sv_dispose Dispose of the string vector memory.
exit return 2:status
usage dc c'Usage: hash',h'0d00'
END
**************************************************************************
*
* SOURCE: builtin command
* syntax: source file [arguments...]
*
* executes a shell file w/o pushing environment
*
**************************************************************************
source START
retval equ 0
space equ retval+2
subroutine (4:argv,2:argc),space
dec argc If no filename was provided,
bne ok
ldx #^usage Print usage string.
lda #usage
jsr errputs
lda #1 Return error status.
sta retval
bra exit
ok stz retval
add2 argv,#4,argv
* ShellExec subroutine (4:path,2:argc,4:argv,2:jobflag)
ldy #2 path is filename argument
lda [argv],y
pha
lda [argv]
pha
pei (argc) reuse argc
pei (argv+2) reuse argv
pei (argv)
pea 0 jobflag = 0
jsl ShellExec
sta retval
exit return 2:retval
usage dc c'usage: source file [arguments...]',h'0d00'
END
**************************************************************************
*
* COMMANDS: builtin command
* syntax: commands
*
* display builtin commands
*
**************************************************************************
cmdbi START
using BuiltinData
sv equ 0
status equ sv+4
space equ status+2
subroutine (4:argv,2:argc),space
stz status
lda argc
dec a
beq docmds
ldx #^Usage
lda #Usage
jsr errputs
inc status Return status = 1.
bra exit
docmds ph2 #50
jsl sv_alloc
sta sv
stx sv+2
ldx #0
;
; loop through every hashed file and add it the string vector
;
addloop lda builtintbl,x
ora builtintbl+2,x
beq doneadd
phx
pei (sv+2)
pei (sv)
lda builtintbl+2,x
pha
lda builtintbl,x
pha
pea 1
jsl sv_add
pla
clc
adc #10
tax
bra addloop
doneadd anop
pei (sv+2)
pei (sv)
jsl sv_sort
pei (sv+2)
pei (sv)
jsl sv_colprint
pei (sv+2)
pei (sv)
jsl sv_dispose
exit return 2:status
usage dc c'Usage: commands',h'0d00'
END