mirror of
https://github.com/RasppleII/a2cloud.git
synced 2024-11-23 23:32:08 +00:00
Merge branch 'master' into jessie
This commit is contained in:
commit
f97f6b1b2a
@ -1,16 +0,0 @@
|
|||||||
# Ivan Drucker's A2CLOUD setup
|
|
||||||
|
|
||||||
A2CLOUD grew up alongside A2SERVER, yet it ends up being substantially
|
|
||||||
different in many ways. Eseentially, it looks like Ivan wrote most of the
|
|
||||||
HTML for A2SERVER first, but had to rewrite the scripts a few times to be more
|
|
||||||
legible and robust.
|
|
||||||
|
|
||||||
A2CLOUD, by contrast, had a wordpress blog category turned into a user guide.
|
|
||||||
The HTML was more "proper" by modern standards (and HTML5-based rather than
|
|
||||||
HTML 3.2), but the scripts seem to be older and less refined. This can be
|
|
||||||
likely attributed to A2SERVER requiring more debugging and therefore more
|
|
||||||
effort to flesh out quickly bodged scripts into readable, debuggable pieces.
|
|
||||||
|
|
||||||
There's less documentation here to archive than there is the original A2CLOUD
|
|
||||||
setup that began this repository, but having it helps inform some design
|
|
||||||
decisions. So it's included here for completeness.
|
|
1600
docs/ivanx/index.md
1600
docs/ivanx/index.md
File diff suppressed because it is too large
Load Diff
@ -1,48 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ ! $(dpkg -l irssi 2> /dev/null | grep '^ii') ]]; then
|
|
||||||
echo "Installing irssi..."
|
|
||||||
supo apt-get -y update
|
|
||||||
sudo apt-get -y install irssi &> /dev/null
|
|
||||||
sudo apt-get -y clean
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $1 == "-n" && $2 ]]; then
|
|
||||||
nickname=$2
|
|
||||||
elif [[ $1 == "-n" ]]; then
|
|
||||||
nickname="0"
|
|
||||||
elif [[ -f ~/.irssi/a2c.nickname ]]; then
|
|
||||||
nickname=$(cat ~/.irssi/a2c.nickname)
|
|
||||||
else
|
|
||||||
nickname=
|
|
||||||
fi
|
|
||||||
|
|
||||||
while [[ ! $nickname || ! $(grep -i '^[a-z_\-\\^{}|`][a-z0-9_\-\\^{}|`]*$' <<< $nickname) ]]; do
|
|
||||||
echo -n "Enter a nickname for chat (to change later, use 'a2chat -n'): "
|
|
||||||
read
|
|
||||||
nickname=$REPLY
|
|
||||||
done
|
|
||||||
|
|
||||||
mkdir -p ~/.irssi
|
|
||||||
echo $nickname > ~/.irssi/a2c.nickname
|
|
||||||
|
|
||||||
if [[ -f ~/.irssi/startup ]]; then
|
|
||||||
mv ~/.irssi/startup ~/.irssi/startup.orig
|
|
||||||
fi
|
|
||||||
echo -e "/network add -autosendcmd '/join #a2c.chat' Palomino.A2\n/server add -auto -network Palomino.A2 irc.a2central.com\n" > ~/.irssi/startup
|
|
||||||
|
|
||||||
if [[ -f ~/.irssi/config ]]; then
|
|
||||||
cp ~/.irssi/config ~/.irssi/config.orig
|
|
||||||
fi
|
|
||||||
|
|
||||||
irssi -n $nickname
|
|
||||||
|
|
||||||
rm ~/.irssi/startup &> /dev/null
|
|
||||||
if [[ -f ~/.irssi/startup.orig ]]; then
|
|
||||||
mv ~/.irssi/startup.orig ~/.irssi/startup
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm ~/.irssi/config &> /dev/null
|
|
||||||
if [[ -f ~/.irssi/config.orig ]]; then
|
|
||||||
mv ~/.irssi/config.orig ~/.irssi/config
|
|
||||||
fi
|
|
@ -1,87 +0,0 @@
|
|||||||
# A2CLOUD aliases:
|
|
||||||
|
|
||||||
alias a2cloud-setup='wget -qO /tmp/a2cloud-setup ivanx.com/a2cloud/setup/; source /tmp/a2cloud-setup'
|
|
||||||
alias a2cloud-help='(IFS=""; while read thisLine; do [[ ${#thisLine} -eq 0 ]] && echo || echo "$(tput bold)${thisLine%% *}$(tput sgr0) ${thisLine#* }"; done < /usr/local/etc/a2cloud-help.txt | more)'
|
|
||||||
alias a2cloud-version='cat /usr/local/etc/A2CLOUD-version'
|
|
||||||
alias a2cloud-update='a2cloud-setup'
|
|
||||||
|
|
||||||
alias system-shutdown='sudo shutdown -h now'
|
|
||||||
alias system-restart='sudo shutdown -r now'
|
|
||||||
|
|
||||||
|
|
||||||
alias raspi-config='[[ -f /usr/bin/raspi-config ]] && sudo /usr/bin/raspi-config || echo "raspi-config not found. Are you using a Raspberry Pi with Raspbian?"'
|
|
||||||
alias appleiipi-update="sudo apt-get -y update && sudo apt-get -y --force-yes install a2pi apple2user gsport"
|
|
||||||
alias raspbian-update='wget -qO /tmp/raspbian-update ivanx.com/a2cloud/setup/raspbian-update.txt; source /tmp/raspbian-update'
|
|
||||||
alias rasppleii-update='raspbian-update a2cloud a2server'
|
|
||||||
|
|
||||||
|
|
||||||
alias welcome-message-edit='sudo nano /etc/motd'
|
|
||||||
|
|
||||||
alias showip='ifconfig eth0 | grep "inet\ addr" | cut -d: -f2 | cut -d" " -f1'
|
|
||||||
alias showmac='ifconfig eth0 | grep "HWaddr" | cut -dH -f2 | cut -c7-23'
|
|
||||||
alias showip-wifi='ifconfig wlan0 | grep "inet\ addr" | cut -d: -f2 | cut -d" " -f1'
|
|
||||||
alias showmac-wifi='ifconfig wlan0 | grep "HWaddr" | cut -dH -f2 | cut -c7-23'
|
|
||||||
alias ifreset='sudo rm /etc/udev/rules.d/70-persistent-net.rules; echo Interfaces removed. You should system-restart now.'
|
|
||||||
|
|
||||||
alias adtpro-stop='sudo pkill -f [A]DTPro'
|
|
||||||
|
|
||||||
|
|
||||||
alias adtpro-restart='sudo pkill -f [A]DTPro; while [[ $(ps aux | grep [A]DTPro) ]]; do sleep 1; done; adtpro-start'
|
|
||||||
|
|
||||||
alias usblogin-off='sudo sed -i "s/^\(.*-scanttyUSB\)/#\1/" /etc/inittab; sudo init q; sudo pkill -f [g]etty'
|
|
||||||
alias usblogin-on='sudo sed -i "s/^#\(.*-scanttyUSB\)/\1/" /etc/inittab; sudo init q'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
alias term='source term'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
alias vsd1='source /usr/local/bin/vsd -d1'
|
|
||||||
alias vsd2='source /usr/local/bin/vsd -d2'
|
|
||||||
forfloppy () { [[ $1 ]] && { mv "$1" /usr/local/adtpro/disks && echo "moved $1 to /usr/local/adtpro/disks" || echo "Unsuccessful. $1 was not moved."; } || echo "Usage: forfloppy imageFileName"; }
|
|
||||||
|
|
||||||
alias vsdsync='adtpro-restart'
|
|
||||||
|
|
||||||
alias nulib=nulib2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
alias a2cat='acmd -l'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
VSD1=$(readlink /usr/local/adtpro/disks/Virtual.po)
|
|
||||||
VSD2=$(readlink /usr/local/adtpro/disks/Virtual2.po)
|
|
||||||
ADTDISKS=/usr/local/adtpro/disks; A2DISKS=/usr/local/adtpro/disks
|
|
||||||
A2CLOUD=/usr/local/adtpro/disks/A2CLOUD.HDV
|
|
||||||
GSDISKS=/usr/local/share/gsdisks
|
|
||||||
GSHD=/usr/local/share/gsdisks/gsoshd.hdv
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ttytter () { ( ansi=; seven=; [[ $(grep ttyUSB <<< $myTTY) || $(grep ttyAMA <<< $myTTY) ]] && { seven="-seven"; [[ $TERM=="ansi" || $TERM=="pcansi" ]] && ansi="-ansi"; }; [[ -f /usr/bin/ttytter ]] && /usr/bin/ttytter -ssl $seven $ansi $@ || /usr/local/bin/ttytter -ssl $seven $ansi $@ ); }
|
|
||||||
|
|
||||||
|
|
||||||
alias raspple-update='rasppleii-update'
|
|
||||||
alias rasappleii-update='rasppleii-update'
|
|
||||||
alias rasapple-update='rasppleii-update'
|
|
@ -1,87 +0,0 @@
|
|||||||
A2CLOUD commands:
|
|
||||||
(note : new commands may be added; use a2cloud-setup to refresh)
|
|
||||||
|
|
||||||
a2cloud-help : show this list of commands
|
|
||||||
a2cloud-version : see installed version of A2CLOUD
|
|
||||||
a2cloud-update : update A2CLOUD, or add features
|
|
||||||
|
|
||||||
system-shutdown : shut down the A2CLOUD machine (or VM)
|
|
||||||
system-restart : shut down and restart the A2CLOUD machine (or VM)
|
|
||||||
|
|
||||||
Raspberry Pi commands, if you're using one:
|
|
||||||
raspi-config : configure Raspberry Pi
|
|
||||||
appleiipi-update : update Apple II Pi and GSport
|
|
||||||
raspbian-update : update Raspbian operating system
|
|
||||||
rasppleii-update : update Raspbian OS, A2CLOUD, A2SERVER, Apple II Pi
|
|
||||||
Apple II Pi: for help, visit http://schmenk.is-a-geek.com/wordpress
|
|
||||||
|
|
||||||
welcome-message-edit : change the welcome message
|
|
||||||
|
|
||||||
showip : show the current ethernet IP address of the server
|
|
||||||
showmac : show the MAC (Ethernet hardware) address of the server
|
|
||||||
showip-wifi : show the current wifi IP address of the server
|
|
||||||
showmac-wifi : show the MAC (wifi hardware) address of the server
|
|
||||||
ifreset : reset all network interfaces (requires restart)
|
|
||||||
|
|
||||||
adtpro-stop : stop the ADTPro service
|
|
||||||
adtpro-start : start the ADTPro service
|
|
||||||
(note: autostarts on appearance of eligible USB-to-serial adapter)
|
|
||||||
adtpro-restart : restart the ADTPro service
|
|
||||||
|
|
||||||
usblogin-off : disable shell login for USB-to-serial adapter
|
|
||||||
usblogin-on : enable shell login with USB-to-serial adapter on upper
|
|
||||||
USB port or hub attached to it, or highest-numbered port on hub
|
|
||||||
attached to lower USB port
|
|
||||||
|
|
||||||
term [-d] mono : use VT-100 (mostly monochrome) emulation in serial
|
|
||||||
shell login for ProTERM, Spectrum, Z-Link, etc. (-d sets default)
|
|
||||||
term [-d] color : use ANSI color and PC graphic text in serial shell
|
|
||||||
login for Spectrum or other PC-ANSI terminal (-d sets default)
|
|
||||||
baud : show or set serial port shell baud rate
|
|
||||||
screen : switch between multiple terminal screens
|
|
||||||
|
|
||||||
vsd1 : show or set the disk image assigned to virtual drive 1
|
|
||||||
vsd2 : show or set the disk image assigned to virtual drive 2
|
|
||||||
forfloppy : move the disk image to the ADTPro disk images folder
|
|
||||||
(/usr/local/adtpro/disks) in preparation for transfer
|
|
||||||
vsdsync : update ADTPro server with the current virtual drive images
|
|
||||||
|
|
||||||
nulib2 : create, extract, and work with NuFX (ShrinkIt) archive files
|
|
||||||
sciibin : decode BinSCII file (they start with 'FiLeStArTfIlEsTaRt')
|
|
||||||
unblu/usq/unbit/unexec : decode Binary II, Squeezed, Executioner,
|
|
||||||
or monitor hex entry EXEC file (old Apple II distribution formats)
|
|
||||||
|
|
||||||
unar : extract non-Apple II archive files (multiformat)
|
|
||||||
lsar : list contents of non-Apple II archive files (multiformat)
|
|
||||||
|
|
||||||
a2cat: catalog Apple II disk image (any format)
|
|
||||||
acmd : do stuff with files inside Apple II disk images
|
|
||||||
mkpo : make blank ProDOS disk image file
|
|
||||||
dos2pro: copy files from DOS 3.3 disk image to ProDOS disk image
|
|
||||||
dopo : convert DOS-ordered disk image to ProDOS, or vice-versa
|
|
||||||
cppo : catalog and copy files from ProDOS image file (slow, but works)
|
|
||||||
shk2image : extract files from ShrinkIt archive to disk image file
|
|
||||||
|
|
||||||
environment variables :
|
|
||||||
$VSD1 = disk image currently "inserted" in virtual drive 1
|
|
||||||
$VSD2 = disk image currently "inserted" in virtual drive 2
|
|
||||||
$ADTDISKS = ADTPro disks directory (/usr/local/adtpro/disks)
|
|
||||||
$A2CLOUD = 800K A2CLOUD disk (/usr/local/adtpro/disks/A2CLOUD.HDV)
|
|
||||||
$GSDISKS = GSport/KEGS disks directory (/usr/local/share/gsdisks)
|
|
||||||
$GSHD = GSport/KEGS hard drive (/usr/local/share/gsdisks/gsoshd.hdv)
|
|
||||||
|
|
||||||
internet tools:
|
|
||||||
ftp : connect to an FTP site (command line operation)
|
|
||||||
cftp : connect to an FTP site (full screen operation)
|
|
||||||
lynx : browse the web (in text only, of course)
|
|
||||||
links : browse the web (alternative to lynx; press ESC for menu)
|
|
||||||
wget : download a single URL from an FTP or web site
|
|
||||||
irssi : IRC chat (general purpose)
|
|
||||||
a2chat : IRC chat (automatically opens to Apple II channel)
|
|
||||||
a2news : read and post on Usenet discussions (default Apple II topics)
|
|
||||||
ttytter : tweet like there's no tomorrow
|
|
||||||
|
|
||||||
emulators:
|
|
||||||
gsport : GSport Apple IIgs emulator
|
|
||||||
kegs : KEGS Apple IIgs emulator
|
|
||||||
linapple : LinApple Apple IIe emulator
|
|
@ -1,34 +0,0 @@
|
|||||||
source /usr/local/etc/a2cloud-aliases
|
|
||||||
|
|
||||||
if [[ -f /usr/local/java/bin/java ]]; then
|
|
||||||
export JAVA_HOME=/usr/local/java
|
|
||||||
elif [[ -f /usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt/bin/java ]]; then # RPi
|
|
||||||
export JAVA_HOME=/usr/lib/jvm/jdk-8-oracle-arm-vfp-hflt
|
|
||||||
elif [[ -f /usr/lib/jvm/java-8-oracle/bin/java ]]; then # webupd8
|
|
||||||
export JAVA_HOME=/usr/lib/jvm/java-8-oracle
|
|
||||||
elif [[ -f /usr/lib/jvm/java-8-oracle/jre/bin/java ]]; then # Ubuntu 14.04 RPi2
|
|
||||||
export JAVA_HOME=/usr/lib/jvm/java-8-oracle/jre
|
|
||||||
elif [[ -f /usr/lib/jvm/jdk-7-oracle-armhf/bin/java ]]; then # RPi
|
|
||||||
export JAVA_HOME=/usr/lib/jvm/jdk-7-oracle-armhf
|
|
||||||
elif [[ -f /usr/lib/jvm/jdk-7-oracle/bin/java ]]; then # webupd8
|
|
||||||
export JAVA_HOME=/usr/lib/jvm/jdk-7-oracle
|
|
||||||
fi
|
|
||||||
[[ ! $(grep java <<< $PATH) ]] && PATH=$PATH:$JAVA_HOME/bin
|
|
||||||
|
|
||||||
if [[ -f /usr/local/etc/a2cloud-lang ]]; then
|
|
||||||
lang8bit=$(cat /usr/local/etc/a2cloud-lang)
|
|
||||||
else
|
|
||||||
lang8bit=C
|
|
||||||
fi
|
|
||||||
if [[ ${TERM:0:6} == "screen" ]]; then
|
|
||||||
myTTY=$(ps hp $(ps hp $(ps hp $$ -o ppid) -o ppid) -o tty)
|
|
||||||
else
|
|
||||||
myTTY=$(tty)
|
|
||||||
export ttyTERM="$TERM"
|
|
||||||
fi
|
|
||||||
if [[ $(grep ttyUSB <<< $myTTY) || $(grep ttyAMA <<< $myTTY) ]]; then
|
|
||||||
LANG=$lang8bit
|
|
||||||
fi
|
|
||||||
if [[ ${TERM:0:6} == "screen" ]]; then
|
|
||||||
TERM=$ttyTERM
|
|
||||||
fi
|
|
@ -1,59 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
defaultNNTP="news.aioe.org"
|
|
||||||
defaultGroups="comp.emulators.apple2:\ncomp.sys.apple2:\ncomp.sys.apple2.comm:\ncomp.sys.apple2.marketplace:\ncomp.sys.apple2.programmer:\ncomp.sys.apple2.usergroups:"
|
|
||||||
|
|
||||||
if [[ ! $(dpkg -l tin 2> /dev/null | grep '^ii') ]]; then
|
|
||||||
echo "Installing Tin newsreader..."
|
|
||||||
sudo apt-get -y update
|
|
||||||
sudo apt-get -y install tin &> /dev/null
|
|
||||||
sudo apt-get -y clean
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $1 == "-h" || $1 == "--help" ]]; then
|
|
||||||
echo "Usage: a2news [-s nntpServerAddress] [-m postingEmailAddress] [otherTinOptions]"
|
|
||||||
echo " note: for full options, instead use 'tin'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
while [[ $1 == "-s" || $1 == "-m" ]]; do
|
|
||||||
if [[ $1 == "-s" && $2 ]]; then
|
|
||||||
nntpServer=$2
|
|
||||||
shift
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $1 == "-m" && $2 ]]; then
|
|
||||||
emailAddress=$2
|
|
||||||
shift
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
mkdir -p ~/.tin
|
|
||||||
|
|
||||||
if [[ ! -f ~/.newsrc ]]; then
|
|
||||||
IFS=''; echo -e "$defaultGroups" > ~/.newsrc
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $nntpServer || ! -f ~/.tin/nntp.server ]]; then
|
|
||||||
[[ ! $nntpServer ]] && nntpServer="$defaultNNTP"
|
|
||||||
echo "$nntpServer" > ~/.tin/nntp.server
|
|
||||||
else
|
|
||||||
nntpServer=$(cat ~/.tin/nntp.server)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $emailAddress || ! -f ~/.tin/tinrc ]]; then
|
|
||||||
while [[ ! $emailAddress || ! $(grep "@" <<< $emailAddress) || ! $(grep "\." <<< $emailAddress) ]]; do
|
|
||||||
echo -n "Enter the email address you want to post as: "
|
|
||||||
read
|
|
||||||
emailAddress=$REPLY
|
|
||||||
done
|
|
||||||
if [[ -f ~/.tin/tinrc ]]; then
|
|
||||||
sed -i "s/^mail_address=.*$/mail_address=$emailAddress/" ~/.tin/tinrc
|
|
||||||
else
|
|
||||||
echo "mail_address=$emailAddress" > ~/.tin/tinrc
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
NNTPSERVER=$nntpServer tin -r "$@"
|
|
@ -1,151 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
decToHex () {
|
|
||||||
# converts single-byte decimal value to hexadecimal equivalent
|
|
||||||
# arg: decimal value from 0-255
|
|
||||||
# out: two-digit hex value from 00-FF
|
|
||||||
#exit: 8=extraneous arg, 11=missing arg, 21=invalid arg
|
|
||||||
[[ $arg1 ]] || return 11
|
|
||||||
[[ $2 ]] && return 8
|
|
||||||
[[ ( $(printf %d "$arg1" 2> /dev/null) == $arg1 ) \
|
|
||||||
&& ( $arg1 -ge 0 ) && ( $arg1 -le 255 ) ]] || return 21
|
|
||||||
# args are valid
|
|
||||||
printf %02X "$arg1"
|
|
||||||
}
|
|
||||||
|
|
||||||
echoerr() {
|
|
||||||
echo "$@" 1>&2;
|
|
||||||
}
|
|
||||||
|
|
||||||
helpExit () {
|
|
||||||
if [[ -s $acmdStdErr ]]; then
|
|
||||||
if [[ $(grep CommandLineHelp $acmdStdErr) ]]; then
|
|
||||||
grep -v ^-[pge][[:space:]] $acmdStdErr | grep -v '^ or' | grep -v 0x2000 1>&2
|
|
||||||
echoerr "-g <imagename> <filename> [<outputFilename>] copy filename out of any"
|
|
||||||
echoerr " disk image. Using - for outputFilename will copy to stdout."
|
|
||||||
echoerr "-e <imagename> <filename> [<outputFilename>] like -g, with conversion"
|
|
||||||
echoerr " to modern file format if possible."
|
|
||||||
echoerr "-p <imagename> <filename> [[$|0x]<type>] [[$|0x]<auxtype>] copy filename"
|
|
||||||
echoerr " into ProDOS disk image. <type> is either three-letter or numeric"
|
|
||||||
echoerr " ProDOS file type (BIN if omitted). Will read from stdin if supplied."
|
|
||||||
echoerr " ProDOS subdirectories in <filename> will be created if needed."
|
|
||||||
echoerr "-c <filename> <imagename> [[$|0x]<type>] [[$|0x]<auxtype>] synonym for -p"
|
|
||||||
echoerr " with filename and imagename reversed."
|
|
||||||
else
|
|
||||||
cat $acmdStdErr
|
|
||||||
fi
|
|
||||||
if [[ $arg1 == "-h" ]]; then
|
|
||||||
exitVal=0
|
|
||||||
else
|
|
||||||
exitVal=1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [[ $vsd1_md5 && ( "$vsd1_md5" != "$(md5sum /usr/local/adtpro/disks/Virtual.po)" || "$vsd2_md5" != "$(md5sum /usr/local/adtpro/disks/Virtual2.po)" ) ]]; then
|
|
||||||
if [[ "$vsd1_md5" != "$(md5sum /usr/local/adtpro/disks/Virtual.po)" || "$vsd2_md5" != "$(md5sum /usr/local/adtpro/disks/Virtual2.po)" ]]; then
|
|
||||||
echoerr "One of the virtual drive image files has changed while ADTPro server is active."
|
|
||||||
echoerr " If using VSDRIVE, type 'vsdsync' now to see changes and prevent corruption."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
exitval=0
|
|
||||||
fi
|
|
||||||
rm $acmdStdErr &> /dev/null
|
|
||||||
exit $exitVal
|
|
||||||
}
|
|
||||||
|
|
||||||
arg1=$1
|
|
||||||
|
|
||||||
acmdStdErr="/tmp/acmd_$RANDOM$RANDOM"
|
|
||||||
|
|
||||||
[[ -f /usr/local/adtpro/adtpro.sh ]] && adtPath="/usr/local/adtpro" || adtPath=$(ls -1d /Applications/ADTPro* | head -1);
|
|
||||||
|
|
||||||
if [[ ! $2 || $arg1 == "-h" ]]; then
|
|
||||||
java -jar "$adtPath"/lib/AppleCommander/AppleCommander-ac.jar 2> $acmdStdErr
|
|
||||||
[[ $? -eq 127 ]] && exit 127 || helpExit $arg1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $arg1 != "-i" && $arg1 != "-ls" && $arg1 != "-l" && $arg1 != "-ll" && $arg1 != "-x" && $arg1 != "-g" && $arg1 != "-e" && $(ps aux | grep [A]DTPro) ]]; then
|
|
||||||
vsd1_md5="$(md5sum /usr/local/adtpro/disks/Virtual.po)"
|
|
||||||
vsd2_md5="$(md5sum /usr/local/adtpro/disks/Virtual2.po)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ( $arg1 == "-p" || $arg1 == "-c" || $arg1 == "-g" || $arg1 == "-e" ) && $2 && $3 ]]; then
|
|
||||||
|
|
||||||
getArg=
|
|
||||||
if [[ $arg1 == "-p" ]]; then
|
|
||||||
prodosArg="$3"
|
|
||||||
imageArg="$2"
|
|
||||||
elif [[ $arg1 == "-c" ]]; then
|
|
||||||
prodosArg="$2"
|
|
||||||
imageArg="$3"
|
|
||||||
elif [[ $arg1 == "-g" || $arg1 == "-e" ]]; then
|
|
||||||
fileArg="$3"
|
|
||||||
imageArg="$2"
|
|
||||||
getArg="$arg1"
|
|
||||||
else
|
|
||||||
exit 2;
|
|
||||||
fi
|
|
||||||
|
|
||||||
shift
|
|
||||||
|
|
||||||
if [[ $getArg ]]; then # get file
|
|
||||||
outFile=
|
|
||||||
[[ $3 && $3 != "-" ]] && outFile="$3"
|
|
||||||
[[ ! $3 ]] && outFile="${2##*/}"
|
|
||||||
java -Xmx128m -jar "$adtPath"/lib/AppleCommander/AppleCommander-ac.jar $getArg "$imageArg" "$fileArg" $outFile 2> $acmdStdErr
|
|
||||||
else # put file
|
|
||||||
|
|
||||||
# test ProDOS name legitimacy
|
|
||||||
prodosPath=$(tr [:lower:] [:upper:] <<< $prodosArg )
|
|
||||||
IFS_orig="$IFS"; IFS="/";
|
|
||||||
prodosPathParts="$prodosPath"
|
|
||||||
for thisProdosPathPart in $prodosPathParts; do
|
|
||||||
if [[ ${#thisProdosPathPart} -gt 15 || ! $(grep ^[A-Z][0-9A-Z\.]*$ <<< $thisProdosPathPart) ]]; then
|
|
||||||
echoerr "Invalid ProDOS name: $prodosPath"; exit 1;
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
IFS="$IFS_orig"
|
|
||||||
|
|
||||||
# process filetype
|
|
||||||
[[ ${3:0:2} == "0x" ]] && ftArg="\$${3:2}" || ftArg="$3"
|
|
||||||
auxType="$4"
|
|
||||||
|
|
||||||
# assume BIN/$2000 if filetype omitted
|
|
||||||
if [[ ! $ftArg ]]; then
|
|
||||||
ft="BIN"
|
|
||||||
auxType="\$2000"
|
|
||||||
# accept hex or decimal number for file type
|
|
||||||
elif [[ ( ${ftArg:0:1} == '$' && ${#ftArg} -eq 3 ) || $(grep [0-9] <<< ${ftArg:0:1}) ]]; then
|
|
||||||
if [[ ${ftArg:0:1} == '$' ]]; then
|
|
||||||
fc=$(tr [:upper:] [:lower:] <<< ${ftArg:1:2})
|
|
||||||
else
|
|
||||||
fc=$(decToHex $ftArg | tr [:upper:] [:lower:])
|
|
||||||
fi
|
|
||||||
P_00=UNK; P_01=BAD; P_02=PCD; P_03=PTX; P_04=TXT; P_05=PDA; P_06=BIN; P_07=FNT; P_08=FOT; P_09=BA3; P_0a=DA3; P_0b=WPF; P_0c=SOS; P_0f=DIR; P_10=RPD; P_11=RPI; P_12=AFD; P_13=AFM; P_14=AFR; P_15=SCL; P_16=PFS; P_19=ADB; P_1a=AWP; P_1b=ASP; P_20=TDM; P_21=IPS; P_22=UPV; P_29=3SD; P_2a=8SC; P_2b=8OB; P_2c=8IC; P_2d=8LD; P_2e=P8C; P_41=OCR; P_42=FTD; P_50=GWP; P_51=GSS; P_52=GDB; P_53=DRW; P_54=GDP; P_55=HMD; P_56=EDU; P_57=STN; P_58=HLP; P_59=COM; P_5a=CFG; P_5b=ANM; P_5c=MUM; P_5d=ENT; P_5e=DVU; P_60=PRE; P_6b=BIO; P_6d=DVR; P_6e=PRE; P_6f=HDV; P_80=GEZ; P_81=GE1; P_82=GEO; P_83=GE3; P_84=GE4; P_85=GE5; P_86=GE6; P_87=GE7; P_88=GE8; P_89=GE9; P_8a=GEA; P_8b=GEB; P_8c=GEC; P_8d=GED; P_8e=GEE; P_8f=GEF; P_a0=WP_; P_ab=GSB; P_ac=TDF; P_ad=BDF; P_b0=SRC; P_b1=OBJ; P_b2=LIB; P_b3=S16; P_b4=RTL; P_b5=EXE; P_b6=STR; P_b7=TSF; P_b8=NDA; P_b9=CDA; P_ba=TOL; P_bb=DRV; P_bc=LDF; P_bd=FST; P_bf=DOC; P_c0=PNT; P_c1=PIC; P_c2=ANI; P_c3=PAL; P_c5=OOG; P_c6=SCR; P_c7=CDV; P_c8=FON; P_c9=FND; P_ca=ICN; P_d5=MUS; P_d6=INS; P_d7=MDI; P_d8=SND; P_db=DBM; P_e0=SHK; P_e2=DTS; P_ee=R16; P_ef=PAS; P_f0=CMD; P_f9=P16; P_fa=INT; P_fb=IVR; P_fc=BAS; P_fd=VAR; P_fe=REL; P_ff=SYS;
|
|
||||||
ftVar="P_$fc";
|
|
||||||
[[ ${!ftVar} ]] && ft=${!ftVar} || ft="\$$fc";
|
|
||||||
else
|
|
||||||
ft="$ftArg"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set auxtype to $0801 for Applesoft programs if not specified
|
|
||||||
[[ $ft == "BAS" && ! $auxType ]] && auxType="\$0801"
|
|
||||||
|
|
||||||
# test for absence of stdin [[ -t 0 ]] and if absent use ProDOS name
|
|
||||||
if [[ -t 0 ]]; then
|
|
||||||
[[ ! -f $prodosArg ]] && { echoerr "$prodosArg not found."; exit 1; }
|
|
||||||
java -Xmx128m -jar "$adtPath"/lib/AppleCommander/AppleCommander-ac.jar -d "$imageArg" $prodosPath &> /dev/null
|
|
||||||
java -Xmx128m -jar "$adtPath"/lib/AppleCommander/AppleCommander-ac.jar -p "$imageArg" $prodosPath $ft $auxType < $prodosArg 2> $acmdStdErr
|
|
||||||
else
|
|
||||||
java -Xmx128m -jar "$adtPath"/lib/AppleCommander/AppleCommander-ac.jar -d "$imageArg" $prodosPath &> /dev/null
|
|
||||||
java -Xmx128m -jar "$adtPath"/lib/AppleCommander/AppleCommander-ac.jar -p "$imageArg" $prodosPath $ft $auxType 2> $acmdStdErr
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
imageArg="$2"
|
|
||||||
java -Xmx128m -jar "$adtPath"/lib/AppleCommander/AppleCommander-ac.jar "$@" 2> $acmdStdErr
|
|
||||||
|
|
||||||
fi
|
|
||||||
|
|
||||||
helpExit
|
|
@ -1,33 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# don't do anything if ADTPro is already running
|
|
||||||
if [[ $(ps aux | grep [A]DTPro) ]]; then
|
|
||||||
|
|
||||||
1&>2 echo "ADTPro server is already running."
|
|
||||||
|
|
||||||
else
|
|
||||||
|
|
||||||
# look for eligible USB-to-serial adapter
|
|
||||||
ttyUSB=
|
|
||||||
# if lower USB port
|
|
||||||
if [[ -c /dev/ttyUSBlower ]]; then
|
|
||||||
ttyUSB=ttyUSBlower
|
|
||||||
# if hub in lower port, use lowest numbered port on hub
|
|
||||||
elif [[ $(ls -1 /dev/ttyUSBlower_hub* 2> /dev/null | wc -l) -gt 0 ]]; then
|
|
||||||
ttyUSB=$(ls -1 /dev/ttyUSBlower_hub* 2> /dev/null | head -1 | cut -c 6-)
|
|
||||||
# if hub in upper port with multiple adapters, use lowest numbered port on hub
|
|
||||||
elif [[ $(ls -1 /dev/ttyUSBupper_hub* 2> /dev/null | wc -l) -gt 1 ]]; then
|
|
||||||
ttyUSB=$(ls -1 /dev/ttyUSBupper_hub* 2> /dev/null | head -1 | cut -c 6-)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $ttyUSB ]]; then
|
|
||||||
echo -n "Please wait..."
|
|
||||||
sudo nohup adtpro.sh headless serial &> /dev/null
|
|
||||||
echo "ok."
|
|
||||||
else
|
|
||||||
1>&2 echo "No USB-to-serial adapter found in the lower USB port, or"
|
|
||||||
1>&2 echo " a hub on the lower USB port, or the lowest-numbered port"
|
|
||||||
1>&2 echo " of a hub on the upper USB port. Not starting ADTPro server."
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
@ -1,141 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# ADTPro - *nix startup shell script
|
|
||||||
#
|
|
||||||
# Note:
|
|
||||||
# Invoke with the name of the communications button to push
|
|
||||||
# in order to start with that mode active (i.e. './adtpro.sh ethernet')
|
|
||||||
#
|
|
||||||
# You can set two variables here:
|
|
||||||
# 1. $MY_JAVA_HOME - to pick a particular java to run under
|
|
||||||
# 2. $ADTPRO_HOME - to say where you installed ADTPro
|
|
||||||
#
|
|
||||||
# Set default ADTPRO_HOME to be the fully qualified
|
|
||||||
# current working directory.
|
|
||||||
#export ADTPRO_HOME="`dirname \"$0\"`"
|
|
||||||
#cd "$ADTPRO_HOME"
|
|
||||||
#export ADTPRO_HOME=`pwd`
|
|
||||||
|
|
||||||
# Uncomment and modify one or both of the lines below if you
|
|
||||||
# want to specify a particular location for Java or ADTPro.
|
|
||||||
# NOTE: be sure to include a trailing slash on MY_JAVA_HOME,
|
|
||||||
# but not on ADTPRO_HOME.
|
|
||||||
#
|
|
||||||
# export MY_JAVA_HOME=/usr/local/java/bin/
|
|
||||||
# export ADTPRO_HOME=~/myuser/adtpro
|
|
||||||
|
|
||||||
usageExit () {
|
|
||||||
echo "usage:" 1>&2
|
|
||||||
echo "adtpro.sh [headless] [serial|ethernet|audio|localhost] [serialPortName]" 1>&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
export ADTPRO_HOME=/usr/local/adtpro
|
|
||||||
cd "$ADTPRO_HOME"
|
|
||||||
|
|
||||||
OS=`uname`
|
|
||||||
OS_ARCH=`uname -m`
|
|
||||||
|
|
||||||
[[ $1 == "headless" ]] && { headless=1; shift; } || headless=
|
|
||||||
|
|
||||||
if [[ $1 && ( $1 != "serial" && $1 != "ethernet" && $1 != "audio" && $1 != "localhost" ) ]]; then
|
|
||||||
usageExit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Linux, use this:
|
|
||||||
if [ "$OS" = "Linux" ]; then
|
|
||||||
|
|
||||||
serialPortName=
|
|
||||||
if [[ $1 == "serial" ]]; then
|
|
||||||
if [[ $2 ]]; then
|
|
||||||
serialPortName="$2"
|
|
||||||
[[ ${serialPortName:0:5} == "/dev/" ]] && serialPortName=${serialPortName:5}
|
|
||||||
if [[ ! -c /dev/$serialPortName ]]; then
|
|
||||||
echo "Serial port $serialPortName not found." 1>&2
|
|
||||||
usageExit
|
|
||||||
fi
|
|
||||||
elif [[ -c /dev/ttyUSBlower ]]; then
|
|
||||||
serialPortName=ttyUSBlower
|
|
||||||
elif [[ $(ls -1 /dev/ttyUSBlower_hub* 2> /dev/null | wc -l) -gt 0 ]]; then
|
|
||||||
serialPortName=$(ls -1 /dev/ttyUSBlower_hub* 2> /dev/null | head -1 | cut -c 6-)
|
|
||||||
elif [[ $(ls -1 /dev/ttyUSBupper_hub* 2> /dev/null | wc -l) -gt 1 ]]; then
|
|
||||||
serialPortName=$(ls -1 /dev/ttyUSBupper_hub* 2> /dev/null | head -1 | cut -c 6-)
|
|
||||||
else
|
|
||||||
echo "No eligible USB-to-serial adapter found." 1>&2
|
|
||||||
echo "Possible ports:" 1>&2
|
|
||||||
echo " lower USB port"
|
|
||||||
echo " any port on lower USB hub with no other adapters"
|
|
||||||
echo " lowest port on USB hub on upper or lower USB port with multiple adapters"
|
|
||||||
usageExit
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $(grep CommPort= /usr/local/adtpro/disks/ADTPro.properties) ]]; then
|
|
||||||
if [[ $serialPortName ]]; then
|
|
||||||
sed -i "s/^CommPort=.*$/CommPort=\/dev\/$serialPortName/" /usr/local/adtpro/disks/ADTPro.properties &> /dev/null
|
|
||||||
else
|
|
||||||
serialPortName=$(grep 'CommPort=/dev/' ADTPro.properties 2> /dev/null | cut -f 3 -d '/')
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "#ADTPro.properties\n#$(date)\nCommPortSpeed=115200\nCommPortBootstrapSpeed=2400\nCommPort=/dev/$serialPortName\nCommPortBootstrapPacing=250\nHardwareHandshaking=false\nSerialIPHost=localhost\nSerialIPPort=1977" > /usr/local/adtpro/disks/ADTPro.properties
|
|
||||||
chmod ugo+w /usr/local/adtpro/disks/ADTPro.properties
|
|
||||||
fi
|
|
||||||
|
|
||||||
ADTPRO_EXTRA_JAVA_PARMS="-Dgnu.io.rxtx.SerialPorts=/dev/$serialPortName"
|
|
||||||
|
|
||||||
if [ -f /usr/bin/raspi-config ]; then
|
|
||||||
export RXTXLIB=lib/rxtx/rxtx-2.2pre2-local/arm
|
|
||||||
elif [ "$OS_ARCH" = "i686" ]; then
|
|
||||||
export RXTXLIB=lib/rxtx/rxtx-2.2pre2-local/i686-pc-linux-gnu
|
|
||||||
else
|
|
||||||
if [ "$OS_ARCH" = "i386" ]; then
|
|
||||||
export RXTXLIB=lib/rxtx/rxtx-2.2pre2-local/i686-pc-linux-gnu
|
|
||||||
else
|
|
||||||
export RXTXLIB=lib/rxtx/rxtx-2.2pre2-local/x86_64-unknown-linux-gnu
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For OSX, use this:
|
|
||||||
if [ "$OS" = "Darwin" ]; then
|
|
||||||
if [ "$OS_ARCH" = "powerpc" ]; then
|
|
||||||
export RXTXLIB=lib/rxtx/rxtx-2.1-7-bins-r2/Mac_OS_X
|
|
||||||
else
|
|
||||||
export RXTXLIB=lib/rxtx/rxtx-2.2pre2-local/mac-10.5
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Solaris, use this:
|
|
||||||
if [ "$OS" = "SunOS" ]; then
|
|
||||||
export RXTXLIB=lib/rxtx/rxtx-2.2pre2-local/sparc-sun-solaris2.10-32
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set up the library location.
|
|
||||||
export TWEAK1="-Djava.library.path="
|
|
||||||
export TWEAK=$TWEAK1$ADTPRO_HOME/$RXTXLIB
|
|
||||||
|
|
||||||
if [[ $headless ]]; then
|
|
||||||
if [[ ! $1 || ! -f /usr/bin/xvfb-run ]]; then
|
|
||||||
if [[ ! -f /usr/bin/xvfb-run ]]; then
|
|
||||||
echo "Headless operation requires xvfb."
|
|
||||||
usageExit
|
|
||||||
else
|
|
||||||
echo "Headless operation requires a communication mode (e.g. serial)."
|
|
||||||
usageExit
|
|
||||||
fi
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
HEADLESS="xvfb-run --auto-servernum "
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $serialPortName && $(ps aux | grep "/sbin/getty.*$serialPortName") ]]; then
|
|
||||||
sudo pkill -f "/sbin/getty.*$serialPortName"
|
|
||||||
fi
|
|
||||||
sudo pkill -f [A]DTPro
|
|
||||||
cd "$ADTPRO_HOME"/disks
|
|
||||||
$HEADLESS"$MY_JAVA_HOME"java -Xms256m -Xmx512m "$TWEAK" $ADTPRO_EXTRA_JAVA_PARMS -cp ../lib/ADTPro.jar:../"$RXTXLIB"/../RXTXcomm.jar:../lib/AppleCommander/AppleCommander-ac.jar org.adtpro.ADTPro $* &
|
|
||||||
if [[ $1 == "serial" ]]; then
|
|
||||||
echo "Starting up on interface $serialPortName. Please wait..."
|
|
||||||
fi
|
|
||||||
sleep 30
|
|
@ -1,29 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ $1 == "-d" ]]; then
|
|
||||||
shift
|
|
||||||
setgetty=1
|
|
||||||
else
|
|
||||||
setgetty=
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $1 -ne 300 && $1 -ne 1200 && $1 -ne 2400 && $1 -ne 4800 && $1 -ne 9600 && $1 -ne 19200 && $1 -ne 38400 && $1 -ne 57600 && $1 -ne 115200 ]]; then
|
|
||||||
echo 'Usage: baud [-d] 300|1200|2400|4800|9600|19200|38400|57600|115200';
|
|
||||||
echo ' -d sets default speed for all serial port shells (takes effect on logout)'
|
|
||||||
echo ' omitting -d makes change temporary and immediate'
|
|
||||||
else
|
|
||||||
if [[ $setgetty ]]; then
|
|
||||||
sudo sed -i "s/ttyAMA0 .* /ttyAMA0 $1 /" /etc/inittab;
|
|
||||||
sudo sed -i "s/ttyAMA0,[0-9]*/ttyAMA0,$1/g" /boot/cmdline.txt;
|
|
||||||
sudo sed -i "s/\(ttyUSB.*\) .* /\1 $1 /g" /etc/inittab;
|
|
||||||
sudo init q;
|
|
||||||
sudo pkill -f "/sbin/getty"
|
|
||||||
else
|
|
||||||
if [[ $(tty | grep tty) ]]; then
|
|
||||||
stty -F $(tty) $1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "$(tput bold)$(tty) current $(stty -a -F $(tty) | grep -o 'speed .* baud')$(tput sgr0)"
|
|
||||||
echo -e "$(tput bold)default speed at login: $(grep ttyUSB /etc/inittab | sed 's/^.*ttyUSB[^ ]* \(.*\) .*$/\1/') baud$(tput sgr0)"
|
|
@ -1,761 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# need to test:
|
|
||||||
# does both -e and -ad work as expected? what if you do both?
|
|
||||||
|
|
||||||
|
|
||||||
#--ID-bashbyter routines
|
|
||||||
|
|
||||||
decToHex () {
|
|
||||||
# converts single-byte decimal value to hexadecimal equivalent
|
|
||||||
# arg: decimal value from 0-255
|
|
||||||
# out: two-digit hex value from 00-FF
|
|
||||||
#exit: 8=extraneous arg, 11=missing arg, 21=invalid arg
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $2 ]] && return 8
|
|
||||||
[[ ( $(printf %d "$1" 2> /dev/null) == $1 ) \
|
|
||||||
&& ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21
|
|
||||||
# args are valid
|
|
||||||
printf %02X "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
hexToDec () {
|
|
||||||
# converts single-byte hexadecimal value to decimal equivalent
|
|
||||||
# arg: two-digit hex value from 00-FF
|
|
||||||
# out: decimal value
|
|
||||||
#exit: 8=extraneous arg, 11=missing arg, 21=invalid arg
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $2 ]] && return 8
|
|
||||||
[[ ${#1} -eq 2 ]] || return 21
|
|
||||||
[[ $(printf %02X "0x$1" 2> /dev/null) == \
|
|
||||||
$(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21
|
|
||||||
# args are valid
|
|
||||||
printf %d "0x$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
hexToBin () {
|
|
||||||
# converts single-byte hexadecimal value to binary string
|
|
||||||
# arg: two-digit hex value from 00-FF
|
|
||||||
# out: binary string value
|
|
||||||
#exit: 8=extraneous arg, 11=missing arg, 21=invalid arg
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $2 ]] && return 8
|
|
||||||
[[ ${#1} -eq 2 ]] || return 21
|
|
||||||
[[ $(printf %02X "0x$1" 2> /dev/null) == \
|
|
||||||
$(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21
|
|
||||||
# args are valid
|
|
||||||
for n in 0 1; do
|
|
||||||
if [[ ${1:n:1} == "0" ]]; then b="0000"
|
|
||||||
elif [[ ${1:n:1} == "1" ]]; then b="0001"
|
|
||||||
elif [[ ${1:n:1} == "2" ]]; then b="0010"
|
|
||||||
elif [[ ${1:n:1} == "3" ]]; then b="0011"
|
|
||||||
elif [[ ${1:n:1} == "4" ]]; then b="0100"
|
|
||||||
elif [[ ${1:n:1} == "5" ]]; then b="0101"
|
|
||||||
elif [[ ${1:n:1} == "6" ]]; then b="0110"
|
|
||||||
elif [[ ${1:n:1} == "7" ]]; then b="0111"
|
|
||||||
elif [[ ${1:n:1} == "8" ]]; then b="1000"
|
|
||||||
elif [[ ${1:n:1} == "9" ]]; then b="1001"
|
|
||||||
elif [[ ${1:n:1} == "A" ]]; then b="1010"
|
|
||||||
elif [[ ${1:n:1} == "B" ]]; then b="1011"
|
|
||||||
elif [[ ${1:n:1} == "C" ]]; then b="1100"
|
|
||||||
elif [[ ${1:n:1} == "D" ]]; then b="1101"
|
|
||||||
elif [[ ${1:n:1} == "E" ]]; then b="1110"
|
|
||||||
elif [[ ${1:n:1} == "F" ]]; then b="1111"
|
|
||||||
fi
|
|
||||||
echo -n $b
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
binToDec () {
|
|
||||||
# converts single-byte binary string (8 bits) value to decimal
|
|
||||||
# warning: no error checking
|
|
||||||
# arg: binary string up to 8 bits
|
|
||||||
# out: decimal value
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
binToHex () {
|
|
||||||
# converts single-byte binary string (8 bits) value to hex
|
|
||||||
# warning: no error checking
|
|
||||||
# arg: binary string up to 8 bits
|
|
||||||
# out: hex value
|
|
||||||
echo $(decToHex $(binToDec $1))
|
|
||||||
}
|
|
||||||
|
|
||||||
charToDec () {
|
|
||||||
# converts single character to corresponding decimal value
|
|
||||||
# stdin OR arg: one character
|
|
||||||
# [arg overrides stdin; stdin is required for NUL (0) or LF (0x0A)]
|
|
||||||
# out: decimal value from 0-255
|
|
||||||
#exit: 8=extraneous arg, 9=invalid stdin,
|
|
||||||
# 11=missing stdin/arg, 21=invalid arg
|
|
||||||
[[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; }
|
|
||||||
[[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; }
|
|
||||||
# arg/stdin is potentially valid (additional check below)
|
|
||||||
charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)"
|
|
||||||
[[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 ))
|
|
||||||
# above line verifies that arg/stdin is valid
|
|
||||||
[[ ${#charX} -ne 2 ]] && { echo -n 0; return 0; }
|
|
||||||
echo -n "${charX:0:1}" | od -t u1 | \
|
|
||||||
head -1 | sed 's/[0\ ]*//' | tr -d ' \n'
|
|
||||||
}
|
|
||||||
|
|
||||||
charToHex () {
|
|
||||||
# converts single character to corresponding hexadecimal value
|
|
||||||
# stdin OR arg: one character
|
|
||||||
# [arg overrides stdin; stdin is required for NUL (0) or LF (0x0A)]
|
|
||||||
# out: decimal value from 0-255
|
|
||||||
#exit: 8=extraneous arg, 9=invalid stdin,
|
|
||||||
# 11=missing stdin/arg, 21=invalid arg
|
|
||||||
[[ ( ! -t 0 ) && $1 ]] && { cat > /dev/null; return 8; }
|
|
||||||
[[ ( -t 0 ) ]] && { [[ $2 ]] && return 8; [[ $1 ]] || return 11; }
|
|
||||||
# arg/stdin is potentially valid (additional check below)
|
|
||||||
charX="$1X"; [[ $1 ]] || charX="$(cat; echo -n 'X';)"
|
|
||||||
[[ ${#charX} -le 2 ]] || return $(( $([[ $1 ]]; echo $?) ? 9 : 21 ))
|
|
||||||
# above line verifies that stdin/arg is valid
|
|
||||||
[[ ${#charX} -ne 2 ]] && { echo -n "00"; return 0; }
|
|
||||||
printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \
|
|
||||||
head -1 | sed 's/[0\ ]*//' | tr -d ' \n')
|
|
||||||
}
|
|
||||||
|
|
||||||
decToChar () {
|
|
||||||
# converts single-byte decimal value to equivalent character
|
|
||||||
# arg: decimal number from 0-255
|
|
||||||
# out: one character
|
|
||||||
#exit: 8=extraneous arg, 11=missing arg, 21=invalid arg
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $2 ]] && return 8
|
|
||||||
[[ ( $(printf %d "$1" 2> /dev/null ) == $1 ) \
|
|
||||||
&& ( $1 -ge 0 ) && ( $1 -le 255 ) ]] || return 21
|
|
||||||
# args are valid
|
|
||||||
echo -n -e "\x$(printf %02X "$1")"
|
|
||||||
}
|
|
||||||
|
|
||||||
hexToChar () {
|
|
||||||
# converts single-byte hexadecimal value to corresponding character
|
|
||||||
# arg: two-digit hexadecimal number from 00-FF
|
|
||||||
# out: one character
|
|
||||||
#exit: 8=extraneous arg, 11=missing arg, 21=invalid arg
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $2 ]] && return 8
|
|
||||||
[[ ${#1} -eq 2 ]] || return 21
|
|
||||||
[[ $(printf %02X "0x$1" 2> /dev/null) == \
|
|
||||||
$(echo -n "$1" | tr [a-z] [A-Z]) ]] || return 21
|
|
||||||
# args are valid
|
|
||||||
echo -n -e "\x$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
readchars () {
|
|
||||||
# read one or more characters from a file
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# arg3: (optional) # of chars to read (default is until end of file)
|
|
||||||
# out: sequence of characters
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1,
|
|
||||||
# 21=invalid arg1, 22=invalid arg2, 23=invalid arg3
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $4 ]] && return 8
|
|
||||||
[[ -f $1 ]] || return 21
|
|
||||||
[[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \
|
|
||||||
&& ( $2 -ge 0 ) ]] || return 22; }
|
|
||||||
[[ $3 ]] && { [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \
|
|
||||||
&& ( $3 -ge 0 ) ]] || return 23; }
|
|
||||||
# args are valid
|
|
||||||
dd if="$1" bs=1 skip=$(($2)) $([[ $3 ]] && echo -n "count=$3") \
|
|
||||||
2> /dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
readcharDec () {
|
|
||||||
# read one character from file & convert to equivalent decimal value
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# out: decimal value from 0-255
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1,
|
|
||||||
# 21=invalid arg1, 22=invalid arg2
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $3 ]] && return 8
|
|
||||||
[[ -f $1 ]] || return 21
|
|
||||||
[[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \
|
|
||||||
&& ( $2 -ge 0 ) ]] || return 22; }
|
|
||||||
# args are valid
|
|
||||||
charX="$(dd if="$1" bs=1 skip=$(($2)) \
|
|
||||||
count=1 2> /dev/null; echo -n X)"
|
|
||||||
[[ ${#charX} -gt 1 ]] || { echo -n 0; return 0; }
|
|
||||||
echo -n "${charX:0:1}" | od -t u1 | \
|
|
||||||
head -1 | sed 's/[0\ ]*//' | tr -d ' \n'
|
|
||||||
}
|
|
||||||
|
|
||||||
readcharHex () {
|
|
||||||
# read one character from file & convert to corresponding hex value
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# out: two-digit hex value from 00-FF
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1,
|
|
||||||
# 21=invalid arg1, 22=invalid arg2
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $3 ]] && return 8
|
|
||||||
[[ -f $1 ]] || return 21
|
|
||||||
[[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \
|
|
||||||
&& ( $2 -ge 0 ) ]] || return 22; }
|
|
||||||
# args are valid
|
|
||||||
charX="$(dd if="$1" bs=1 skip=$(($2)) \
|
|
||||||
count=1 2> /dev/null; echo -n X)"
|
|
||||||
[[ ${#charX} -gt 1 ]] || { echo -n "00"; return 0; }
|
|
||||||
printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \
|
|
||||||
head -1 | sed 's/[0\ ]*//' | tr -d ' \n')
|
|
||||||
}
|
|
||||||
|
|
||||||
### 2-15-11 above tested on OS X and Linux
|
|
||||||
|
|
||||||
writechars () {
|
|
||||||
# write one or more characters (bytes) to file
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before writing)
|
|
||||||
# arg3 OR stdin: sequence of characters
|
|
||||||
# [stdin required if writing NUL (0) or trailing LF (0x0A) chars]
|
|
||||||
# out: nothing
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1,
|
|
||||||
# 13=missing stdin/arg3, 22=invalid arg2
|
|
||||||
[[ $1 ]] || { [[ -t 0 ]] || cat > /dev/null; return 11; }
|
|
||||||
[[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) && \
|
|
||||||
( $2 -ge 0 ) ]] || { [[ -t 0 ]] || cat > /dev/null; return 22; } }
|
|
||||||
[[ ( ! -t 0 ) && $3 ]] && { cat > /dev/null; return 8; }
|
|
||||||
[[ ( -t 0 ) ]] && { [[ $4 ]] && return 8; [[ $3 ]] || return 13; }
|
|
||||||
# args are valid
|
|
||||||
if [[ -t 0 ]]; then
|
|
||||||
echo -n "$3" | \
|
|
||||||
dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null
|
|
||||||
else
|
|
||||||
dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
writecharDec () {
|
|
||||||
# write corresponding character of single-byte decimal value into file
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: offset (# of bytes to skip before writing)
|
|
||||||
# arg3: decimal number from 0-255
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2,
|
|
||||||
# 13=missing arg3, 22=invalid arg2, 23=invalid arg3
|
|
||||||
# out: nothing
|
|
||||||
[[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13
|
|
||||||
[[ $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
|
|
||||||
# args are valid
|
|
||||||
echo -n -e "\x$(printf %02X "$3")" | \
|
|
||||||
dd of="$1" bs=1 seek=$(($2)) conv=notrunc 2> /dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
writecharHex () {
|
|
||||||
# write corresponding character of single-byte hex value into file
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: offset (# of bytes to skip before writing)
|
|
||||||
# arg3: two-digit hexadecimal number from 00-FF
|
|
||||||
# out: nothing
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2,
|
|
||||||
# 13=missing arg3, 22=invalid arg2, 23=invalid arg3
|
|
||||||
[[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13
|
|
||||||
[[ $4 ]] && return 8
|
|
||||||
[[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \
|
|
||||||
&& ( $2 -ge 0 ) ]] || return 22
|
|
||||||
[[ $(printf %02X "0x$3" 2> /dev/null) == \
|
|
||||||
$(echo -n "$3" | tr [a-z] [A-Z]) ]] || return 23
|
|
||||||
# args are valid
|
|
||||||
echo -n -e "\x$3" | \
|
|
||||||
dd of="$1" bs=1 seek=$2 conv=notrunc 2> /dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
writecharsHex () {
|
|
||||||
# write corresponding characters of hex values into file
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: offset (# of bytes to skip before writing)
|
|
||||||
# arg3: string of two-digit hexadecimal numbers from 00-FF, period delimited (not checked!)
|
|
||||||
# out: nothing
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2,
|
|
||||||
# 13=missing arg3, 22=invalid arg2, 23=invalid arg3
|
|
||||||
[[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13
|
|
||||||
[[ $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
|
|
||||||
# args are valid
|
|
||||||
echo -n -e "\x$outByte" | \
|
|
||||||
dd of="$1" bs=1 seek=$offset conv=notrunc 2> /dev/null
|
|
||||||
(( p += 3 ))
|
|
||||||
(( offset++ ))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# ---
|
|
||||||
|
|
||||||
pdosDateToUnixDate () {
|
|
||||||
# input: ProDOS date/time bit sequence string in format:
|
|
||||||
# yyyyyyymmmmddddd000hhhhh00mmmmmm
|
|
||||||
# output: seconds since Unix epoch (1-Jan-1970), or current date/time if no ProDOS date
|
|
||||||
year=$(( $(binToDec ${1:0:7}) + 1900 ))
|
|
||||||
(( $year < 1940 )) && (( year+=100 ))
|
|
||||||
month=$(binToDec ${1:7:4})
|
|
||||||
day=$(binToDec ${1:11:5})
|
|
||||||
hour=$(binToDec ${1:19:5})
|
|
||||||
minute=$(binToDec ${1:26:6})
|
|
||||||
date -d "$year-$month-$day $hour:$minute:00" "+%s" 2> /dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
unixDateToADDate () {
|
|
||||||
# input: seconds since Unix epoch (1-Jan-1970 00:00:00 GMT)
|
|
||||||
# output: seconds since Netatalk epoch (1-Jan-2000 00:00:00 GMT),
|
|
||||||
# in four period-delimited hex bytes (big endian)
|
|
||||||
adDate=$(( $1 - 946684800 ));
|
|
||||||
if (( $adDate < 0 )); then
|
|
||||||
(( adDate+=4294967296 )) # to get negative hex number
|
|
||||||
fi
|
|
||||||
adDateHex=$(printf %08X $adDate)
|
|
||||||
echo "${adDateHex:0:2}.${adDateHex:2:2}.${adDateHex:4:2}.${adDateHex:6:2}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# cppo support routines:
|
|
||||||
# arg1: directory block
|
|
||||||
# arg2: file index (if applicable)
|
|
||||||
# arg3: directory chunk # (if applicable)
|
|
||||||
|
|
||||||
# returns byte position in disk image file
|
|
||||||
getStartPos () {
|
|
||||||
echo $(( ($1 * 512) + (39 * ( ($2 + ($2>11) ) % 13) ) + ( ($2>11) ? 4 : 43) ))
|
|
||||||
}
|
|
||||||
|
|
||||||
getStorageType () {
|
|
||||||
start=$(getStartPos $1 $2)
|
|
||||||
firstByte=$(readcharDec "$image" $start)
|
|
||||||
echo $(($firstByte/16))
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileName () {
|
|
||||||
start=$(getStartPos $1 $2)
|
|
||||||
firstByte=$(readcharDec "$image" $start)
|
|
||||||
entryType=$(($firstByte/16))
|
|
||||||
nameLength=$(($firstByte-$entryType*16))
|
|
||||||
echo $(readchars "$image" $(($start+1)) $nameLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileType () {
|
|
||||||
start=$(getStartPos $1 $2)
|
|
||||||
echo $(readcharHex "$image" $(($start+16)) )
|
|
||||||
}
|
|
||||||
|
|
||||||
getKeyPointer () {
|
|
||||||
start=$(getStartPos $1 $2)
|
|
||||||
echo $(( $(readcharDec "$image" $(($start+17)) ) + \
|
|
||||||
$(readcharDec "$image" $(($start+18)) ) * 256 ))
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileLength () {
|
|
||||||
start=$(getStartPos $1 $2)
|
|
||||||
echo $(( $(readcharDec "$image" $(($start+21)) ) + \
|
|
||||||
$(readcharDec "$image" $(($start + 22)) ) * 256 + \
|
|
||||||
$(readcharDec "$image" $(($start + 23)) ) * 65536 ))
|
|
||||||
}
|
|
||||||
|
|
||||||
getAuxType () {
|
|
||||||
start=$(getStartPos $1 $2)
|
|
||||||
echo $(readcharHex "$image" $(($start+32)) ).$(readcharHex "$image" $(($start+31)) )
|
|
||||||
}
|
|
||||||
|
|
||||||
getCreationDate () {
|
|
||||||
#outputs prodos creation date/time as Unix time (seconds since Jan 1 1970 GMT)
|
|
||||||
#or "NONE" if there is none
|
|
||||||
start=$(getStartPos $1 $2)
|
|
||||||
pdosDate=\
|
|
||||||
$( hexToBin $(readcharHex "$image" $(($start+25)) ) )\
|
|
||||||
$( hexToBin $(readcharHex "$image" $(($start+24)) ) )\
|
|
||||||
$( hexToBin $(readcharHex "$image" $(($start+27)) ) )\
|
|
||||||
$( hexToBin $(readcharHex "$image" $(($start+26)) ) )
|
|
||||||
pdosDateToUnixDate $pdosDate || echo "NONE"
|
|
||||||
}
|
|
||||||
|
|
||||||
getModifiedDate () {
|
|
||||||
#outputs prodos modified date/time as Unix time (seconds since Jan 1 1970 GMT)
|
|
||||||
start=$(getStartPos $1 $2)
|
|
||||||
pdosDate=\
|
|
||||||
$( hexToBin $(readcharHex "$image" $(($start+34)) ) )\
|
|
||||||
$( hexToBin $(readcharHex "$image" $(($start+33)) ) )\
|
|
||||||
$( hexToBin $(readcharHex "$image" $(($start+36)) ) )\
|
|
||||||
$( hexToBin $(readcharHex "$image" $(($start+35)) ) )
|
|
||||||
pdosDateToUnixDate $pdosDate || echo "NONE"
|
|
||||||
}
|
|
||||||
|
|
||||||
#isLocked () {
|
|
||||||
# #returns 1 (meaning locked) if bit 7, 6, or 1 are clear; otherwise returns 0
|
|
||||||
# start=$(getStartPos $1 $2)
|
|
||||||
# access=$( $hexToBin $(readcharHex "$image" $(($start+30)) ) )
|
|
||||||
# if [[ ${access:0:1} != "1" || ${access:1:1} != "1" || ${access:7:1} != "1" ]]; then
|
|
||||||
# echo 1
|
|
||||||
# else
|
|
||||||
# echo 0
|
|
||||||
# fi
|
|
||||||
#}
|
|
||||||
|
|
||||||
getVolumeName () {
|
|
||||||
echo $(getWorkingDirName 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
getWorkingDirName () {
|
|
||||||
start=$(( $1 * 512 ))
|
|
||||||
firstByte=$(readcharDec "$image" $(($start+4)) )
|
|
||||||
entryType=$(($firstByte/16))
|
|
||||||
nameLength=$(($firstByte-$entryType*16))
|
|
||||||
echo $(readchars "$image" $(($start+5)) $nameLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
getDirEntryCount () {
|
|
||||||
start=$(( $1 * 512 ))
|
|
||||||
echo $(( $(readcharDec "$image" $(($start+37)) ) + \
|
|
||||||
$(readcharDec "$image" $(($start+38)) ) * 256 ))
|
|
||||||
}
|
|
||||||
|
|
||||||
getDirNextChunkPointer () {
|
|
||||||
start=$(( $1 * 512 ))
|
|
||||||
echo $(( $(readcharDec "$image" $(($start+2)) ) + \
|
|
||||||
$(readcharDec "$image" $(($start+3)) ) * 256 ))
|
|
||||||
}
|
|
||||||
|
|
||||||
# -- script begins in earnest here
|
|
||||||
|
|
||||||
copyFile () {
|
|
||||||
activeFileBytesCopied=0
|
|
||||||
storageType=$(getStorageType $1 $2)
|
|
||||||
keyPointer=$(getKeyPointer $1 $2)
|
|
||||||
fileLen=$(getFileLength $1 $2)
|
|
||||||
if (( $storageType == 1 )); then #seedling
|
|
||||||
copyBlock $keyPointer $fileLen
|
|
||||||
elif (( $storageType == 2 )); then #sapling
|
|
||||||
processIndexBlock $keyPointer
|
|
||||||
elif (( $storageType == 3 )); then #tree
|
|
||||||
processMasterIndexBlock $keyPointer
|
|
||||||
elif (( $storageType == 5)); then #forked fileLen
|
|
||||||
processForkedFile $keyPointer
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
copyBlock () {
|
|
||||||
#arg1: block to copy
|
|
||||||
#arg2: bytes to write (should be 512, unless final block with less than 512 bytes)
|
|
||||||
#echo $1 $2 $activeFileBytesCopied
|
|
||||||
(( $1 == 0 )) && blockSource=/dev/zero || blockSource="$image"
|
|
||||||
if (( $resourceFork > 0 )); then
|
|
||||||
[[ $AD ]] && dd if="$blockSource" of="$ADdir/$targetName" bs=1 count=$2 skip=$(($1*512)) seek=$(($activeFileBytesCopied + 741)) 2> /dev/null
|
|
||||||
[[ $EX ]] && dd if="$blockSource" of="$targetDir/${eTargetName}r" bs=1 count=$2 skip=$(($1*512)) seek=$activeFileBytesCopied 2> /dev/null
|
|
||||||
else
|
|
||||||
dd if="$blockSource" of="$targetDir/$targetName" bs=1 count=$2 skip=$(($1*512)) seek="$activeFileBytesCopied" 2> /dev/null
|
|
||||||
fi
|
|
||||||
activeFileBytesCopied=$(( $activeFileBytesCopied + $2 ))
|
|
||||||
}
|
|
||||||
|
|
||||||
processDir () {
|
|
||||||
# arg1: dirBlock
|
|
||||||
# arg2/3/4/5: for non-key chunks: entryCount, entry#,
|
|
||||||
# workingDirName, processedEntryCount
|
|
||||||
|
|
||||||
local entryCount
|
|
||||||
local e
|
|
||||||
local pe
|
|
||||||
local workingDirName
|
|
||||||
|
|
||||||
if [[ $2 ]]; then
|
|
||||||
entryCount=$2
|
|
||||||
e=$3
|
|
||||||
workingDirName=$4
|
|
||||||
pe=$5
|
|
||||||
else
|
|
||||||
e=0
|
|
||||||
pe=0
|
|
||||||
entryCount=$(getDirEntryCount $1)
|
|
||||||
workingDirName=$(getWorkingDirName $1)
|
|
||||||
DIRPATH="$DIRPATH/$workingDirName"
|
|
||||||
if [[ $PDOSPATH_INDEX ]]; then
|
|
||||||
if (( $PDOSPATH_INDEX == 1 )); then
|
|
||||||
if [[ "/$PDOSPATH_SEGMENT" != "$DIRPATH" ]]; then
|
|
||||||
echo "ProDOS volume name does not match disk image."
|
|
||||||
exit 2
|
|
||||||
else
|
|
||||||
(( PDOSPATH_INDEX++ ))
|
|
||||||
PDOSPATH_SEGMENT=${PDOSPATH[PDOSPATH_INDEX]}
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo $DIRPATH
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
while (( $pe < $entryCount )); do
|
|
||||||
if (( $(getStorageType $1 $e) > 0 )); then
|
|
||||||
processEntry $1 $e
|
|
||||||
(( pe++ ))
|
|
||||||
fi
|
|
||||||
(( e++ ))
|
|
||||||
(( ($e + ( $e>11 ) ) % 13 )) || { processDir $(getDirNextChunkPointer $1) $entryCount $e $workingDirName $pe; break; }
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
processEntry () {
|
|
||||||
#echo $(getFileName $1 $2) $(getStorageType $1 $2) $(getFileType $1 $2) $(getKeyPointer $1 $2) $(getFileLength $1 $2) $(getAuxType $1 $2) $(getCreationDate $1 $2) $(getModifiedDate $1 $2)
|
|
||||||
activeFileName=$(getFileName $1 $2)
|
|
||||||
activeFileSize=$(getFileLength $1 $2)
|
|
||||||
[[ $PDOSPATH_INDEX ]] || echo " $activeFileName"
|
|
||||||
|
|
||||||
if [[ ( ! $PDOSPATH_INDEX ) || ( $activeFileName == $PDOSPATH_SEGMENT ) ]]; then
|
|
||||||
|
|
||||||
if (( $(getStorageType $1 $2) == 13 )); then
|
|
||||||
[[ $PDOSPATH_INDEX ]] || targetDir="$targetDir/$activeFileName"
|
|
||||||
ADdir="$targetDir/.AppleDouble"
|
|
||||||
[[ $DIR || -d $targetDir ]] || mkdir -p $targetDir
|
|
||||||
[[ $DIR || ! $AD || -d $ADdir ]] || mkdir -p $ADdir
|
|
||||||
if [[ $PDOSPATH_SEGMENT ]]; then
|
|
||||||
(( PDOSPATH_INDEX++ ))
|
|
||||||
PDOSPATH_SEGMENT=${PDOSPATH[PDOSPATH_INDEX]}
|
|
||||||
fi
|
|
||||||
processDir $(getKeyPointer $1 $2)
|
|
||||||
DIRPATH=${DIRPATH%/*}
|
|
||||||
[[ $PDOSPATH_INDEX ]] || targetDir="$targetDir/.."
|
|
||||||
ADdir="$targetDir/.AppleDouble"
|
|
||||||
else
|
|
||||||
[[ $DIR ]] && return
|
|
||||||
[[ $targetName ]] || targetName=$activeFileName
|
|
||||||
[[ $EX ]] && eTargetName="$targetName#$(getFileType $1 $2 | tr [:upper:] [:lower:])$(getAuxType $1 $2 | sed 's/\.//' | tr [:upper:] [:lower:])"
|
|
||||||
touch "$targetDir/$targetName"
|
|
||||||
makeADfile
|
|
||||||
copyFile $1 $2
|
|
||||||
creationDate=$(getCreationDate $1 $2);
|
|
||||||
modifiedDate=$(getModifiedDate $1 $2);
|
|
||||||
if [[ $creationDate == "NONE" && $modifiedDate != "NONE" ]]; then
|
|
||||||
creationDate=$modifiedDate
|
|
||||||
elif [[ $creationDate != "NONE" && $modifiedDate == "NONE" ]]; then
|
|
||||||
modifiedDate=$creationDate
|
|
||||||
elif [[ $creationDate == "NONE" && $modifiedDate == "NONE" ]]; then
|
|
||||||
creationDate=$(date "+%s")
|
|
||||||
modifiedDate=$creationDate
|
|
||||||
fi
|
|
||||||
if [[ $AD ]]; then # AppleDouble
|
|
||||||
# set dates
|
|
||||||
ADfilePath="$ADdir/$targetName"
|
|
||||||
writecharsHex "$ADfilePath" 637 $(unixDateToADDate $creationDate).$(unixDateToADDate $modifiedDate)
|
|
||||||
writecharHex "$ADfilePath" 645 80
|
|
||||||
writecharHex "$ADfilePath" 649 80
|
|
||||||
#set type/creator
|
|
||||||
writechars "$ADfilePath" 653 "p"
|
|
||||||
writecharsHex "$ADfilePath" 654 "$(getFileType $1 $2).$(getAuxType $1 $2)"
|
|
||||||
writechars "$ADfilePath" 657 "pdos"
|
|
||||||
fi
|
|
||||||
touch -d @$modifiedDate "$targetDir/$targetName"
|
|
||||||
if [[ $EX ]]; then # extended name
|
|
||||||
mv "$targetDir/$targetName" "$targetDir/$eTargetName"
|
|
||||||
[[ -f $targetDir/${eTargetName}r ]] && touch -d @$modifiedDate "$targetDir/${eTargetName}r"
|
|
||||||
fi
|
|
||||||
[[ $PDOSPATH_SEGMENT ]] && syncExit
|
|
||||||
targetName=
|
|
||||||
fi
|
|
||||||
|
|
||||||
#else
|
|
||||||
#echo "$activeFileName doesn't match $PDOSPATH_SEGMENT"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
processForkedFile () {
|
|
||||||
# finder info except type/creator
|
|
||||||
fInfoA_entryType=$(readcharDec "$image" 9)
|
|
||||||
fInfoB_entryType=$(readcharDec "$image" 27)
|
|
||||||
if (( $fInfoA_entryType==1 )); then
|
|
||||||
readchars "$image" 18 8 | writechars "$image" 661
|
|
||||||
elif (( $fInfoA_entryType==2 )); then
|
|
||||||
readchars "$image" 10 16 | writechars "$image" 669
|
|
||||||
fi
|
|
||||||
if (( $fInfoB_entryType==1 )); then
|
|
||||||
readchars "$image" 36 8 | writechars "$image" 661
|
|
||||||
elif (( $fInfoB_entryType==2 )); then
|
|
||||||
readchars "$image" 28 16 | writechars "$image" 669
|
|
||||||
fi
|
|
||||||
|
|
||||||
for f in 0 256; do
|
|
||||||
resourceFork=$f
|
|
||||||
activeFileBytesCopied=0
|
|
||||||
forkStart=$(( ($1 * 512) )) # start of Forked File key block
|
|
||||||
# echo --$forkStart
|
|
||||||
forkStorageType=$(readcharDec "$image" $(($forkStart+$f+0)) )
|
|
||||||
forkKeyPointer=$(( $(readcharDec "$image" $(($forkStart+$f+1)) ) + \
|
|
||||||
$(readcharDec "$image" $(($forkStart+$f+2)) ) * 256 ))
|
|
||||||
forkFileLen=$(( $(readcharDec "$image" $(($forkStart+$f+5)) ) + \
|
|
||||||
$(readcharDec "$image" $(($forkStart+$f+6)) ) * 256 + \
|
|
||||||
$(readcharDec "$image" $(($forkStart+$f+7)) ) * 65536 ))
|
|
||||||
activeFileSize=$forkFileLen
|
|
||||||
if (( $resourceFork > 0 )); then
|
|
||||||
rsrcForkLenHex=$(readcharHex "$image" $(($forkStart+$f+7)) ).\
|
|
||||||
$(readcharHex "$image" $(($forkStart+$f+6)) ).\
|
|
||||||
$(readcharHex "$image" $(($forkStart+$f+5)) )
|
|
||||||
# echo ">>>$rsrcForkLenHex"
|
|
||||||
echo " [resource fork]"
|
|
||||||
[[ $AD ]] && writecharsHex "$ADdir/$targetName" 35 "$rsrcForkLenHex"
|
|
||||||
else
|
|
||||||
echo " [data fork]"
|
|
||||||
fi
|
|
||||||
if (( $forkStorageType == 1 )); then #seedling
|
|
||||||
copyBlock $forkKeyPointer $forkFileLen
|
|
||||||
elif (( $forkStorageType == 2 )); then #sapling
|
|
||||||
processIndexBlock $forkKeyPointer
|
|
||||||
elif (( $forkStorageType == 3 )); then #tree
|
|
||||||
processMasterIndexBlock $forkKeyPointer
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
# echo
|
|
||||||
resourceFork=0
|
|
||||||
}
|
|
||||||
|
|
||||||
processMasterIndexBlock() {
|
|
||||||
processIndexBlock $1 1
|
|
||||||
}
|
|
||||||
|
|
||||||
processIndexBlock () {
|
|
||||||
#arg1: indexBlock
|
|
||||||
#arg2: if set, it's a Master Index Block
|
|
||||||
local pos=0
|
|
||||||
local bytesRemaining
|
|
||||||
while (( $activeFileBytesCopied < $activeFileSize )); do
|
|
||||||
targetBlock=$(( $(readcharDec $image $(($1*512+$pos)) ) + $(readcharDec $image $(($1*512+($pos+256) )) )*256 ))
|
|
||||||
if [[ $2 ]]; then
|
|
||||||
processIndexBlock $targetBlock
|
|
||||||
else
|
|
||||||
bytesRemaining=$(($activeFileSize - $activeFileBytesCopied))
|
|
||||||
bs=$(( $bytesRemaining<512 ? $bytesRemaining : 512 ))
|
|
||||||
copyBlock $targetBlock $bs
|
|
||||||
fi
|
|
||||||
(( pos++ ))
|
|
||||||
(( $pos > 255 )) && break # go to next entry in Master Index Block (tree)
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
makeADfile () {
|
|
||||||
ADfilePath="$ADdir/$targetName"
|
|
||||||
[[ ! $AD ]] && return
|
|
||||||
dd if=/dev/zero of="$ADfilePath" bs=741 count=1 2> /dev/null
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 00) "00.05.16.07.00.02.00.00" # ADv2 header
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 18) "00.0D" # number of entries
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 1A) "00.00.00.02.00.00.02.E5.00.00.00.00" # Resource Fork
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 26) "00.00.00.03.00.00.00.B6.00.00.00.00" # Real Name
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 32) "00.00.00.04.00.00.01.B5.00.00.00.00" # Comment
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 3E) "00.00.00.08.00.00.02.7D.00.00.00.10" # Dates Info
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 4A) "00.00.00.09.00.00.02.8D.00.00.00.20" # Finder Info
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 56) "00.00.00.0B.00.00.02.C1.00.00.00.08" # ProDOS file info
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 62) "00.00.00.0D.00.00.02.B5.00.00.00.00" # AFP short name
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 6E) "00.00.00.0E.00.00.02.B1.00.00.00.04" # AFP File Info
|
|
||||||
writecharsHex "$ADfilePath" $(hexToDec 7A) "00.00.00.0F.00.00.02.AD.00.00.00.04" # AFP Directory ID
|
|
||||||
# dbd (second time) will create DEV, INO, SYN, SV~
|
|
||||||
}
|
|
||||||
|
|
||||||
syncExit () {
|
|
||||||
if [[ -d /usr/local/etc/netatalk && $AD ]]; then
|
|
||||||
echo "File(s) have been copied to the target directory. If the directory" 1>&2
|
|
||||||
echo "is shared by Netatalk, please use 'afpsync' now." 1>&2
|
|
||||||
fi
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
usage () {
|
|
||||||
echo "usage:"
|
|
||||||
echo "copy all files: cppo [-ad|-e] imagefile targetDirectory"
|
|
||||||
echo "copy one file : cppo [-ad|-e] imagefile /FULL/PRODOS/FILE/PATH targetPath"
|
|
||||||
echo "catalog image : cppo -cat imagefile"
|
|
||||||
echo
|
|
||||||
echo "cppo copies either one file or all files from a ProDOS raw disk image"
|
|
||||||
echo "to a folder shared by Netatalk. -cat displays all files on the image."
|
|
||||||
echo "No verification or validation of the disk image is performed."
|
|
||||||
echo
|
|
||||||
echo "-ad enables creating AppleDouble header files and copying resource forks."
|
|
||||||
echo "-e appends the ProDOS type and auxtype to filenames, and copies resource"
|
|
||||||
echo " forks, so they can be preserved when added to ShrinkIt archives by"
|
|
||||||
echo " nulib2 (using its -e option)."
|
|
||||||
echo
|
|
||||||
echo "Wildcard matching (*) is not supported."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- start
|
|
||||||
|
|
||||||
if [[ $1 == "-ad" ]]; then
|
|
||||||
AD=1
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
if [[ $1 == "-e" ]]; then
|
|
||||||
[[ $AD ]] && usage
|
|
||||||
EX=1
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $1 == "-cat" ]]; then
|
|
||||||
DIR=1
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
[[ ( $DIR && $1 ) || ( $1 && $2 ) ]] || usage
|
|
||||||
[[ $3 && ( ${2:0:1} != "/" ) && ( ${2:0:1} != ":" ) ]] && usage
|
|
||||||
|
|
||||||
image="$1"
|
|
||||||
[[ -f "$image" ]] || { echo "Source image not found."; exit 2; }
|
|
||||||
if [[ $3 ]]; then
|
|
||||||
pdospath=$(echo $2 | tr [:lower:] [:upper:])
|
|
||||||
targetPath=$3
|
|
||||||
if [[ -d $targetPath ]]; then
|
|
||||||
targetDir=$targetPath
|
|
||||||
else
|
|
||||||
targetDir="${targetPath%/*}"
|
|
||||||
targetName="${targetPath##*/}"
|
|
||||||
fi
|
|
||||||
[[ -d $targetDir ]] || { echo "Target directory not found."; exit 2; }
|
|
||||||
else
|
|
||||||
if [[ ! $DIR ]]; then
|
|
||||||
[[ -d "$2" ]] || { echo "Target directory not found."; exit 2; }
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
activeDirBlock=0
|
|
||||||
activeFileName=""
|
|
||||||
activeFileSize=0
|
|
||||||
activeFileBytesCopied=0
|
|
||||||
resourceFork=0
|
|
||||||
|
|
||||||
if [[ $3 ]]; then
|
|
||||||
IFS='/:'
|
|
||||||
PDOSPATH=($pdospath)
|
|
||||||
unset IFS
|
|
||||||
[[ ! ${PDOSPATH[0]} ]] && (( PDOSPATH_INDEX++ ))
|
|
||||||
PDOSPATH_SEGMENT=${PDOSPATH[PDOSPATH_INDEX]}
|
|
||||||
ADdir="$targetDir/.AppleDouble"
|
|
||||||
[[ ! $AD || -d $ADdir ]] || mkdir $ADdir
|
|
||||||
processDir 2
|
|
||||||
echo "ProDOS file not found within image file."
|
|
||||||
exit 2
|
|
||||||
else
|
|
||||||
if [[ ! $DIR ]]; then
|
|
||||||
targetDir="$2/$(getVolumeName)"
|
|
||||||
ADdir="$targetDir/.AppleDouble"
|
|
||||||
[[ -d $targetDir ]] || mkdir -p $targetDir
|
|
||||||
[[ ! $AD || -d $ADdir ]] || mkdir -p $ADdir
|
|
||||||
fi
|
|
||||||
processDir 2
|
|
||||||
[[ $DIR ]] || syncExit
|
|
||||||
fi
|
|
@ -1,882 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
"""cppo: Copy or catalog one or all files from a ProDOS raw disk image.
|
|
||||||
|
|
||||||
copy all files:
|
|
||||||
cppo [-ad|-e] imagefile target_directory
|
|
||||||
copy one file:
|
|
||||||
cppo [-ad|-e] imagefile /FULL/PRODOS/FILE/PATH target_path
|
|
||||||
catalog image:
|
|
||||||
cppo -cat imagefile
|
|
||||||
|
|
||||||
-ad : Create AppleDouble header files and preserve resource forks.
|
|
||||||
-e : Append ProDOS type and auxtype to filenames, and copy resource
|
|
||||||
forks, for adding to ShrinkIt archives with Nulib2
|
|
||||||
using its -e option.
|
|
||||||
|
|
||||||
Wildcard matching/globbing (*) is not supported.
|
|
||||||
No verification or validation of the disk image is performed.
|
|
||||||
|
|
||||||
(Compatible with Python 2.6 and later, including 3.x.)
|
|
||||||
"""
|
|
||||||
|
|
||||||
# cppo by Ivan X, ivan@ivanx.com, ivanx.com/appleii
|
|
||||||
|
|
||||||
# If anyone's looking at this, and feels it's not sufficiently Pythonic,
|
|
||||||
# I know that. It's pretty much a line-for-line conversion of the original
|
|
||||||
# Bash script. I did start a beautiful from-the-ground-up object-oriented
|
|
||||||
# version, then realized it would be faster to translate it ugly and quick.
|
|
||||||
|
|
||||||
# imports for python 3 code compatibility
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
# Intentially fails on pre-2.6 so user can see what's wrong
|
|
||||||
b'ERROR: cppo requires Python 2.6 or later, including 3.x.'
|
|
||||||
|
|
||||||
class Globals(object):
|
|
||||||
pass
|
|
||||||
|
|
||||||
g = Globals()
|
|
||||||
|
|
||||||
g.imageData = b''
|
|
||||||
g.outFileData = bytearray(b'')
|
|
||||||
g.adFileData = bytearray(b'')
|
|
||||||
g.exFileData = bytearray(b'')
|
|
||||||
|
|
||||||
g.activeDirBlock = None
|
|
||||||
g.activeFileName = None
|
|
||||||
g.activeFileSize = None
|
|
||||||
g.activeFileBytesCopied = 0
|
|
||||||
g.resourceFork = 0
|
|
||||||
|
|
||||||
g.PDOSPATH = []
|
|
||||||
g.PDOSPATH_INDEX = 0
|
|
||||||
g.PDOSPATH_SEGMENT = None
|
|
||||||
g.DIRPATH = ""
|
|
||||||
|
|
||||||
g.targetName = None
|
|
||||||
g.targetDir = ""
|
|
||||||
g.ADdir = None
|
|
||||||
g.imageFile = None
|
|
||||||
|
|
||||||
g.AD = 0
|
|
||||||
g.EX = 0
|
|
||||||
g.DIR = 0
|
|
||||||
g.silent = 0
|
|
||||||
|
|
||||||
# functions
|
|
||||||
|
|
||||||
def pdosDateToUnixDate(arg1):
|
|
||||||
# input: ProDOS date/time bit sequence string in format:
|
|
||||||
# "yyyyyyymmmmddddd000hhhhh00mmmmmm" (ustr)
|
|
||||||
# output: seconds since Unix epoch (1-Jan-1970),
|
|
||||||
# or current date/time if no ProDOS date
|
|
||||||
year = (binToDec(slyce(arg1,0,7)) + 1900)
|
|
||||||
if (year < 1940): year += 100
|
|
||||||
month = binToDec(slyce(arg1,7,4))
|
|
||||||
day = binToDec(slyce(arg1,11,5))
|
|
||||||
hour = binToDec(slyce(arg1,19,5))
|
|
||||||
minute = binToDec(slyce(arg1,26,6))
|
|
||||||
# print(year, month, day, hour, minute)
|
|
||||||
td = (datetime.datetime(year, month, day, hour, minute) -
|
|
||||||
datetime.datetime(1970,1,1))
|
|
||||||
unixDate_naive = (td.days*24*60*60 + td.seconds)
|
|
||||||
td2 = (datetime.datetime.fromtimestamp(unixDate_naive) -
|
|
||||||
datetime.datetime.utcfromtimestamp(unixDate_naive))
|
|
||||||
utcoffset = (td2.days*24*60*60 + td2.seconds)
|
|
||||||
# print(unixDate_naive - utcoffset)
|
|
||||||
return (unixDate_naive - utcoffset) # local time zone with DST
|
|
||||||
|
|
||||||
def unixDateToADDate(arg1):
|
|
||||||
# input: seconds since Unix epoch (1-Jan-1970 00:00:00 GMT)
|
|
||||||
# output: seconds since Netatalk epoch (1-Jan-2000 00:00:00 GMT),
|
|
||||||
# in hex-ustr (big endian)
|
|
||||||
adDate = (arg1 - 946684800)
|
|
||||||
if (adDate < 0 ):
|
|
||||||
adDate += 4294967296 # to get negative hex number
|
|
||||||
adDateHex = to_hex(adDate).zfill(8).upper()
|
|
||||||
# print(arg1, adDate, adDateHex)
|
|
||||||
return adDateHex
|
|
||||||
|
|
||||||
# cppo support routines:
|
|
||||||
# arg1: directory block
|
|
||||||
# arg2: file index (if applicable)
|
|
||||||
# arg3: directory chunk # (if applicable)
|
|
||||||
|
|
||||||
#most of these not tested yet in Python
|
|
||||||
# returns byte position in disk image file
|
|
||||||
def getStartPos(arg1, arg2):
|
|
||||||
return ( (arg1 * 512) +
|
|
||||||
(39 * ((arg2 + (arg2 > 11)) % 13)) +
|
|
||||||
(4 if (arg2 > 11) else 43) )
|
|
||||||
|
|
||||||
def getStorageType(arg1, arg2):
|
|
||||||
start = getStartPos(arg1, arg2)
|
|
||||||
firstByte = readcharDec(g.imageData, start)
|
|
||||||
return (firstByte//16)
|
|
||||||
|
|
||||||
def getFileName(arg1, arg2):
|
|
||||||
start = getStartPos(arg1, arg2)
|
|
||||||
firstByte = readcharDec(g.imageData, start)
|
|
||||||
entryType = (firstByte//16)
|
|
||||||
nameLength = (firstByte - entryType*16)
|
|
||||||
return readchars(g.imageData, start+1, nameLength)
|
|
||||||
|
|
||||||
def getFileType(arg1, arg2):
|
|
||||||
start = getStartPos(arg1, arg2)
|
|
||||||
return readcharHex(g.imageData, start+16)
|
|
||||||
|
|
||||||
def getKeyPointer(arg1, arg2):
|
|
||||||
start = getStartPos(arg1, arg2)
|
|
||||||
return (readcharDec(g.imageData, start+17) +
|
|
||||||
readcharDec(g.imageData, start+18)*256)
|
|
||||||
|
|
||||||
def getFileLength(arg1, arg2):
|
|
||||||
start = getStartPos(arg1, arg2)
|
|
||||||
return (readcharDec(g.imageData, start+21) +
|
|
||||||
readcharDec(g.imageData, start+22)*256 +
|
|
||||||
readcharDec(g.imageData, start+23)*65536)
|
|
||||||
|
|
||||||
def getAuxType(arg1, arg2):
|
|
||||||
start = getStartPos(arg1, arg2)
|
|
||||||
return (readcharHex(g.imageData, start+32) +
|
|
||||||
readcharHex(g.imageData, start+31))
|
|
||||||
|
|
||||||
def getCreationDate(arg1, arg2):
|
|
||||||
#outputs prodos creation date/time as Unix time
|
|
||||||
# (seconds since Jan 1 1970 GMT)
|
|
||||||
#or None if there is none
|
|
||||||
start = getStartPos(arg1, arg2)
|
|
||||||
pdosDate = (hexToBin(readcharHex(g.imageData, start+25)) +
|
|
||||||
hexToBin(readcharHex(g.imageData, start+24)) +
|
|
||||||
hexToBin(readcharHex(g.imageData, start+27)) +
|
|
||||||
hexToBin(readcharHex(g.imageData, start+26)))
|
|
||||||
try:
|
|
||||||
rVal = pdosDateToUnixDate(pdosDate)
|
|
||||||
except Exception:
|
|
||||||
rVal = None
|
|
||||||
return rVal
|
|
||||||
|
|
||||||
def getModifiedDate(arg1, arg2):
|
|
||||||
#outputs prodos modified date/time as Unix time
|
|
||||||
# (seconds since Jan 1 1970 GMT)
|
|
||||||
#or None if there is none
|
|
||||||
start = getStartPos(arg1, arg2)
|
|
||||||
pdosDate = (hexToBin(readcharHex(g.imageData, start+34)) +
|
|
||||||
hexToBin(readcharHex(g.imageData, start+33)) +
|
|
||||||
hexToBin(readcharHex(g.imageData, start+36)) +
|
|
||||||
hexToBin(readcharHex(g.imageData, start+35)))
|
|
||||||
try:
|
|
||||||
rVal = pdosDateToUnixDate(pdosDate)
|
|
||||||
except Exception:
|
|
||||||
rVal = None
|
|
||||||
return rVal
|
|
||||||
|
|
||||||
def getVolumeName():
|
|
||||||
return getWorkingDirName(2)
|
|
||||||
|
|
||||||
def getWorkingDirName(arg1):
|
|
||||||
start = ( arg1 * 512 )
|
|
||||||
firstByte = readcharDec(g.imageData, start+4)
|
|
||||||
entryType = (firstByte//16)
|
|
||||||
nameLength = (firstByte - entryType*16)
|
|
||||||
return readchars(g.imageData, start+5, nameLength)
|
|
||||||
|
|
||||||
def getDirEntryCount(arg1):
|
|
||||||
start = ( arg1 * 512 )
|
|
||||||
return (readcharDec(g.imageData, start+37) +
|
|
||||||
readcharDec(g.imageData, start+38)*256)
|
|
||||||
|
|
||||||
def getDirNextChunkPointer(arg1):
|
|
||||||
start = ( arg1 * 512 )
|
|
||||||
return (readcharDec(g.imageData, start+2) +
|
|
||||||
readcharDec(g.imageData, start+3)*256)
|
|
||||||
|
|
||||||
# -- script begins in earnest here
|
|
||||||
|
|
||||||
def copyFile(arg1, arg2):
|
|
||||||
g.outFileData = bytearray(b'')
|
|
||||||
g.exFileData = bytearray(b'')
|
|
||||||
g.activeFileBytesCopied = 0
|
|
||||||
storageType = getStorageType(arg1, arg2)
|
|
||||||
keyPointer = getKeyPointer(arg1, arg2)
|
|
||||||
fileLen = getFileLength(arg1, arg2)
|
|
||||||
if (storageType == 1): #seedling
|
|
||||||
copyBlock(keyPointer, fileLen)
|
|
||||||
elif (storageType == 2): #sapling
|
|
||||||
processIndexBlock(keyPointer)
|
|
||||||
elif (storageType == 3): #tree
|
|
||||||
processMasterIndexBlock(keyPointer)
|
|
||||||
elif (storageType == 5): #extended (forked)
|
|
||||||
processForkedFile(keyPointer)
|
|
||||||
|
|
||||||
def copyBlock(arg1, arg2):
|
|
||||||
#arg1: block to copy
|
|
||||||
#arg2: bytes to write (should be 512,
|
|
||||||
# unless final block with less than 512 bytes)
|
|
||||||
#print(arg1 + " " + arg2 + " " + g.activeFileBytesCopied)
|
|
||||||
if (arg1 == 0):
|
|
||||||
outBytes = (b'\x00' * arg2)
|
|
||||||
else:
|
|
||||||
outBytes = slyce(g.imageData, arg1*512, arg2)
|
|
||||||
if (g.resourceFork > 0):
|
|
||||||
if g.AD:
|
|
||||||
g.adFileData[g.activeFileBytesCopied+741:
|
|
||||||
(g.activeFileBytesCopied+741 + arg2)] = outBytes
|
|
||||||
if g.EX:
|
|
||||||
g.exFileData[g.activeFileBytesCopied:
|
|
||||||
(g.activeFileBytesCopied + arg2)] = outBytes
|
|
||||||
else:
|
|
||||||
g.outFileData[g.activeFileBytesCopied:
|
|
||||||
(g.activeFileBytesCopied + arg2)] = outBytes
|
|
||||||
g.activeFileBytesCopied += arg2
|
|
||||||
|
|
||||||
def processDir(arg1, arg2=None, arg3=None, arg4=None, arg5=None):
|
|
||||||
# arg1: dirBlock
|
|
||||||
# arg2/3/4/5: for non-key chunks: entryCount, entry#,
|
|
||||||
# workingDirName, processedEntryCount
|
|
||||||
|
|
||||||
entryCount = None
|
|
||||||
e = None
|
|
||||||
pe = None
|
|
||||||
workingDirName = None
|
|
||||||
|
|
||||||
if arg2:
|
|
||||||
entryCount = arg2
|
|
||||||
e = arg3
|
|
||||||
workingDirName = arg4
|
|
||||||
pe = arg5
|
|
||||||
else:
|
|
||||||
e = 0
|
|
||||||
pe = 0
|
|
||||||
entryCount = getDirEntryCount(arg1)
|
|
||||||
workingDirName = getWorkingDirName(arg1).decode("L1")
|
|
||||||
g.DIRPATH = (g.DIRPATH + "/" + workingDirName)
|
|
||||||
if g.PDOSPATH_INDEX:
|
|
||||||
if (g.PDOSPATH_INDEX == 1):
|
|
||||||
if (("/" + g.PDOSPATH_SEGMENT) != g.DIRPATH):
|
|
||||||
print("ProDOS volume name does not match disk image.")
|
|
||||||
sys.exit(2)
|
|
||||||
else:
|
|
||||||
g.PDOSPATH_INDEX += 1
|
|
||||||
g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX]
|
|
||||||
else:
|
|
||||||
print(g.DIRPATH)
|
|
||||||
while (pe < entryCount):
|
|
||||||
if (getStorageType(arg1, e) > 0):
|
|
||||||
processEntry(arg1, e)
|
|
||||||
pe += 1
|
|
||||||
e += 1
|
|
||||||
if not ((e + ( e>11 ) ) % 13):
|
|
||||||
processDir(getDirNextChunkPointer(arg1),
|
|
||||||
entryCount,
|
|
||||||
e,
|
|
||||||
workingDirName,
|
|
||||||
pe)
|
|
||||||
break
|
|
||||||
|
|
||||||
def processEntry(arg1, arg2):
|
|
||||||
'''
|
|
||||||
print(getFileName(arg1, arg2), getStorageType(arg1, arg2),
|
|
||||||
getFileType(arg1, arg2), getKeyPointer(arg1, arg2),
|
|
||||||
getFileLength(arg1, arg2), getAuxType(arg1, arg2),
|
|
||||||
getCreationDate(arg1, arg2), getModifiedDate(arg1, arg2))
|
|
||||||
'''
|
|
||||||
g.activeFileName = getFileName(arg1 ,arg2).decode("L1")
|
|
||||||
g.activeFileSize = getFileLength(arg1, arg2)
|
|
||||||
|
|
||||||
if ((not g.PDOSPATH_INDEX) or (g.activeFileName == g.PDOSPATH_SEGMENT)):
|
|
||||||
|
|
||||||
if (getStorageType(arg1, arg2) == 13): # if ProDOS directory
|
|
||||||
if not g.PDOSPATH_INDEX:
|
|
||||||
g.targetDir = (g.targetDir + "/" + g.activeFileName)
|
|
||||||
g.ADdir = (g.targetDir + "/.AppleDouble")
|
|
||||||
if not (g.DIR or os.path.isdir(g.targetDir)):
|
|
||||||
makedirs(g.targetDir)
|
|
||||||
if not (g.DIR or (not g.AD) or os.path.isdir(g.ADdir)):
|
|
||||||
makedirs(g.ADdir)
|
|
||||||
if g.PDOSPATH_SEGMENT:
|
|
||||||
g.PDOSPATH_INDEX += 1
|
|
||||||
g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX]
|
|
||||||
processDir(getKeyPointer(arg1, arg2))
|
|
||||||
g.DIRPATH = g.DIRPATH.rsplit("/", 1)[0]
|
|
||||||
if not g.PDOSPATH_INDEX:
|
|
||||||
g.targetDir = g.targetDir.rsplit("/", 1)[0]
|
|
||||||
g.ADdir = (g.targetDir + "/.AppleDouble")
|
|
||||||
else: # if ProDOS file
|
|
||||||
if not g.PDOSPATH_INDEX:
|
|
||||||
print(" " + g.activeFileName)
|
|
||||||
if g.DIR:
|
|
||||||
return
|
|
||||||
if not g.targetName:
|
|
||||||
g.targetName = g.activeFileName
|
|
||||||
if g.EX:
|
|
||||||
eTargetName = (g.targetName + "#" +
|
|
||||||
getFileType(arg1, arg2).lower() +
|
|
||||||
getAuxType(arg1, arg2).lower())
|
|
||||||
touch(g.targetDir + "/" + g.targetName)
|
|
||||||
if g.AD: makeADfile()
|
|
||||||
copyFile(arg1, arg2)
|
|
||||||
saveFile((g.targetDir + "/" + g.targetName), g.outFileData)
|
|
||||||
creationDate = getCreationDate(arg1, arg2)
|
|
||||||
modifiedDate = getModifiedDate(arg1, arg2)
|
|
||||||
if (creationDate is None and modifiedDate is not None):
|
|
||||||
creationDate = modifiedDate
|
|
||||||
elif (creationDate is not None and modifiedDate is None):
|
|
||||||
modifiedDate = creationDate
|
|
||||||
elif (creationDate is None and modifiedDate is None):
|
|
||||||
creationDate = (datetime.datetime.today() -
|
|
||||||
datetime.datetime(1970,1,1)).days*24*60*60
|
|
||||||
modifiedDate = creationDate
|
|
||||||
if g.AD: # AppleDouble
|
|
||||||
# set dates
|
|
||||||
ADfilePath = (g.ADdir + "/" + g.targetName)
|
|
||||||
writecharsHex(g.adFileData,
|
|
||||||
637,
|
|
||||||
(unixDateToADDate(creationDate) +
|
|
||||||
unixDateToADDate(modifiedDate)))
|
|
||||||
writecharHex(g.adFileData, 645, "80")
|
|
||||||
writecharHex(g.adFileData, 649, "80")
|
|
||||||
#set type/creator
|
|
||||||
writechars(g.adFileData, 653, b'p')
|
|
||||||
writecharsHex(g.adFileData,
|
|
||||||
654,
|
|
||||||
(getFileType(arg1, arg2) +
|
|
||||||
getAuxType(arg1, arg2)))
|
|
||||||
writechars(g.adFileData, 657, b'pdos')
|
|
||||||
saveFile(ADfilePath, g.adFileData)
|
|
||||||
touch((g.targetDir + "/" + g.targetName), modifiedDate)
|
|
||||||
if g.EX: # extended name
|
|
||||||
os.rename((g.targetDir + "/" + g.targetName),
|
|
||||||
(g.targetDir + "/" + eTargetName))
|
|
||||||
if (len(g.exFileData) > 0):
|
|
||||||
saveFile((g.targetDir + "/" + eTargetName + "r"),
|
|
||||||
g.exFileData)
|
|
||||||
touch((g.targetDir + "/" + eTargetName + "r"),
|
|
||||||
modifiedDate)
|
|
||||||
if g.PDOSPATH_SEGMENT:
|
|
||||||
syncExit()
|
|
||||||
g.targetName = None
|
|
||||||
|
|
||||||
#else:
|
|
||||||
#print(g.activeFileName + " doesn't match " + g.PDOSPATH_SEGMENT)
|
|
||||||
|
|
||||||
def processForkedFile(arg1):
|
|
||||||
# finder info except type/creator
|
|
||||||
fInfoA_entryType = readcharDec(g.imageData, 9)
|
|
||||||
fInfoB_entryType = readcharDec(g.imageData, 27)
|
|
||||||
if (fInfoA_entryType == 1):
|
|
||||||
writechars(g.imageData, 661, readchars(g.imageData, 18, 8))
|
|
||||||
elif (fInfoA_entryType == 2):
|
|
||||||
writechars(g.imageData, 669, readchars(g.imageData, 10, 16))
|
|
||||||
if (fInfoB_entryType == 1):
|
|
||||||
writechars(g.imageData, 661, readchars(g.imageData, 36, 8))
|
|
||||||
elif (fInfoB_entryType == 2):
|
|
||||||
writechars(g.imageData, 669, readchars(g.imageData, 28, 16))
|
|
||||||
|
|
||||||
for f in [0, 256]:
|
|
||||||
g.resourceFork = f
|
|
||||||
g.activeFileBytesCopied = 0
|
|
||||||
forkStart = (arg1 * 512) # start of Forked File key block
|
|
||||||
# print("--" + forkStart)
|
|
||||||
forkStorageType = readcharDec(g.imageData, forkStart+f+0)
|
|
||||||
forkKeyPointer = (readcharDec(g.imageData, forkStart+f+1) +
|
|
||||||
readcharDec(g.imageData, forkStart+f+2)*256)
|
|
||||||
forkFileLen = (readcharDec(g.imageData, forkStart+f+5) +
|
|
||||||
readcharDec(g.imageData, forkStart+f+6)*256 +
|
|
||||||
readcharDec(g.imageData, forkStart+f+7)*256*256)
|
|
||||||
g.activeFileSize = forkFileLen
|
|
||||||
if (g.resourceFork > 0):
|
|
||||||
rsrcForkLenHex = (readcharHex(g.imageData, forkStart+f+7) +
|
|
||||||
readcharHex(g.imageData, forkStart+f+6) +
|
|
||||||
readcharHex(g.imageData, forkStart+f+5))
|
|
||||||
# print(">>>" + rsrcForkLenHex)
|
|
||||||
print(" [resource fork]")
|
|
||||||
if g.AD:
|
|
||||||
writecharsHex(g.adFileData, 35, rsrcForkLenHex)
|
|
||||||
else:
|
|
||||||
print(" [data fork]")
|
|
||||||
if (forkStorageType == 1): #seedling
|
|
||||||
copyBlock(forkKeyPointer, forkFileLen)
|
|
||||||
elif (forkStorageType == 2): #sapling
|
|
||||||
processIndexBlock(forkKeyPointer)
|
|
||||||
elif (forkStorageType == 3): #tree
|
|
||||||
processMasterIndexBlock(forkKeyPointer)
|
|
||||||
# print()
|
|
||||||
g.resourceFork = 0
|
|
||||||
|
|
||||||
def processMasterIndexBlock(arg1):
|
|
||||||
processIndexBlock(arg1, True)
|
|
||||||
|
|
||||||
def processIndexBlock(arg1, arg2=False):
|
|
||||||
#arg1: indexBlock
|
|
||||||
#arg2: if True, it's a Master Index Block
|
|
||||||
pos = 0
|
|
||||||
bytesRemaining = g.activeFileSize
|
|
||||||
while (g.activeFileBytesCopied < g.activeFileSize):
|
|
||||||
targetBlock = (readcharDec(g.imageData, arg1*512+pos) +
|
|
||||||
readcharDec(g.imageData, arg1*512+(pos+256))*256)
|
|
||||||
if arg2:
|
|
||||||
processIndexBlock(targetBlock)
|
|
||||||
else:
|
|
||||||
bytesRemaining = (g.activeFileSize - g.activeFileBytesCopied)
|
|
||||||
bs = (bytesRemaining if (bytesRemaining < 512) else 512)
|
|
||||||
copyBlock(targetBlock, bs)
|
|
||||||
pos += 1
|
|
||||||
if (pos > 255):
|
|
||||||
break # go to next entry in Master Index Block (tree)
|
|
||||||
|
|
||||||
def makeADfile():
|
|
||||||
if not g.AD: return
|
|
||||||
touch(g.ADdir + "/" + g.targetName)
|
|
||||||
g.adFileData = bytearray(b'\x00' * 741)
|
|
||||||
# ADv2 header
|
|
||||||
writecharsHex(g.adFileData, hexToDec("00"), "0005160700020000")
|
|
||||||
# number of entries
|
|
||||||
writecharsHex(g.adFileData, hexToDec("18"), "000D")
|
|
||||||
# Resource Fork
|
|
||||||
writecharsHex(g.adFileData, hexToDec("1A"), "00000002000002E500000000")
|
|
||||||
# Real Name
|
|
||||||
writecharsHex(g.adFileData, hexToDec("26"), "00000003000000B600000000")
|
|
||||||
# Comment
|
|
||||||
writecharsHex(g.adFileData, hexToDec("32"), "00000004000001B500000000")
|
|
||||||
# Dates Info
|
|
||||||
writecharsHex(g.adFileData, hexToDec("3E"), "000000080000027D00000010")
|
|
||||||
# Finder Info
|
|
||||||
writecharsHex(g.adFileData, hexToDec("4A"), "000000090000028D00000020")
|
|
||||||
# ProDOS file info
|
|
||||||
writecharsHex(g.adFileData, hexToDec("56"), "0000000B000002C100000008")
|
|
||||||
# AFP short name
|
|
||||||
writecharsHex(g.adFileData, hexToDec("62"), "0000000D000002B500000000")
|
|
||||||
# AFP File Info
|
|
||||||
writecharsHex(g.adFileData, hexToDec("6E"), "0000000E000002B100000004")
|
|
||||||
# AFP Directory ID
|
|
||||||
writecharsHex(g.adFileData, hexToDec("7A"), "0000000F000002AD00000004")
|
|
||||||
# dbd (second time) will create DEV, INO, SYN, SV~
|
|
||||||
|
|
||||||
def syncExit():
|
|
||||||
if (not g.silent and g.AD and os.path.isdir("/usr/local/etc/netatalk")):
|
|
||||||
print("File(s) have been copied to the target directory. " +
|
|
||||||
"If the directory")
|
|
||||||
print("is shared by Netatalk, please type 'afpsync' now.")
|
|
||||||
# saveFile(g.imageFile, g.imageData)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
def usage():
|
|
||||||
print(sys.modules[__name__].__doc__)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# --- ID bashbyter functions (adapted)
|
|
||||||
|
|
||||||
def decToHex(arg1):
|
|
||||||
# converts single-byte decimal value to hexadecimal equivalent
|
|
||||||
# arg: decimal value from 0-255
|
|
||||||
# out: two-digit hex string from 00-FF
|
|
||||||
#exit: 21=invalid arg
|
|
||||||
if (arg1<0 or arg1>255): sys.exit(21)
|
|
||||||
return to_hex(arg1).upper()
|
|
||||||
|
|
||||||
def hexToDec(arg1):
|
|
||||||
# converts single-byte hexadecimal value to decimal equivalent
|
|
||||||
# arg: two-digit hex value from 00-FF
|
|
||||||
# out: decimal value
|
|
||||||
#exit: 21=invalid arg
|
|
||||||
if (len(arg1) != 2): return 21
|
|
||||||
return to_dec(arg1)
|
|
||||||
|
|
||||||
def hexToBin(arg1):
|
|
||||||
# converts single-byte hexadecimal value to binary string
|
|
||||||
# arg: two-digit hex value from 00-FF
|
|
||||||
# out: binary string value
|
|
||||||
#exit: 21=invalid arg
|
|
||||||
if (len(arg1) != 2): return 21
|
|
||||||
return to_bin(arg1).zfill(8)
|
|
||||||
|
|
||||||
def binToDec(arg1):
|
|
||||||
# converts single-byte binary string (8 bits) value to decimal
|
|
||||||
# warning: no error checking
|
|
||||||
# arg: binary string up to 8 bits
|
|
||||||
# out: decimal value
|
|
||||||
return to_dec([arg1])
|
|
||||||
|
|
||||||
def binToHex(arg1):
|
|
||||||
# converts single-byte binary string (8 bits) value to hex
|
|
||||||
# warning: no error checking
|
|
||||||
# arg: binary string up to 8 bits
|
|
||||||
# out: hex value
|
|
||||||
return to_hex(arg1).upper()
|
|
||||||
|
|
||||||
def charToDec(arg1):
|
|
||||||
# converts single char (of type bytes) to corresponding decimal value
|
|
||||||
# arg: one char (of type bytes)
|
|
||||||
# out: decimal value from 0-255
|
|
||||||
#exit: 21=invalid arg
|
|
||||||
if (len(arg1) != 1): return 21
|
|
||||||
return to_dec(arg1)
|
|
||||||
|
|
||||||
def charToHex(arg1):
|
|
||||||
# converts single char (of type bytes) to corresponding hex value
|
|
||||||
# arg: one char (of type bytes)
|
|
||||||
# out: hexadecimal value from 00-FF
|
|
||||||
#exit: 21=invalid arg
|
|
||||||
if (len(arg1) != 1): return 21
|
|
||||||
return to_hex(arg1).upper()
|
|
||||||
|
|
||||||
def decToChar(arg1):
|
|
||||||
# converts single-byte decimal value to equivalent char (of type bytes)
|
|
||||||
# arg: decimal number from 0-255
|
|
||||||
# out: one character
|
|
||||||
#exit: 21=invalid arg
|
|
||||||
if (arg1<0 or arg1>255): sys.exit(21)
|
|
||||||
return to_bytes(arg1)
|
|
||||||
|
|
||||||
def hexToChar(arg1):
|
|
||||||
# converts single-byte hex value to corresponding char (of type bytes)
|
|
||||||
# arg: two-digit hexadecimal number from 00-FF
|
|
||||||
# out: one character
|
|
||||||
#exit: 21=invalid arg
|
|
||||||
if (len(arg1) != 2): return 21
|
|
||||||
return to_bytes(arg1)
|
|
||||||
|
|
||||||
def readchars(arg1, arg2=0, arg3=0):
|
|
||||||
# read one or more characters from a bytes variable
|
|
||||||
# arg1: bytes or bytearray variable
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# arg3: (optional) # of chars to read (default is to end of bytes var)
|
|
||||||
# out: sequence of characters (bytes or bytearray)
|
|
||||||
# exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3
|
|
||||||
if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)):
|
|
||||||
sys.exit(21)
|
|
||||||
if (arg2<0): sys.exit(22)
|
|
||||||
if (arg3<0): sys.exit(23)
|
|
||||||
if (arg3 == 0):
|
|
||||||
arg3 = len(arg1)
|
|
||||||
return slyce(arg1, arg2, arg3)
|
|
||||||
|
|
||||||
def readcharDec(arg1, arg2=0):
|
|
||||||
# read one character from bytes var & convert to equivalent dec value
|
|
||||||
# arg1: bytes var
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# out: decimal value from 0-255
|
|
||||||
# exit: 21=invalid arg1, 22=invalid arg2
|
|
||||||
if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)):
|
|
||||||
sys.exit(21)
|
|
||||||
if (arg2<0): sys.exit(22)
|
|
||||||
return to_dec(slyce(arg1, arg2, 1))
|
|
||||||
|
|
||||||
def readcharHex(arg1, arg2=0):
|
|
||||||
# read one character from bytes var & convert to corresponding hex value
|
|
||||||
# arg1: bytes var
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# out: two-digit hex value from 00-FF
|
|
||||||
# exit: 21=invalid arg1, 22=invalid arg2
|
|
||||||
if not (isinstance(arg1, bytes) or isinstance(arg1, bytearray)):
|
|
||||||
sys.exit(21)
|
|
||||||
if (arg2<0): sys.exit(22)
|
|
||||||
return to_hex(slyce(arg1, arg2, 1))
|
|
||||||
|
|
||||||
def writechars(arg1, arg2, arg3):
|
|
||||||
# write one or more characters (bytes) to bytearray
|
|
||||||
# arg1: bytearray variable
|
|
||||||
# arg2: offset (# of bytes to skip before writing)
|
|
||||||
# arg3: sequence of bytes (or bytearray)
|
|
||||||
# out: nothing
|
|
||||||
# exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3
|
|
||||||
if not isinstance(arg1, bytearray): sys.exit(21)
|
|
||||||
if (arg2<0): sys.exit(22)
|
|
||||||
if not (isinstance(arg3, bytes) or isinstance(arg3, bytearray)):
|
|
||||||
sys.exit(23)
|
|
||||||
arg1[arg2:arg2+len(arg3)] = arg3
|
|
||||||
|
|
||||||
def writecharDec(arg1, arg2, arg3):
|
|
||||||
# write corresponding char of single-byte decimal value into bytearray
|
|
||||||
# arg1: bytearray
|
|
||||||
# arg2: offset (# of bytes to skip before writing)
|
|
||||||
# arg3: decimal number from 0-255
|
|
||||||
# exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3
|
|
||||||
# out: nothing
|
|
||||||
if not isinstance(arg1, bytearray): sys.exit(21)
|
|
||||||
if (arg2<0): sys.exit(22)
|
|
||||||
if not isnumber(arg3): sys.exit(23)
|
|
||||||
arg1[arg2:arg2+1] = to_bytes(arg3)
|
|
||||||
|
|
||||||
def writecharHex(arg1, arg2, arg3):
|
|
||||||
# write corresponding character of single-byte hex value into bytearray
|
|
||||||
# arg1: bytearray
|
|
||||||
# arg2: offset (# of bytes to skip before writing)
|
|
||||||
# arg3: two-digit hexadecimal number from 00-FF
|
|
||||||
# out: nothing
|
|
||||||
# exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3
|
|
||||||
if not isinstance(arg1, bytearray): sys.exit(21)
|
|
||||||
if (arg2<0): sys.exit(22)
|
|
||||||
if not isinstance(arg3, type("".encode().decode())): sys.exit(23)
|
|
||||||
arg1[arg2:arg2+1] = to_bytes(arg3)
|
|
||||||
|
|
||||||
def writecharsHex(arg1, arg2, arg3):
|
|
||||||
# write corresponding characters of hex values into bytearray
|
|
||||||
# arg1: bytearray
|
|
||||||
# arg2: offset (# of bytes to skip before writing)
|
|
||||||
# arg3: string of two-digit hexadecimal numbers from 00-FF
|
|
||||||
# out: nothing
|
|
||||||
# exit: 21=invalid arg1, 22=invalid arg2, 23=invalid arg3
|
|
||||||
if not isinstance(arg1, bytearray): sys.exit(21)
|
|
||||||
if (arg2<0): sys.exit(22)
|
|
||||||
if not isinstance(arg3, type("".encode().decode())): sys.exit(23)
|
|
||||||
arg1[arg2:arg2+len(to_bytes(arg3))] = to_bytes(arg3)
|
|
||||||
|
|
||||||
#---- IvanX general purpose functions ----#
|
|
||||||
|
|
||||||
def slyce(val, start_pos=0, length=1, reverse=False):
|
|
||||||
"""returns slice of object (but not a slice object)
|
|
||||||
allows specifying length, and 3.x "bytes" consistency"""
|
|
||||||
the_slyce = val[start_pos:start_pos+length]
|
|
||||||
return (the_slyce[::-1] if reverse else the_slyce)
|
|
||||||
|
|
||||||
def to_hex(val):
|
|
||||||
"""convert bytes, decimal number, or [bin-ustr] to two-digit hex values
|
|
||||||
unlike hex(), accepts bytes; has no leading 0x or trailing L"""
|
|
||||||
from binascii import b2a_hex
|
|
||||||
if isinstance(val, list): # [bin-ustr]
|
|
||||||
val = int(val[0], 2)
|
|
||||||
if isinstance(val, bytes): # bytes
|
|
||||||
return b2a_hex(val).decode("L1")
|
|
||||||
elif isnumber(val):
|
|
||||||
# .encode().decode() always returns unicode in both P2 and P3
|
|
||||||
return (hex(val)[2:].split("L")[0]).encode("L1").decode("L1")
|
|
||||||
else:
|
|
||||||
raise Exception("to_hex() requires bytes, int/long, or [bin-ustr]")
|
|
||||||
|
|
||||||
def hex_slyce(val, start_pos=0, length=1, little_endian=False):
|
|
||||||
"""returns bytes slyce as hex-ustr"""
|
|
||||||
return to_hex(slyce(val, start_pos, length, little_endian))
|
|
||||||
|
|
||||||
def dec_slyce(val, start_pos=0, length=1, little_endian=False):
|
|
||||||
"""returns bytes slyce converted to decimal int/long"""
|
|
||||||
return to_dec(hex_slyce(val, start_pos, length, little_endian))
|
|
||||||
|
|
||||||
def bin_slyce(val, start_pos=0, length=1, little_endian=False):
|
|
||||||
"""returns bytes slyce converted to bin-ustr"""
|
|
||||||
return to_bin(hex_slyce(val, start_pos, length, little_endian))
|
|
||||||
|
|
||||||
def to_dec(val):
|
|
||||||
"""convert bytes, hex-ustr or [bin-ustr] to decimal int/long"""
|
|
||||||
if isinstance(val, list): # [bin-ustr]
|
|
||||||
return int(val[0], 2)
|
|
||||||
elif isinstance(val, bytes): # bytes
|
|
||||||
return int(to_hex(val), 16)
|
|
||||||
elif isinstance(val, type("".encode().decode())): # hex-ustr
|
|
||||||
return int(val, 16)
|
|
||||||
else:
|
|
||||||
raise Exception("to_dec() requires bytes, hex-ustr or [bin-ustr]")
|
|
||||||
|
|
||||||
def to_bin(val):
|
|
||||||
"""convert bytes, hex-ustr, or int/long to bin-ustr"""
|
|
||||||
if isinstance(val, bytes): # bytes
|
|
||||||
return (bin(to_dec(to_hex(val))))[2:].encode("L1").decode("L1")
|
|
||||||
elif isinstance(val, type("".encode().decode())): # hex-ustr
|
|
||||||
return (bin(int(val, 16)))[2:].encode("L1").decode("L1")
|
|
||||||
elif isnumber(val): # int/long
|
|
||||||
return (bin(val))[2:].encode("L1").decode("L1")
|
|
||||||
else:
|
|
||||||
raise Exception("to_bin() requires bytes, hex-ustr, or int/long")
|
|
||||||
|
|
||||||
def to_bytes(val):
|
|
||||||
"""converts hex-ustr, int/long, or [bin-ustr] to bytes"""
|
|
||||||
from binascii import a2b_hex
|
|
||||||
if isinstance(val, list): # [bin-ustr]
|
|
||||||
val = to_hex(val[0])
|
|
||||||
if isnumber(val): # int/long
|
|
||||||
val = to_hex(val)
|
|
||||||
if isinstance(val, type("".encode().decode())): # hex-ustr
|
|
||||||
return a2b_hex(bytes(val.encode("L1"))) # works on both P2 and P3
|
|
||||||
else:
|
|
||||||
raise Exception(
|
|
||||||
"to_bytes() requires hex-ustr, int/long, or [bin-ustr]")
|
|
||||||
|
|
||||||
def shift(items):
|
|
||||||
"""Shift list items to left, losing the first item.
|
|
||||||
|
|
||||||
in : list
|
|
||||||
out: list
|
|
||||||
"""
|
|
||||||
for i in range(0, (len(items)-1)):
|
|
||||||
items[i] = items[i+1]
|
|
||||||
del items[-1]
|
|
||||||
return items
|
|
||||||
|
|
||||||
def s(string):
|
|
||||||
"""Perform local variable substution, e.g. 'total: {num} items'"""
|
|
||||||
# http://stackoverflow.com/questions/2960772/
|
|
||||||
# putting-a-variable-inside-a-string-python
|
|
||||||
# http://stackoverflow.com/questions/6618795/
|
|
||||||
# get-locals-from-calling-namespace-in-python
|
|
||||||
import inspect
|
|
||||||
frame = inspect.currentframe()
|
|
||||||
try:
|
|
||||||
rVal = string.format(**frame.f_back.f_locals)
|
|
||||||
finally:
|
|
||||||
del frame
|
|
||||||
return rVal
|
|
||||||
|
|
||||||
def get_object_names(cls, include_subclasses=True):
|
|
||||||
object_names = []
|
|
||||||
for (this_object_name, this_object_id) in list(globals().items()):
|
|
||||||
if include_subclasses:
|
|
||||||
if isinstance(this_object_id, cls):
|
|
||||||
object_names.append(this_object_name)
|
|
||||||
else:
|
|
||||||
if type(this_object_id) is cls:
|
|
||||||
object_names.append(this_object_name)
|
|
||||||
return object_names
|
|
||||||
|
|
||||||
def touch(filePath, modTime=None):
|
|
||||||
# http://stackoverflow.com/questions/1158076/implement-touch-using-python
|
|
||||||
import os
|
|
||||||
if (os.name == "nt"):
|
|
||||||
if filePath[-1] == ".": filePath += "-"
|
|
||||||
filePath = filePath.replace("./", ".-/")
|
|
||||||
with open(filePath, "ab"):
|
|
||||||
os.utime(filePath, (None if (modTime is None) else (modTime, modTime)))
|
|
||||||
|
|
||||||
def mkdir(dirPath):
|
|
||||||
import os
|
|
||||||
if (os.name == "nt"):
|
|
||||||
if dirPath[-1] == ".": dirPath += "-"
|
|
||||||
dirPath = dirPath.replace("./", ".-/")
|
|
||||||
try:
|
|
||||||
os.mkdir(dirPath)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def makedirs(dirPath):
|
|
||||||
import os
|
|
||||||
if (os.name == "nt"):
|
|
||||||
if dirPath[-1] == ".": dirPath += "-"
|
|
||||||
dirPath = dirPath.replace("./", ".-/")
|
|
||||||
try:
|
|
||||||
os.makedirs(dirPath)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def loadFile(filePath):
|
|
||||||
import os
|
|
||||||
if (os.name == "nt"):
|
|
||||||
if filePath[-1] == ".": filePath += "-"
|
|
||||||
filePath = filePath.replace("./", ".-/")
|
|
||||||
with open(filePath, "rb") as imageHandle:
|
|
||||||
return imageHandle.read()
|
|
||||||
|
|
||||||
def saveFile(filePath, fileData):
|
|
||||||
import os
|
|
||||||
if (os.name == "nt"):
|
|
||||||
if filePath[-1] == ".": filePath += "-"
|
|
||||||
filePath = filePath.replace("./", ".-/")
|
|
||||||
with open(filePath, "wb") as imageHandle:
|
|
||||||
imageHandle.write(fileData)
|
|
||||||
|
|
||||||
def isnumber(number):
|
|
||||||
try: # make sure it's not a string
|
|
||||||
len(number)
|
|
||||||
return False
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
int(number)
|
|
||||||
except ValueError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
#---- end IvanX general purpose functions ----#
|
|
||||||
|
|
||||||
|
|
||||||
# --- start
|
|
||||||
|
|
||||||
args = sys.argv
|
|
||||||
if (len(args) == 1):
|
|
||||||
usage()
|
|
||||||
|
|
||||||
if (args[1] == "-s"):
|
|
||||||
g.silent=1
|
|
||||||
args = args[1:] #shift
|
|
||||||
|
|
||||||
if (args[1] == "-ad"):
|
|
||||||
g.AD = 1
|
|
||||||
args = args[1:] #shift
|
|
||||||
|
|
||||||
if (args[1] == "-e"):
|
|
||||||
if g.AD: usage()
|
|
||||||
g.EX = 1
|
|
||||||
args = args[1:] #shift
|
|
||||||
|
|
||||||
if (args[1] == "-cat"):
|
|
||||||
g.DIR = 1
|
|
||||||
args = args[1:]
|
|
||||||
|
|
||||||
if not ((g.DIR and len(args) >= 2) or (len(args) >= 3)):
|
|
||||||
usage()
|
|
||||||
if ((len(args) == 4) and
|
|
||||||
(slyce(args[2],0,1) != "/") and
|
|
||||||
(slyce(args[2],0,1) != ":")):
|
|
||||||
usage()
|
|
||||||
|
|
||||||
g.imageFile = args[1]
|
|
||||||
if not os.path.isfile(g.imageFile):
|
|
||||||
print("Source " + g.imageFile + " was not found.")
|
|
||||||
sys.exit(2)
|
|
||||||
g.imageData = loadFile(g.imageFile)
|
|
||||||
|
|
||||||
if (len(args) == 4):
|
|
||||||
g.PDOSPATH = args[2].upper()
|
|
||||||
targetPath = args[3]
|
|
||||||
if os.path.isdir(targetPath):
|
|
||||||
g.targetDir = targetPath
|
|
||||||
else:
|
|
||||||
g.targetDir = targetPath.rsplit("/", 1)[0]
|
|
||||||
g.targetName = targetPath.rsplit("/", 1)[1]
|
|
||||||
if not os.path.isdir(g.targetDir):
|
|
||||||
print("Target directory not found.")
|
|
||||||
sys.exit(2)
|
|
||||||
else:
|
|
||||||
if not g.DIR:
|
|
||||||
if not os.path.isdir(args[2]):
|
|
||||||
print("Target directory not found.")
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
g.activeDirBlock = 0
|
|
||||||
g.activeFileName = ""
|
|
||||||
g.activeFileSize = 0
|
|
||||||
g.activeFileBytesCopied = 0
|
|
||||||
g.resourceFork = 0
|
|
||||||
g.PDOSPATH_INDEX = 0
|
|
||||||
|
|
||||||
if (len(args) == 4):
|
|
||||||
g.PDOSPATH = g.PDOSPATH.replace(':', '/').split('/')
|
|
||||||
if not g.PDOSPATH[0]:
|
|
||||||
g.PDOSPATH_INDEX += 1
|
|
||||||
g.PDOSPATH_SEGMENT = g.PDOSPATH[g.PDOSPATH_INDEX]
|
|
||||||
g.ADdir = (g.targetDir + "/.AppleDouble")
|
|
||||||
if not ((not g.AD) or os.path.isdir(g.ADdir)):
|
|
||||||
mkdir(g.ADdir)
|
|
||||||
processDir(2)
|
|
||||||
print("ProDOS file not found within image file.")
|
|
||||||
sys.exit(2)
|
|
||||||
else:
|
|
||||||
if not g.DIR:
|
|
||||||
# print(args[0], args[1], args[2])
|
|
||||||
g.targetDir = (args[2] + "/" + getVolumeName().decode("L1"))
|
|
||||||
g.ADdir = (g.targetDir + "/.AppleDouble")
|
|
||||||
if not os.path.isdir(g.targetDir):
|
|
||||||
makedirs(g.targetDir)
|
|
||||||
if not ((not g.AD) or os.path.isdir(g.ADdir)):
|
|
||||||
makedirs(g.ADdir)
|
|
||||||
processDir(2)
|
|
||||||
if not g.DIR:
|
|
||||||
syncExit()
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# follows gzip syntax -- acts in place if filename provided, outputs to
|
|
||||||
# stdout with -c, accepts stdin and outputs to stdout if filename is - or absent
|
|
||||||
|
|
||||||
# output to stdout?
|
|
||||||
if [[ "$1" == "-c" ]]; then
|
|
||||||
shift;
|
|
||||||
stdout=1;
|
|
||||||
else
|
|
||||||
stdout=
|
|
||||||
fi
|
|
||||||
|
|
||||||
# use stdin?
|
|
||||||
if [[ ! $1 || "$1" == "-" ]]; then
|
|
||||||
stdin=1
|
|
||||||
stdout=1
|
|
||||||
elif [[ $1 && ! -f "$1" ]]; then
|
|
||||||
echo "usage: dopo [-c] [-|140KdiskImageFilename] 1>&2";
|
|
||||||
exit 1;
|
|
||||||
else
|
|
||||||
stdin=
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $stdout ]]; then
|
|
||||||
#get filename extension, in lowercase
|
|
||||||
f="$(tr [:upper:] [:lower:] <<< ${1##*.})";
|
|
||||||
|
|
||||||
#if it's dsk/do/po, get name without extension
|
|
||||||
[[ "$f" == "dsk" || "$f" == "do" || "$f" == "po" ]] && of="${1%.*}" || of="$1";
|
|
||||||
|
|
||||||
#if name had .po extension, append .dsk to outfile name, otherwise append .po
|
|
||||||
[[ "$f" == "po" ]] && of="$of.dsk" || of="$of.po"
|
|
||||||
|
|
||||||
# set outfile param for dd
|
|
||||||
ofile="$of"
|
|
||||||
else
|
|
||||||
ofile="/tmp/$$.dopo_out"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $stdin ]]; then
|
|
||||||
# set infile param for dd
|
|
||||||
ifile="$1"
|
|
||||||
elif [[ -t 0 ]]; then
|
|
||||||
echo "usage: dopo [-c] [-|140KdiskImageFilename]" 1>&2; exit 1;
|
|
||||||
else
|
|
||||||
ifile="/tmp/$$.dopo_in"
|
|
||||||
cat > "$ifile"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# verify file is 140K by successfully reading 140K'th byte, and failing to read the one past
|
|
||||||
[[ $(dd if="$ifile" of=/dev/null bs=1 skip=143359 2>&1 | tail -1 | cut -d ' ' -f 1) -ne 1 || $(dd if="$ifile" of=/dev/null bs=1 skip=143360 2>&1 | tail -1 | cut -d ' ' -f 1) -ne 0 ]] && badInput=1 || badInput=
|
|
||||||
|
|
||||||
if [[ $badInput ]]; then
|
|
||||||
if [[ ! $stdin ]]; then
|
|
||||||
echo -n "$1 doesn't appear to be a 140K image. Continue? " 1>&2;
|
|
||||||
read
|
|
||||||
[[ ${REPLY:0:1} == "y" || ${REPLY:0:1} == "Y" ]] || exit 1;
|
|
||||||
else
|
|
||||||
echo "warning: Input file doesn't appear to be a 140K image." 1>&2
|
|
||||||
echo " Output file is likely to be useless." 1>&2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# for each track
|
|
||||||
for t in {0..34}; do
|
|
||||||
# read each sector in the right sequence to make (or unmake)
|
|
||||||
# valid ProDOS blocks (sector pairs)
|
|
||||||
for s in 0 14 13 12 11 10 9 8 7 6 5 4 3 2 1 15; do
|
|
||||||
# copy the sector from the old file to the new one
|
|
||||||
dd if="$ifile" of="$ofile" bs=256 count=1 skip=$(( t*16 + s )) seek=$(( t*16 + (s==0 || s==15 ? s : 15-s) )) 2> /dev/null
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# remove the old one
|
|
||||||
[[ ! $stdin && ! $stdout ]] && rm "$1" &> /dev/null
|
|
||||||
|
|
||||||
# dump to stdout if -c or stdin used
|
|
||||||
[[ $stdout ]] && { cat $ofile; rm $ofile &> /dev/null; }
|
|
||||||
[[ $stdin ]] && rm $ifile &> /dev/null;
|
|
@ -1,124 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
readcharDec () {
|
|
||||||
# read one character from file & convert to equivalent decimal value
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# out: decimal value from 0-255
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1,
|
|
||||||
# 21=invalid arg1, 22=invalid arg2
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $3 ]] && return 8
|
|
||||||
[[ -f $1 ]] || return 21
|
|
||||||
[[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \
|
|
||||||
&& ( $2 -ge 0 ) ]] || return 22; }
|
|
||||||
# args are valid
|
|
||||||
charX="$(dd if="$1" bs=1 skip=$(($2)) \
|
|
||||||
count=1 2> /dev/null; echo -n X)"
|
|
||||||
[[ ${#charX} -gt 1 ]] || { echo -n 0; return 0; }
|
|
||||||
echo -n "${charX:0:1}" | od -t u1 | \
|
|
||||||
head -1 | sed 's/[0\ ]*//' | tr -d ' \n'
|
|
||||||
}
|
|
||||||
|
|
||||||
readcharHex () {
|
|
||||||
# read one character from file & convert to corresponding hex value
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# out: two-digit hex value from 00-FF
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1,
|
|
||||||
# 21=invalid arg1, 22=invalid arg2
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $3 ]] && return 8
|
|
||||||
[[ -f $1 ]] || return 21
|
|
||||||
[[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \
|
|
||||||
&& ( $2 -ge 0 ) ]] || return 22; }
|
|
||||||
# args are valid
|
|
||||||
charX="$(dd if="$1" bs=1 skip=$(($2)) \
|
|
||||||
count=1 2> /dev/null; echo -n X)"
|
|
||||||
[[ ${#charX} -gt 1 ]] || { echo -n "00"; return 0; }
|
|
||||||
printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \
|
|
||||||
head -1 | sed 's/[0\ ]*//' | tr -d ' \n')
|
|
||||||
}
|
|
||||||
|
|
||||||
### start
|
|
||||||
|
|
||||||
usage () {
|
|
||||||
echo "Usage:"
|
|
||||||
echo "all files: dos2pro dosImageName"
|
|
||||||
echo "one file : dos2pro dosImageName DOSFILE"
|
|
||||||
echo "notes:"
|
|
||||||
echo " Wildcard matching (*) is not supported."
|
|
||||||
echo " Illegal prodos characters will be made into periods, and names"
|
|
||||||
echo " will be truncated at 15 characters and possibly overwrite"
|
|
||||||
echo " other files if they match a previous name conversion."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
[[ $1 == "-h" || $1 == "--help" || ! $1 || ! -f "$1" ]] && usage
|
|
||||||
|
|
||||||
dosImage="$1"
|
|
||||||
fileName="$2"
|
|
||||||
|
|
||||||
dosImageBasename=$(basename "$dosImage")
|
|
||||||
proImage="${dosImageBasename%.*}_prodos.po"
|
|
||||||
|
|
||||||
if [[ ! -f "$proImage" ]]; then
|
|
||||||
echo "Creating $proImage..."
|
|
||||||
mkpo -b 280 "$proImage"
|
|
||||||
else
|
|
||||||
echo "Found $proImage..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $(acmd -i "$dosImage" 2> /dev/null | grep "Disk Format: DOS 3.3") ]]; then
|
|
||||||
echo "The file '$dosImage' doesn't appear to be a DOS 3.3 disk image."
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
dosLines=$(acmd -ll "$dosImage")
|
|
||||||
|
|
||||||
IFS=''
|
|
||||||
while read thisLine; do
|
|
||||||
if [[ ${thisLine:0:2} == "* " || ${thisLine:0:2} == " " ]]; then
|
|
||||||
dosName=$(cut -c 5- <<< $thisLine | rev | sed 's/^[^ ]* [^ ]* [^ ]* [^ ]* [^ ]* \(.*$\)/\1/' | rev)
|
|
||||||
if [[ ! $fileName || "$fileName" == "$dosName" ]]; then
|
|
||||||
|
|
||||||
dosType=$(cut -c 3 <<< $thisLine)
|
|
||||||
if [[ $dosType == "A" ]]; then
|
|
||||||
proType="BAS"
|
|
||||||
binAddr="0801"
|
|
||||||
elif [[ $dosType == "I" ]]; then
|
|
||||||
proType="INT"
|
|
||||||
elif [[ $dosType == "T" ]]; then
|
|
||||||
proType="TXT"
|
|
||||||
elif [[ $dosType == "B" ]]; then
|
|
||||||
proType="BIN"
|
|
||||||
sector=$(rev <<< $thisLine | cut -f2 -d ' ' | rev | cut -c 2-)
|
|
||||||
track=$(rev <<< $thisLine | cut -f3 -d ' ' | rev | cut -c 2-)
|
|
||||||
offset=$(( (track * 16 + sector) * 256 + 12 ))
|
|
||||||
track=$(readcharDec "$dosImage" $offset)
|
|
||||||
sector=$(readcharDec "$dosImage" $((offset+1)))
|
|
||||||
offset=$(( (track * 16 + sector) * 256 ))
|
|
||||||
binAddr=$(readcharHex "$dosImage" $((offset+1)))$(readcharHex "$dosImage" $offset)
|
|
||||||
else
|
|
||||||
echo "Error: Unknown DOS 3.3 file type."
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
proName=$(sed 's/^[^A-Za-z]/A/' <<< $dosName | sed 's/[^A-Za-z0-9\.]/./g')
|
|
||||||
|
|
||||||
auxType=
|
|
||||||
[[ $binAddr ]] && auxType="\$$binAddr"
|
|
||||||
echo "Copying '$dosName' to '$proName'"
|
|
||||||
acmd -g "$dosImage" "$dosName" - | acmd -p "$proImage" "$proName" "$proType" "$auxType"
|
|
||||||
filesCopied=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done <<< $dosLines
|
|
||||||
|
|
||||||
if [[ ! $filesCopied ]]; then
|
|
||||||
if [[ $fileName ]]; then
|
|
||||||
echo "File '$fileName' not found on DOS 3.3 disk image."
|
|
||||||
else
|
|
||||||
echo "No files copied."
|
|
||||||
fi
|
|
||||||
fi
|
|
@ -1,6 +0,0 @@
|
|||||||
wget -qO /tmp/gsport-setup appleii.ivanx.com/a2cloud/setup/gsport-setup.txt
|
|
||||||
if [[ $(wc -c /tmp/gsport-setup | grep '^0 ') ]]; then
|
|
||||||
echo "Please connect to the internet to set up GSport."
|
|
||||||
else
|
|
||||||
source /tmp/gsport-setup "$@"
|
|
||||||
fi
|
|
@ -1,573 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
readcharHex () {
|
|
||||||
# read one character from file & convert to corresponding hex value
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# out: two-digit hex value from 00-FF
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1,
|
|
||||||
# 21=invalid arg1, 22=invalid arg2
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $3 ]] && return 8
|
|
||||||
[[ -f $1 ]] || return 21
|
|
||||||
[[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \
|
|
||||||
&& ( $2 -ge 0 ) ]] || return 22; }
|
|
||||||
# args are valid
|
|
||||||
charX="$(dd if="$1" bs=1 skip=$(($2)) \
|
|
||||||
count=1 2> /dev/null; echo -n X)"
|
|
||||||
[[ ${#charX} -gt 1 ]] || { echo -n "00"; return 0; }
|
|
||||||
printf %02X $(echo -n "${charX:0:1}" | od -t u1 | \
|
|
||||||
head -1 | sed 's/[0\ ]*//' | tr -d ' \n') | tr [A-Z] [a-z]
|
|
||||||
}
|
|
||||||
|
|
||||||
readchars () {
|
|
||||||
# read one or more characters from a file
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: (optional) offset (# of bytes to skip before reading)
|
|
||||||
# arg3: (optional) # of chars to read (default is until end of file)
|
|
||||||
# out: sequence of characters
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1,
|
|
||||||
# 21=invalid arg1, 22=invalid arg2, 23=invalid arg3
|
|
||||||
[[ $1 ]] || return 11
|
|
||||||
[[ $4 ]] && return 8
|
|
||||||
[[ -f $1 ]] || return 21
|
|
||||||
[[ $2 ]] && { [[ ( $(printf %d "$2" 2> /dev/null) == $2 ) \
|
|
||||||
&& ( $2 -ge 0 ) ]] || return 22; }
|
|
||||||
[[ $3 ]] && { [[ ( $(printf %d "$3" 2> /dev/null) == $3 ) \
|
|
||||||
&& ( $3 -ge 0 ) ]] || return 23; }
|
|
||||||
# args are valid
|
|
||||||
dd if="$1" bs=1 skip=$(($2)) $([[ $3 ]] && echo -n "count=$3") \
|
|
||||||
2> /dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
writecharsHex () {
|
|
||||||
# write corresponding characters of hex values into file
|
|
||||||
# arg1: filename
|
|
||||||
# arg2: offset (# of bytes to skip before writing)
|
|
||||||
# arg3: string of two-digit hexadecimal numbers from 00-FF, period delimited (not checked!)
|
|
||||||
# out: nothing
|
|
||||||
# exit: 8=extraneous arg, 11=missing arg1, 12=missing arg2,
|
|
||||||
# 13=missing arg3, 22=invalid arg2, 23=invalid arg3
|
|
||||||
[[ $1 ]] || return 11; [[ $2 ]] || return 12; [[ $3 ]] || return 13
|
|
||||||
[[ $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
|
|
||||||
# args are valid
|
|
||||||
echo -n -e "\x$outByte" | \
|
|
||||||
dd of="$1" bs=1 seek=$offset conv=notrunc 2> /dev/null
|
|
||||||
(( p += 3 ))
|
|
||||||
(( offset++ ))
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
### start
|
|
||||||
|
|
||||||
[[ -f /usr/bin/raspi-config ]] && isRpi=1 || isRpi=
|
|
||||||
|
|
||||||
emulatorName="GSport"
|
|
||||||
emulatorStart="gsport"
|
|
||||||
emulatorSetup="gsport-setup"
|
|
||||||
romFileName="ROM"
|
|
||||||
configFileName="config.txt"
|
|
||||||
|
|
||||||
imagesDir="/usr/local/share/gsdisks"
|
|
||||||
gsosHD="gsoshd.hdv"
|
|
||||||
gsosHDvolName="GSOS.HD"
|
|
||||||
tempDir="/tmp/gs"
|
|
||||||
|
|
||||||
rom=ROM3
|
|
||||||
slot6=
|
|
||||||
autoAnswerYes=
|
|
||||||
noDisks=
|
|
||||||
gisk=
|
|
||||||
installDisks=
|
|
||||||
kegs=
|
|
||||||
|
|
||||||
{ acmd &> /dev/null || [[ $? -ne 127 ]]; } && acmdOK=1 || acmdOK=
|
|
||||||
|
|
||||||
|
|
||||||
while { [[ $1 ]] || (( (0 + $gisk + $noDisks + $installDisks + 0) > 1 )); }; do
|
|
||||||
arg=$(tr -d '-' <<< ${1,,})
|
|
||||||
if [[ $arg == "6" ]]; then
|
|
||||||
slot6=1
|
|
||||||
shift
|
|
||||||
elif [[ $arg == "rom1" ]]; then
|
|
||||||
rom=ROM1
|
|
||||||
shift
|
|
||||||
elif [[ $arg == "rom3" ]]; then
|
|
||||||
rom=ROM3
|
|
||||||
shift
|
|
||||||
elif [[ $arg == "n" ]]; then
|
|
||||||
noDisks=1
|
|
||||||
shift
|
|
||||||
elif [[ $arg == "g" ]]; then
|
|
||||||
gisk=1
|
|
||||||
shift
|
|
||||||
elif [[ $arg == "i" ]]; then
|
|
||||||
installDisks=1
|
|
||||||
shift
|
|
||||||
elif [[ $arg == "y" ]]; then
|
|
||||||
autoAnswerYes=1
|
|
||||||
shift
|
|
||||||
elif [[ $arg == "k" ]]; then
|
|
||||||
kegs=1
|
|
||||||
shift
|
|
||||||
else
|
|
||||||
echo "Usage: $emulatorSetup [rom1|rom3] [-6] [-y [-g|-i|-n]]"
|
|
||||||
echo "rom1: use GS ROM 01"
|
|
||||||
echo "rom3: use GS ROM 03"
|
|
||||||
echo "-k: set up KEGS (rather than GSport)"
|
|
||||||
echo "-6: put blank disks in slot 6"
|
|
||||||
echo "-y: auto-answer yes (no prompting)"
|
|
||||||
echo "-i: use GS/OS and Spectrum installer disk images (use with -y)"
|
|
||||||
echo "-g: use GSport Internet Starter Kit disk image (use with -y)"
|
|
||||||
echo "-n: don't provide any disk images (use with -y)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ $kegs ]]; then
|
|
||||||
emulatorName="KEGS"
|
|
||||||
emulatorStart="kegs"
|
|
||||||
emulatorSetup="kegs-setup"
|
|
||||||
romFileName="rom.kegs"
|
|
||||||
configFileName="config.kegs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo
|
|
||||||
if [[ ! -f /usr/local/lib/$romFileName ]]; then
|
|
||||||
echo "$emulatorName needs to be set up. This may take several minutes."
|
|
||||||
if [[ ! $autoAnswerYes ]]; then
|
|
||||||
echo -n "Do you want to set up $emulatorName now? ";
|
|
||||||
read
|
|
||||||
if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo "Ok, let's go!"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $autoAnswerYes ]]; then
|
|
||||||
noDisks=
|
|
||||||
gisk=
|
|
||||||
while true; do
|
|
||||||
option1=0
|
|
||||||
option2=0
|
|
||||||
echo
|
|
||||||
echo "Do you want to:"
|
|
||||||
echo
|
|
||||||
if [[ $acmdOK ]]; then
|
|
||||||
[[ $kegs ]] && andSpectrum= || andSpectrum="and Spectrum "
|
|
||||||
echo "1) install GS/OS ${andSpectrum}from the installer disk images"
|
|
||||||
option1=1
|
|
||||||
fi
|
|
||||||
if [[ ! $kegs ]]; then
|
|
||||||
echo "2) use the premade GSport Internet Starter Kit hard drive image"
|
|
||||||
option2=2
|
|
||||||
fi
|
|
||||||
echo "3) prepare $emulatorName for use but don't provide any disk images"
|
|
||||||
echo "4) do nothing and quit"
|
|
||||||
echo
|
|
||||||
echo -n "Your choice: "
|
|
||||||
read
|
|
||||||
noDisks=
|
|
||||||
if [[ ${REPLY} == "4" ]]; then
|
|
||||||
[[ $0 == "-bash" ]] && return 1 || exit 1
|
|
||||||
elif [[ ${REPLY} == "3" ]]; then
|
|
||||||
noDisks=1; break
|
|
||||||
elif [[ ${REPLY} == $option2 ]]; then
|
|
||||||
gisk=1; break
|
|
||||||
elif [[ ${REPLY} == $option1 ]]; then
|
|
||||||
gisk=; break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
sudo mkdir -p "$imagesDir"
|
|
||||||
sudo chmod ugo+rw "$imagesDir"
|
|
||||||
mkdir -p "$tempDir"
|
|
||||||
cd "$tempDir"
|
|
||||||
|
|
||||||
echo "Updating package lists..."
|
|
||||||
sudo apt-get -y update > /dev/null
|
|
||||||
|
|
||||||
if [[ ! -f /usr/local/bin/unar ]]; then
|
|
||||||
echo "Installing The Unarchiver..."
|
|
||||||
sudo apt-get -y install libgnustep-base1.22
|
|
||||||
sudo apt-get -y clean
|
|
||||||
wget -qO- appleii.ivanx.com/a2cloud/setup/unar.tgz | sudo tar Pzx
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f /usr/local/bin/mkpo ]]; then
|
|
||||||
echo "Installing mkpo..."
|
|
||||||
sudo wget -qO /usr/local/bin/mkpo appleii.ivanx.com/a2cloud/setup/mkpo.txt
|
|
||||||
sudo chmod ugo+x /usr/local/bin/mkpo
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f /usr/local/bin/nulib2 ]]; then
|
|
||||||
echo "Installing nulib2..."
|
|
||||||
wget -qO- appleii.ivanx.com/a2cloud/setup/nulib2.tgz | sudo tar Pzx
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f $imagesDir/ROM1 ]]; then
|
|
||||||
echo "Getting GS ROM 01..."
|
|
||||||
wget -qO ROM1.zip http://web.archive.org/web/20130216031247/http://www.whatisthe2gs.apple2.org.za/files/rom1.zip
|
|
||||||
unzip ROM1.zip &> /dev/null
|
|
||||||
mv APPLE2GS.ROM $imagesDir/ROM1
|
|
||||||
chmod ugo-w $imagesDir/ROM1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f $imagesDir/ROM3 ]]; then
|
|
||||||
echo "Getting GS ROM 3..."
|
|
||||||
wget -qO ROM3.zip http://web.archive.org/web/20130216031247/http://www.whatisthe2gs.apple2.org.za/files/rom3.zip
|
|
||||||
unzip ROM3.zip &> /dev/null
|
|
||||||
mv APPLE2GS.ROM2 $imagesDir/ROM3
|
|
||||||
chmod ugo-w $imagesDir/ROM3
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f /usr/local/lib/$romFileName || $arg ]]; then
|
|
||||||
echo "Setting $emulatorName to use $rom..."
|
|
||||||
echo " (to change, use '$emulatorSetup rom1' or '$emulatorSetup rom3')"
|
|
||||||
sudo rm /usr/local/lib/$romFileName &> /dev/null
|
|
||||||
sudo ln -s $imagesDir/$rom /usr/local/lib/$romFileName &> /dev/null
|
|
||||||
sudo ln -s $romFileName /usr/local/lib/ROM &> /dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $slot6 ]]; then
|
|
||||||
echo "Putting blank disks in slot 6..."
|
|
||||||
sudo sed -i 's@^s6d1.*$@s6d1 = $imagesDir/slot6drive1.po@' /usr/local/lib/$configFileName
|
|
||||||
sudo sed -i 's@^s6d2.*$@s6d2 = $imagesDir/slot6drive2.po@' /usr/local/lib/$configFileName
|
|
||||||
if [[ ! -f $imagesDir/slot6drive1.po || ! -f $imagesDir/slot6drive2.po ]]; then
|
|
||||||
wget -qO- ivanx.com/a2cloud/files/slot6.tgz | sudo tar Pzx 2> /dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $kegs ]]; then
|
|
||||||
# set AppleTalk to turbo (works more reliably than Normal)
|
|
||||||
echo "Setting AppleTalk to turbo..."
|
|
||||||
if ! grep -q 'g_appletalk_turbo' /usr/local/lib/$configFileName; then
|
|
||||||
if grep -q 'bram1\[00\]' /usr/local/lib/$configFileName; then
|
|
||||||
sudo sed -i 's/^\(bram1\[00\]\)/g_appletalk_turbo = 1\n\n\1/' /usr/local/lib/$configFileName
|
|
||||||
else
|
|
||||||
echo -e '\ng_appletalk_turbo = 1' | sudo tee -a /usr/local/lib/$configFileName > /dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
sudo sed -i 's/g_appletalk_turbo = 0/g_appletalk_turbo = 1/' /usr/local/lib/$configFileName
|
|
||||||
|
|
||||||
# enable Uthernet
|
|
||||||
echo "Enabling Uthernet card emulation..."
|
|
||||||
if ! grep -q 'g_ethernet[^_]' /usr/local/lib/$configFileName; then
|
|
||||||
if grep -q 'bram1\[00\]' /usr/local/lib/$configFileName; then
|
|
||||||
sudo sed -i 's/^\(bram1\[00\]\)/g_ethernet = 1\n\n\1/' /usr/local/lib/$configFileName
|
|
||||||
else
|
|
||||||
echo -e '\ng_ethernet = 1' | sudo tee -a /usr/local/lib/$configFileName > /dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
sudo sed -i 's/g_ethernet = 0/g_ethernet = 1/' /usr/local/lib/$configFileName
|
|
||||||
|
|
||||||
# GISK
|
|
||||||
if [[ $gisk ]]; then
|
|
||||||
echo "Getting GSport Internet Starter Kit..."
|
|
||||||
wget -O /tmp/GSport_Internet_Starter_Kit.zip http://sourceforge.net/projects/gsport/files/Emulator%20Software%20Images/GSport_Internet_Starter_Kit.zip
|
|
||||||
unzip -d /tmp /tmp/GSport_Internet_Starter_Kit.zip "GSport Internet Starter Kit/GSport Internet Starter Kit.2mg"
|
|
||||||
sudo mv "/tmp/GSport Internet Starter Kit/GSport Internet Starter Kit.2mg" $imagesDir
|
|
||||||
rm -r /tmp/GSport*
|
|
||||||
if [[ $(grep ^s7d1 /usr/local/lib/$configFileName) ]]; then
|
|
||||||
sudo sed -i "s:^s7d1.*$:s7d1 = $imagesDir/GSport Internet Starter Kit.2mg:" /usr/local/lib/$configFileName
|
|
||||||
else
|
|
||||||
echo "s7d1 = $imagesDir/GSport Internet Starter Kit.2mg" | tee -a /usr/local/lib/$configFileName > /dev/null
|
|
||||||
fi
|
|
||||||
noDisks=1
|
|
||||||
fi
|
|
||||||
if [[ $noDisks ]]; then
|
|
||||||
echo
|
|
||||||
echo
|
|
||||||
echo "Setup complete. You can now start $emulatorName."
|
|
||||||
echo
|
|
||||||
if [[ ! $autoAnswerYes ]]; then
|
|
||||||
echo -n "Press return to continue..."
|
|
||||||
read
|
|
||||||
fi
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# non-GISK; get installer disks
|
|
||||||
if [[ ! -f $imagesDir/INSTALL.HDV ]] \
|
|
||||||
|| [[ ! -f $imagesDir/SYSTEM.DISK.HDV ]] \
|
|
||||||
|| [[ ! -f $imagesDir/SYSTEMTOOLS1.HDV ]] \
|
|
||||||
|| [[ ! -f $imagesDir/SYSTEMTOOLS2.HDV ]] \
|
|
||||||
|| [[ ! -f $imagesDir/FONTS.HDV ]] \
|
|
||||||
|| [[ ! -f $imagesDir/SYNTHLAB.HDV ]] \
|
|
||||||
|| [[ ! -f $imagesDir/"$gsosHD" ]] \
|
|
||||||
|| [[ ! $kegs && ! -f $imagesDir/spectrum.hdv ]]; then
|
|
||||||
|
|
||||||
# if [[ ! $autoAnswerYes ]]; then
|
|
||||||
# echo
|
|
||||||
# echo -n "Do you want to download the GS/OS installer disks"
|
|
||||||
# if [[ ! -f $imagesDir/"$gsosHD" ]]; then
|
|
||||||
# echo -n -e "\nand create a hard disk image file"
|
|
||||||
# fi
|
|
||||||
# if [[ ! $kegs && -f /usr/local/bin/acmd && ! -f $imagesDir/spectrum.hdv ]]; then
|
|
||||||
# echo -n -e "\nand download Spectrum communications software"
|
|
||||||
# fi
|
|
||||||
# echo -n "? "
|
|
||||||
# read
|
|
||||||
# fi
|
|
||||||
|
|
||||||
REPLY="y"
|
|
||||||
if [[ $autoAnswerYes || ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then
|
|
||||||
|
|
||||||
echo
|
|
||||||
activeDisk=0
|
|
||||||
for diskname in Install System.Disk SystemTools1 SystemTools2 Fonts synthLAB; do
|
|
||||||
(( activeDisk++ ))
|
|
||||||
outfile="$imagesDir/$(tr [:lower:] [:upper:] <<< $diskname).HDV"
|
|
||||||
if [[ ! -f "$outfile" ]]; then
|
|
||||||
echo "Getting GS/OS disk ${activeDisk} of 6: $diskname"
|
|
||||||
wget -qO "Disk_${activeDisk}_of_7-$diskname.sea.bin" "http://archive.org/download/download.info.apple.com.2012.11/download.info.apple.com.2012.11.zip/download.info.apple.com%2FApple_Support_Area%2FApple_Software_Updates%2FEnglish-North_American%2FApple_II%2FApple_IIGS_System_6.0.1%2FDisk_${activeDisk}_of_7-$diskname.sea.bin"
|
|
||||||
unar -k skip "Disk_${activeDisk}_of_7-$diskname.sea.bin" &> /dev/null
|
|
||||||
truncate -s 819284 "Disk ${activeDisk} of 7-${diskname}.sea"
|
|
||||||
dd if="Disk ${activeDisk} of 7-${diskname}.sea" of=${outfile} bs=84 skip=1 &> /dev/null
|
|
||||||
chmod ugo-w "$outfile"
|
|
||||||
if [[ $activeDisk -eq 1 ]]; then
|
|
||||||
if [[ $(grep ^s5d1 /usr/local/lib/$configFileName) ]]; then
|
|
||||||
sudo sed -i "s:^s5d1.*$:s5d1 = $imagesDir/INSTALL.HDV:" /usr/local/lib/$configFileName
|
|
||||||
else
|
|
||||||
echo "s5d1 = $imagesDir/INSTALL.HDV" | tee -a /usr/local/lib/$configFileName > /dev/null
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [[ $(grep ^s7d$activeDisk /usr/local/lib/$configFileName) ]]; then
|
|
||||||
sudo sed -i "s:^s7d$activeDisk.*$:s7d$activeDisk = $outfile:" /usr/local/lib/$configFileName
|
|
||||||
else
|
|
||||||
echo "s7d$activeDisk = $outfile" | tee -a /usr/local/lib/$configFileName > /dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "GS/OS disk ${activeDisk} of 6: $diskname has already been downloaded."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
rm *.sea* &> /dev/null
|
|
||||||
|
|
||||||
if [[ ! -f $imagesDir/"$gsosHD" ]]; then
|
|
||||||
echo "Creating 32 MB blank image at $imagesDir/$gsosHD..."
|
|
||||||
if [[ -f /usr/local/bin/acmd ]]; then
|
|
||||||
# if acmd exists, make a ProDOS disk with GS-ShrinkIt and Teach
|
|
||||||
|
|
||||||
if [[ ! -f /usr/local/adtpro/lib/AppleCommander/AppleCommander-1.3.5.13id-ac.jar ]]; then
|
|
||||||
echo "Installing AppleCommander-1.3.5.13id..."
|
|
||||||
sudo mkdir -p /usr/local/adtpro/lib/AppleCommander
|
|
||||||
wget -qO /usr/local/adtpro/lib/AppleCommander/AppleCommander-1.3.5.13id-ac.jar http://downloads.sourceforge.net/project/applecommander/AppleCommander%20-%20Interim/testcase/AppleCommander-1.3.5.13id-ac.jar
|
|
||||||
rm /usr/local/adtpro/lib/AppleCommander/AppleCommander-ac.jar &> /dev/null
|
|
||||||
ln -s AppleCommander-1.3.5.13id-ac.jar /usr/local/adtpro/lib/AppleCommander/AppleCommander-ac.jar
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Copying ProDOS..."
|
|
||||||
acmd -g "$imagesDir/INSTALL.HDV" PRODOS "PRODOS#ff0000"
|
|
||||||
#writecharsHex "PRODOS#ff0000" 0 "4C.00.C5.00"
|
|
||||||
wget -qO- ivanx.com/a2cloud/files/${emulatorName}SPLASH.SYS | dd of="PRODOS#ff0000" conv=notrunc &> /dev/null
|
|
||||||
echo "Copying Teach..."
|
|
||||||
cppo -e $imagesDir/SYSTEMTOOLS2.HDV /SYSTEMTOOLS2/TEACH . &> /dev/null
|
|
||||||
echo "Downloading GS-ShrinkIt..."
|
|
||||||
wget -qO- http://web.archive.org/web/20131031160750/http://nulib.com/library/gshk11.sea | nulib2 -x -e - GSHK &> /dev/null
|
|
||||||
nulib2 -a -e $gsosHD.shk "PRODOS#"* "GSHK#"* "TEACH#"* &> /dev/null
|
|
||||||
acmd -convert $gsosHD.shk $imagesDir/"$gsosHD" 65535
|
|
||||||
rm "PRODOS#"* "GSHK#"* "TEACH#"* $gsosHD.shk &> /dev/null
|
|
||||||
|
|
||||||
acmd -n $imagesDir/"$gsosHD" $gsosHDvolName
|
|
||||||
dd bs=512 count=1 conv=notrunc if="$imagesDir/INSTALL.HDV" of="$imagesDir/$gsosHD" 2> /dev/null
|
|
||||||
sudo chmod ugo+rw $imagesDir/"$gsosHD"
|
|
||||||
#acmd -p "$imagesDir/$gsosHD" PRODOS SYS < $tempDir/PRODOS
|
|
||||||
#rm $tempDir/PRODOS
|
|
||||||
fi
|
|
||||||
if [[ $(grep ^s7d1 /usr/local/lib/$configFileName) ]]; then
|
|
||||||
sudo sed -i "s:^s7d1.*$:s7d1 = $imagesDir/$gsosHD:" /usr/local/lib/$configFileName
|
|
||||||
else
|
|
||||||
echo "s7d1 = $imagesDir/$gsosHD" | tee -a /usr/local/lib/$configFileName > /dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $(grep ^g_limit_speed /usr/local/lib/$configFileName) ]]; then
|
|
||||||
sudo sed -i "s:^g_limit_speed.*$:g_limit_speed = 0:" /usr/local/lib/$configFileName
|
|
||||||
else
|
|
||||||
echo "g_limit_speed = 0" | tee -a /usr/local/lib/$configFileName > /dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -f /usr/local/bin/acmd && ! $(acmd -ls $imagesDir/$gsosHD | grep 'GSHK') ]]; then
|
|
||||||
echo
|
|
||||||
echo "Downloading GS-ShrinkIt..."
|
|
||||||
wget -qO- http://web.archive.org/web/20131031160750/http://nulib.com/library/gshk11.sea | acmd -p $imagesDir/$gsosHD GS.SHRINKIT.SEA S16
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Spectrum starts here
|
|
||||||
|
|
||||||
if [[ ! $kegs ]]; then
|
|
||||||
|
|
||||||
mkdir -p /tmp/spectrum
|
|
||||||
cd /tmp/spectrum
|
|
||||||
|
|
||||||
imageName="/tmp/spectrum/spectrum.dmg"
|
|
||||||
hfsName="/tmp/spectrum/spectrumH.dmg"
|
|
||||||
ullName="/tmp/spectrum/uthernet.bxy"
|
|
||||||
|
|
||||||
if [[ ! -f /usr/bin/hcopy || ! -f /usr/bin/macsave ]]; then
|
|
||||||
echo "Installing HFS utilities..."
|
|
||||||
sudo apt-get -y install hfsutils macutils &> /dev/null
|
|
||||||
else
|
|
||||||
echo "HFS utilities are already installed."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f /usr/local/adtpro/lib/AppleCommander/AppleCommander-1.3.5.13id-ac.jar ]]; then
|
|
||||||
echo "Installing AppleCommander..."
|
|
||||||
sudo mkdir -p /usr/local/adtpro/lib/AppleCommander
|
|
||||||
wget -qO /usr/local/adtpro/lib/AppleCommander/AppleCommander-1.3.5.13id-ac.jar http://downloads.sourceforge.net/project/applecommander/AppleCommander%20-%20Interim/testcase/AppleCommander-1.3.5.13id-ac.jar
|
|
||||||
rm /usr/local/adtpro/lib/AppleCommander/AppleCommander-ac.jar &> /dev/null
|
|
||||||
ln -s AppleCommander-1.3.5.13id-ac.jar /usr/local/adtpro/lib/AppleCommander/AppleCommander-ac.jar
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f "$imageName" ]]; then
|
|
||||||
echo "Downloading Spectrum Deluxe..."
|
|
||||||
wget -qO spectrum.dmg http://www.wannop.info/speccie/software/spectrum_2.5.3_deluxe.dmg
|
|
||||||
else
|
|
||||||
echo "Spectrum Deluxe has already been downloaded."
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p mnt
|
|
||||||
mkdir -p extract
|
|
||||||
mkdir -p shkstage
|
|
||||||
cp "$imageName" "$hfsName"
|
|
||||||
sudo mount -r -t hfs "$imageName" mnt
|
|
||||||
hmount "$hfsName"
|
|
||||||
|
|
||||||
IFS=''
|
|
||||||
cd /tmp/spectrum/mnt
|
|
||||||
find Spectrum.2.5.3 -type d | while read thisDirPath; do
|
|
||||||
mkdir -p /tmp/spectrum/shkstage/"$thisDirPath"
|
|
||||||
hcd
|
|
||||||
IFS='/'
|
|
||||||
for thisDir in $thisDirPath; do
|
|
||||||
hcd $thisDir
|
|
||||||
done
|
|
||||||
echo " Copying: $(hpwd)"
|
|
||||||
IFS=''
|
|
||||||
cd /tmp/spectrum/extract
|
|
||||||
hls -1 | while read thisFile; do
|
|
||||||
hcopy -m "$thisFile" - 2> /dev/null | macsave -f 2> /dev/null
|
|
||||||
if [[ -f "$thisFile".info ]]; then
|
|
||||||
if [[ $(readcharHex "$thisFile".info 65) == "70" ]]; then
|
|
||||||
fileType=$(readcharHex "$thisFile".info 66)
|
|
||||||
auxType=$(readcharHex "$thisFile".info 67)$(readcharHex "$thisFile".info 68)
|
|
||||||
else
|
|
||||||
auxType="0000"
|
|
||||||
fMac=$(readchars "$thisFile".info 65 4)
|
|
||||||
if [[ "$fMac" == "PS16" ]]; then
|
|
||||||
fileType="b3";
|
|
||||||
elif [[ "$fMac" == "PSYS" ]]; then
|
|
||||||
fileType="ff";
|
|
||||||
elif [[ "$fMac" == "BINA" ]]; then
|
|
||||||
fileType="00";
|
|
||||||
elif [[ "$fMac" == "TEXT" ]]; then
|
|
||||||
fileType="04";
|
|
||||||
elif [[ "$fMac" == "MIDI" ]]; then
|
|
||||||
fileType="D7";
|
|
||||||
elif [[ "$fMac" == "AIFF" || "$fMac" == "AIFC" ]]; then
|
|
||||||
fileType="D8";
|
|
||||||
elif [[ "$fMac" == "dImg" ]]; then
|
|
||||||
fileType="E0";
|
|
||||||
else
|
|
||||||
echo "WARNING: unknown file type '$fMac' found for file $thisFile"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
[[ -f "$thisFile".rsrc ]] && mv "$thisFile".rsrc /tmp/spectrum/shkstage/"$thisDirPath"/"${thisFile}#${fileType}${auxType}r"
|
|
||||||
[[ -f "$thisFile".data ]] && mv "$thisFile".data /tmp/spectrum/shkstage/"$thisDirPath"/"${thisFile}#${fileType}${auxType}"
|
|
||||||
rm "$thisFile".info 2> /dev/null
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
cd /tmp/spectrum/mnt
|
|
||||||
done
|
|
||||||
|
|
||||||
cd /tmp/spectrum/shkstage/Spectrum*
|
|
||||||
humount
|
|
||||||
sudo umount /tmp/spectrum/mnt
|
|
||||||
|
|
||||||
mkdir -p Marinetti/Uthernet
|
|
||||||
cp SAFE2.Archive/Link.Layers/"Uthernet#bc4083" Marinetti/Uthernet
|
|
||||||
echo -n "After installing Marinetti, put Uthernet in the TCPIP folder of your System folder, and restart GS/OS. Then open Control Panels, choose TCP/IP, and choose Setup Connection. Choose Uthernet for the link layer. Under Primary Domain Name Server, enter 8.8.8.8, then click Configure and select Slot 3 and DHCP. Then click Save." > Marinetti/Uthernet/"Uthernet.README#040000"
|
|
||||||
|
|
||||||
echo "Making archive for conversion to disk image..."
|
|
||||||
rm /tmp/spectrum/spectrum.shk 2> /dev/null
|
|
||||||
nulib2 -a -r -0 -e /tmp/spectrum/spectrum.shk * &> /dev/null
|
|
||||||
echo "Converting archive to disk image..."
|
|
||||||
acmd -convert /tmp/spectrum/spectrum.shk $imagesDir/spectrum.hdv 20480
|
|
||||||
acmd -n $imagesDir/spectrum.hdv SPECTRUM.DELUXE
|
|
||||||
|
|
||||||
if [[ $(grep ^s7d7 /usr/local/lib/$configFileName) ]]; then
|
|
||||||
sudo sed -i "s:^s7d7.*$:s7d7 = $imagesDir/spectrum.hdv:" /usr/local/lib/$configFileName
|
|
||||||
else
|
|
||||||
echo "s7d7 = $imagesDir/spectrum.hdv" | tee -a /usr/local/lib/$configFileName > /dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd /tmp
|
|
||||||
|
|
||||||
rm -rf /tmp/spectrum/extract /tmp/spectrum/shkstage /tmp/spectrum/spectrum.shk /tmp/spectrum/mnt &> /dev/null
|
|
||||||
fi
|
|
||||||
# Spectrum ends here
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd
|
|
||||||
rm -r "$tempDir"
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo
|
|
||||||
if [[ -f "$imagesDir/$gsosHD" ]]; then
|
|
||||||
echo
|
|
||||||
echo "You can now start $emulatorName."
|
|
||||||
echo "When the installer boots, you can click Easy Update or Customize"
|
|
||||||
echo "to install GS/OS, if you downloaded the installer disks aobve."
|
|
||||||
else
|
|
||||||
# if no acmd, create unformatted disk
|
|
||||||
# requires that the disk first be formatted with Advanced Disk Utility
|
|
||||||
dd bs=512 count=65535 if=/dev/zero of=$imagesDir/"$gsosHD" 2> /dev/null
|
|
||||||
writecharsHex $imagesDir/"$gsosHD" 0 "00.4C.00.C5.00"
|
|
||||||
echo
|
|
||||||
echo "You can now start $emulatorName."
|
|
||||||
echo
|
|
||||||
echo "If you downloaded the installer disks above:"
|
|
||||||
echo "When the installer boots, quit it, change to the SystemTools1 disk,"
|
|
||||||
echo "run Advanced Disk Utility, click Disk until a hard drive icon appears"
|
|
||||||
echo "that says Uninitialized, and initialize it. Then quit Advanced Disk"
|
|
||||||
echo "Utility, change to the Install Disk, and run Installer. When it loads,"
|
|
||||||
echo "click Easy Update or Customize to install GS/OS."
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
echo "When it's done, reboot."
|
|
||||||
echo "(Use Shut Down, ctrl-F12, or ctrl-solidapple-equals.)"
|
|
||||||
if [[ -f "$imagesDir/spectrum.hdv" ]]; then
|
|
||||||
echo
|
|
||||||
echo "Then on the Spectrum disk, optionally install:"
|
|
||||||
echo "Marinetti (plus update): TCP/IP driver for GS/OS"
|
|
||||||
echo "Uthernet: Ethernet driver for Marinetti"
|
|
||||||
echo "Spectrum: serial and telnet communications"
|
|
||||||
echo "SAFE: FTP client"
|
|
||||||
echo "SNAP: Usenet newsgroups (NNTP) client"
|
|
||||||
echo "SAM2: Email (POP) client"
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
echo "After installing, press F4 and choose 'Disk Configuration' to"
|
|
||||||
echo "eject all disks other than slot 7 drive 1."
|
|
||||||
echo
|
|
||||||
if [[ ! $autoAnswerYes ]]; then
|
|
||||||
echo -n "Press return to continue..."
|
|
||||||
read
|
|
||||||
fi
|
|
@ -1,122 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ ( $(grep USB <<< $myTTY) || $(grep AMA <<< $myTTY) || $SSH_CLIENT || $REMOTEHOST ) && ! $DISPLAY ]]; then
|
|
||||||
echo "Please run GSport on the console, or in an X Window."
|
|
||||||
else
|
|
||||||
|
|
||||||
if [[ -f /usr/local/lib/ROM ]]; then
|
|
||||||
if [[ ! $(grep snd-pcm-oss /etc/modules) ]]; then
|
|
||||||
echo "Configuring GSport sound..."
|
|
||||||
echo "snd-pcm-oss" | sudo tee -a /etc/modules > /dev/null
|
|
||||||
[[ ! $(lsmod | grep snd_pcm_oss) ]] && sudo modprobe snd-pcm-oss
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $(dpkg -l xfonts-base 2> /dev/null | grep '^ii') ]]; then
|
|
||||||
echo "Configuring GSport fonts..."
|
|
||||||
sudo apt-get -y update
|
|
||||||
touch /tmp/updated
|
|
||||||
sudo apt-get -y install xfonts-base &> /dev/null
|
|
||||||
sudo apt-get -y clean
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $(dpkg -l libpcap0.8-dev 2> /dev/null | grep '^ii') ]]; then
|
|
||||||
echo "Configuring GSport networking..."
|
|
||||||
[[ ! -f /tmp/updated ]] && sudo apt-get -y update
|
|
||||||
sudo apt-get -y install libpcap0.8-dev &> /dev/null
|
|
||||||
sudo apt-get -y clean
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm /tmp/updated &> /dev/null
|
|
||||||
else
|
|
||||||
gsport-setup
|
|
||||||
[[ $? -ne 0 ]] && exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
displayOK=
|
|
||||||
if [[ $DISPLAY ]]; then # X Window
|
|
||||||
displayOK=1
|
|
||||||
else # console/framebuffer
|
|
||||||
if [[ ! -f /usr/local/etc/gsportconsolewarningoff ]] && { dpkg -l | grep -q -i virtualbox; }; then
|
|
||||||
echo
|
|
||||||
echo "If you have difficulties moving the mouse in GS/OS, choose"
|
|
||||||
echo "'Disable Mouse Integration' from the Machine menu. To free the mouse"
|
|
||||||
echo "from the virtual machine, press the Host key (shown in the lower right"
|
|
||||||
echo "corner of the virtual machine window)."
|
|
||||||
echo
|
|
||||||
echo "Press alt-F4 to exit GSport."
|
|
||||||
echo
|
|
||||||
echo "Press return to continue,"
|
|
||||||
echo -n " or type 'OK' if you want to stop seeing this message: "
|
|
||||||
read
|
|
||||||
if [[ $REPLY == "ok" || $REPLY == "ok" || $REPLY == "Ok" ]]; then
|
|
||||||
sudo touch /usr/local/etc/gsportconsolewarningoff
|
|
||||||
fi
|
|
||||||
# echo "If you wish to run GSport in the console window, the mouse will not work"
|
|
||||||
# echo "unless you uninstall VirtualBox Guest Additions. If you don't want to do"
|
|
||||||
# echo "this, you can instead run GSport in an X window (e.g. by typing 'startx')."
|
|
||||||
# echo "If you're not sure, just uninstall it now. Nothing terrible will happen."
|
|
||||||
# echo
|
|
||||||
# echo -n "Do you want to uninstall VirtualBox Guest Additions now? "
|
|
||||||
# read
|
|
||||||
# if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then
|
|
||||||
# echo "Ok, on the case..."
|
|
||||||
# sudo /etc/init.d/vboxadd-service stop 2> /dev/null
|
|
||||||
# sudo /etc/init.d/virtualbox-guest-utils stop &> /dev/null
|
|
||||||
# sudo rmmod vboxvideo 2> /dev/null
|
|
||||||
# sudo rmmod vboxsf 2> /dev/null
|
|
||||||
# sudo rmmod vboxguest 2> /dev/null
|
|
||||||
# while { lsmod | grep -q vbox; }; do
|
|
||||||
# sleep 1
|
|
||||||
# sudo rmmod vboxvideo 2> /dev/null
|
|
||||||
# sudo rmmod vboxsf 2> /dev/null
|
|
||||||
# sudo rmmod vboxguest 2> /dev/null
|
|
||||||
# done
|
|
||||||
# if [ -f /opt/VBoxGuestAdditions*/uninstall.sh ]; then
|
|
||||||
# sudo /opt/VBoxGuestAdditions*/uninstall.sh &> /dev/null
|
|
||||||
# sudo rmdir /opt/VBoxGuestAdditions* 2> /dev/null
|
|
||||||
# fi
|
|
||||||
# if { dpkg -l 2> /dev/null | grep -q -i virtualbox; }; then
|
|
||||||
# sudo apt-get -y purge $(dpkg -l 2> /dev/null | grep -i virtualbox | cut -f 3 -d ' ' | tr '\n' ' ') &> /dev/null
|
|
||||||
# fi
|
|
||||||
# touch /tmp/gsport-consolesetup
|
|
||||||
# fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $(grep 'input' <<< $(groups) ) ]]; then
|
|
||||||
sudo groupadd input &> /dev/null
|
|
||||||
sudo usermod -a -G input $USER
|
|
||||||
echo 'SUBSYSTEM=="input", GROUP="input", MODE="0660"' | sudo tee /etc/udev/rules.d/99-input.rules > /dev/null
|
|
||||||
touch /tmp/gsport-consolesetup
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -c /dev/fb0 ]]; then
|
|
||||||
[[ ! -f /tmp/gsport-consolesetup ]] && displayOK=1
|
|
||||||
else
|
|
||||||
if [[ -f /etc/default/grub ]]; then
|
|
||||||
if [[ ! $(grep 'GRUB_GFXPAYLOAD_LINUX' /etc/default/grub) ]]; then
|
|
||||||
echo "Preparing GSport for console use..."
|
|
||||||
sudo sed -i 's/^\(GRUB_CMDLINE_LINUX=.*\)$/\1\nGRUB_GFXPAYLOAD_LINUX=640x480/' /etc/default/grub
|
|
||||||
sudo update-grub &> /dev/null
|
|
||||||
touch /tmp/gsport-consolesetup
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "No framebuffer available. Please run GSport in an X window."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $DISPLAY && -f /tmp/gsport-consolesetup ]]; then
|
|
||||||
echo "GSport will be ready for console use after you restart your system."
|
|
||||||
echo "You can restart now by typing 'system-restart'."
|
|
||||||
elif [[ $displayOK ]]; then
|
|
||||||
if [[ $(xdpyinfo 2> /dev/null) ]]; then
|
|
||||||
exec gsportx
|
|
||||||
else
|
|
||||||
exec gsportfb
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "GSport has a problem. Please try updating A2CLOUD by"
|
|
||||||
echo "typing 'a2cloud-setup'."
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
@ -1,6 +0,0 @@
|
|||||||
wget -qO /tmp/gsport-setup ivanx.com/a2cloud/setup/gsport-setup.txt
|
|
||||||
if [[ $(wc -c /tmp/gsport-setup | grep '^0 ') ]]; then
|
|
||||||
echo "Please connect to the internet to set up KEGS."
|
|
||||||
else
|
|
||||||
source /tmp/gsport-setup -k "$@"
|
|
||||||
fi
|
|
@ -1,6 +0,0 @@
|
|||||||
if [[ -f /usr/local/bin/gsport-setup ]]; then
|
|
||||||
wget -O /tmp/gsport-setup ivanx.com/a2cloud/gsport-setup.txt
|
|
||||||
source /tmp/gsport-setup -k "$@"
|
|
||||||
else
|
|
||||||
gsport-setup -k "$@"
|
|
||||||
fi
|
|
@ -1,27 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ ! $DISPLAY ]]; then
|
|
||||||
echo "Please run KEGS in an X Window."
|
|
||||||
echo "(If you are using the console, type 'startx'.)"
|
|
||||||
else
|
|
||||||
if [[ -f /usr/local/lib/rom.kegs ]]; then
|
|
||||||
if [[ ! $(grep snd-pcm-oss /etc/modules) ]]; then
|
|
||||||
echo "Configuring KEGS sound..."
|
|
||||||
echo "snd-pcm-oss" | sudo tee -a /etc/modules > /dev/null
|
|
||||||
[[ ! $(lsmod | grep snd_pcm_oss) ]] && sudo modprobe snd-pcm-oss
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $(dpkg -l xfonts-base 2> /dev/null | grep '^ii') ]]; then
|
|
||||||
echo "Configuring KEGS fonts..."
|
|
||||||
sudo apt-get -y update
|
|
||||||
sudo apt-get -y install xfonts-base &> /dev/null
|
|
||||||
sudo apt-get -y clean
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec xkegs
|
|
||||||
else
|
|
||||||
kegs-setup
|
|
||||||
[[ $? -ne 0 ]] && exit 1
|
|
||||||
exec kegs
|
|
||||||
fi
|
|
||||||
fi
|
|
@ -1,52 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [[ ( $(grep USB <<< $myTTY) || $(grep AMA <<< $myTTY) || $SSH_CLIENT || $REMOTEHOST ) && ! $DISPLAY ]]; then
|
|
||||||
echo "Please run LinApple on the console, or in an X Window."
|
|
||||||
else
|
|
||||||
if [[ $(dpkg -l libsdl1.2debian libcurl3 zlib1g libzip2 2> /dev/null | grep ^ii | wc -l) -ne 4 ]]; then
|
|
||||||
echo "Configuring LinApple libraries (this may take a moment)..."
|
|
||||||
sudo apt-get -y update &> /dev/null
|
|
||||||
sudo apt-get -y install libsdl1.2debian libcurl3 zlib1g libzip2 &> /dev/null
|
|
||||||
sudo apt-get -y clean
|
|
||||||
fi
|
|
||||||
|
|
||||||
linappleOk=
|
|
||||||
|
|
||||||
if [[ $DISPLAY ]]; then # X Window
|
|
||||||
linappleOk=1
|
|
||||||
else # console/framebuffer
|
|
||||||
if [[ ! -f /tmp/linapple-consolesetup && ! $(grep 'input' <<< $(groups) ) ]]; then
|
|
||||||
sudo groupadd input &> /dev/null
|
|
||||||
sudo usermod -a -G input $USER
|
|
||||||
echo 'SUBSYSTEM=="input", GROUP="input", MODE="0660"' | sudo tee /etc/udev/rules.d/99-input.rules > /dev/null
|
|
||||||
touch /tmp/linapple-consolesetup
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -c /dev/fb0 ]]; then
|
|
||||||
[[ ! -f /tmp/linapple-consolesetup ]] && linappleOk=1
|
|
||||||
else
|
|
||||||
if [[ -f /etc/default/grub ]]; then
|
|
||||||
if [[ ! $(grep 'GRUB_GFXPAYLOAD_LINUX' /etc/default/grub) ]]; then
|
|
||||||
echo "Preparing LinApple for console use..."
|
|
||||||
sudo sed -i 's/^\(GRUB_CMDLINE_LINUX=.*\)$/\1\nGRUB_GFXPAYLOAD_LINUX=640x480/' /etc/default/grub
|
|
||||||
sudo update-grub &> /dev/null
|
|
||||||
touch /tmp/linapple-consolesetup
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "No framebuffer available. Please run LinApple in an X window."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $DISPLAY && -f /tmp/linapple-consolesetup ]]; then
|
|
||||||
echo "LinApple will be ready for console use after you restart your system."
|
|
||||||
echo "You can restart now by typing 'system-restart'."
|
|
||||||
elif [[ $linappleOk ]]; then
|
|
||||||
cd /usr/local/linapple
|
|
||||||
./linapple
|
|
||||||
else
|
|
||||||
echo "LinApple has a problem. Please try updating A2CLOUD by"
|
|
||||||
echo "typing 'a2cloud-setup'."
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
@ -1,160 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 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
|
|
@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
Welcome to A2CLOUD!
|
|
||||||
Instructions and help: http://appleii.ivanx.com
|
|
||||||
|
|
||||||
Type 'a2cloud-help' for a list of A2CLOUD commands.
|
|
||||||
Type 'system-shutdown' to turn off your Raspberry Pi.
|
|
||||||
|
|
||||||
Type 'raspi-config' to configure your Raspberry Pi.
|
|
||||||
Type 'startx' to start the Raspbian desktop.
|
|
||||||
|
|
||||||
Type 'lynx' or 'links' to browse the web and 'cftp' to log into FTP sites.
|
|
||||||
Type 'a2chat' or 'a2news' to talk about Apple II stuff with others.
|
|
||||||
Type 'ttytter' to tweet. Type 'term color' for a color terminal on a IIgs.
|
|
||||||
|
|
||||||
Type 'gsport' or 'kegs' to use the GSport or KEGS Apple IIgs emulators.
|
|
||||||
Type 'linapple' to use the LinApple Apple IIe emulator.
|
|
@ -1,16 +0,0 @@
|
|||||||
|
|
||||||
Welcome to A2CLOUD!
|
|
||||||
Instructions and help: http://appleii.ivanx.com
|
|
||||||
|
|
||||||
Type 'a2cloud-help' for a list of A2CLOUD commands.
|
|
||||||
Type 'system-shutdown' to turn off your Raspberry Pi.
|
|
||||||
|
|
||||||
Type 'raspi-config' to configure your Raspberry Pi.
|
|
||||||
Type 'startx' to start the Raspbian desktop.
|
|
||||||
|
|
||||||
Type 'lynx' or 'links' to browse the web and 'cftp' to log into FTP sites.
|
|
||||||
Type 'a2chat' or 'a2news' to talk about Apple II stuff with others.
|
|
||||||
Type 'ttytter' to tweet. Type 'term color' for a color terminal on a IIgs.
|
|
||||||
|
|
||||||
Type 'gsport' or 'kegs' to use the GSport or KEGS Apple IIgs emulators.
|
|
||||||
Type 'linapple' to use the LinApple Apple IIe emulator.
|
|
@ -1 +0,0 @@
|
|||||||
motd-rpi.txt
|
|
@ -1,233 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# raspbian-update
|
|
||||||
# updates Raspbian to latest version, including NOOBS if installed
|
|
||||||
|
|
||||||
[[ -f /usr/bin/raspi-config ]] && isRpi=1 || isRpi=
|
|
||||||
|
|
||||||
if [[ ! $isRpi ]]; then
|
|
||||||
echo "This ain't a Raspberry Pi."
|
|
||||||
[[ $0 == "-bash" ]] && return 1 || exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
skipRepoUpdate=
|
|
||||||
autoYes=
|
|
||||||
updateA2Cloud=
|
|
||||||
updateA2Server=
|
|
||||||
while [[ $1 ]]; do
|
|
||||||
if [[ $1 == "-r" ]]; then
|
|
||||||
shift
|
|
||||||
skipRepoUpdate="-r"
|
|
||||||
elif [[ $1 == "-y" ]]; then
|
|
||||||
shift
|
|
||||||
autoYes="-y"
|
|
||||||
elif [[ $1 == "-n" ]]; then
|
|
||||||
shift
|
|
||||||
noobsOnly="-n"
|
|
||||||
elif [[ $1 == "a2cloud" ]]; then
|
|
||||||
shift
|
|
||||||
updateA2Cloud=1
|
|
||||||
elif [[ $1 == "a2server" ]]; then
|
|
||||||
shift
|
|
||||||
updateA2Server=1
|
|
||||||
elif [[ $1 ]]; then
|
|
||||||
echo "options:"
|
|
||||||
echo "-y: auto-answer yes to all prompts and don't prompt for restart"
|
|
||||||
echo "-r: don't update package repositories"
|
|
||||||
echo "-n: update NOOBS only; don't update Raspbian"
|
|
||||||
echo "a2cloud : update A2CLOUD when complete"
|
|
||||||
echo "a2server: update A2SERVER when complete"
|
|
||||||
[[ $0 == "-bash" ]] && return 1 || exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
noobs=
|
|
||||||
readarray -t partitions < <(sudo fdisk -l | grep '^/dev')
|
|
||||||
if [[ \
|
|
||||||
${partitions[0]:0:14} == "/dev/mmcblk0p1" && ${partitions[0]:57:2} == " e" &&
|
|
||||||
${partitions[1]:0:14} == "/dev/mmcblk0p2" && ${partitions[1]:57:2} == "85" &&
|
|
||||||
${partitions[2]:0:14} == "/dev/mmcblk0p3" && ${partitions[2]:57:2} == "83" &&
|
|
||||||
${partitions[3]:0:14} == "/dev/mmcblk0p5" && ${partitions[3]:57:2} == " c" &&
|
|
||||||
${partitions[4]:0:14} == "/dev/mmcblk0p6" && ${partitions[4]:57:2} == "83" ]]; then
|
|
||||||
noobs=" and the NOOBS install manager"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $autoYes ]]; then
|
|
||||||
echo
|
|
||||||
echo "You are about to update your SD card to the latest version of the"
|
|
||||||
echo "Raspbian operating system${noobs}."
|
|
||||||
echo
|
|
||||||
echo "This may take an hour or more, and will require restarting when complete."
|
|
||||||
echo "You might want a backup before continuing in case it doesn't go as planned."
|
|
||||||
echo
|
|
||||||
echo -n "Update Raspbian? "
|
|
||||||
read
|
|
||||||
if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then
|
|
||||||
[[ $0 == "-bash" ]] && return 2 || exit 2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
origDir="$PWD"
|
|
||||||
cd /tmp
|
|
||||||
|
|
||||||
if [[ ! $skipRepoUpdate ]]; then
|
|
||||||
echo "Updating package repositories..."
|
|
||||||
sudo apt-get -y update > /dev/null
|
|
||||||
else
|
|
||||||
echo "Not updating package repositories..."
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $noobsOnly ]]; then
|
|
||||||
{ cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null
|
|
||||||
freeSpace=$(df / | tail -1 | awk '{ print $4 }')
|
|
||||||
if (( $freeSpace < 400000 )); then
|
|
||||||
if dpkg -l | grep -q wolfram-engine; then
|
|
||||||
if [[ ! $autoYes ]]; then
|
|
||||||
echo "In order to create enough space on your SD card to upgrade,"
|
|
||||||
echo "the Wolfram Language and Mathematica software packages must be removed."
|
|
||||||
echo "If you don't know what these are, this won't affect you at all."
|
|
||||||
echo
|
|
||||||
echo -n "Remove Wolfram software? "
|
|
||||||
read
|
|
||||||
if [[ ${REPLY:0:1} != "Y" && ${REPLY:0:1} != "y" ]]; then
|
|
||||||
[[ $0 == "-bash" ]] && return 2 || exit 2
|
|
||||||
fi
|
|
||||||
sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null
|
|
||||||
sudo apt-get -y purge wolfram-engine
|
|
||||||
else
|
|
||||||
echo "Removing Wolfram software due to space constraints..."
|
|
||||||
sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null
|
|
||||||
sudo apt-get -y purge wolfram-engine
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "You don't have enough free space on your SD card to upgrade."
|
|
||||||
echo "Sorry, man. Delete some stuff or get a bigger card."
|
|
||||||
[[ $0 == "-bash" ]] && return 1 || exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
{ cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null
|
|
||||||
dpkg -l | grep -q a2pi && sudo apt-get -y --force-yes install a2pi
|
|
||||||
dpkg -l | grep -q apple2user && sudo apt-get -y --force-yes install apple2user gsport
|
|
||||||
if dpkg -l | grep -q wolfram-engine; then
|
|
||||||
sudo rm /opt/Wolfram/WolframEngine/10.0/SystemFiles/Java/Linux-ARM 2> /dev/null
|
|
||||||
if [[ $freeSpace -lt 750000 && $(apt-get -s install wolfram-engine | grep upgraded) ]]; then
|
|
||||||
sudo apt-get -y purge wolfram-engine
|
|
||||||
{ cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null
|
|
||||||
fi
|
|
||||||
sudo apt-get -y install wolfram-engine
|
|
||||||
{ cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null
|
|
||||||
fi
|
|
||||||
sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade
|
|
||||||
{ cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null
|
|
||||||
sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade
|
|
||||||
{ cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null
|
|
||||||
sudo apt-get -y install raspberrypi-ui-mods
|
|
||||||
{ cd /tmp; sudo apt-get -y autoremove; sudo apt-get -y autoclean; sudo apt-get -y clean; } > /dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $noobs ]]; then
|
|
||||||
echo "Updating NOOBS..."
|
|
||||||
|
|
||||||
# update Partition 3
|
|
||||||
mkdir -p /tmp/p3
|
|
||||||
sudo mount /dev/mmcblk0p3 /tmp/p3
|
|
||||||
sudo rm -rf /tmp/p3/os/* 2> /dev/null
|
|
||||||
if grep -q 'Raspple II' /tmp/p3/installed_os.json; then
|
|
||||||
echo "Downloading Raspple II lite..."
|
|
||||||
noobsUrl="ivanx.com/rasppleii/files/RasppleII_lite.zip"
|
|
||||||
noobsOSurl="ivanx.com/rasppleii/noobs-os"
|
|
||||||
distDir="Raspple_II"
|
|
||||||
sudo mkdir -p /tmp/p3/os/$distDir
|
|
||||||
sudo sed -i 's:/Raspbian:/Raspple_II:' /tmp/p3/installed_os.json
|
|
||||||
sudo wget -qO /tmp/p3/icon.png $noobsOSurl/Raspple_II.png
|
|
||||||
wget -qO- $noobsOSurl/slidesAB.tar | sudo tar -C /tmp/p3/os/$distDir -x
|
|
||||||
else
|
|
||||||
echo "Downloading NOOBS lite..."
|
|
||||||
noobsRoot="downloads.raspberrypi.org/NOOBS_lite/images/"
|
|
||||||
noobsDir=$(wget -qO- $noobsRoot | grep '^<tr><td' | tail -1 | grep -P -o 'href=".*?"' | cut -c 6- | tr -d '"')
|
|
||||||
noobsUrl=$noobsRoot$noobsDir$(wget -qO- $noobsRoot$noobsDir | grep -P -o 'href=".*.zip"' | cut -c 6- | tr -d '"')
|
|
||||||
noobsOSurl="downloads.raspberrypi.org/raspbian"
|
|
||||||
distDir="Raspbian"
|
|
||||||
sudo mkdir -p /tmp/p3/os/$distDir
|
|
||||||
sudo wget -qO /tmp/p3/icon.png $noobsOSurl/Raspbian.png
|
|
||||||
wget -qO- $noobsOSurl/marketing.tar | sudo tar -C /tmp/p3/os/$distDir -x
|
|
||||||
fi
|
|
||||||
sudo rm -rf /tmp/p3/cache 2> /dev/null
|
|
||||||
releaseDate=$(wget -qO- $noobsOSurl/os.json | grep 'release_date' | cut -f 4 -d '"')
|
|
||||||
sudo sed -i 's/"release_date".*$/"release_date" : "'$releaseDate'"/' /tmp/p3/installed_os.json
|
|
||||||
sudo sed -i 's/keyboard_layout=gb/keyboard_layout=us/' /tmp/p3/noobs.conf
|
|
||||||
sudo sed -i 's:/mnt/:/settings/:' /tmp/p3/installed_os.json
|
|
||||||
sudo sed -i 's@"icon".*,@"icon" : "/settings/os/'$distDir'/icon.png",@' /tmp/p3/installed_os.json
|
|
||||||
sudo cp /tmp/p3/icon.png /tmp/p3/os/$distDir
|
|
||||||
sudo wget -qO /tmp/p3/os/$distDir/os.json $noobsOSurl/os.json
|
|
||||||
sudo wget -qO /tmp/p3/os/$distDir/partition_setup.sh $noobsOSurl/partition_setup.sh
|
|
||||||
sudo wget -qO /tmp/p3/os/$distDir/partitions.json $noobsOSurl/partitions.json
|
|
||||||
sudo umount /tmp/p3
|
|
||||||
rmdir /tmp/p3
|
|
||||||
|
|
||||||
# update Partition 1
|
|
||||||
mkdir -p /tmp/p1
|
|
||||||
sudo mount /dev/mmcblk0p1 /tmp/p1
|
|
||||||
wget -qO /tmp/noobs_lite.zip $noobsUrl
|
|
||||||
sudo rm -rf /tmp/p1/*
|
|
||||||
sudo unzip -d /tmp/p1 /tmp/noobs_lite.zip
|
|
||||||
sudo sed -i 's/^runinstaller //' /tmp/p1/recovery.cmdline
|
|
||||||
sudo sed -i 's/silentinstall//' /tmp/p1/recovery.cmdline
|
|
||||||
grep -q 'keyboard=us' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 keyboard=us/' /tmp/p1/recovery.cmdline
|
|
||||||
grep -q 'disablesafemode' /tmp/p1/recovery.cmdline || sudo sed -i '1 s/^\(.*\)$/\1 disablesafemode/' /tmp/p1/recovery.cmdline
|
|
||||||
sudo umount /tmp/p1
|
|
||||||
rmdir /tmp/p1
|
|
||||||
|
|
||||||
sudo sed -i 's/\(Raspple II release.*[^u]$\)/\1u/' /etc/issue
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "*** Raspbian update completed. ***"
|
|
||||||
echo
|
|
||||||
|
|
||||||
cd /tmp
|
|
||||||
|
|
||||||
if [[ $updateA2Cloud ]]; then
|
|
||||||
wget -qO /tmp/a2cloud-setup ivanx.com/a2cloud/setup/
|
|
||||||
source /tmp/a2cloud-setup -y -r noSetGroups
|
|
||||||
if acmd -g /usr/share/gsport/disks/GSport\ Internet\ Starter\ Kit.2mg SYSTEM/FONTS/SIS.4.10 &> /dev/null; then
|
|
||||||
wget -qO /tmp/ua2.txt ivanx.com/rasppleii/files/a/ua2.txt
|
|
||||||
source /tmp/ua2.txt
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
echo "*** A2CLOUD update completed. ***"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd /tmp
|
|
||||||
|
|
||||||
if [[ $updateA2Server ]]; then
|
|
||||||
wget -q -O /tmp/a2server-setup ivanx.com/a2server/setup/
|
|
||||||
if ps aux | grep -q [s]mbd; then
|
|
||||||
source /tmp/a2server-setup -y -r -w
|
|
||||||
else
|
|
||||||
source /tmp/a2server-setup -y -r
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
echo "*** A2SERVER update completed. ***"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$origDir"
|
|
||||||
|
|
||||||
if [[ ! $autoYes ]]; then
|
|
||||||
echo
|
|
||||||
echo
|
|
||||||
echo "Your system has been updated and needs to reboot to use its new software."
|
|
||||||
echo
|
|
||||||
echo -n "Reboot now (recommended)? "
|
|
||||||
read
|
|
||||||
if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then
|
|
||||||
sudo shutdown -r now
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "*** raspbian-update completed. ***"
|
|
||||||
sudo shutdown -r now
|
|
||||||
fi
|
|
@ -1 +0,0 @@
|
|||||||
v1.8.2.txt
|
|
@ -1,24 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
origDir="$PWD"
|
|
||||||
[[ ! -n $1 || ! -n $2 ]] && { echo "Usage: shk2image archiveFileName imageFileName [PRODOS.DIR.NAME]"; exit 1; };
|
|
||||||
imageFileName="$2";
|
|
||||||
prodosDir="$3";
|
|
||||||
[[ ! -f "$1" ]] && { echo "Archive file '$1' was not found."; exit 1; };
|
|
||||||
[[ ! -f "$imageFileName" ]] && mkpo "$imageFileName";
|
|
||||||
[[ -n $prodosDir ]] && dirName="$prodosDir/" || dirName=;
|
|
||||||
IFS="";
|
|
||||||
[[ ${1:0:1} == "/" ]] && archiveFile="$1" || archiveFile="$origDir/$1"
|
|
||||||
mkdir -p /tmp/shk2image_temp
|
|
||||||
cd /tmp/shk2image_temp
|
|
||||||
shkFiles=$(nulib2 -xse "$archiveFile" | tr "\r" "~" | cut -d "~" -f 2 | cut -c 18-);
|
|
||||||
cd "$origDir"
|
|
||||||
while read thisFile; do
|
|
||||||
fileName=${thisFile%%#*};
|
|
||||||
fileType=${thisFile##*#};
|
|
||||||
echo "extracting $fileName...";
|
|
||||||
acmd -d "$imageFileName" $dirName$fileName &>/dev/null;
|
|
||||||
acmd -p "$imageFileName" $dirName$fileName \$${fileType:0:2} \$${fileType:2:4} < /tmp/shk2image_temp/"$thisFile"
|
|
||||||
rm /tmp/shk2image_temp/"$thisFile"
|
|
||||||
done <<< $shkFiles
|
|
||||||
rm -r /tmp/shk2image_temp
|
|
@ -1,46 +0,0 @@
|
|||||||
if [[ $1 == "-d" ]]; then
|
|
||||||
shift
|
|
||||||
setgetty=1
|
|
||||||
else
|
|
||||||
setgetty=
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $1 == "-f" ]]; then
|
|
||||||
shift
|
|
||||||
force=1
|
|
||||||
else
|
|
||||||
force=
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! $1 || $1 == "--help" || $1 == "-h" ]]; then
|
|
||||||
echo 'Usage: term [-d] mono|color|none|<terminalName>';
|
|
||||||
echo ' -d sets default emulation for all serial port shells (takes effect on logout)'
|
|
||||||
echo ' omitting -d makes change temporary and immediate'
|
|
||||||
echo ' -f forces change even if not running on serial port (e.g. within "screen")'
|
|
||||||
echo ' Terminal emulation: mono->VT-100, color->PC-ANSI/ANSI-BBS, none->no emulation'
|
|
||||||
else
|
|
||||||
if [[ $(tr [:upper:] [:lower:] <<< $1) == "mono" ]]; then
|
|
||||||
term="vt100"
|
|
||||||
elif [[ $(tr [:upper:] [:lower:] <<< $1) == "color" ]]; then
|
|
||||||
term="pcansi"
|
|
||||||
elif [[ $(tr [:upper:] [:lower:] <<< $1) == "none" ]]; then
|
|
||||||
term="dumb"
|
|
||||||
else
|
|
||||||
term="$1"
|
|
||||||
fi
|
|
||||||
if [[ $setgetty ]]; then
|
|
||||||
sudo sed -i "s/\(ttyAMA0 .*\) .*$/\1 $term/" /etc/inittab;
|
|
||||||
sudo sed -i "s/\(ttyUSB.* .*\) .*$/\1 $term/g" /etc/inittab;
|
|
||||||
sudo init q;
|
|
||||||
sudo pkill -f "/sbin/getty"
|
|
||||||
else
|
|
||||||
if [[ $force || $(tty | grep tty) ]]; then
|
|
||||||
TERM="$term"
|
|
||||||
else
|
|
||||||
echo 1>&2 "Not running on serial port. No action taken. Use -f to set anyway."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "$(tty) current emulation: $(tput bold)$TERM$(tput sgr0)"
|
|
||||||
echo -e "default serial port emulation at login: $(tput bold)$(grep ttyUSB /etc/inittab | sed 's/^.*ttyUSB[^ ]* .* \(.*\)$/\1/')$(tput sgr0)"
|
|
@ -1,45 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# called by udev as:
|
|
||||||
# ttyusbhandler [add|remove] ttyUSBname
|
|
||||||
|
|
||||||
# depending on what port ttyUSB adapter was added or removed from,
|
|
||||||
# automatically launches or kills ADTPro as needed
|
|
||||||
# restarts getty as needed
|
|
||||||
|
|
||||||
# remove:
|
|
||||||
# kill any ADTPro for this port
|
|
||||||
# if a getty is on this port, do nothing here, it will be killed and respawn
|
|
||||||
# iteself
|
|
||||||
|
|
||||||
# add:
|
|
||||||
# stagger adds by port number to prevent problems during simultaneous add at startup
|
|
||||||
# if lower port, solo adapter on lower port USB hub, or lower port of any USB hub,
|
|
||||||
# kill any ADTPro, rescan for getty if sleeping, and launch adtPro
|
|
||||||
# if upper port, solo adapter on upper port USB hub, or higher port of any USB hub,
|
|
||||||
# rescan for getty
|
|
||||||
|
|
||||||
if [[ $1 == "remove" ]]; then
|
|
||||||
rm /tmp/udev-$2-removed &> /dev/null
|
|
||||||
touch /tmp/udev-$2-removed
|
|
||||||
pkill -f "$2.*ADTPro"
|
|
||||||
elif [[ $1 == "add" ]]; then
|
|
||||||
[[ $2 == "ttyUSBlower" ]] && sleep 1.5
|
|
||||||
[[ ${#2} -gt 11 ]] && sleep "${2:15:2}"
|
|
||||||
if [[ $2 == "ttyUSBlower" || \
|
|
||||||
$2 == $(ls -1 /dev/ttyUSBlower_hub* 2> /dev/null | head -1 | cut -c 6-) || \
|
|
||||||
( ${2:0:12} == "ttyUSBlower_" && $2 != $(ls -1 /dev/ttyUSBupper_hub* 2> /dev/null | tail -1 | cut -c 6-) ) \
|
|
||||||
]]; then
|
|
||||||
rm /tmp/udev-ttyUSBlower-added &> /dev/null
|
|
||||||
touch /tmp/udev-ttyUSBlower-added
|
|
||||||
pkill -f "[A]DTPro"
|
|
||||||
pkill -f "[u]sbgetty"
|
|
||||||
exec /usr/local/adtpro/adtpro.sh headless serial
|
|
||||||
else # ttyUSBupper
|
|
||||||
rm /tmp/udev-ttyUSBupper-added &> /dev/null
|
|
||||||
touch /tmp/udev-ttyUSBupper-added
|
|
||||||
pkill -f "[g]etty.*ttyUSB"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
exit 2
|
|
||||||
fi
|
|
@ -1,47 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
ttyUSB=
|
|
||||||
|
|
||||||
pkill -f "sleep 86399"
|
|
||||||
|
|
||||||
if [[ $(grep -e '-scanttyUSB' <<< "$*") ]]; then
|
|
||||||
# called with -scantty isntead of device name?
|
|
||||||
# echo "-scantty mode"
|
|
||||||
|
|
||||||
# if upper USB port
|
|
||||||
if [[ -c /dev/ttyUSBupper ]]; then
|
|
||||||
ttyUSB=ttyUSBupper
|
|
||||||
|
|
||||||
# if hub in upper port, use highest numbered port on hub
|
|
||||||
elif [[ $(ls -1 /dev/ttyUSBupper_hub* 2> /dev/null | wc -l) -gt 0 ]]; then
|
|
||||||
ttyUSB=$(ls -1 /dev/ttyUSBupper_hub* 2> /dev/null | tail -1 | cut -c 6-)
|
|
||||||
|
|
||||||
# if hub in lower port with multiple adapters, use highest numbered port on hub
|
|
||||||
elif [[ $(ls -1 /dev/ttyUSBlower_hub* 2> /dev/null | wc -l) -gt 1 ]]; then
|
|
||||||
ttyUSB=$(ls -1 /dev/ttyUSBlower_hub* 2> /dev/null | tail -1 | cut -c 6-)
|
|
||||||
|
|
||||||
# no port found eligible for getty
|
|
||||||
else
|
|
||||||
# echo "scantty no devices eligible: sleeping"
|
|
||||||
sleep 86399
|
|
||||||
fi
|
|
||||||
|
|
||||||
# echo "result:$ttyUSB"
|
|
||||||
elif [[ $(grep -o 'ttyUSB[^ ]*' <<< "$*") ]]; then
|
|
||||||
# echo "device specified"
|
|
||||||
# if specified USB device name is found
|
|
||||||
ttyUSB=$(grep -o 'ttyUSB[^ ]*' <<< "$*")
|
|
||||||
else
|
|
||||||
# echo "specified device failed: sleeping"
|
|
||||||
sleep 86399
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -c /dev/$ttyUSB && ! $(ps aux | grep "[g]etty.*$ttyUSB") ]]; then
|
|
||||||
# if adapter seems to exist and doesn't already have a getty,
|
|
||||||
# kill all USB gettys and start the getty, otherwise do nothing
|
|
||||||
pkill -f "/sbin/getty.*ttyUSB"
|
|
||||||
exec /sbin/getty $(sed "s/-scanttyUSB/$ttyUSB/" <<< "$@");
|
|
||||||
else
|
|
||||||
# echo "getty already running or doesn't exist: sleeping"
|
|
||||||
sleep 86399
|
|
||||||
fi
|
|
File diff suppressed because it is too large
Load Diff
@ -1,42 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
skipWarning=
|
|
||||||
drive=
|
|
||||||
if [[ $1 == "-1" || $1 == "-d1" ]]; then
|
|
||||||
shift
|
|
||||||
elif [[ $1 = "-2" || $1 == "-d2" ]]; then
|
|
||||||
drive=2
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
if [[ ! $1 ]]; then
|
|
||||||
echo "virtual drive $(( drive ? 2 : 1 )): $(readlink /usr/local/adtpro/disks/Virtual${drive}.po)"
|
|
||||||
else
|
|
||||||
if [[ $1 == "-f" ]]; then
|
|
||||||
shift
|
|
||||||
skipWarning=1
|
|
||||||
fi
|
|
||||||
if [[ ! -f $1 ]]; then
|
|
||||||
echo "Image file '$1' was not found."
|
|
||||||
elif [[ -f /usr/local/adtpro/disks/Virtual${drive}.po && ! -L /usr/local/adtpro/disks/Virtual${drive}.po ]]; then
|
|
||||||
echo "/usr/local/adtpro/disks/Virtual${drive}.po is an actual disk image"
|
|
||||||
echo "file, not a symbolic link. Please move or rename it, and try again."
|
|
||||||
else
|
|
||||||
rm /usr/local/adtpro/disks/Virtual${drive}.po &>/dev/null;
|
|
||||||
[[ ${1:0:1} != "/" ]] && pwd="$PWD/";
|
|
||||||
ln -s "$pwd$1" /usr/local/adtpro/disks/Virtual${drive}.po
|
|
||||||
[[ $drive ]] && VSD2="$pwd$1" || VSD1="$pwd$1"
|
|
||||||
if [[ $(ps aux | grep [A]DTPro) ]]; then
|
|
||||||
if [[ ! $skipWarning ]]; then
|
|
||||||
echo "Please make sure you're not writing to either virtual drive on your Apple II."
|
|
||||||
echo -n " Press return when ready, or control-C to cancel..."
|
|
||||||
read
|
|
||||||
fi
|
|
||||||
sudo pkill -f [A]DTPro
|
|
||||||
while [[ $(ps aux | grep [A]DTPro) ]]; do sleep 1; done
|
|
||||||
/usr/local/bin/adtpro-start
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
unset drive
|
|
||||||
unset pwd
|
|
Loading…
Reference in New Issue
Block a user