10 REM > MkUnix v0.03
   20 REM Creates blank 16-bit Unix images
   30 REM Block numbers in free block lists ordered downwards
   40 :
   50 ON ERROR REPORT:PROCCloseAll:PRINT:PROCexit(ERR)
   60 PRINT "Make a blank PDP11 Unix disk image"
   70 INPUT "Image file:  "out$
   80 INPUT "Image size:  "fsize$:IF fsize$="":fsize$="720K"
   90 INPUT "16bit/24bit: "bitsz$:IF bitsz$="":bitsz$="16"
  100 INPUT "Disk title:  "title$:title$=LEFT$(title$,20)
  110 :
  120 bitsz%=VAL(bitsz$):IF bitsz%<>16:IF bitsz%<>24:bitsz%=16
  130 fsize%=VAL(fsize$)
  140 IF INSTR(fsize$,"K"OR INSTR(fsize$,"k"):fsize%=fsize%*2
  150 VDU 11,11,11
  160 PRINT STRING$(13,CHR$9);fsize%;" blocks, ";fsize%DIV2;"K "
  170 PRINT STRING$(13,CHR$9);bitsz%;"  "
  180 PRINT '
  190 :
  200 super% =1                     :REM Superblock always block 1
  210 itable%=2                     :REM Start block of itable
  220 isize% =fsize% DIV (43+(fsize% DIV 1000)) :REM Size of itable
  230 root%  =itable%+isize%        :REM Start block of root directory
  240 cfree% =root%+1               :REM Start of disk data space
  250 :
  260 n1%    =fsize%-cfree%         :REM Number of data blocks
  270 lsize% =n1% DIV 100           :REM Number of data blocks used to hold free blocks
  280 nfree% =(n1% MOD 100)+1       :REM Number of in-core free blocks
  290 lfree% =cfree%+nfree%-1       :REM Start of on-disk free block list
  300 bfree% =lfree%+lsize%         :REM Start of free disk blocks
  310 dfree% =fsize%-bfree%+nfree%  :REM Disk free space
  320 dused% =fsize%-dfree%         :REM Disk used space
  330 today% =FNswap(FNtoday)       :REM Today's date
  340 :
  350 PRINT"fsize:   ";fsize%
  360 PRINT"itable:  ";FNh0(itable%,4);" + ";FNh0(isize%,4)
  370 PRINT"root:    ";FNh0(root%  ,4)
  380 PRINT"cfree:   ";FNh0(cfree% ,4);" + ";FNh0(nfree%,4)
  390 PRINT"lfree:   ";FNh0(lfree% ,4);" + ";FNh0(lsize%,4)
  400 PRINT"bfree:   ";FNh0(bfree% ,4);" - ";FNh0(fsize%-1,4)
  410 PRINT"dfree:   ";FNh0(dfree% ,4);", ";dfree%DIV2;"K"
  420 PRINT"dused:   ";FNh0(dused% ,4);", ";dused%DIV2;"K"
  430 PRINT"dsize:   ";FNh0(fsize% ,4);", ";fsize%DIV2;"K"
  440 IF bitsz%<>16:PRINT"Can only do 16-bit at the mo.":PROCexit(126)
  450 IF isize%<1:PRINT"Error: disk image too small":PROCexit(127)
  460 IF out$="":PRINT"No disk image file name":PROCexit(0)
  470 :
  480 DIM mem% 512
  490 out%=OPENOUT(out$):IF out%=0:PRINT"Can't create '"out$"'":PROCexit(192)
  500 wr%=2
  510 :
  520 REM Boot block at &0000
  530 REM -------------------
  540 PROCclr
  550 PROCgbpb(wr%,out%,mem%,512,0)
  560 :
  570 REM Superblock at &0001
  580 REM -------------------
  590 mem%!&000=isize%
  600 mem%!&002=fsize%
  610 mem%!&004=nfree%
  620 FOR A%=1 TO nfree%:mem%!(4+A%*2)=cfree%+nfree%-A%:NEXT
  630 mem%!&0CE=0      :REM No in-code free inodes, first save will fetch free blocks
  640 mem%!&19C=today% :REM Creation date
  650 $(mem%+&1DC)=title$:mem%?(&1DC+LENtitle$)=0
  660 PROCgbpb(wr%,out%,mem%,512,super%*512)
  670 :
  680 REM itable at &0002
  690 REM ---------------
  700 PROCclr        :REM inode 1
  710 mem%!00=&C1FF  :REM mode =dwrxwrxwrx
  720 mem%?02=&02    :REM links=2
  730 mem%!03=&0000  :REM user=0, group=0
  740 mem%?05=&00    :REM size DIV 65536=0
  750 mem%!06=&20    :REM size=32, two directory entries
  760 mem%!08=root%  :REM first block of root directory
  770 mem%!24=today% :REM access time
  780 mem%!28=today% :REM modify time
  790 PROCgbpb(wr%,out%,mem%,512,itable%*512)
  800 :
  810 REM rest of itable
  820 REM --------------
  830 PROCclr
  840 IF isize%>1:FOR blk%=itable%+1 TO itable%+isize%-1:PROCgbpb(wr%,out%,mem%,512,blk%*512):NEXT
  850 :
  860 REM root directory
  870 REM --------------
  880 mem%!00=&0001:mem%!02=&002E:REM "."
  890 mem%!16=&0001:mem%!18=&2E2E:REM ".."
  900 PROCgbpb(wr%,out%,mem%,512,root%*512)
  910 :
  920 REM core free blocks
  930 REM ----------------
  940 PROCclr
  950 IF nfree%>1:FOR blk%=cfree% TO cfree%+nfree%-2:PROCgbpb(wr%,out%,mem%,512,blk%*512):NEXT
  960 :
  970 REM linked list of blocks of free blocks
  980 REM ------------------------------------
  990 REM Each block will always start with 100 entries
 1000 FOR blk%=lfree% TO lfree%+lsize%-1
 1010   PROCclr
 1020   mem%!0=100
 1030   IF blk%=lfree%+lsize%-1:mem%!2=0 ELSE mem%!2=blk%+1
 1040   FOR A%=2 TO 100:mem%!(A%*2)=bfree%+100-A%:NEXT
 1050   bfree%=bfree%+99
 1060   PROCgbpb(wr%,out%,mem%,512,blk%*512)
 1070 NEXT blk%
 1080 :
 1090 CLOSE#out%:out%=0
 1100 PROCexit(0):END
 1110 :
 1120 :
 1130 DEFPROCclr:FOR A%=0 TO 511 STEP 4:mem%!A%=0:NEXT:ENDPROC
 1140 DEFFNtoday
 1150 A$=TIME$:dy%=VALMID$(A$,5):yr%=VALMID$(A$,12):IF yr%<1970:yr%=yr%+100
 1160 mn%=INSTR("JanFebMarAprMayJunJulAugSepOctNovDec",MID$(A$,8,3))DIV3
 1170 dy%=VALMID$("000031059090120151181212243273304334",mn%*3+1,3)+dy%
 1180 IF (yr%MOD4)=0:IFmn%>1:dy%=dy%+1
 1190 =((yr%-1970)*365.25+dy%)*86400
 1200 :
 1210 DEFPROCCloseAll
 1220 in%=in%:IFin%:A%=in%:in%=0:CLOSE#A%
 1230 out%=out%:IFout%:A%=out%:out%=0:CLOSE#A%
 1240 ENDPROC
 1250 DEFPROCexit(A%):OSCLI"FX1,"+STR$(A%AND255):IF PAGE>&FFFFF:QUIT A% ELSE END
 1260 ENDPROC
 1270 DEFFNh0(A%,N%)=RIGHT$("0000000"+STR$~A%,N%)
 1280 DEFPROCgbpb(A%,chn%,adr%,num%,ptr%):PTR#chn%=ptr%:IF num%=0:ENDPROC
 1290 REPEATBPUT#chn%,?adr%:adr%=adr%+1:num%=num%-1:UNTILnum%<1:ENDPROC
 1300 DEFFNswap(N%):DIM A%-1:A%!0=N%:A%!4=N%:=A%!2