10 REM > UxFiler 1.31
   20 REM 05-Oct-2007 v0.10 Initial version based on SJFiler
   30 REM 08-Feb-2008 v0.11 IMPORT added
   40 REM 22-Aug-2008 v0.12 Reads UFSv7 images, EXPORT works
   50 REM 21-Jan-2012 v0.13 EXPORT doesn't match EX, save doesn't create empty *.bbc file
   60 REM 31-Aug-2013 v0.14 FREE works, INFO displays SuperBlock info
   70 REM 04-Apr-2019 v1.29 Bring all Filers to same version number
   80 REM 21-Mar-2020 v1.30a Probe for FSOp before writing long info
   90 REM 25-Mar-2020 v1.30b IF/ENDIF optimised for pre-BASIC V
  100 REM 30-Mar-2020 v1.30c Standard DiskIO code, home%, floppy access, (C)onfirm
  110 REM                    Sets metadata on final dir after copying
  120 REM 27-Apr-2020 v1.31 IF/ENDIF optimised for pre-BASIC V
  130 :
  140 os%=FNfx(0,1)AND&FF:VDU10,8:A%=POS:VDU13:IFA%<50:MODE&87:IFHIMEM>&7C00:MODE&83:IFHIMEM>&4000:MODE&80
  150 IFHIMEM<&FFFF:HIMEM=FNfx(132,0)
  160 PROCinit:PRINT"UxFiler v"ver$" by J.G.Harston"':ON ERROR IF FNerr:END
  170 REPEAT:X%=ctrl%:Y%=X%DIV256:IF POS:PRINT
  180   VDU 8:wdt%=POS+1:PRINT
  190   IFdrv$="":PRINTCHR$(D%+48)"> "ELSE PRINT"["drv$"] ";
  200   csd%=home%:INPUTLINE""A$:PROCdo(FNs(A$))
  210 UNTIL FALSE
  220 :
  230 DEFPROCinit:ver$="1.31a"
  240 DIM ctrl% 127,name% 255,zp% 7,data% 511,data2% 511,ientry% 63,dir% 515,object% 63,thisdir% 63,diskrec% 255 AND (os%=6)
  250 X%=ctrl%:Y%=X%DIV256:res%=0:D%=0:drv$="":path$="/":title$="":home%=-1:csd%=-1:fsv%=6
  260 fs%=FNfs:d$=".":s$="/":IFos%AND-24:d$="/":s$=".":IFos%AND-32:d$="\"
  270 cmd$=":MOUNT:DIR:CD:CAT:EX:LS:INFO:TYPE:DUMP:IMPORT:EXPORT:FREE:BLOCK:HELP:QUIT:"
  280 hlp$=":<drive>|<image>:<dir>|&<inode>:<dir>|&<inode>::::(<file>):<file> [CTRLS]:<file> [7BIT]:<host source> <unix dest> (<opts>):<unix source> <host dest> (<opts>)::<blocknum>:::"
  290 ENDPROC
  300 :
  310 DEFFNerr:OSCLI"FX229":IF POS:PRINT
  320 REPORT:IFFNfs<>fs%:OSCLI"FX143,18,"+STR$fs%
  330 PROCCloseAll:A%=ERR<>17 AND ERR<>28:PRINTLEFT$(" at line "+STR$ERL,ERR<128 AND A%):=INKEY-1 AND A%
  340 DEFPROCCloseAll:in%=in%:IFin%:A%=in%:in%=0:CLOSE#A%
  350 out%=out%:IFout%:A%=out%:out%=0:CLOSE#A%
  360 dsk%=dsk%:IFdsk%:A%=dsk%:dsk%=0:CLOSE#A%
  370 ENDPROC
  380 :
  390 DEFPROCdo(A$):IFA$="?":A$="HELP"
  400 IF LEFT$(A$,1)=";" OR A$="":ENDPROC
  410 IF LEFT$(A$,1)="*":OSCLIMID$(A$,2):ENDPROC
  420 IF LEFT$(A$,1)=".":A$="CAT "+MID$(A$,2)
  430 A%=INSTR(A$+" "," "):B$=FNuc(LEFT$(A$,A%-1)):A$=FNs(MID$(A$,A%+1))
  440 IF B$="COPY":B$="EXPORT":REM Temp fix
  450 IF LENB$=1 AND INSTR("0123",B$):drv$="":D%=VALB$:home%=-1:ENDPROC
  460 A%=INSTR(cmd$,":"+B$+":"):IF A%=0:PRINT"Bad command":ENDPROC
  470 A%=EVAL("FN_"+B$+"(A$)"):ENDPROC
  480 :
  490 DEFFNsyn(S$):IF A$="":PRINT "Syntax: "B$" "S$:=TRUE ELSE =FALSE
  500 :
  510 REM Commands
  520 REM ========
  530 ; FN_INFO, FN_QUIT, FN_FREE, FN_DIR, FN_MOUNT, FN_LS, FN_EXPORT, FN_CD :REM Prevent crunching
  540 ; FN_HELP, FN_TYPE, FN_DUMP, FN_CAT, FN_BLOCK, FN_EX, FN_IMPORT
  550 :
  560 DEFFN_QUIT(A$):PRINT"Quit"
  570 ON ERROR END
  580 IF os%>5:*QUIT
  590 END
  600 :
  610 DEFFN_HELP(A$):p%=2:q%=2:REPEAT
  620   A%=INSTR(cmd$,":",p%):PRINT SPC2MID$(cmd$,p%,A%-p%);:p%=A%+1
  630   A%=INSTR(hlp$,":",q%):PRINT TAB(9)MID$(hlp$,q%,A%-q%):q%=A%+1
  640 UNTIL p%>LENcmd$:=0
  650 :
  660 DEFFN_MOUNT(A$):home%=-1:IF LENA$<2:PROCdo(A$):=0 ELSE drv$=A$:D%=-1:=0
  670 DEFFN_CAT(A$):PROCLstDir(0):=0
  680 DEFFN_EX(A$):PROCLstDir(1):=0
  690 :
  700 DEFFN_LS(A$)=FN_EX(A$)
  710 DEFFN_CD(A$)=FN_DIR(A$)
  720 DEFFN_COPY(A$)=FN_EXPORT(A$)
  730 :
  740 DEFFN_DIR(A$):curr%=-1:IF FNsyn("<dir>|&<inode>"):=TRUE
  750 REM IFLEFT$(A$,1)="&":A%=FNMount:home%=EVAL(FNuc(A$)):path$="&"+FNh0(home%,6):=0
  760 IF A$="/":A%=FNMount:home%=root%:path$="/":=0
  770 IF FNlook:=TRUE
  780 IF(mode% AND 16384)=0:PRINT"'"src$"' not a directory":=TRUE
  790 path$=path$+fname$+"/":home%=ptr%
  800 IF RIGHT$(path$,3)="../":path$=LEFT$(path$,LENpath$-4):REPEAT:path$=LEFT$(path$,LENpath$-1):UNTILRIGHT$(path$,1)="/"
  810 IF RIGHT$(path$,2)="./":path$=LEFT$(path$,LENpath$-2)
  820 =0
  830 :
  840 DEFFN_BLOCK(A$):IF FNsyn("<blocknum>"):=TRUE
  850 blk%=EVAL("&"+FNuc(A$)):PROCRdBlocks(data%,blk%,D%,1):O%=data%:ln%=512:PROCdump(FALSE)
  860 =0
  870 :
  880 DEFFN_DUMP(A$):IF FNsyn("<fsp>"):=TRUE
  890 IF FNlook:=TRUE
  900 PROCdump(TRUE)
  910 =0
  920 :
  930 DEFPROCdump(F%):cols%=16:IF wdt%<80:cols%=8
  940 FOR P%=0 TO ln%-1 STEP cols%:B$=""
  950   PRINT FNh0(P%,6)" ";:IF F%:IF (P%AND&1FF)=0:PROCReadData(P%):O%=data%
  960   FOR Q%=P% TO P%+cols%-1
  970     IF Q%<ln%:PRINT FNh0(?O%,2)" "ELSE ?O%=32:PRINT SPC3;
  980     A$=CHR$(?O%AND&7F):IF A$>=" " AND A$<="~" B$=B$+A$ ELSE B$=B$+"."
  990 O%=O%+1:NEXT:PRINT B$:NEXT:ENDPROC
 1000 :
 1010 DEFFN_TYPE(A$):IF FNsyn("<fsp>"):=TRUE
 1020 msk%=INSTR(A$," [")<>0:msk%=(msk%AND&80)OR&7F:A$=LEFT$(A$,INSTR(A$+" "," ")-1)
 1030 IF FNlook:=TRUE
 1040 last%=0:FOR P%=0 TO ln%-1:IF(P%AND&1FF)=0:PROCReadData(P%):O%=data%
 1050   Q%=?O%ANDmsk%:IFmsk%=255:VDUQ% ELSE IFQ%=10 OR Q%=13 OR Q%>31 VDUQ%
 1060   IF(Q%=10 OR Q%=13) AND Q%<>last%:VDU23-Q%
 1070   IFQ%=9:PRINTSPC(8-(POS MOD 8));
 1080 last%=?O%:O%=O%+1:NEXT:IF POS:PRINT
 1090 =0
 1100 :
 1110 DEFFN_FREE(A$)
 1120 PROCRdInode(0):PROCRdBlocks(dir%,1,D%,1):isize%=dir%!0 AND &FFFF
 1130 IF fsv%=6:fsize%=dir%!2 AND &FFFF:nfree%=dir%!4 AND &FFFF:ptr%=dir%!6 AND &FFFF
 1140 IF fsv%=7:fsize%=FNswap32(dir%!2):nfree%=dir%!6 AND &FFFF:ptr%=FNswap32(dir%!8)
 1150 free%=nfree%:REPEAT
 1160   IF ptr%:PROCRdBlocks(data%,ptr%,D%,1):IF data%?1=0:free%=free%+data%?0
 1170   IF ptr%:IF fsv%=6:ptr%=data%!2 AND &FFFF
 1180   IF ptr%:IF fsv%=7:ptr%=FNswap32(data%!2)
 1190 UNTILptr%<2 OR ptr%>=fsize%:used%=fsize%-free%
 1200 PRINT"Disk free: &"FNh0(free%,8)" blocks, &"FNh0(free%*512,8)" bytes, ";free%DIV2;"K"
 1210 PRINT"Disk used: &"FNh0(used%,8)" blocks, &"FNh0(used%*512,8)" bytes, ";used%DIV2;"K"
 1220 PRINT"Disk size: &"FNh0(fsize%,8)" blocks, &"FNh0(fsize%*512,8)" bytes, ";fsize%DIV2;"K"
 1230 =0
 1240 :
 1250 DEFFN_INFO(A$)
 1260 IF A$="":PROCPrSBlock:=0
 1270 IF FNlook:=TRUE
 1280 inode%=ptr%:x%=0:PROCListFile(1)
 1290 IF fsv%=6:FOR p%=8 TO isz%-1 STEP 2:PRINTFNh0(ientry%!p%,4)" ";:NEXT:PRINT
 1300 IF fsv%=7:FOR p%=12 TO 41 STEP 3:PRINTFNh0(FNswap24(ientry%!p%),6)" ";:NEXT:PRINT
 1310 IF fsv%=7:FOR p%=42 TO 48 STEP 3:PRINTFNh0(FNswap24(ientry%!p%),6)" ";:NEXT:PRINT
 1320 =0
 1330 :
 1340 DEFFN_EXPORT(A$):IF FNsyn("<unix source> (inf:)<host dest> (<C>onfirm)"):=TRUE
 1350 REM copy * path
 1360 REM copy * inf:path
 1370 A%=INSTR(A$+" "," "):src$=LEFT$(A$,A%-1):dst$=FNs(MID$(A$,A%+1))
 1380 cnf%=FNuc(RIGHT$(dst$,2))=" C":IF cnf%:dst$=FNs(LEFT$(dst$,LENdst$-2))
 1390 inf%=FNuc(LEFT$(dst$,4))="INF:":IFinf%:dst$=MID$(dst$,5)
 1400 IFdst$="":PRINT"<dest> missing":=TRUE
 1410 IFos%<6:IFINSTR(dst$,"::")ORLEFT$(dst$,1)="-":PRINT"FS prefix unsupported":=TRUE
 1420 A$=src$:IF A$<>"/":A%=FNlook:cblk%=ptr%:IF A%:=TRUE
 1430 IF A$ ="/":A%=FNMount:cblk%=root%:IF A%<0:=TRUE
 1440 PROCFileInfo(cblk%)
 1450 IF(mode%AND24576)<>16384:fptr%=ientry%:leaf$=src$:PROCCopyOneFile(src$,dst$):=0:REM Copy one file
 1460 :
 1470 REM src=directory, copy all recursively
 1480 A%=FNfile(dst$,8):dst$=dst$+d$:PROCCopyDirectory(dst$)
 1490 PROCMetaInfo(thisdir%):PROCAcornInfo
 1500 PROCSetInfo(LEFT$(dst$,LENdst$-1)):REM Set top directory's metadata
 1510 =0
 1520 :
 1530 DEFFN_IMPORT(A$):IF FNsyn("<host source> <unix dest>"):=TRUE
 1540 A%=INSTR(A$," "):src$=LEFT$(A$,A%-1):A$=MID$(A$,A%+1)
 1550 A%=INSTR(A$," "):dst$=LEFT$(A$,A%-1):A$=MID$(A$,A%+1)
 1560 ptr%=FNfind(dst$):IFptr%=0:PRINT"'"dst$"' not found":=TRUE
 1570 PROCFileInfo(ptr%):REM ln%=length%
 1580 in%=FNf_openin(src$):IFin%=0:PRINT"'"src$"' not found":=TRUE
 1590 ln%=EXT#in%:IFln%>length%:CLOSE#in%:in%=0:PRINT"Source file longer than dest":=TRUE
 1600 REM IF ln%>16383:CLOSE#in%:in%=0:PRINT"Can't do long files yet":=TRUE
 1610 IF ln%>1024*1024-1:CLOSE#in%:in%=0:PRINT"Can't 1M+ files yet":=TRUE
 1620 FOR P%=0 TO ln%-1:B%=0:REM B% doesn't seem to be used for anything
 1630   IF(P%AND&1FF)=0:PROCf_gbpb(3,in%,data%,512,P%):PROCWriteData(P%)
 1640 NEXT:CLOSE#in%:in%=0
 1650 =0
 1660 :
 1670 :
 1680 REM File copying code
 1690 REM =================
 1700 REM Fails to continue if more than 32*4 entries
 1710 :
 1720 DEFPROCCopyDirectory(dst$):LOCAL entry%,bit%,inode%,fptr%,fname$,blk%,dptr%,alloc%
 1730 REM cblk%=inode number of source dir
 1740 REM ientry contains source dir infor
 1750 REM fptr% points to current object's ientry
 1760 FOR A%=0 TO 63 STEP 4:thisdir%!A%=ientry%!A%:NEXT
 1770 alloc%=all0%
 1780 REPEAT
 1790     blk%=thisdir%!alloc% AND &FFFFFF:IFfsv%=6:blk%=blk% AND &FFFF
 1800     IF blk%:PROCCopyBlock
 1810     alloc%=alloc%+alsz%
 1820     REM  IF alloc%<almx%:PROCRdInode(cblk%)
 1830 UNTIL blk%=0 OR alloc%>almx%-1
 1840 ENDPROC
 1850 :
 1860 REM This is almost the same as PROCLstBlock
 1870 DEFPROCCopyBlock
 1880 PROCRdBlocks(dir%,blk%,D%,1):dptr%=dir%
 1890 REPEAT
 1900     inode%=!dptr% AND &FFFF
 1910     A%=dptr%?16:dptr%?16=13:fname$=$(dptr%+2)+CHR$0:dptr%?16=A%
 1920     fname$=LEFT$(fname$,INSTR(fname$,CHR$0)-1)
 1930     IF inode% THEN PROCCopyObject
 1940     dptr%=dptr%+16
 1950 UNTIL dptr%>=dir%+512
 1960 ENDPROC
 1970 :
 1980 DEFPROCCopyObject:LOCAL ptr%,bit%,old_cblk%,thisdir$,bitmap$,object$
 1990 IF fname$="." OR fname$="..":ENDPROC
 2000 IFcnf%:PRINT"Copy "fname$;:cnf%=FNyna(cnf%):IFcnf%>0:PRINT:ENDPROC ELSE VDU13
 2010 PROCFileInfo(inode%):leaf$=fname$:fname$=LEFT$(FNfn_undos(fname$),10):fptr%=ientry%
 2020 IF(mode%AND24576)<>16384:PROCCopyOneFile(leaf$,dst$+fname$):ENDPROC
 2030 :
 2040 REM Descend into directory
 2050 old_cblk%=cblk% :REM Save current directory inode number
 2060 FOR A%=0 TO 63:thisdir$=thisdir$+CHR$thisdir%?A%:NEXT  :REM Save current object info
 2070 FOR A%=0 TO 63:object$ =object$ +CHR$fptr%?A%   :NEXT  :REM Save current object info
 2080 cblk%=inode%                      :REM Current inode is this directory
 2090 A%=FNfile(dst$+fname$,8)          :REM Create matching destination directory
 2100 PROCCopyDirectory(dst$+fname$+d$) :REM Copy directory at cblk%
 2110 FOR A%=0 TO 63:object%?A%=ASCMID$(object$,A%+1):NEXT   :REM Restore object info
 2120 PROCMetaInfo(object%)
 2130 PROCAcornInfo:PROCSetInfo(dst$+fname$)                 :REM Set directory's metadata
 2140 :
 2150 REM Restore into current (parent) directory
 2160 FOR A%=0 TO 63:thisdir%?A%=ASCMID$(thisdir$,A%+1):NEXT :REM Restore current object info
 2170 cblk%=old_cblk%:PROCRdBlocks(dir%,blk%,D%,1)           :REM Restore current directory block
 2180 ENDPROC
 2190 :
 2200 DEFPROCCopyOneFile(src$,dst$):LOCAL cblk%
 2210 PRINT"Copying "src$;SPC(15-LENsrc$)"to "dst$SPC3;
 2220 FOR A%=0 TO 63 STEP 4:object%!A%=fptr%!A%:NEXT
 2230 PROCMetaInfo(object%):IFFNfile(dst$,5):X%?14=&33:A%=FNfile(dst$,4)
 2240 PROCAcornInfo:X%!2=load%:X%!6=exec%:X%!10=0:X%!14=length%:A%=FNfile(dst$,7)
 2250 IFlength%:PROCCopyData            :REM Copy if length<>0
 2260 PROCSetInfo(dst$):PRINTSTRING$(3,CHR$127):ENDPROC
 2270 :
 2280 DEFPROCCopyData
 2290 out%=FNf_openout(dst$):P%=0:REPEAT:PROCReadData(P%):IF POS=0:PRINTSPC4;
 2300   IF(P%AND1023)=0:PRINT STRING$(3,CHR$8)FNd(100*P%DIVlength%,2)"%";
 2310   num%=512:IFP%+num%>length%:num%=length%-P%
 2320 PROCf_gbpb(2,out%,data%,num%,0):P%=P%+512:UNTILP%>=length%
 2330 CLOSE#out%:out%=0:ENDPROC
 2340 :
 2350 DEFPROCSetInfo(dst$):X%!2=load%:X%!6=exec%:X%!10=length%:X%!14=attr%:A%=FNfile(dst$,1)
 2360 A$=leaf$+STRING$(15-LENleaf$," ")+FNh0(load%,8)+" "+FNh0(exec%,8)+" "+FNh0(length%,8)+CHR$13+CHR$10:REM +" "+FNh0(attr%,2)+" "+CHR$13+CHR$10
 2370 IFinf%:out%=OPENOUT(dst$+s$+"inf"):FOR p%=1 TO LEN A$:BPUT#out%,ASCMID$(A$,p%,1):NEXT:CLOSE#out%:out%=0
 2380 IFfs%<>5:ENDPROC
 2390 REM A%=FNNetFS_Op(19,CHR$4+CHR$access%+dst$) :REM Write access
 2400 X%!8=cdate%:A%=FNNetFS_OpN(19,5,10,dst$) :REM Write create date
 2410 IF FNNetFS_Op(18,CHR$64+dst$):ENDPROC    :REM create&mod date&time don't exist
 2420 X%!8=cdate%:X%!10=ctime%:X%!13=mdate%:X%!15=mtime%
 2430 A%=FNNetFS_OpN(19,64,18,dst$)            :REM Write create&mod date&time
 2440 A%=FNNetFS_Op(0,"ACCOUNT "+dst$+" "+STR$~acc%+" ("+STR$~aux%+")")
 2450 ENDPROC
 2460 :
 2470 :
 2480 REM Object display routines
 2490 REM =======================
 2500 :
 2510 DEFPROCLstDir(cflg%):x%=0:IF FNMount:PRINT"Not a UNIX disk":ENDPROC
 2520 REM cflg%=0 - CAT, cflg%=1 - EX
 2530 PROCRdInode(csd%):REM IFcsd%=-1:csd%=root%:path$="/"
 2540 IF(ientry%?1 AND (64+32))<>64 THEN PRINT "inode "FNh0(csd%,4)" is not a directory":ENDPROC
 2550 PRINT "Path: "path$
 2560 IF(cflg%AND1):PRINT "inode filename"SPC12"mode"SPC6"nd uid gid len   ctime"SPC4"mtime"SPC4"atime"
 2570 alloc%=all0%
 2580 REPEAT
 2590     blk%=ientry%!alloc% AND &FFFFFF:IFfsv%=6:blk%=blk% AND &FFFF
 2600     IF blk%:PROCListBlock
 2610     alloc%=alloc%+alsz%
 2620     IF alloc%<almx%:PROCRdInode(csd%)
 2630 UNTIL blk%=0 OR alloc%>almx%-1
 2640 IF(cflg%AND1)=0:IF(x%AND3):PRINT
 2650 ENDPROC
 2660 :
 2670 REM This is almost the same as PROCCopyBlock
 2680 DEFPROCListBlock
 2690 PROCRdBlocks(dir%,blk%,D%,1):dptr%=dir%
 2700 REPEAT
 2710     inode%=!dptr% AND &FFFF
 2720     A%=dptr%?16:dptr%?16=13:fname$=$(dptr%+2)+CHR$0:dptr%?16=A%
 2730     fname$=LEFT$(fname$,INSTR(fname$,CHR$0)-1)
 2740     IF inode%:PROCListFile(cflg%)
 2750     dptr%=dptr%+16
 2760 UNTIL dptr%>=dir%+512
 2770 ENDPROC
 2780 :
 2790 DEFPROCListFile(cflg%)
 2800 IF(cflg%AND1):PRINT FNh0(inode%,4)" ";
 2810 PROCFileInfo(inode%):PRINTfname$;SPC(15-LENfname$);
 2820 IF(cflg%AND1)=0:x%=x%+1:IF x%<wdt% DIV 15:PRINT " "ELSE IF(cflg%AND1)=0:x%=0:PRINT
 2830 IF(cflg%AND1)=0:ENDPROC
 2840 PRINT FNattr(mode%)" ";   :REM mode
 2850 PRINT FNh0(nlink%,2)" ";  :REM nlink - nb, 16-bit on v7
 2860 PRINT FNh0(uid%,2)" ";    :REM uid   - nb, 16-bit on v7
 2870 PRINT FNh0(gid%,2)" ";    :REM gid   - nb, 16-bit on v7
 2880 PRINT FNd(length%,6);     :REM size
 2890 PRINT ;
 2900 PRINT " "FNdate(cdate%);
 2910 PRINT " "FNdate(mdate%);
 2920 PRINT " "FNdate(adate%);
 2930 PRINT:ENDPROC
 2940 :
 2950 DEFPROCPrSBlock
 2960 A%=FN_FREE("")
 2970 PRINT "UnixFS version:";SPC14;fsv%;" (";8*fsv%-32;"-bit)"
 2980 PRINT "isize: inode table size:"SPC5"&"FNh0(isize%,4)" blocks, max inode: &";~isize%*512/isz%
 2990 REM       - &"FNh0(isize%*512,6)" bytes, ";(isize%*512)/isz%;" entries"
 3000 PRINT "in-core free blocks: &"FNh0(nfree%,4)
 3010 IF fsv%=6:fbk%=6:stp%=2:ino%=&CE:in1%=&197
 3020 IF fsv%=7:fbk%=8:stp%=4:ino%=&D0:in1%=&199
 3030 FOR n%=fbk% TO ino%-1 STEP stp%:IF fsv%=6:PRINT FNh0(dir%!n%,4); ELSE IF fsv%=7:PRINT FNh0(FNswap32(dir%!n%),8);
 3040   IF (n% AND 31)=4:PRINTCHR$ELSE PRINT" ";
 3050 NEXT:PRINT
 3060 PRINT "in-core free inodes: &"FNh0(dir%!ino%,4)
 3070 FOR n%=ino%+2 TO in1% STEP 2:PRINT FNh0(dir%!n%,4);:IF ((n%-ino%-2) AND 31)=30:PRINTCHR$ELSE PRINT" ";
 3080 NEXT:PRINT
 3090 PRINT "flock: free list lock:"SPC7FNh0(dir%?(in1%+1),2);SPC8;
 3100 PRINT "ilock: inode table lock: "FNh0(dir%?(in1%+2),2)
 3110 PRINT "fmod:  superblock modified:  "FNh0(dir%?(in1%+3),2);SPC8;
 3120 PRINT "dlock: disk read only:"SPC3FNh0(dir%?(in1%+4),2)
 3130 PRINT "time:  disk last update:"SPC5FNdate(FNswap32(dir%!(in1%+5)))
 3140 FOR n%=in1%+9 TO &1FF STEP 2:PRINT FNh0(dir%!n%,4);:IF ((n%-in1%-9) AND 31)=30:PRINTCHR$ELSE PRINT" ";
 3150 NEXT:IF POS:PRINT
 3160 ENDPROC
 3170 :
 3180 DEFFNattr(A%):A$=""
 3190 IF(A%AND1)     THEN A$="x" ELSE A$="-"
 3200 IF(A%AND2)     THEN A$="w"+A$ ELSE A$="-"+A$
 3210 IF(A%AND4)     THEN A$="r"+A$ ELSE A$="-"+A$
 3220 IF(A%AND8)     THEN A$="x"+A$ ELSE A$="-"+A$
 3230 IF(A%AND16)    THEN A$="w"+A$ ELSE A$="-"+A$
 3240 IF(A%AND32)    THEN A$="r"+A$ ELSE A$="-"+A$
 3250 IF(A%AND64)    THEN A$="x"+A$ ELSE A$="-"+A$
 3260 IF(A%AND128)   THEN A$="w"+A$ ELSE A$="-"+A$
 3270 IF(A%AND256)   THEN A$="r"+A$ ELSE A$="-"+A$
 3280 IF(A%AND512)   THEN A$="s"+A$ ELSE A$="-"+A$
 3290 IF(A%AND1024)  THEN A$="g"+A$ ELSE A$="-"+A$
 3300 IF(A%AND2048)  THEN A$="u"+A$ ELSE A$="-"+A$
 3310 IF(A%AND4096)  THEN A$="l"+A$ ELSE A$="-"+A$
 3320 IF(A%AND8192)  THEN A$="c"+A$ ELSE A$="-"+A$
 3330 IF(A%AND16384) THEN A$="d"+A$ ELSE A$="-"+A$
 3340 IF(A%AND32768) THEN A$="a"+A$ ELSE A$="-"+A$
 3350 =A$
 3360 :
 3370 DEFFNdate(A%):REM seconds since 1970, &33:6E996A00
 3380 LOCAL day%,month%,year%,hour%,minute%,second%
 3390 X%!1=A%/2.56:X%!1=X%!1+&336E996A:PROCDate_ToOrd(X%)
 3400 =FNd0(day%,2)+"/"+FNd0(month%,2)+"/"+FNd0(year%,2)
 3410 :
 3420 DEFFNtime(A%):REM seconds since 1970, &33:6E996A00
 3430 LOCAL day%,month%,year%,hour%,minute%,second%
 3440 X%!1=A%/2.56:X%!1=X%!1+&336E996A:PROCDate_ToOrd(X%)
 3450 =FNd0(hour%,2)+":"+FNd0(minute%,2)
 3460 :
 3470 DEFPROCUnixDateToAcorn(A%):REM seconds since 1970, &33:6E996A00
 3480 X%!1=A%/2.56:X%!1=X%!1+&336E996A:PROCDate_ToOrd(X%)
 3490 date%=&101:IFyear%>1980:date%=FNf_date(day%,month%,year%)
 3500 time%=FNf_time(hour%,minute%,second%)
 3510 ENDPROC
 3520 :
 3530 DEFPROCAcornInfo
 3540 attr%=(mode%AND256)DIV256+(mode%AND128)DIV64+(mode%AND64)DIV16
 3550 attr%=attr%+(((mode%AND32)/2)OR((mode%AND4)*4))+(((mode%AND16)*2)OR((mode%AND2)*16))+(((mode%AND8)*8)OR((mode%AND1)*64))
 3560 IF cdate%>mdate%:cdate%=mdate%:REM If Change>Modify, make Create=Modify
 3570 REM PROCUnixDateToAcorn(adate%):adate%=date%:atime%=time%
 3580 PROCUnixDateToAcorn(cdate%):cdate%=date%:ctime%=time%
 3590 PROCUnixDateToAcorn(mdate%):mdate%=date%:mtime%=time%
 3600 PROCDate_FromOrd(X%,day%,month%,year%,hour%,minute%,second%,0)
 3610 X%!5=&FFFFFF:IF(mode%AND&49):X%!5=&FFFFE6
 3620 load%=X%!4:exec%=!X%:attr%=attr%+256*mdate%:acc%=uid%:aux%=gid%
 3630 ENDPROC
 3640 :
 3650 REM Catalog manipulation routines
 3660 REM =============================
 3670 :
 3680 DEFFNlook:src$=A$:ptr%=FNfind(src$):IFptr%:PROCFileInfo(ptr%):ln%=length%:=FALSE
 3690 PRINT"'"src$"' not found":=TRUE
 3700 :
 3710 DEFFNfind(A$):match$=FNuc(LEFT$(A$,16)):match%=0:IFFNMount:=0
 3720 PROCRdInode(csd%):IFcsd%=-1:csd%=root%
 3730 alloc%=all0%:match%=0
 3740 REPEAT
 3750     blk%=ientry%!alloc% AND &FFFFFF:IFfsv%=6:blk%=blk% AND &FFFF
 3760     IF blk%:PROCFileBlock
 3770     alloc%=alloc%+alsz%
 3780     IF NOT match%:IF alloc%<almx%:PROCRdInode(csd%)
 3790 UNTIL blk%=0 OR alloc%>almx%-1 OR match%
 3800 IF match%:=inode% ELSE =0
 3810 :
 3820 REM This is almost the same as PROCListBlock, PROCCopyBlock
 3830 DEFPROCFileBlock
 3840 PROCRdBlocks(dir%,blk%,D%,1):dptr%=dir%
 3850 REPEAT
 3860     inode%=!dptr% AND &FFFF
 3870     A%=dptr%?16:dptr%?16=13:fname$=$(dptr%+2)+CHR$0:dptr%?16=A%
 3880     fname$=LEFT$(fname$,INSTR(fname$,CHR$0)-1)
 3890     match%=(FNuc(fname$)=match$)
 3900     dptr%=dptr%+16
 3910 UNTIL dptr%>=dir%+512 OR match%
 3920 ENDPROC
 3930 :
 3940 DEFPROCFileInfo(f%):PROCRdInode(f%):PROCMetaInfo(ientry%):ENDPROC
 3950 :
 3960 DEFPROCMetaInfo(i%)
 3970 REM P.:FOR A%=0 TO 63:P.FNh0(ientry%?A%,2)" ";:NEXT:P.
 3980 mode%  =i%!0 AND &FFFF
 3990 nlink% =i%!2 AND &FFFF              :IF fsv%=6:nlink%=nlink% AND &FF
 4000 uid%   =i%!(2+usz%/2) AND &FFFF     :IF fsv%=6:uid%=uid% AND &FF
 4010 gid%   =i%!(2+2*(usz%/2)) AND &FFFF :IF fsv%=6:gid%=gid% AND &FF
 4020 IF fsv%=6:length%=FNswap24(i%!5)
 4030 IF fsv%=7:length%=FNswap32(i%!8)
 4040 IF fsv%=6:adate%=FNswap32(i%!tm%)    :mdate%=FNswap32(i%!(tm%+4)):cdate%=mdate%
 4050 IF fsv%=7:adate%=FNswap32(i%!(tm%+8)):mdate%=FNswap32(i%!(tm%+4)):cdate%=FNswap32(i%!tm%)
 4060 ENDPROC
 4070 :
 4080 REM DEFPROCRdDir:IFcurr%=csd%:ENDPROC
 4090 REM Read directory
 4100 REM curr%=csd%:ENDPROC
 4110 :
 4120 :
 4130 REM Disk access routines
 4140 REM ====================
 4150 :
 4160 DEFPROCRdInode(i%)
 4170 PROCRdBlocks(data%,2,D%,1)
 4180 REM fsv%=6:            isz%=32:root%=1:all0%=8 :almx%=&18:alsz%=2:tm%=&18:usz%=2
 4190 REM IFdata%!8=0:fsv%=7:isz%=64:root%=2:all0%=13:almx%=&34:alsz%=3:tm%=&34:usz%=4
 4200 REM IFi%=-1:i%=root%
 4210 PROCRdBlocks(data%,(&400+i%*isz%-isz%)DIV512,D%,1)
 4220 i%=(&400+i%*isz%-isz%)AND511
 4230 FOR A%=0 TO isz%-1 STEP 4:ientry%!A%=data%!(A%+i%):NEXT
 4240 ENDPROC
 4250 :
 4260 DEFFNMount:IFcsd%<>-1:=0
 4270 PROCfdcInit(diskrec%,9,9,2,2,80,1):PROCRdBlocks(data%,2,D%,1)
 4280 fsv%=6:            isz%=32:root%=1:all0%=8 :almx%=&18:alsz%=2:tm%=&18:usz%=2
 4290 IFdata%!8=0:fsv%=7:isz%=64:root%=2:all0%=13:almx%=&34:alsz%=3:tm%=&34:usz%=4
 4300 REM IF fsv%=6:IF (data%?1 AND 64)=0 OR data%?2<2:=TRUE                :REM 16-bit
 4310 REM IF fsv%=7:IF (data%?65 AND 64)=0 OR (data%!66 AND &FFFF)<2:=TRUE  :REM 24-bit
 4320 REM REM Check root starts with '..' and '.'
 4330 REM PROCRdInode(root%):PROCRdBlocks(data%,ientry%!all0%,D%,1)
 4340 REM IF data%!0<>root%+&2E2E0000 OR data%!16<>root%+&002E0000:=TRUE
 4350 csd%=root%:home%=csd%:path$="/"
 4360 =0
 4370 :
 4380 DEFPROCReadData(ptr%):PROCTxData(FALSE):ENDPROC
 4390 DEFPROCWriteData(ptr%):PROCTxData(TRUE):ENDPROC
 4400 :
 4410 DEFPROCTxData(write%):LOCAL p%
 4420 vec%=(mode%AND4096)<>0
 4430 IF fsv%=6:PROCTx6
 4440 IF fsv%=7:PROCTx7
 4450 IF p%=0:IF NOT write%:FOR A%=0 TO 511 STEP 4:data%!A%=0:NEXT:ENDPROC
 4460 IF p%:PROCTxBlocks(data%,p%,D%,1,write%)
 4470 ENDPROC
 4480 :
 4490 DEFPROCTx7
 4500 IF ptr%<&1400:p%=ptr%DIV512:p%=12+p%*3:p%=FNswap24(ientry%!p%):ENDPROC
 4510 IF ptr%<&11400:p%=&2A ELSE p%=&2D
 4520 p%=FNswap24(ientry%!p%):PROCRdBlocks(data2%,p%,D%,1)
 4530 IF ptr%<&11400:ptr%=ptr%-&1400:p%=ptr%DIV512 ELSE ptr%=ptr%-&11400:p%=ptr%DIV(512*128):p%=FNswap32(data2%!(p%*4)):PROCRdBlocks(data2%,p%,D%,1):p%=(ptr%DIV512)AND127
 4540 p%=FNswap32(data2%!(p%*4))
 4550 ENDPROC
 4560 :
 4570 REM DEFPROCTx7:LOCAL q%
 4580 REM IF ptr%<&1400 THEN
 4590 REM  p%=ptr%DIV512
 4600 REM  p%=12+p%*3
 4610 REM  p%=FNswap24(ientry%!p%)
 4620 REM ELSE
 4630 REM  IF ptr%<&11400 THEN
 4640 REM   p%=&2A
 4650 REM   p%=FNswap24(ientry%!p%)
 4660 REM   PROCRdBlocks(data2%,p%,D%,1)
 4670 REM   ptr%=ptr%-&1400
 4680 REM   p%=ptr%DIV512
 4690 REM   p%=p%*4
 4700 REM   p%=FNswap32(data2%!p%)
 4710 REM  ELSE
 4720 REM   p%=&2D
 4730 REM   p%=FNswap24(ientry%!p%)
 4740 REM   PROCRdBlocks(data2%,p%,D%,1)
 4750 REM   ptr%=ptr%-&11400
 4760 REM   p%=ptr%DIV(512*128)
 4770 REM   p%=p%*4
 4780 REM   p%=FNswap32(data2%!p%)
 4790 REM   PROCRdBlocks(data2%,p%,D%,1)
 4800 REM   p%=(ptr%DIV512)AND127
 4810 REM   p%=p%*4
 4820 REM   p%=FNswap32(data2%!p%)
 4830 REM  ENDIF
 4840 REM ENDIF
 4850 REM ENDPROC
 4860 :
 4870 DEFPROCTx6
 4880 IF vec%=0:p%=8+2*(ptr%DIV512):p%=ientry%!p%:ENDPROC
 4890 p%=8+2*(ptr% DIV (128*1024))
 4900 REM -- If length%>1M, needs to use extended vectors
 4910 PROCRdBlocks(data2%,ientry%!p%,D%,1)
 4920 p%=(ptr%DIV512)AND&FF:p%=data2%!(p%*2)
 4930 ENDPROC
 4940 :
 4950 REM DEFPROCTx6
 4960 REM IF vec%=0 THEN
 4970 REM  p%=8+2*(ptr%DIV512)
 4980 REM  p%=ientry%!p%
 4990 REM ELSE
 5000 REM  p%=8+2*(ptr% DIV (128*1024))
 5010 REM  REM -- If length%>1M, needs to use extended vectors
 5020 REM  PROCRdBlocks(data2%,ientry%!p%,D%,1)
 5030 REM  p%=(ptr%DIV512)AND&FF
 5040 REM  p%=p%*2
 5050 REM  p%=data2%!p%
 5060 REM ENDIF
 5070 REM ENDPROC
 5080 :
 5090 DEFPROCRdBlocks(a%,b%,d%,n%):PROCTxBlocks(a%,b%,d%,n%,FALSE):ENDPROC
 5100 DEFPROCWrBlocks(a%,b%,d%,n%):PROCTxBlocks(a%,b%,d%,n%,TRUE):ENDPROC
 5110 :
 5120 DEFPROCTxBlocks(addr%,block%,drive%,number%,write%):LOCAL q%
 5130 err%=0:block%=block%AND&FFFFFF:IFfsv%=6:block%=block%AND&FFFF
 5140 FOR q%=0 TO number%-1:PROCfdcAct(2+(write%=0),addr%+q%*512,block%+res%+q%,drive%,1,0):NEXT
 5150 ENDPROC
 5160 :
 5170 :
 5180 REM FDC routines
 5190 REM ============
 5200 :
 5210 DEFPROCfdcInit(dskrec%,bps%,spt%,hds%,den%,trks%,sec0%)
 5220 LOCAL i%:IFos%<>6:ENDPROC
 5230 dskrec%?0=bps%:dskrec%?1=spt%:dskrec%?2=hds%:dskrec%?3=den%:IFden%=1:dskrec%?2=1
 5240 FOR i%=4 TO 59 STEP 4:dskrec%!i%=0:NEXT:dskrec%!60=&20000000:dskrec%!64=&20000000
 5250 dskrec%?8=sec0%:dskrec%!16=trks%*spt%*(2^bps%)*hds%
 5260 ENDPROC
 5270 :
 5280 DEFPROCfdcAct(op%,ad%,sc%,dv%,nm%,dn%)
 5290 IFop%=1:FORA%=0TO511STEP4:ad%!A%=0:NEXT
 5300 IFdv%>1:err%=-1:ENDPROC
 5310 IFdrv$="":REPEAT:PROCfdcOp(op%):ad%=ad%+512:sc%=sc%+1:nm%=nm%-1:UNTILnm%<1:ENDPROC
 5320 IFop%=2:dsk%=FNf_openup(drv$):IFdsk%=0:err%=-2:ENDPROC
 5330 IFop%=1:dsk%=FNf_openin(drv$):IFdsk%=0:err%=-2:ENDPROC
 5340 IFop%=1:IFsc%*512>EXT#dsk%:CLOSE#dsk%:dsk%=0:err%=-3:PRINT"Disk error: past end of image":ENDPROC
 5350 PROCf_gbpb(5-op%*2,dsk%,ad%,nm%*512,sc%*512):CLOSE#dsk%:dsk%=0
 5360 ENDPROC
 5370 :
 5380 DEFPROCfdcOp(op%)
 5390 IFos%>6:err%=-1
 5400 IFos%=6:CASEATN"XADFS_DiscOp",,op%+(diskrec%<<6),sc%*512+((dv%AND3)<<29),ad%,512 TO err%
 5410 IFos%<6:trk%=sc%DIV9:trk%=trk%DIV2+80*(trk%AND1):err%=FNscsi(ad%,6+op%*2,dv%OR4,trk%*16+sc%MOD9+1,1)
 5420 IFcsd%=0:ENDPROC
 5430 IFerr%:IFPOS:PRINT
 5440 IFerr%=-1:PRINT"Unsupported":ENDPROC
 5450 IFerr%:PRINT"Disk error &"FNh0(err%,2)" at ";dv%":"FNh0(sc%,6)
 5460 ENDPROC
 5470 :
 5480 DEFFNswap24(A%):zp%!0=A%:zp%!3=A%:=zp%!1 AND &FFFFFF
 5490 DEFFNswap32(A%):zp%!0=A%:zp%!4=A%:=zp%!2
 5500 DEFFNs(A$):IFLEFT$(A$,1)=" ":REPEATA$=MID$(A$,2):UNTILLEFT$(A$,1)<>" "
 5510 IFRIGHT$(A$,1)=" ":REPEATA$=LEFT$(A$,LENA$-1):UNTILRIGHT$(A$,1)<>" "
 5520 =A$
 5530 DEFFNuc(A$):IFA$="":=""
 5540 FORA%=1TOLENA$:IFMID$(A$,A%,1)>"_":A$=LEFT$(A$,A%-1)+CHR$(ASCMID$(A$,A%,1)AND&5F)+MID$(A$,A%+1)
 5550 NEXT:=A$
 5560 DEFFNfx(A%,X%):LOCAL Y%:Y%=X%DIV256:=(USR&FFF4 AND &FFFF00)DIV256
 5570 :
 5580 REM Translate leafname if not saving to DOS
 5590 REM =======================================
 5600 REM . # $ ^ & @ % ~ become / ? < > + = ; \
 5610 DEFFNfn_undos(A$):LOCALB%:IF(os%AND-32):=A$
 5620 FORA%=1TOLENA$:B%=INSTR(".#$^&@%~",MID$(A$,A%,1)):IFB%:A$=LEFT$(A$,A%-1)+MID$("/?<>+=;\",B%,1)+MID$(A$,A%+1)
 5630 NEXT:=A$
 5640 :
 5650 DEFFNyna(A%):IFA%=0:=0
 5660 PRINT"? (Y/N/A)";:REPEAT:A%=INSTR("YAN",CHR$(GETAND&DF)):UNTILA%
 5670 PRINTSTRING$(7,CHR$127);MID$("YesAllNo ",A%*3-2,3);:=A%-2
 5680 :
 5690 REM > BLib.Number
 5700 REM =============
 5710 DEFFNh0(A%,N%):=RIGHT$("00000000"+STR$~A%,N%)
 5720 DEFFNd0(A%,N%):=RIGHT$("00000000"+STR$A%,N%)
 5730 DEFFNd(A%,N%):=RIGHT$("         "+STR$A%,N%)
 5740 :
 5750 REM > BLib.DiskIO
 5760 REM =============
 5770 DEFFNdisk(addr%,cmd%,drv%,trk%,sec%,num%,den%):LOCALfs%,n%
 5780 fs%=FNfs:IFfs%<>4:*FX143,18,4
 5790 REPEAT:n%=num%:IFsec%+n%>10:n%=10-sec%
 5800   REPEAT:X%?0=drv%+den%*24+8+2*(trk%DIV80):X%!1=addr%:X%?5=3-7*(cmd%>127)
 5810     X%?6=cmd%:X%?7=trk%MOD80:X%?8=sec%:X%!9=n%OR&1E20:A%=127:CALL&FFF1
 5820   A%=X%?(7+X%?5):UNTILA%<>&10:addr%=addr%+n%*256:num%=num%-n%:sec%=(sec%+n%)MOD10:trk%=trk%+1
 5830 UNTILA%<>0ORnum%<1:IFfs%<>4:OSCLI"FX143,18,"+STR$fs%
 5840 =A%
 5850 :
 5860 DEFFNscsi(addr%,cmd%,drv%,sect%,num%):LOCALfs%
 5870 fs%=FNfs:IFfs%<>8:*FADFS
 5880 X%?0=0:X%!1=addr%:X%?5=cmd%:X%?6=drv%*32+((sect%AND&1F0000)DIV65536)
 5890 X%?7=((sect%AND&FF00)DIV256):X%?8=sect%:X%!9=num%:X%!11=0
 5900 A%=&72:CALL&FFF1:A%=?X%:IFfs%<>8:OSCLI"FX143,18,"+STR$fs%
 5910 =A%
 5920 :
 5930 DEFFNlvfs(addr%,cmd%,drv%,sect%,num%):LOCALfs%
 5940 fs%=FNfs:IFfs%<>10:*FX143,18,10
 5950 X%?0=0:X%!1=addr%:X%?5=cmd%:X%?6=drv%*32+((sect%AND&1F0000)DIV65536)
 5960 X%?7=((sect%AND&FF00)DIV256):X%?8=sect%:X%!9=num%:X%!11=0
 5970 A%=&62:CALL&FFF1:A%=?X%:IFfs%<>10:OSCLI"FX143,18,"+STR$fs%
 5980 =A%
 5990 :
 6000 DEFFNscsi_err(A%,S%)
 6010 IFA%:PRINT"Disk error "FNh0(A%,2)" ("MID$("fddhdd",(A%AND64)/64+1,3)") at "FNh0(S%,6)
 6020 =A%
 6030 :
 6040 DEFFNdisk_err(A%,S%)
 6050 IFA%:PRINT"Disk error "FNh0(A%,2)" at "FNh0(S%,4)
 6060 =A%
 6070 :
 6080 REM > BLib.Generic.FileIO
 6090 REM =====================
 6100 DEFFNfs:IF(os%AND-32)=0:LOCAL A%,Y%,E%:=(USR&FFDA)AND&FF
 6110 =29
 6120 :
 6130 DEFPROCf_gbpb(A%,chn%,addr%,num%,ptr%)
 6140 ?X%=chn%:X%!1=addr%:X%!5=num%:X%!9=ptr%:IFPAGE<&FFFFF:CALL&FFD1:ENDPROC
 6150 IFA%=1ORA%=3:PTR#?X%=X%!9
 6160 REPEAT:IFA%=1ORA%=2:BPUT#?X%,?X%!1 ELSE IFA%=3ORA%=4:?X%!1=BGET#?X%
 6170 X%!1=X%!1+1:X%!5=X%!5-1:UNTIL(EOF#?X% AND A%>2)OR X%!5<1:ENDPROC
 6180 :
 6190 DEFFNfile(A$,A%):IFA%-8:IFPAGE<&FFFFF:$name%=A$:?X%=name%:X%?1=name%DIV256:=(USR&FFDD)AND&FF
 6200 A$=FNf_name(A$):IFA%=255 OR A%=5:X%!14=OPENIN(A$):IFX%!14:X%!10=EXT#X%!14:CLOSE#X%!14:X%!14=&33
 6210 IFA%=255:IFX%?6=0:OSCLI"LOAD """+A$+""" "+STR$~X%!2:=1
 6220 IFA%=5:IFX%!14:=1 ELSE IFA%=5:=0
 6230 IFA%=0:OSCLI"SAVE """+A$+""" "+STR$~X%!10+" "+STR$~X%!14:X%!10=X%!14-X%!10:=1
 6240 IFA%=7:OSCLI"SAVE """+A$+""" "+STR$~PAGE+"+"+STR$~X%!10:X%!10=X%!14-X%!10:=1
 6250 IFA%-8:=0
 6260 IF(os%AND-24):A$="mkdir "+A$ ELSE A$="cdir "+A$
 6270 IFHIMEM>&FFFF:LOCAL ERROR:ON ERROR LOCAL:=0
 6280 OSCLIA$:=2
 6290 :
 6300 DEFFNf_openin(A$)=OPENIN(FNf_name(A$))
 6310 DEFFNf_openout(A$)=OPENOUT(FNf_name(A$))
 6320 DEFFNf_openup(A$)=OPENUP(FNf_name(A$))
 6330 DEFFNf_name(A$):IFos%AND-32:LOCALA%,B%:REPEATB%=A%:A%=INSTR(A$,"\",A%+1):UNTILA%=0:IFINSTR(A$,".",B%)=0:A$=A$+"."
 6340 =A$
 6350 :
 6360 REM > BLib.Generic.NetFS
 6370 REM ====================
 6380 DEFFNNetFS_Op(A%,A$)=FNNetFS_OpN(A%,0,7,A$)
 6390 DEFFNNetFS_OpN(A%,T%,O%,A$):!X%=0:X%?1=O%+1+LENA$:X%!3=A%:X%?7=T%:$(X%+O%)=A$
 6400 IFHIMEM>&FFFF:CASEATN&60048,A%,X%+7,X%?1,120TOA%:IFA%=0:X%?3=0:=0
 6410 IFHIMEM>&FFFF:IFA%>&FFFF:X%?3=?A%:CASEATN&2002B,A%+4TO$(X%+4):=X%?3
 6420 A%=&14:CALL&FFF1:=X%?3
 6430 :
 6440 REM > BLib.Date
 6450 REM ===========
 6460 DEFPROCDate_FromOrd(mem%,d%,m%,y%,hr%,mn%,sc%,cs%):y%=y%MOD400
 6470 d%=y%*365.25+m%*30+d%+VALMID$("120112234455",m%,1)+((y%MOD4)=0)-((y%-1)DIV100)-(m%>2AND((y%MOD4)=0AND(y%MOD100)<>0ORy%=0))+36493
 6480 IFd%>146066:d%=d%-146097
 6490 d%=d%*&41EB:mem%!1=d%+d%:d%=((hr%*60+mn%)*60+sc%)*100+cs%
 6500 ?mem%=d%:mem%!1=mem%!1+d%DIV256:ENDPROC
 6510 :
 6520 DEFPROCDate_ToOrd(mem%):LOCAL A%,B%,C%,D%
 6530 year%=0:month%=0:day%=0:hour%=0:minute%=0:second%=0:centi%=0
 6540 IFmem%!1<0:ENDPROC:REM Problems with negatives ATM
 6550 D%=mem%!1DIV&83D6+2447065:C%=mem%?0+256*(mem%!1MOD&83D6):centi%=C%MOD100
 6560 C%=C%DIV100:second%=C%MOD60:C%=C%DIV60:minute%=C%MOD60:hour%=C%DIV60
 6570 B%=((D%*4+3)MOD146097AND-4)+3:C%=B%MOD1461DIV4*5+2:D%=D%*4+3
 6580 A%=C%DIV153+2:day%=C%MOD153DIV5+1:month%=A%MOD12+1
 6590 year%=D%DIV146097*100+B%DIV1461+A%DIV12-4800
 6600 ENDPROC
 6610 :
 6620 REM > BLib.FDate
 6630 REM ============
 6640 DEFFNf_date(d%,m%,y%):y%=y%-1981:=d%+m%*256+(y%AND15)*4096+(y%DIV16)*32
 6650 DEFFNf_time(h%,m%,s%):=h%+m%*256+s%*65536
 6660 DEFPROCf_date(d%):day%=d%AND31:month%=(d%AND&F00)DIV256
 6670 year%=(d%AND&F000)DIV4096+(d%AND&E0)/2+1981:ENDPROC
 6680 DEFPROCf_time(t%):hour%=t%AND255:minute%=(t%AND&FF00)DIV256
 6690 second%=(t%AND&FF0000)DIV65536:ENDPROC
 6700 :