2015-10-30 12:34:48 +00:00
|
|
|
#! /bin/bash
|
|
|
|
# vim: set tabstop=4 shiftwidth=4 expandtab filetype=sh:
|
2015-10-30 11:04:28 +00:00
|
|
|
|
|
|
|
# ID-bashByter routines
|
|
|
|
|
2015-10-30 12:38:31 +00:00
|
|
|
function binToDec ()
|
|
|
|
{
|
2015-10-30 11:04:28 +00:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2015-10-30 12:38:31 +00:00
|
|
|
function writecharDec ()
|
|
|
|
{
|
2015-10-30 11:04:28 +00:00
|
|
|
[[ -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
|
|
|
|
};
|
|
|
|
|
2015-10-30 12:38:31 +00:00
|
|
|
function writecharsHex ()
|
|
|
|
{
|
2015-10-30 11:04:28 +00:00
|
|
|
[[ -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;
|
2015-10-30 12:38:31 +00:00
|
|
|
done
|
2015-10-30 11:04:28 +00:00
|
|
|
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;
|
2015-10-30 12:38:31 +00:00
|
|
|
|
2015-10-30 11:04:28 +00:00
|
|
|
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
|