a2cloud/setup/mkpo

169 lines
4.9 KiB
Bash
Executable File

#! /bin/bash
# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh:
# mkpo - create ProDOS disk image
#
# To the extent possible under law, T. Joseph Carter and Ivan Drucker have
# waived all copyright and related or neighboring rights to the a2cloud
# scripts themselves. Software used or installed by these scripts is subject
# to other licenses. This work is published from the United States.
# ID-bashByter routines
function binToDec ()
{
dec=0;
bits=$1;
while (( ${#bits} < 8 )); do
bits="0$bits";
done;
for n in {0..7};
do
(( dec+=( ${bits:$n:1} * ( 2**(7-$n) ) ) ));
done;
echo -n $dec
};
function writecharDec ()
{
[[ -n $1 ]] || return 11;
[[ -n $2 ]] || return 12;
[[ -n $3 ]] || return 13;
[[ -n $4 ]] && return 8;
[[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && ( $2 -ge 0 ) ]] || return 22;
[[ ( $(printf %d "$3" 2> /dev/null) == $3 ) && ( $3 -ge 0 ) && ( $3 -lt 255 ) ]] || return 23;
echo -n -e "\x$(printf %02X "$3")" | dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null
};
function writecharsHex ()
{
[[ -n $1 ]] || return 11;
[[ -n $2 ]] || return 12;
[[ -n $3 ]] || return 13;
[[ -n $4 ]] && return 8;
[[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && ( $2 -ge 0 ) ]] || return 22;
p=0;
offset=$2;
len=${#3};
while (( p < len )); do
outByte=${3:$p:2};
[[ $(printf %02X "0x$outByte" 2> /dev/null) == $(echo -n "$outByte" | tr [a-z] [A-Z]) ]] || return 23;
echo -n -e "\x$outByte" | dd of="$1" bs=1 seek=$offset conv=notrunc 2> /dev/null;
(( p += 3 ));
(( offset++ ));
done
};
# mkpo
[[ ! -n $1 ]] && { echo "Usage: mkpo [-b totalBlocks] newImageName [PRODOS.VOL.NAME]"; exit 1; };
[[ -f /usr/local/adtpro/adtpro.sh ]] && adtPath="/usr/local/adtpro" || adtPath=$(ls -1d /Applications/ADTPro* | head -1);
[[ ! -d "$adtPath" ]] && { echo "AppleCommander not found."; exit 1; }
if [[ $1 == "-b" ]]; then
totalBlocks="$2"
shift
shift
fi
[[ -f $1 ]] && { echo "Image '$1' already exists."; exit 1; }
[[ $2 ]] && prodosVolName="$2" || prodosVolName="UNTITLED"
# test ProDOS name legitimacy
prodosVolName=$(tr [:lower:] [:upper:] <<< $prodosVolName )
if [[ ${#prodosVolName} -gt 15 || ! $(grep ^[A-Z][0-9A-Z\.]*$ <<< $prodosVolName) ]]; then
echo "Invalid ProDOS name: $prodosVolName"; exit 1;
fi
# see if nulib2 is available; if so, acmd -convert will create image
# with specified block size
nulib2 &> /dev/null
[[ $? == 2 ]] && nulib2=1 || nulib2=
if [[ $nulib2 ]]; then
if [[ $totalBlocks ]]; then
imageBlocks="$totalBlocks"
else
if [[ $(tr [:upper:] [:lower:] <<< "${1##*.}") == "dsk" ]]; then
imageBlocks=280
else
imageBlocks=1600
fi
fi
rm /tmp/blank.shk &> /dev/null
orig_dir="$PWD"
cd /tmp
rm blank.shk EMPTY &> /dev/null
touch EMPTY
nulib2 -a blank.shk EMPTY &> /dev/null
cd "$orig_dir"
acmd -convert /tmp/blank.shk "$1" $imageBlocks
acmd -d "$1" EMPTY
rm /tmp/blank.shk /tmp/EMPTY
acmd -n "$1" "$prodosVolName"
else
# make the disk image without converting archive
if [[ $totalBlocks || $(tr [:upper:] [:lower:] <<< "${1##*.}") == "dsk" ]]; then
acmd -pro140 "$1" $prodosVolName;
else
acmd -pro800 "$1" $prodosVolName;
fi
fi
# make the disk bootable
if [ -f "$adtPath"/disks/ADTPRO*PO ]; then
dd bs=512 count=1 of="$1" conv=notrunc < "$adtPath"/disks/ADTPRO*PO 2> /dev/null
fi
# change .DSK to DOS-ordered
if [[ ! $totalBlocks && $(tr [:upper:] [:lower:] <<< "${1##*.}") == "dsk" ]]; then
mv "$1" "$1".tmp
for t in {0..34}; do
for s in 0 14 13 12 11 10 9 8 7 6 5 4 3 2 1 15; do
dd bs=256 count=1 if="$1".tmp of="$1" skip=$(( $t*16 + $s )) seek=$(( $t*16 + ( $s==0||$s==15 ? $s : 15-$s ) )) 2> /dev/null;
done;
done
rm "$1".tmp
fi
# if nulib2 isn't available, patch the disk image to use specified block size
if [[ ! $nulib2 && $totalBlocks ]]; then
# change total block count
bcHex=$(printf "%04X" $totalBlocks);
writecharsHex "$1" 1065 "${bcHex:2:2}.${bcHex:0:2}";
# fix FSB
dd if=/dev/zero of="$1" bs=512 seek=280 count=$(( $totalBlocks - 280 )) 2> /dev/null;
dd if="$1" of="$1" bs=1 skip=3073 seek=3107 count=$(( ($totalBlocks / 8) - 35 )) conv=notrunc 2> /dev/null;
bits=$(( $totalBlocks % 8 ));
if (( bits > 0 )); then
usedString="00000000";
freeString=;
for ((b=0; b<$bits; b++))
do
freeString=$freeString"1";
done;
binString=$freeString${usedString:$bits};
writecharDec "$1" $(( ( ($totalBlocks / 8) - 35) + 3107 )) $(binToDec $binString);
fi;
# assign extra blocks to FSB if needed
fsbExtraBlocks=$(( ($totalBlocks-1)/4096 ));
if (( fsbExtraBlocks > 0 )); then
dd if=/dev/zero of="$1" bs=1 seek=3072 count=$(( (fsbExtraBlocks > 8) + 1 )) conv=notrunc 2> /dev/null;
(( fsbExtraBlocks-- ));
fi;
bits=$(( fsbExtraBlocks % 8 ));
if (( bits > 0 )); then
freeString="11111111";
usedString=;
for ((b=0; b<$bits; b++))
do
usedString=$usedString"0";
done;
binString=$usedString${freeString:$bits};
writecharDec "$1" $(( (fsbExtraBlocks>7)+3073 )) $(binToDec $binString);
fi;
fi