NB. file access utilities
NB.
NB. read verbs take a right argument of a filename, optionally 
NB. linked with one or two numbers (as for 1!:11):
NB.   0 = start of read (may be negative)
NB.   1 = length of read (default rest of file)
NB.
NB. write verbs return number of characters written.
NB.
NB. filenames may be open or boxed character strings.
NB.
NB. string verbs write out text delimited by CRLF, and read in
NB. text delimited by LF.
NB.
NB. Use charsub (defined in misc.js) to substitute unwanted characters,
NB. e.g. '-_' charsub fread 'mydata.dat' replaces - with _
NB.
NB.   dat fappend fl    append
NB.   dat fappends fl   append string
NB.       fdir          file directory
NB.       ferase fl     erase file
NB.       fexist fl     return 1 if file exists
NB.   opt fread fl      read file
NB.       freadr fl     read records (flat file)
NB.       freads fl     read string
NB.   dat freplace fl   replace in file
NB.   opt fselect txt   select file
NB.       fsize fl      size of file
NB.   str fss fl        string search file
NB.       fview fl      view file
NB.   dat fwrite fl     write file
NB.   dat fwrites fl    write string
NB.
NB. on error, the result is _1, 
NB. i.e. for file not found/file read error/file write error
      
t=. 'fappend fappends fdir ferase fexist fread freadr freads'
SCRIPTNAMES=. t,' freplace fselect fsize fss fview fwrite fwrites'

NB. fappend
fappend=: 4 : 0
y.=. boxopen y.
x.=. ,x.
try. #x. [ x. 1!:3 y.
catch. _1 end.
)

NB. fappends
fappends=: 4 : 0
y.=. boxopen y.
if. -. 0 e. $x. do.  
  if. 1>:#$x. do. 
    x.=. toHOST x. 
    x.=. x.,(LF ~: {:x.)#CRLF
  else. x.=. x.,"1 CRLF 
  end.
end.
x.=. ,x.
try. #x. [ x. 1!:3 y.
catch. _1 end.
)

NB. fdir
fdir=: 1!:0 

NB. ferase
ferase=: 3 : 0
try. 1!:55 boxopen y.
catch. _1 end.
)

NB. fexist
fexist=:  3 : 0
y.=. boxopen y.
try. 1 [ 1!:11 y.,<0 0
catch. 0
end.
)

NB. fread
fread=: 3 : 0
NB. read file
NB. y. is filename {;start size}
NB. x. is optional:
NB.    = b    read as boxed vector
NB.    = m    read as matrix
NB.    = s    read as string (same as freads)
'' fread y.
:
y.=. boxopen y.
r=. 1!:(1 11 {~ 2=#y.)
try. dat=. r y.
catch. _1 return. end.
if. 0=#x. do. dat return. end.
dat=. dat,LF #~ LF ~: {:dat=. toJ dat
if. 'b'e.x. do. dat=. <;._2 dat
elseif. 'm'e.x. do. dat=. ];._2 dat
end.
)

NB. freadr
freadr=: 3 : 0
NB. read records from flat file
NB. y. is filename {;record start, # of records}
NB. records are assumed of fixed length delimited by. 
NB. one (only.) of CR, LF, or CRLF.
NB. the result is a matrix of records.
'fs'=. 2{.boxopen y.
try. max=. 1!:4 <f
catch. _1 return. end.
NB. find record length:
pos=. 0 
step=. 10000
whilst. blk = cls
do.
  blk=. step<.max-pos
  if. 0=blk do. 'file not organized in records' return. end.
  dat=. 1!:11 f;pos,blk
  cls=. <./dat i.CRLF
  pos=. pos+step
end.
len=. cls+pos-step
dat=. 1!:11 f;len,2<.max-len
dlm=. +/CRLF e. dat
wid=. len+dlm
s=. wid*s,0 #~ 0=#s
dat=. 1!:11 f;s
dat=. (-wid)[\dat
(-dlm)}."1 dat
)

NB. freads
freads=: 3 : 0
NB. read file as string
NB. y. is filename {;start size}
y.=. boxopen y.
r=. 1!:(1 11 {~ 2=#y.)
try. dat=. r y.
catch. _1 return. end.
dat,LF #~ LF ~: {:dat=. toJ dat
)

NB. freplace
freplace=: 3 : 0
NB. dat freplace file;pos
:
x.=. ,x.
try. #x. [ x. 1!:12 y.
catch. _1 end.
)

NB. fselect  - select files
fselect=: 3 : 0
NB. y. = DOS filespec or ''
NB. returns user selection
y.=. y.,(0 e. #y.)#'*.*'
path=. }: y. #~ b=. +./\.y.='\'
def=. y. #~ -. b
t=. 'mbopen "Select File" "',path,'" "',def,'" '
t=. t,'"All(*.*)|*.*" ofn_filemustexist ofn_pathmustexist;'
wd t
)

NB. fsize
fsize=:  3 : 0
y.=. boxopen y.
try. 1!:4 y. 
catch. _1
end.
)

NB. fss
NB. str fss file
NB. search file for string, returning indices
fss=: 4 : 0
y=. boxopen y.
try. size=. 1!:4 y
catch. _1 return. end. 
bx=. # i.@#
blk=. (#x.) >. 100000 <. size
r=. i.pos=. 0
while. pos < size do.
  dat=. 1!:11 y,<pos,blk <. size-pos
  r=. r,pos+bx x. E. dat
  pos=. pos+blk+1-#x.
end.
r
)

NB. fview
fview=: 3 : 0
NB. view file
NB. uses standard Windows edit control,
NB. which is limited to around 20K size.
y.=. boxopen y.
r=. 1!:(1 11 {~ 2=#y.)
try. dat=. r y.
catch. _1 return. end.
empty (>y.) wdview dat
)

NB. fwrite
fwrite=: 4 : 0
y.=. boxopen y.
x.=. ,x.
try. #x. [ x. 1!:2 y.
catch. _1 end.
)

NB. fwrites
fwrites=: 4 : 0
y.=. boxopen y.
if. -. 0 e. $x. do.  
  if. 1>:#$x. do. 
    x.=. toHOST x. 
    x.=. x.,(LF ~: {:x.)#CRLF
  else. x.=. x.,"1 CRLF 
  end.
end.
x.=. ,x.
try. #x. [ x. 1!:2 y.
catch. _1 end.
)
