#!/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