NB. component file definitions
NB. built from project: ~Source\packages\jfiles\jfiles
NB. jfiles
NB.
NB. main functions:
NB.
NB.   jappend
NB.   jcreate
NB.   jdup
NB.   jerase
NB.   jread
NB.   jreplace
NB.   jsize
NB.
NB. other functions:
NB.
NB.   jopen
NB.   jclose
NB.   jseqno
NB.
NB. header structure:
NB.
NB.   [0]   v  version
NB.   [1]   s  starting component
NB.   [2]   c  number of components
NB.   [3]   l  file length
NB.   [4]   d  directory pointer
NB.   [5]   f  freelist pointer
NB.   [6]   q  sequence number
NB.
NB. error results:
NB.
NB.   _1   file not found
NB.   _2   invalid component
NB.   _3   invalid data
NB.   _4   host access error

coclass 'jfiles'


NB.*jcreate v create jfile, jcreate 'dat'
NB.*jappend v append to jfile, (<i.2 3) jappend 'dat'
NB.*jdup v duplicate jfile, 'new' jdup 'dat'
NB.*jerase v erase jfile, jerase 'dat'
NB.*jread v read jfile, jread 'dat';2
NB.*jreplace v replace in jfile, ('new value';123) jreplace 'dat';2 5
NB.*jsize v return size of jfile, jsize 'dat'

NB. jfile  utilities

V64L=: 1718235186  NB. J64 little endian
V32L=: 1718235187  NB. J32 little endian (default new 32bit)
V32B=: 1718235188  NB. J32 big endian
V64B=: 1718235189  NB. J64 big endian (default new 64bit)

M32=: 4294967296  NB. 2^32

B4=: 4 # 256
B8=: 8 # 256

