mirror of
https://github.com/GnoConsortium/gno.git
synced 2024-12-22 14:30:29 +00:00
6269a8ca25
Fixed several mutual exclusion problems, including a particularly nasty one that would cause gsh to loop forever inside the memory manager. (You could identify this one by the "BRA (-23)" at the bottom of the infinite loop.) Fixed the string vector print routine to properly handle all numbers of entries in the hash table. Previously, it would always print duplicate entries if there were < 6 commands hashed, and would sometimes print duplicates (depending on previous contents of an internal table) for other numbers of commands. gsh would wait on background processes started from an exec file (executed, not sourced). Now the exec file does not wait on the process, but the background process is not associated with the parent shell after the exec file terminates. Made gsh globbing work more like csh: if none of the requested patterns are found, print "No match" and exit. At startup, if /etc/glogin, $HOME/glogin, or $HOME/gshrc does not exist, don't report a "file not found" error message. (PR#100)
1203 lines
21 KiB
NASM
1203 lines
21 KiB
NASM
**************************************************************************
|
|
*
|
|
* The GNO Shell Project
|
|
*
|
|
* Developed by:
|
|
* Jawaid Bazyar
|
|
* Tim Meekins
|
|
*
|
|
* $Id: hash.asm,v 1.8 1998/12/31 18:29:13 tribby Exp $
|
|
*
|
|
**************************************************************************
|
|
*
|
|
* HASH.ASM
|
|
* By Tim Meekins & Greg Thompson
|
|
* Modified by Dave Tribby for GNO 2.0.6
|
|
*
|
|
* Command hashing routines
|
|
*
|
|
* Note: text set up for tabs at col 16, 22, 41, 49, 57, 65
|
|
* | | | | | |
|
|
* ^ ^ ^ ^ ^ ^
|
|
**************************************************************************
|
|
*
|
|
* Interfaces defined in this file:
|
|
*
|
|
* hash jsr with params: (2:num, 4:name)
|
|
*
|
|
* dohash subroutine (4:files)
|
|
* return 4:table
|
|
*
|
|
* search subroutine (4:file,4:table,4:paths)
|
|
* return 4:full_path
|
|
*
|
|
* dispose_table subroutine (4:table)
|
|
* return
|
|
*
|
|
* free_files subroutine (4:files)
|
|
* return
|
|
*
|
|
* dir_search subroutine (4:dir,2:dirNum,4:files)
|
|
* return
|
|
*
|
|
* hashpath jsl with no parameters
|
|
* no returned value
|
|
*
|
|
* dispose_hash jsr with no parameters
|
|
* no returned value
|
|
*
|
|
**************************************************************************
|
|
|
|
mcopy /obj/gno/bin/gsh/hash.mac
|
|
|
|
dummyhash start ; ends up in .root
|
|
end
|
|
|
|
setcom 60
|
|
|
|
C1 gequ 11
|
|
C2 gequ 13
|
|
TAB_MULT gequ 4
|
|
|
|
;
|
|
; Structure for filenames
|
|
;
|
|
; struct filenode {
|
|
; short dirnum;
|
|
; char name[32];
|
|
; filenode *next;
|
|
; };
|
|
fn_dirNum gequ 0
|
|
fn_name gequ fn_dirNum+2
|
|
fn_next gequ fn_name+32
|
|
fn_size gequ fn_next+4
|
|
|
|
;
|
|
; Structure for hash table
|
|
;
|
|
; struct tablenode {
|
|
; short dirnum;
|
|
; char *name[32];
|
|
; };
|
|
tn_dirNum gequ 0
|
|
tn_name gequ tn_dirNum+2
|
|
tn_size gequ tn_name+32
|
|
|
|
**************************************************************************
|
|
*
|
|
* Calculate hash value for a filename
|
|
*
|
|
**************************************************************************
|
|
|
|
hash START
|
|
|
|
using hashdata
|
|
|
|
space equ 1
|
|
num equ space+2
|
|
name equ num+2
|
|
end equ name+4
|
|
|
|
* NOTE: hash should only be called after hashmutex is locked
|
|
|
|
;
|
|
; No local variables; just need to save old Dir Page pointer and set
|
|
; up new one to point to parameters.
|
|
;
|
|
tsc
|
|
phd
|
|
tcd
|
|
|
|
lda num If this isn't the first time
|
|
bne hasher through, reuse the value of "h".
|
|
|
|
;
|
|
; First time through for the name: calculate value for "h"
|
|
;
|
|
stz h
|
|
ldy #0
|
|
loop lda [name],y
|
|
and #$FF
|
|
beq hasher
|
|
sta addit+1 Modify "adc #$FFFF"
|
|
lda h ;left shift 7
|
|
xba
|
|
and #$FF00
|
|
lsr a
|
|
addit adc #$FFFF NOTE: immediate data was modified.
|
|
phy
|
|
UDivide (@a,t_size),(@a,@a)
|
|
sta h
|
|
ply
|
|
iny
|
|
bra loop
|
|
|
|
;
|
|
; "h" has been calculated; now do the rest of the hash function
|
|
;
|
|
hasher lda num ;num*num
|
|
sta tmp
|
|
lda #0
|
|
ldx #16
|
|
mulloop asl a
|
|
asl tmp
|
|
bcc nomul
|
|
clc
|
|
adc num
|
|
nomul dex
|
|
bne mulloop
|
|
|
|
pha ;Acc * C2
|
|
asl a
|
|
asl a
|
|
sec
|
|
sbc 1,s (Use top word on stack as temp var)
|
|
asl a
|
|
asl a
|
|
adc 1,s
|
|
sta 1,s
|
|
|
|
lda num ;num*C1 + (Acc*C2) + h
|
|
asl a
|
|
adc num
|
|
asl a
|
|
asl a
|
|
adc 1,s
|
|
adc h
|
|
sec
|
|
sbc num
|
|
plx (Remove temp var from stack)
|
|
UDivide (@a,t_size),(@a,@y)
|
|
|
|
;
|
|
; Return the hashed value to the user
|
|
;
|
|
lda space
|
|
sta end-2
|
|
pld
|
|
tsc
|
|
clc
|
|
adc #end-3
|
|
tcs
|
|
|
|
tya Final hash value is in accumulator.
|
|
rts
|
|
|
|
h ds 2 NOTE: h must be a "static" variable.
|
|
tmp ds 2
|
|
|
|
END
|
|
|
|
**************************************************************************
|
|
*
|
|
* dohash
|
|
*
|
|
**************************************************************************
|
|
|
|
dohash START
|
|
|
|
using hashdata
|
|
|
|
h equ 1
|
|
temp equ h+2
|
|
qh equ temp+4
|
|
table equ qh+2
|
|
space equ table+4
|
|
files equ space+3
|
|
end equ files+4
|
|
|
|
; subroutine (4:files),space
|
|
|
|
tsc
|
|
sec
|
|
sbc #space-1
|
|
tcs
|
|
phd
|
|
tcd
|
|
|
|
lda hash_numexe
|
|
bne mktsize
|
|
|
|
stz table
|
|
stz table+2
|
|
jmp done
|
|
;
|
|
; t_size = (TAB_MULT * numexe) - 1
|
|
; [Shift since TAB_MULT is 4, change later if needed]
|
|
;
|
|
mktsize asl a
|
|
asl a
|
|
dec a
|
|
sta t_size
|
|
;
|
|
; table = (tablenode **)malloc(sizeof(tablenode *) * t_size);
|
|
;
|
|
inc a ;safety precaution
|
|
asl a
|
|
asl a
|
|
pea 0
|
|
pha
|
|
~NEW
|
|
sta table
|
|
stx table+2
|
|
;
|
|
; for (i=0; i < t_size; ++i) table[i] = NULL;
|
|
;
|
|
ldy #0
|
|
ldx t_size
|
|
tya
|
|
clrtbl sta [table],y
|
|
iny
|
|
iny
|
|
sta [table],y
|
|
iny
|
|
iny
|
|
dex
|
|
bne clrtbl
|
|
;
|
|
; files = files->next
|
|
;
|
|
mainloop ldy #fn_next
|
|
lda [files],y
|
|
tax
|
|
ldy #fn_next+2
|
|
lda [files],y
|
|
sta files+2
|
|
stx files
|
|
;
|
|
; while (files != NULL) {
|
|
;
|
|
ora files
|
|
jeq done
|
|
stz qh
|
|
;
|
|
; while (table[h = hash(files->name, qh))]) { ++qh; ++colls; }
|
|
;
|
|
hashloop pei (files+2)
|
|
lda files
|
|
inc a
|
|
inc a
|
|
pha
|
|
pei (qh)
|
|
jsr hash
|
|
asl a
|
|
asl a
|
|
sta h
|
|
tay
|
|
lda [table],y
|
|
tax
|
|
iny2
|
|
ora [table],y
|
|
beq gotit
|
|
|
|
; If it's the same name, skip the duplicate entry
|
|
|
|
ldy h Calculate address
|
|
clc of hash entry's
|
|
lda [table],y name field.
|
|
adc #tn_name
|
|
tax
|
|
iny2
|
|
lda [table],y
|
|
adc #0
|
|
pha High-order word of address.
|
|
phx Low-order word of address.
|
|
pei (files+2)
|
|
lda files
|
|
inc a
|
|
inc a
|
|
pha
|
|
jsr cmpcstr
|
|
beq mainloop
|
|
|
|
inc qh
|
|
bra hashloop
|
|
;
|
|
; table[h] = (tablenode *)malloc(sizeof(tablenode))
|
|
;
|
|
gotit ph4 #tn_size
|
|
~NEW
|
|
sta temp
|
|
stx temp+2
|
|
ldy h
|
|
sta [table],y
|
|
iny
|
|
iny
|
|
txa
|
|
sta [table],y
|
|
;
|
|
; table[h]->dirnum = files->dirNum
|
|
;
|
|
lda [files]
|
|
sta [temp]
|
|
;
|
|
; strcpy(table[h]->name, files->name);
|
|
;
|
|
pei (files+2)
|
|
lda files
|
|
inc a
|
|
inc a
|
|
pha
|
|
pei (temp+2)
|
|
lda temp
|
|
inc a
|
|
inc a
|
|
pha
|
|
jsr copycstr
|
|
jmp mainloop
|
|
|
|
done anop
|
|
; return 4:table
|
|
|
|
ldx table+2
|
|
ldy table
|
|
|
|
lda space
|
|
sta end-3
|
|
lda space+1
|
|
sta end-2
|
|
pld
|
|
tsc
|
|
clc
|
|
adc #end-4
|
|
tcs
|
|
|
|
tya
|
|
rtl
|
|
|
|
END
|
|
|
|
**************************************************************************
|
|
*
|
|
* Search the hash table
|
|
*
|
|
**************************************************************************
|
|
|
|
search START
|
|
|
|
using hashdata
|
|
|
|
ptr equ 1
|
|
name_len equ ptr+4
|
|
full_path equ name_len+2
|
|
qh equ full_path+4
|
|
space equ qh+2
|
|
paths equ space+3
|
|
table equ paths+4
|
|
file equ table+4
|
|
end equ file+4
|
|
|
|
; subroutine (4:file,4:table,4:paths),space
|
|
|
|
tsc
|
|
sec
|
|
sbc #space-1
|
|
tcs
|
|
phd
|
|
tcd
|
|
|
|
lock hashmutex
|
|
|
|
stz qh
|
|
stz full_path Set result to NULL.
|
|
stz full_path+2
|
|
|
|
lda table If hash table hasn't
|
|
ora table+2 been allocated,
|
|
jeq done return null string.
|
|
|
|
pei (file+2)
|
|
pei (file)
|
|
jsr lowercstr
|
|
mainloop pei (file+2) Get hash(qh,file)
|
|
pei (file)
|
|
pei (qh)
|
|
jsr hash
|
|
asl a Multiply by 4
|
|
asl a
|
|
tay Use as index into table.
|
|
lda [table],y ptr = table[hash(qh,file)]
|
|
sta ptr
|
|
tax
|
|
iny
|
|
iny
|
|
ora [table],y If == 0,
|
|
jeq done all done.
|
|
|
|
lda [table],y
|
|
sta ptr+2
|
|
|
|
pei (file+2)
|
|
pei (file)
|
|
pha ;ptr+2
|
|
inx ;ptr + #2
|
|
inx
|
|
phx
|
|
jsr cmpcstr Compare filename against entry.
|
|
beq found
|
|
inc qh
|
|
bra mainloop
|
|
|
|
;
|
|
; Found an entry that matches the filename. Calculate full path.
|
|
;
|
|
found lda [ptr]
|
|
asl a
|
|
asl a
|
|
adc paths ;(cf=0)
|
|
sta ptr
|
|
ldx paths+2
|
|
stx ptr+2
|
|
|
|
pei (file+2)
|
|
pei (file)
|
|
jsr cstrlen Get length of prog name.
|
|
sta name_len
|
|
|
|
ldy #2
|
|
lda [ptr],y
|
|
pha
|
|
lda [ptr]
|
|
pha
|
|
jsr cstrlen Get length of path.
|
|
pha
|
|
sec
|
|
adc name_len Add name length + 1 (carry bit).
|
|
pea 0
|
|
pha
|
|
~NEW Allocate memory,
|
|
sta full_path storing address at
|
|
stx full_path+2 functional return value.
|
|
|
|
ldy #2
|
|
lda [ptr],y
|
|
pha
|
|
lda [ptr]
|
|
pha
|
|
pei (full_path+2)
|
|
pei (full_path)
|
|
jsr copycstr Copy pathname into buffer.
|
|
|
|
pla ;length of path
|
|
pei (file+2)
|
|
pei (file)
|
|
pei (full_path+2)
|
|
clc
|
|
adc full_path
|
|
pha
|
|
jsr copycstr Put filename at end of pathname.
|
|
|
|
done unlock hashmutex
|
|
|
|
ldx full_path+2 Load return value into Y- & X- regs
|
|
ldy full_path
|
|
|
|
; Adjust stack in preparation for return
|
|
lda space
|
|
sta end-3
|
|
lda space+1
|
|
sta end-2
|
|
pld
|
|
tsc
|
|
clc
|
|
adc #end-4
|
|
tcs
|
|
|
|
tya A- & X- regs contain ptr (or NULL)
|
|
|
|
rtl
|
|
|
|
END
|
|
|
|
**************************************************************************
|
|
*
|
|
* Dispose the hash table
|
|
*
|
|
**************************************************************************
|
|
|
|
dispose_table START
|
|
|
|
using hashdata
|
|
|
|
ptr equ 0
|
|
count equ ptr+4
|
|
space equ count+2
|
|
|
|
subroutine (4:table),space
|
|
|
|
mv4 table,ptr
|
|
mv2 t_size,count
|
|
loop ldy #2
|
|
lda [ptr],y
|
|
pha
|
|
lda [ptr]
|
|
pha
|
|
jsl nullfree
|
|
add2 ptr,#4,ptr
|
|
dec count
|
|
bne loop
|
|
|
|
pei (table+2)
|
|
pei (table)
|
|
jsl nullfree
|
|
|
|
return
|
|
|
|
END
|
|
|
|
**************************************************************************
|
|
*
|
|
* Dispose the file table
|
|
*
|
|
**************************************************************************
|
|
|
|
free_files START
|
|
|
|
space equ 0
|
|
|
|
subroutine (4:files),space
|
|
|
|
loop ora2 files,files+2,@a
|
|
beq done
|
|
ldy #fn_next
|
|
lda [files],y
|
|
tax
|
|
ldy #fn_next+2
|
|
lda [files],y
|
|
pei (files+2)
|
|
pei (files)
|
|
stx files
|
|
sta files+2
|
|
jsl nullfree
|
|
bra loop
|
|
|
|
done return
|
|
|
|
END
|
|
|
|
**************************************************************************
|
|
*
|
|
* Directory search
|
|
*
|
|
**************************************************************************
|
|
|
|
dir_search START
|
|
|
|
using hashdata
|
|
|
|
temp2 equ 0
|
|
temp equ temp2+4
|
|
entry equ temp+4
|
|
numEntries equ entry+2
|
|
ptr equ numEntries+2
|
|
space equ ptr+4
|
|
|
|
subroutine (4:dir,2:dirNum,4:files),space
|
|
|
|
* NOTE: dir_search is only called from hashpath (after hashmutex locked)
|
|
|
|
;
|
|
; Open directory name passed as 1st parameter
|
|
;
|
|
ld2 3,ORec
|
|
pei (dir+2) Turn "dir" c-string into
|
|
pei (dir) a GS/OS string, allocated
|
|
jsr c2gsstr via ~NEW.
|
|
sta ORecPath
|
|
stx ORecPath+2
|
|
phx Put GS/OS string addr on stack
|
|
pha so it can be deallocated.
|
|
Open ORec Open that file.
|
|
bcc goodopen If there was an error,
|
|
jsl nullfree Free the GS/OS string
|
|
jmp exit and exit.
|
|
|
|
goodopen jsl nullfree Free the GS/OS string.
|
|
|
|
;
|
|
; Set up parameter block for GetDirEntry
|
|
;
|
|
mv2 ORecRef,DRecRef Copy the file ref num from open.
|
|
stz DRecBase Zero the base and
|
|
stz DRecDisp displacement.
|
|
GetDirEntry DRec Make DirEntry call.
|
|
|
|
mv2 DRecEntry,numEntries Save number of entries.
|
|
ld2 1,(DRecBase,DRecDisp)
|
|
stz entry # processed entries = 0.
|
|
;
|
|
; Process each entry in the directory
|
|
;
|
|
loop lda entry If number of processed entries
|
|
cmp numEntries equals the total number,
|
|
jge done we are all done.
|
|
;
|
|
; Get directory entry's information
|
|
;
|
|
GetDirEntry DRec
|
|
|
|
; Check for filetype $B3: GS/OS Application (S16)
|
|
if2 DRecFileType,eq,#$B3,goodfile
|
|
|
|
; Check for filetype $B5: GS/OS Shell Application (EXE)
|
|
if2 @a,eq,#$B5,goodfile
|
|
|
|
; Check for filetype $B0, subtype $0006: Shell command file (EXEC)
|
|
cmp #$B0
|
|
bne nextfile
|
|
lda DRecAuxType
|
|
cmp #$06
|
|
bne nextfile
|
|
lda DRecAuxType+2
|
|
bne nextfile
|
|
;
|
|
; This directory entry points to an executable file.
|
|
; Included it in the file list.
|
|
;
|
|
goodfile inc hash_numexe Bump the (global) # files.
|
|
|
|
ldx TempRBlen Get length word from GS/OS string
|
|
short a
|
|
stz TempRBname,x Store terminating null byte.
|
|
long a
|
|
|
|
ph4 #TempRBname
|
|
jsr lowercstr Convert name to lower case.
|
|
|
|
ph4 #TempRBname Push src addr for copycstr.
|
|
|
|
ldy #fn_next temp = files->next.
|
|
lda [files],y
|
|
sta temp
|
|
ldy #fn_next+2
|
|
lda [files],y
|
|
sta temp+2
|
|
|
|
ph4 #fn_size temp2 = new entry.
|
|
~NEW
|
|
sta temp2
|
|
stx temp2+2
|
|
|
|
ldy #fn_next files->next = temp2
|
|
sta [files],y
|
|
ldy #fn_next+2
|
|
txa
|
|
pha
|
|
sta [files],y
|
|
|
|
lda temp2
|
|
clc
|
|
adc #fn_name
|
|
pha
|
|
jsr copycstr Copy string into entry.
|
|
|
|
lda dirNum temp2->dirnum = dirNum
|
|
sta [temp2]
|
|
|
|
ldy #fn_next temp2->next = temp
|
|
lda temp
|
|
sta [temp2],y
|
|
ldy #fn_next+2
|
|
lda temp+2
|
|
sta [temp2],y
|
|
|
|
nextfile inc entry Bump entry number
|
|
jmp loop and stay in the loop.
|
|
|
|
;
|
|
; Done adding entries to the hash table from this directory
|
|
;
|
|
done anop
|
|
|
|
ld2 1,ORec ORec.pCount = 1
|
|
Close ORec
|
|
|
|
exit return
|
|
|
|
|
|
; Parameter block for GS/OS Open and Close calls
|
|
ORec dc i'3' pCount (3 for Open, 1 for Close)
|
|
ORecRef ds 2 refNum
|
|
ORecPath ds 4 pathname (result buf)
|
|
ORecAccess dc i'1' requested access = read
|
|
|
|
; Parameter block for GS/OS GetDirEntry call
|
|
DRec dc i'13' pCount
|
|
DRecRef ds 2 refNum
|
|
DRecFlag ds 2 flags: extended/not
|
|
DRecBase dc i'0' base: displacement is absolute entry #
|
|
DRecDisp dc i'0' displacement: get tot # active entries
|
|
DRecName dc i4'TempResultBuf' name: result buf
|
|
DRecEntry ds 2 entryNum: entry # whose info is rtrned
|
|
DRecFileType ds 2 fileType
|
|
DRecEOF ds 4 eof: # bytes in data fork
|
|
DRecBlockCnt ds 4 blockCount: # blocks in data fork
|
|
DRecCreate ds 8 createDateTime
|
|
DRecMod ds 8 modDateTime
|
|
DRecAccess ds 2 access attribute
|
|
DRecAuxType ds 4 auxType
|
|
|
|
; GS/OS result buffer for getting a directory entry's name
|
|
TempResultBuf dc i2'68' Total length = 64 bytes + 4 for length
|
|
TempRBlen ds 2 Value's length returned here
|
|
TempRBname ds 64 Allow 64 bytes for returned name
|
|
ds 1 Extra byte for null string termination
|
|
|
|
END
|
|
|
|
**************************************************************************
|
|
*
|
|
* Hash the path variable
|
|
*
|
|
**************************************************************************
|
|
|
|
hashpath START
|
|
|
|
using hashdata
|
|
using vardata
|
|
using global
|
|
|
|
len equ 1
|
|
pathnum equ len+2
|
|
ptr equ pathnum+2
|
|
files equ ptr+4
|
|
pathptr equ files+4
|
|
qflag equ pathptr+4
|
|
qptr equ qflag+2
|
|
gsosbuf equ qptr+4
|
|
space equ gsosbuf+4
|
|
end equ space+3
|
|
|
|
;
|
|
; Allocate space on stack for direct page variables
|
|
;
|
|
tsc
|
|
sec
|
|
sbc #space-1
|
|
tcs
|
|
phd
|
|
tcd
|
|
|
|
lock hashmutex
|
|
;
|
|
; Allocate special file node
|
|
;
|
|
ph4 #fn_size
|
|
~NEW
|
|
sta hash_files
|
|
sta files
|
|
stx hash_files+2
|
|
stx files+2
|
|
|
|
;
|
|
; Initialize counters and pointers
|
|
;
|
|
lda #0
|
|
sta hash_numexe
|
|
sta pathnum
|
|
ldy #fn_next
|
|
sta [files],y
|
|
ldy #fn_next+2
|
|
sta [files],y
|
|
ldy #fn_name
|
|
sta [files],y
|
|
sta [files]
|
|
;
|
|
; Get value of $PATH environment variable string
|
|
;
|
|
ph4 #pathname
|
|
jsl getenv
|
|
sta gsosbuf Save address of allocated buffer.
|
|
stx gsosbuf+2
|
|
ora gsosbuf+2 If null,
|
|
bne setptr
|
|
ldx #^nopatherr print error message
|
|
lda #nopatherr
|
|
jsr errputs
|
|
jmp noprint and exit.
|
|
|
|
setptr clc Add 4 bytes to
|
|
lda gsosbuf direct page pointer
|
|
adc #4 to get the addr of
|
|
sta pathptr beginning of text.
|
|
lda gsosbuf+2
|
|
adc #0
|
|
sta pathptr+2
|
|
|
|
;
|
|
; Begin parsing $PATH
|
|
;
|
|
loop lda [pathptr]
|
|
and #$FF
|
|
jeq pathdone
|
|
;
|
|
; parse next pathname
|
|
;
|
|
stz qflag Clear quote flag for this path
|
|
|
|
mv4 pathptr,ptr
|
|
ldy #0
|
|
despace lda [pathptr],y
|
|
and #$FF
|
|
beq gotspace0
|
|
if2 @a,eq,#' ',gotspace1
|
|
if2 @a,eq,#009,gotspace1
|
|
if2 @a,eq,#013,gotspace1
|
|
if2 @a,eq,#'\',gotquote
|
|
iny
|
|
bra despace
|
|
|
|
; Found "\"
|
|
gotquote anop
|
|
iny2
|
|
ldx qflag If quote flag hasn't already been set,
|
|
bne despace
|
|
sty qflag set it to index of first "\" + 2.
|
|
bra despace
|
|
|
|
; Found null byte
|
|
gotspace0 tyx Why put Y-reg in X???
|
|
bra gotspace3
|
|
|
|
; Found " ", tab, or creturn
|
|
gotspace1 tyx Why put Y-reg in X???
|
|
short a
|
|
lda #0
|
|
sta [pathptr],y
|
|
long a
|
|
gotspace2 iny
|
|
lda [pathptr],y
|
|
and #$FF
|
|
if2 @a,eq,#' ',gotspace2
|
|
if2 @a,eq,#009,gotspace2
|
|
if2 @a,eq,#013,gotspace2
|
|
|
|
gotspace3 anop
|
|
clc Bump pathptr by
|
|
tya the number of bytes
|
|
adc pathptr indicated in Y-reg.
|
|
sta pathptr
|
|
lda pathptr+2
|
|
adc #0
|
|
sta pathptr+2
|
|
|
|
lda pathnum
|
|
cmp #32*4
|
|
bcc numok
|
|
ldx #^toomanyerr
|
|
lda #toomanyerr
|
|
jsr errputs
|
|
jmp pathdone
|
|
|
|
;
|
|
; Convert c string to GS/OS string (allocating space for it)
|
|
;
|
|
numok pei (ptr+2)
|
|
pei (ptr)
|
|
jsr c2gsstr
|
|
phx Push allocated address onto
|
|
pha stack for later deallocation.
|
|
sta EPinputPath Save address in ExpandPath
|
|
stx EPinputPath+2 parameter block.
|
|
;
|
|
; If any quoted characters were included, the "\" chars must be removed
|
|
;
|
|
ldy qflag Get quote flag (index to "\" char).
|
|
beq xpandit If no "\", go ahead with expansion.
|
|
|
|
sta qptr Save EPinputPath pointer in
|
|
stx qptr+2 direct page variable.
|
|
lda [qptr] Store length + 2 (since we're indexing
|
|
inc2 a from before length word) in qflag.
|
|
sta qflag
|
|
tyx X = index of 1st overwritten "\".
|
|
short a Use 1-byte accumulator
|
|
;
|
|
; Copy characters toward front of string, removing "\" chars
|
|
;
|
|
chkloop2 lda [qptr],y Get next character.
|
|
cmp #'\' If it's a quote,
|
|
bne storeit
|
|
lda [qptr] Decrement length.
|
|
dec a
|
|
sta [qptr]
|
|
iny Skip over "\".
|
|
lda [qptr],y Get character following.
|
|
storeit phy Push source index onto stack
|
|
txy so destination index can be
|
|
sta [qptr],y used to store the character.
|
|
ply Restore the source index.
|
|
inx Bump destination and
|
|
iny source index registers.
|
|
cpy qflag If source index < length,
|
|
bcc chkloop2 stay in copy loop.
|
|
|
|
long a Restore long accumulator.
|
|
|
|
;
|
|
; Convert the input pathname into the corresponding full pathname with
|
|
; colons as separators. Use temp result buf this time, just to get length.
|
|
;
|
|
xpandit anop
|
|
ld4 TempResultBuf,EPoutputPath
|
|
ExpandPath EPParm
|
|
;
|
|
; Allocate memory for ExpandPath GS/OS result string
|
|
;
|
|
lda TempRBlen Get length of value.
|
|
inc2 a Add 4 bytes for result buf len words.
|
|
inc2 a
|
|
sta len Save result buf len.
|
|
inc a Add 1 more for terminator.
|
|
pea 0
|
|
pha
|
|
~NEW Request the memory.
|
|
sta EPoutputPath Store address in ReadVariable
|
|
stx EPoutputPath+2 parameter block and
|
|
sta ptr direct page pointer.
|
|
stx ptr+2
|
|
ora ptr+2 If address == NULL,
|
|
jeq donext get next entry.
|
|
|
|
lda len Store result buffer length
|
|
sta [ptr] at beginning of buf.
|
|
|
|
ExpandPath EPParm Call again, and get the name.
|
|
bcc epok
|
|
|
|
ldx #^eperrstr Print error message:
|
|
lda #eperrstr "Invalid pathname syntax."
|
|
jsr errputs
|
|
donext jsl nullfree Free GS/OS string (pushed earlier).
|
|
jmp next Get the next one.
|
|
|
|
epok anop
|
|
jsl nullfree Free source string (addr on stack)
|
|
|
|
ldy #2
|
|
lda [ptr],y Get length of text
|
|
sta len
|
|
tay
|
|
iny4 and add four.
|
|
short a
|
|
lda #0 Store 0 at end of text so it
|
|
sta [ptr],y can act like a C string.
|
|
long a
|
|
;
|
|
; Move text in GS/OS result buffer to beginning of buffer
|
|
; (overwritting the two length words).
|
|
;
|
|
clc Source is result
|
|
lda ptr buffer plus
|
|
adc #4 four bytes.
|
|
tay
|
|
lda ptr+2
|
|
adc #0
|
|
pha
|
|
phy
|
|
pei (ptr+2) Destination is first
|
|
pei (ptr) byte of buffer.
|
|
jsr copycstr
|
|
|
|
lda ptr
|
|
ldy pathnum
|
|
sta hash_paths,y Store address of this
|
|
lda ptr+2 path's address in the
|
|
sta hash_paths+2,y hash path table.
|
|
|
|
ldy len
|
|
beq bumppnum
|
|
dey
|
|
lda [ptr],y If last character
|
|
and #$FF of path name
|
|
cmp #':' isn't ":",
|
|
beq bumppnum
|
|
iny
|
|
lda #':' store ":\0"
|
|
sta [ptr],y at end of string.
|
|
|
|
bumppnum anop
|
|
add2 pathnum,#4,pathnum Bump path pointer.
|
|
next jmp loop Stay in loop.
|
|
|
|
;
|
|
; The $PATH entries have been created. Now we need to search each of the
|
|
; directories for executable files and add them to the "files" list.
|
|
; The earliest versions of gsh added files to the list in the order that
|
|
; directories appeared in $PATH, which put the earliest directories' files
|
|
; at the end of the list. Check for existence of $OLDPATHMODE environment
|
|
; variable to see if the user wants this, or would rather have them hashed
|
|
; in the expected order.
|
|
;
|
|
pathdone anop
|
|
lda varoldpmode
|
|
beq neworder
|
|
|
|
;
|
|
; Search directories and add executables to file list starting at the
|
|
; beginning of $PATH and working to the end.
|
|
;
|
|
stz pathnum Start at beginning of path table.
|
|
|
|
nextpath1 ldy pathnum Get offset into hash table.
|
|
cpy #32*4
|
|
bcs filesdone
|
|
lda hash_paths,y If address of this path
|
|
ora hash_paths+2,y has not been set,
|
|
beq filesdone all done.
|
|
lda hash_paths,y Get address of this
|
|
ldx hash_paths+2,y path's address in the
|
|
phx hash path table.
|
|
pha
|
|
tya Directory number =
|
|
lsr2 a offset / 4
|
|
pha
|
|
pei (files+2) Pointer to file list.
|
|
pei (files)
|
|
jsl dir_search Add executables from this directory.
|
|
add2 pathnum,#4,pathnum Bump path offset.
|
|
bra nextpath1
|
|
|
|
;
|
|
; Search directories and add executables to file list starting at end
|
|
; of $PATH and working back to the beginning. (Note: Loop begins at
|
|
; "neworder", but structuring the code this ways saves an instruction.)
|
|
;
|
|
nextpath2 dey4 Decrement path offset.
|
|
sty pathnum
|
|
lda hash_paths,y Get address of this
|
|
ldx hash_paths+2,y path's address in the
|
|
phx hash path table.
|
|
pha
|
|
tya Directory number =
|
|
lsr2 a offset / 4
|
|
pha
|
|
pei (files+2) Pointer to file list.
|
|
pei (files)
|
|
jsl dir_search Add executables from this directory.
|
|
neworder ldy pathnum Get offset into hash table.
|
|
bne nextpath2 When == 0, no more to do.
|
|
|
|
|
|
;
|
|
; Executable files in $PATH have been added to the list. Print
|
|
; number of files, then build the hash table.
|
|
;
|
|
filesdone anop
|
|
ph4 gsosbuf Free memory allocated for
|
|
jsl nullfree $PATH string.
|
|
|
|
lda done_init If initialization isn't complete,
|
|
beq noprint don't print the # of files.
|
|
|
|
Int2Dec (hash_numexe,#hashnum,#3,#0)
|
|
ldx #^hashmsg
|
|
lda #hashmsg
|
|
jsr puts
|
|
|
|
noprint anop
|
|
|
|
;
|
|
; Create the hash table from the file list.
|
|
;
|
|
ph4 hash_files
|
|
jsl dohash
|
|
sta hash_table
|
|
stx hash_table+2
|
|
|
|
unlock hashmutex
|
|
|
|
pld
|
|
tsc
|
|
clc
|
|
adc #end-4
|
|
tcs
|
|
|
|
rtl
|
|
|
|
pathname gsstr 'path'
|
|
|
|
hashmsg dc c'hashed '
|
|
hashnum dc c'000 files',h'0d00'
|
|
|
|
; Parameter block for GS/OS call ExpandPath
|
|
EPParm dc i'2' pCount = 2
|
|
EPinputPath ds 4 ptr to inputPath (GS/OS string)
|
|
EPoutputPath ds 4 ptr to outputPath (Result buffer)
|
|
|
|
; GS/OS result buffer for getting the full length of expanded name
|
|
TempResultBuf dc i2'5' Only five bytes total.
|
|
TempRBlen ds 2 Value's length returned here.
|
|
ds 1 Only 1 byte for value.
|
|
|
|
eperrstr dc c'rehash: Invalid pathname syntax.',h'0d00'
|
|
toomanyerr dc c'rehash: Too many paths specified.',h'0d00'
|
|
nopatherr dc c'rehash: PATH string is not set.',h'0d00'
|
|
|
|
END
|
|
|
|
**************************************************************************
|
|
*
|
|
* Dispose of hashing tables
|
|
*
|
|
**************************************************************************
|
|
|
|
dispose_hash START
|
|
|
|
using hashdata
|
|
|
|
ora2 hash_table,hash_table+2,@a
|
|
beq done
|
|
|
|
ldx #32 32 different paths, maximum
|
|
ldy #0 Start looking at the first entry.
|
|
|
|
loop1 phx Save path counter
|
|
phy and index.
|
|
lda hash_paths+2,y Put address for this
|
|
pha path table entry on
|
|
lda hash_paths,y the stack.
|
|
pha
|
|
lda #0 Zero out the table entry.
|
|
sta hash_paths+2,y
|
|
sta hash_paths,y
|
|
jsl nullfree Free the entry's memory.
|
|
next1 ply Restore path index
|
|
plx and counter.
|
|
iny4 Bump pointer to next address.
|
|
dex If more paths to process,
|
|
bne loop1 stay in the loop.
|
|
|
|
ph4 hash_files
|
|
jsl free_files
|
|
stz hash_files
|
|
stz hash_files+2
|
|
|
|
ph4 hash_table
|
|
jsl dispose_table
|
|
stz hash_table
|
|
stz hash_table+2
|
|
|
|
done rts
|
|
|
|
END
|
|
|
|
**************************************************************************
|
|
*
|
|
* Hash data
|
|
*
|
|
**************************************************************************
|
|
|
|
hashdata DATA
|
|
|
|
hashmutex key Mutual exclusion key
|
|
|
|
t_size ds 2 t_size = (TAB_MULT * numexe) - 1
|
|
|
|
hash_paths dc 32i4'0' 32 paths max for now.
|
|
hash_files dc i4'0'
|
|
hash_table dc i4'0' Pointer to table (t_size entries)
|
|
hash_numexe dc i2'0' Number of hashed executables
|
|
|
|
END
|