NB. =========================================================
j_blk=: [: <. >.&.(2&^.)@#
j_box=: <^:(L. = 0:)
j_ext=: , #&'.ijf' @ (0: = '.'"_ e. ([: >./ # | i:&'/\') }. ])
j_nos=: [: ; [: {."1 (1!:20)
j_read=: 3!:2 @ (1!:11)
j_rep=: 3!:1
j_take0=: {.!.({.a.)
j_writerep=: j_rep&.>@[ j_write ]
j_vcur=: 3 : '(2 * IF64) }. V32L,V32B,V64B'

NB. =========================================================
NB. j_compress  - compress free list
j_compress=: 3 : 0
f=. /:~ y.
bgn=. {."1 f
end=. bgn + {:"1 f
min=. 0, }: end
bgn=. bgn >. min
b=. bgn ~: min
if. 0 e. b do.
  f=. (b#bgn) ,. b +/;.1 (end-bgn)
end.
f /: {:"1 f
)

NB. =========================================================
j_dir=: 3 : 0
hdr=. 1!:11 y.;0 512
try.
  <. each 7 {. 3!:2 :: 0: hdr
catch.
  <. each 7 {. (3!:2) 256 {. hdr
end.

)

NB. =========================================================
NB. get effective version
j_getver=: 3 : 0
h=. y.
'v s c l d f q'=. j_dir h
if. v >: V64L do. v return. end.
if. c = 0 do. V32L return. end.
free=. j_read h;f
dir=. j_readdir V32B,h,c,d
if. 1 e. l < {."1 dir do. V32L return. end.
r=. /:~ f,d,dir,free
p=. {.{.r
y=. p,+/"1 r
(y -: ({."1 r),l) { V32L,V32B
)

NB. =========================================================
NB. j_name
NB. returns file name (or handle if given)
j_name=: 3 : 0
y=. >y.
if. 2=3!:0 y do.
  y=. j_ext y
end.
)

NB. =========================================================
NB. j_open        - open file
NB. returns 2 elements: handle,ifopened
j_open=: 3 : 0
y=. >y.
if. 0 e. #y do. _1 return. end.
if. 2=3!:0 y do.
  y=. j_ext y
  j=. 1!:11 :: _1: y;0 0
  if. _1 -: j do. return. end.
  n=. ;{."1 [ 1!:20''
  h=. 1!:21 <y
  h,-.h e. n
else.
  y,0
end.
)

NB. =========================================================
NB. j_readcpt read directory for given components
j_readcpt=: 4 : 0
'v h d'=. x.
select. v
case. V64B do.
  <. B8 #. _8 [\"1 a. i. 1!:11 h,.(d+y.*16),.16
case. V32L do.
  <. B4 #. _4 |.\"1 a. i. 1!:11 h,.(d+y.*8),.8
case. V32B do.
  <. B4 #. _4 [\"1 a. i. 1!:11 h,.(d+y.*8),.8
case. V64L do.
  <. B8 #. _8 |.\"1 a. i. 1!:11 h,.(d+y.*16),.16
end.
)

NB. =========================================================
NB. j_readdir read all component directory
j_readdir=: 3 : 0
'v h c d e'=. y.
select. v
case. V64B do.
  _2[\ <. B8 #. _8 [\ a. i. 1!:11 h,d,c*16
case. V32L do.
  _2[\ <. B4 #. _4 |.\ a. i. 1!:11 h,d,c*8
case. V32B do.
  _2[\ <. B4 #. _4 [\ a. i. 1!:11 h,d,c*8
case. V64L do.
  _2[\ <. B8 #. _8 |.\ a. i. 1!:11 h,d,c*16
end.
)

NB. =========================================================
NB. j_upver
NB. update version number to current
j_upver=: 3 : 0
h=. y.
'v s c l d f q'=. j_dir h
if. v e. j_vcur '' do. return. end.
v=. j_getver h
dir=. j_readdir v,h,c,d
if. IF64 +. v = V64L do. v=. V64B end.
dir=. , v j_tochar dir
dir=. (512 >. #dir) j_take0 dir
d=. 512 >. d
free=. j_read h;f
free=. j_compress d,f,free
'l free new'=. (<dir) j_write l;free;h
'l f'=. j_writefree l;free;h
d=. ,new
q=. >:{.q,0
res=. v;s;c;l;d;f;q
(512 j_take0 j_rep res) 1!:12 h;0
res
)

NB. =========================================================
NB. following used for creating directory entries
j_tochar=: 4 : 0
select. x.
case. V64B do.
  ,"2 a. {~ B8 #: y.
case. V32L do.
  ,"2 |."1 a. {~ B4 #: y.
case. V32B do.
  ,"2 a. {~ B4 #: y.
case. V64L do.
  ,"2 |."1 a. {~ B8 #: y.
end.
)

NB. =========================================================
NB. j_write     - write data to file
NB. x. = data as boxed list
NB. y. = filelength;freelist;file
NB. result = filelength;freelist;position
j_write=: 4 : 0
'l f h'=. y.
x=. ,x.
d=. i.0 2
while. #x do.
  blk=. j_blk dat=. >{.x
  x=. }.x
  if.
    (#f) > ndx=. 1 i.~ blk <: {:"1 f
  do.
    'p s'=. ndx{f
    d=. d,p,blk
    if. blk < s do.
      f=. ((p+blk),s-blk) ndx } f
    else.
      f=. (ndx{.f),(>:ndx)}.f
    end.
    dat 1!:12 h;p
  else.
    d=. d,l,blk
    l=. l+blk
    (blk{.dat) 1!:3 h
  end.
end.
l;f;d
)

NB. =========================================================
NB. j_writefree   - write freelist to file
NB. y. = filelength;freelist;file
NB. result = filelength;position
j_writefree=: 3 : 0
'l f h'=. y.
blk=. 256 >. j_blk dat=. j_rep f
if.
  (#f) > ndx=. 1 i.~ blk <: {:"1 f
do.
  'p s'=. ndx{f
  d=. p,blk
  if. blk < s do.
    f=. ((p+blk),s-blk) ndx } f
  else.
    f=. (ndx{.f),(>:ndx)}.f
  end.
  (j_rep f) 1!:12 h;p
else.
  d=. l,blk
  l=. l+blk
  (blk{.dat) 1!:3 h
end.
l;d
)


NB. dup

NB. =========================================================
NB. jdup         - duplicate file
NB.
NB. if specific components are to be duplicated, these are read
NB. and written one at a time, otherwise the file is duplicated
NB. in batches of up to the size <max> given in the function.
jdup=: 3 : 0
'' jdup y.
:

fl=. x.
'y sel'=. 2{.boxopen y.
y=. j_name y

max=. 100000

if. own=. 0=#fl do.
  fl=. ((+./\.y=PATHSEP_j_)#y),'eraseme.pls'
end.

'h o'=. j_open y
if. h=_1 do. return. end.

if. #sel do.
  (c=. #sel) jcreate fl
  hx=. jopen fl
  whilst. #sel=. }.sel do.
    (jread h;{.sel) jappend hx
  end.
  
else.
  'v s c l d f q'=. j_dir h
  w=. (v e. V64B,V64L) { 8 16
  c jcreate fl
  hx=. jopen fl
  pos=. 0
  blk=. 1000
  read=. j_read@(h&;)
  
  while. c > pos do.
    j=. (({.d)+w*pos),w*blk<.c-pos
    dir=. j_readdir v,h,c,d
    pos=. pos+blk
    while. #dir do.
      siz=. {:"1 dir
      len=. 1>.(max<+/\siz)i.1
      (read &.> <"1 len{.dir) jappend hx
      dir=. len}.dir
    end.
  end.
  
end.

jclose hx
if. o do. jclose h end.

if. own do.
  pos=. 0
  siz=. 1!:4 <fl
  '' 1!:2 <y
  while. siz>pos do.
    len=. max<.siz-pos
    (1!:11 fl;pos,len) 1!:3 <y
    pos=. pos+max
  end.
  1!:55 <fl
end.

j_validate fl
c
)



NB. main

NB. =========================================================
NB. jappend      - append to file
jappend=: 4 : 0
'h o'=. j_open y.
if. h=_1 do. return. end.
'v s c l d f q'=. j_dir h
if. -. v e. j_vcur '' do.
  'v s c l d f q'=. j_upver h
end.
w=. (v = V64B) { 8 16
free=. j_read h;f
dat=. j_box x.
if. 1<#$dat do.
  if. o do. jclose h end.
  _3 return.
end.
res=. c+ i.#dat
'l free new'=. dat j_writerep l;free;h
dat=. , v j_tochar new
'b e'=. d
if. e>w*{:res do.
  dat 1!:12 h;b+w*c
  (j_rep free) 1!:12 h;{.f
else.
  dat=. (1!:11 h;b,w*c),dat
  free=. j_compress d,f,free
  'l free new'=. (<dat) j_write l;free;h
  'l f'=. j_writefree l;free;h
  d=. ,new
end.
c=. >:{:res
q=. >:{.q,0
(j_rep v;s;c;l;d;f;q) 1!:12 h;0
if. o do. jclose h end.
j_validate y.
res
)

NB. =========================================================
NB. jclose      - close file
jclose=: 1!:22 :: _4:

NB. =========================================================
NB. jcreate      - create file
NB. overwrites any existing file
NB. optional left argument is initial # of components
jcreate=: 3 : 0
0 jcreate y.
:
q=. s=. c=. 0
d=. 1024,<. >.&.(2&^.) 512>.8*x.
f=. (+/d),256
l=. +/f
v=. IF64 { V32L,V64B
hdr=. ({.f){.j_rep v;s;c;l;d;f;q;s
hdr=. l{.hdr,j_rep i.0 2
y=. <j_name y.
1!:55 :: 0: y
f=. (1: [ 1!:2) :: 0:
hdr f y
)

NB. =========================================================
NB. jerase       - erase file
jerase=: 1!:55 @ < @: j_name

NB. =========================================================
NB. jopen        - open file
NB. returns handle or _1
jopen=: 3 : 0
y=. >y.
if. 0 e. #y do. _1 return. end.
if. 2=3!:0 y do.
  y=. <j_ext y
  1!:21 :: _1: y
end.
)

NB. =========================================================
NB. jread        - read file
jread=: 3 : 0
'y x'=. y.
'h o'=. j_open y
if. h=_1 do. return. end.
'v s c l d f q'=. j_dir h
if. v < V64L do.
  v=. j_getver h
end.
w=. (v e. V64B,V64L) { 8 16
cpt=. ,x
if. (0=#cpt) +. 1 e. (cpt<0) +. cpt>:c do.
  if. o do. jclose h end.
  _2 return.
end.
dir=. (v,h,{.d) j_readcpt cpt
dat=. j_read &.> <"1 h,.dir
if. o do. jclose h end.
($x)$dat
)

NB. =========================================================
NB. jreplace     - replace in file
jreplace=: 4 : 0
'y x'=. y.
'h o'=. j_open y
if. h=_1 do. return. end.
'v s c l d f q'=. j_dir h
if. -. v e. j_vcur '' do.
  'v s c l d f q'=. j_upver h
end.
w=. (v = V64B) { 8 16
free=. j_read h;f
cpt=. ,x
if. 0=#cpt do. return. end.
if. 1 e. (cpt<0) +. cpt>:c
do.
  if. o do. jclose h end.
  _2 return.
end.
dat=. j_box x.
if. 1<#$dat do.
  if. o do. jclose h end.
  _3 return.
end.
dat=. (#cpt)$dat
dir=. (v,h,{.d) j_readcpt cpt
free=. j_compress dir,f,free
'l free new'=. dat j_writerep l;free;h
new=. <"1 v j_tochar new
new (1!:12 h&;) &.> ({.d)+cpt*w
'l f'=. j_writefree l;free;h
q=. >:{.q,0
(j_rep v;s;c;l;d;f;q) 1!:12 h;0
if. o do. jclose h end.
j_validate >{.y.
cpt
)

NB. =========================================================
NB. jseqno
jseqno=: 3 : 0
'h o'=. j_open y.
if. h=_1 do. return. end.
q=. >6{j_dir h
if. o do. jclose h end.
q
)

NB. =========================================================
NB. jsize
jsize=: 3 : 0
'h o'=. j_open y.
if. h=_1 do. return. end.
'v s c l d f q'=. j_dir h
free=. j_read h;f
if. o do. jclose h end.
s,c,l,{:+/free
)


NB. validate

NB. =========================================================
NB. j_valcheck
NB. checks directory + freelist
j_valcheck=: 3 : 0
'h o'=. j_open y.
if. h=_1 do. 1 return. end.
'v s c l d f q'=. j_dir h
free=. j_read h;f
dir=. j_readdir v,h,c,d
r=. /:~ f,d,dir,free
p=. {.{.r
s=. p e. 256 512 1024
y=. p,+/"1 r
if. o do. jclose h end.
s *. y -: ({."1 r),l
)

NB. =========================================================
NB. j_validate
NB. use for testing only - set to ] in distributed system
j_validate=: 3 : 0
13!:8 (-.j_valcheck y.) # 12
)

j_validate=: ]



NB. z definitions

jappend_z_=: jappend_jfiles_
jcreate_z_=: jcreate_jfiles_
jdup_z_=: jdup_jfiles_
jerase_z_=: jerase_jfiles_
jread_z_=: jread_jfiles_
jreplace_z_=: jreplace_jfiles_
jsize_z_=: jsize_jfiles_
