Classic implementation of 'modern' tech

Anything not about Mac emulation.

Moderators: Cat_7, Ronald P. Regensburg

Post Reply
User avatar
sentient06
Apple Corer
Posts: 248
Joined: Tue Mar 29, 2011 8:57 pm
Location: London, UK

Classic implementation of 'modern' tech

Post by sentient06 »

Hello, I'm considering a few projects to get my hands dirty developing for classic Mac OS, but there are a few hurdles.

For example, I need SHA-1 implementation, and ZLIB. I also need to use regular expressions, and to learn how to traverse directories, create, hide, show and delete files, which, I assume, are part of the toolbox.

I don't want to reinvent the wheel and go on a quest to develop a ZLIB library, which sounds overkill. I assume someone already did these things. Does anyone know about implementations of things like that, or where to find it, or which keywords could help me locating implementations like that on the web?

So, that's basically me surveying the options and trying to figure out how much of a learning curve and how much extra work I will have to deal with.

Thanks!
User avatar
adespoton
Forum All-Star
Posts: 4473
Joined: Fri Nov 27, 2009 5:11 am
Location: Emaculation.com

Re: Classic implementation of 'modern' tech

Post by adespoton »

sentient06 wrote: Sat Sep 14, 2024 6:33 pm Hello, I'm considering a few projects to get my hands dirty developing for classic Mac OS, but there are a few hurdles.

For example, I need SHA-1 implementation, and ZLIB. I also need to use regular expressions, and to learn how to traverse directories, create, hide, show and delete files, which, I assume, are part of the toolbox.

I don't want to reinvent the wheel and go on a quest to develop a ZLIB library, which sounds overkill. I assume someone already did these things. Does anyone know about implementations of things like that, or where to find it, or which keywords could help me locating implementations like that on the web?

So, that's basically me surveying the options and trying to figure out how much of a learning curve and how much extra work I will have to deal with.

Thanks!
SHA1 and ZLIB I believe are both dependencies for SSH? So I'd say the first place to start would be with the people who developed those 68k clients. I believe some of them are active on MG and 68kmla; probably the best places to start.
User avatar
sentient06
Apple Corer
Posts: 248
Joined: Tue Mar 29, 2011 8:57 pm
Location: London, UK

Re: Classic implementation of 'modern' tech

Post by sentient06 »

adespoton wrote: Mon Sep 16, 2024 3:39 pm SHA1 and ZLIB I believe are both dependencies for SSH? So I'd say the first place to start would be with the people who developed those 68k clients. I believe some of them are active on MG and 68kmla; probably the best places to start.
Beautiful! I went to 68kmla and found a source code for a VNC app that uses a minimalistic ZLIB library that could work. SHA1 shouldn't be that large, might try to code that myself to practice.

https://github.com/marciot/mac-minivnc/ ... iniz-3.0.2

Thanks adespoton!
User avatar
sentient06
Apple Corer
Posts: 248
Joined: Tue Mar 29, 2011 8:57 pm
Location: London, UK

Re: Classic implementation of 'modern' tech

Post by sentient06 »

It would be nice to have a programming board in the forum.

So, as I mentioned before, I've been trying my hands at classic programming. I've been writing some code that can be reused in other projects. I copy these snippets into a repository, so anyone can make use of them.

Here's the URL in case anyone is interested: https://github.com/sentient06/classic-mac-snippets

Of course, with time I will add stuff to it. I'm in the process of learning how to use a few common Macintosh Toolbox routines, so I'll keep dumping whatever I think is useful here.
User avatar
sentient06
Apple Corer
Posts: 248
Joined: Tue Mar 29, 2011 8:57 pm
Location: London, UK

Re: Classic implementation of 'modern' tech

Post by sentient06 »

Do you guys know whether we can setup QEMU to spit some serial output to a file in the host system?

I was reading these pages about Retro68 and there's a guy who came up with a logging function that does exactly that and he can get the logs from the serial output, check it out (search for writeSerialPort):

https://www.toughdev.com/content/2018/1 ... -emulator/

He is using PCE/macplus here.
User avatar
adespoton
Forum All-Star
Posts: 4473
Joined: Fri Nov 27, 2009 5:11 am
Location: Emaculation.com

Re: Classic implementation of 'modern' tech

Post by adespoton »

sentient06 wrote: Thu Nov 21, 2024 8:45 pm Do you guys know whether we can setup QEMU to spit some serial output to a file in the host system?

I was reading these pages about Retro68 and there's a guy who came up with a logging function that does exactly that and he can get the logs from the serial output, check it out (search for writeSerialPort):

https://www.toughdev.com/content/2018/1 ... -emulator/

He is using PCE/macplus here.
https://superuser.com/questions/1373226 ... -or-a-port

- the answer, pulled from the QEMU docs:
According to QEMU 3.1.0 documentation, you can use a chardev with options stdio and logfile and redirect your serial into it.

Code: Select all

qemu-system-x86_64 -chardev stdio,id=char0,logfile=serial.log,signal=off \
  -serial chardev:char0
Moreover, if you use mux=on option within chardev, you can redirect a monitor (mon), another serial or other interfaces supporting chardev backend into it simultaneously:

Code: Select all

qemu-system-x86_64 -chardev stdio,id=char0,mux=on,logfile=serial.log,signal=off \
  -serial chardev:char0 -mon chardev=char0
See the example in the doc. link above.
User avatar
sentient06
Apple Corer
Posts: 248
Joined: Tue Mar 29, 2011 8:57 pm
Location: London, UK

Re: Classic implementation of 'modern' tech

Post by sentient06 »

Alright, I spent a few days working on something, I think it would be nice to share it here.

So, I'm on a macOS 15. Apple silicon.

First, I got Retro68 up and running. So I can develop for classic mac on a modern system. I set up VSCode to search for the libs inside the Retro68 dir, so it highlights code normally.

Next, I got QEMU running Mac OS 9.2.2. Unfortunately, I need to run as root to use the network. My script goes..

Code: Select all

echo "password" | sudo -kS ./qemu-system-ppc \
# etc.
Next, the projects all have a Makefile like this one:

Code: Select all

# Path to RETRO68
RETRO68 := ../../../Retro68-build/toolchain

# Tools
PREFIX := $(RETRO68)/m68k-unknown-elf
CC     := $(RETRO68)/bin/m68k-unknown-elf-gcc
CXX    := $(RETRO68)/bin/m68k-unknown-elf-g++
REZ    := $(RETRO68)/bin/Rez

# Flags
LDFLAGS := -lRetroConsole
RINCLUDES := $(PREFIX)/RIncludes
REZFLAGS := -I$(RINCLUDES)

# Targets
BINARIES := HelloWorld.bin HelloWorld.APPL HelloWorld.dsk

all: $(BINARIES)

# Build HelloWorld.bin
HelloWorld.bin: HelloWorld.flt
	$(REZ) $(REZFLAGS) \
		-DFLT_FILE_NAME=\"HelloWorld.flt\" "$(RINCLUDES)/Retro68APPL.r" \
		-t APPL -c ???? \
		-o $@

# Build HelloWorld.APPL
HelloWorld.APPL: HelloWorld.flt
	$(REZ) $(REZFLAGS) \
		-DFLT_FILE_NAME=\"HelloWorld.flt\" "$(RINCLUDES)/Retro68APPL.r" \
		--cc $@

# Build HelloWorld.dsk
HelloWorld.dsk: HelloWorld.flt
	$(REZ) $(REZFLAGS) \
		-DFLT_FILE_NAME=\"HelloWorld.flt\" "$(RINCLUDES)/Retro68APPL.r" \
		--cc $@

# Link the object file into the flat binary
HelloWorld.flt: hello.o
	$(CXX) $< -o $@ $(LDFLAGS)

# C++ used for linking because RetroConsole needs it

# Implicit rule for object file
%.o: %.c
	$(CC) -c $< -o $@

%.o: %.cpp
	$(CXX) -c $< -o $@

# Clean up generated files
.PHONY: clean
clean:
	rm -f $(BINARIES) HelloWorld.flt HelloWorld.flt.gdb hello.o
And a CMakeLists.txt like this one:

Code: Select all

# Minimum version of CMake required
cmake_minimum_required(VERSION 2.8)

# Project name and version
project(HelloWorld)

add_application(HelloWorld
    hello.c
    CREATOR "HELL"
)   
Next, all projects live in the same dir with a few scripts. The first script builds an app:

Code: Select all

if [ $# -ne 1 ] ; then
    echo 'Syntax: ./build.sh [project_name]'
    exit 1
fi

if [ ! -d "$1" ]; then
    echo 'The specified folder does not exist'
    exit 1
fi

cd "$1"
rm -rf build
mkdir build
cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=/Users/user/Development/Classic/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake
make
The next script uses HFS Tools to build an image with the executable inside. It defaults to 800K or the size of the binary plus 80K:

Code: Select all

#!/bin/bash

if test "$#" -ne 1; then
    echo "Syntax: ./create_hfs_disk.sh [input_file]"
    exit 1
fi

if [ ! -f "$1" ]; then
    echo "Input file not found!"
    exit 1
fi

# Create R68Discs directory if it doesn't exist
mkdir -p R68Discs

# Get the filename without extension
input_file="$1"
filename=$(basename "$input_file")
filename_no_ext="${filename%.*}"

# Calculate size in KB and add 80KB
size_kb=$(du -k "$input_file" | cut -f1)
total_size=$((size_kb + 80))

# Ensure minimum size of 800KB
if [ $total_size -lt 800 ]; then
    total_size=800
fi

# Create output filename with .img extension in R68Discs directory
output_file="R68Discs/${filename_no_ext}.img"

echo "Creating disk image '$output_file' with size ${total_size}KB..."

dd if=/dev/zero of="$output_file" bs=1024 count="$total_size"
hformat -l "$filename_no_ext" "$output_file"
hmount "$output_file"
hcopy "$input_file" ":$filename_no_ext"
humount "$output_file"

echo "Disk image created successfully in R68Discs directory!"
And here's the cherry on top: QEMU is set up with a monitor option, and a cd drive:

Code: Select all

echo "password" | sudo -kS ./qemu-system-ppc \
# stuff here
-device ide-cd,bus=ide.1,drive=cd0 \
-drive if=none,id=cd0,media=cdrom \
# more stuff here
-monitor unix:/tmp/qemu-monitor.sock,server,nowait
This allows me to mount a CD image on the fly via a script, which is in this prototype I got:

Code: Select all

#!/bin/bash

if [ $# -ne 2 ] ; then
    echo "Syntax: $0 [project_name] [should_build = 0 | 1]"
    exit 1
fi

if [ ! -d "$1" ]; then
    echo 'The specified project folder does not exist'
    exit 1
fi

PRNAME=${1%/}
SBUILD=${2%}

if [ "$SBUILD" = "1" ]; then
   rm -rf "$PRNAME/build"
   ./build.sh "$PRNAME"
fi

OUTFILE="$PRNAME/build/$PRNAME.bin"
IMGFILE="./R68Discs/$PRNAME.img"

if [ -f $OUTFILE ]; then
   rm -rf $IMGFILE
   ./create_hfs_disk.sh "$OUTFILE"

   if [ -f $IMGFILE ]; then
        if echo "password" | sudo -kS ./check-qemu.sh; then
            echo "VM is running, proceeding to mount CD-ROM..."
            echo "password" | sudo -kS ./attach-cdrom.sh "$(pwd)/R68Discs/$PRNAME.img"
        else
            echo "VM is not running, please start it first"
        fi
   fi

else
    echo "Build failed: $OUTFILE not found!"
    exit 1
fi
Oh, and I almost forgot, there's a script to check whether QEMU is running or not:

Code: Select all

#!/bin/bash

QEMU_SOCKET="/tmp/qemu-monitor.sock"

check_qemu_process() {
    pgrep -f "qemu-system-ppc.*mac99" > /dev/null
}

check_monitor_socket() {
    [ -S "$QEMU_SOCKET" ] && echo "info status" | nc -U -w 1 "$QEMU_SOCKET" > /dev/null 2>&1
}

if check_qemu_process; then
    if check_monitor_socket; then
        echo "QEMU PowerPC VM is running normally"
        exit 0
    else
        echo "QEMU PowerPC VM process exists but monitor is not responding"
        exit 2
    fi
else
    echo "QEMU PowerPC VM is not running"
    exit 1
fi
So, if QEMU is running, I can compile the code, generating a binary, placing it inside a disc image, then it mounts on QEMU on the fly, I just test it, either by copying the binary or executing directly, then eject the disc. Rinse and repeat.

If QEMU is down, one script compiles the app, the other compiles and puts in an image file.

My next tests will be on logging, dealing with resource forks, and trying to compile a PowerPC app. But so far, that's a neat little system here, and it's much more efficient than typing code into the emulator, in my opinion.

This setup was used with a Hello World example that I found in a tutorial that uses a Retro68 "console" window. But that thing takes over Mac OS by not yielding processor time and doesn't quit. So I moved to a Hello World that uses the Toolbox instead and quits on click. I can share the code here if you'd like. (I didn't try ⌘+⌥+ESC on the original Hello World because I didn't know how, although now with the monitor it might be possible. Still, it's a badly coded Hello World and should be avoided.)

My Retro68 is a fork from kanjitalk755 (which I'm sure I saw in a forum somewhere). He raised a PR that fixed the compiling of the project for me: https://github.com/autc04/Retro68/pull/268

I documented my setup steps for this, I can post here later if there's interest.

I'll look into the serial port now to try and add some logging. (I've read you reply, adespoton, thanks for the pointers.)
thecloud
Student Driver
Posts: 20
Joined: Mon Oct 19, 2015 4:39 am

Re: Classic implementation of 'modern' tech

Post by thecloud »

sentient06 wrote: Sat Nov 23, 2024 2:04 pm Next, I got QEMU running Mac OS 9.2.2. Unfortunately, I need to run as root to use the network. My script goes..

Code: Select all

echo "password" | sudo -kS ./qemu-system-ppc \
# etc.
Instead of embedding your password in plain text inside a script, you can use the macOS keychain, which stores it in an encrypted container. The /usr/bin/security command provides the command-line interface to the keychain. It will let you store and look up a password based on its service and account.

As an example, you can store a password in the keychain (a one-time command) for a service named "QEMU" whose account is "root". The actual strings don't matter, they are just whatever keys you want to use for subsequent lookups. The value for the -w option is your actual password.

Code: Select all

security add-generic-password -s "QEMU" -a "root" -w "s3kr1t"
Then, in a script, you can retrieve that password by its service and account attributes. Your script would look like this:

Code: Select all

echo `security find-generic-password -s "QEMU" -a "root" -w` | sudo -kS ./qemu-system-ppc \
# etc.
User avatar
sentient06
Apple Corer
Posts: 248
Joined: Tue Mar 29, 2011 8:57 pm
Location: London, UK

Re: Classic implementation of 'modern' tech

Post by sentient06 »

thecloud wrote: Sun Nov 24, 2024 7:38 pm Instead of embedding your password in plain text inside a script, you can use the macOS keychain, which stores it in an encrypted container. The /usr/bin/security command provides the command-line interface to the keychain. It will let you store and look up a password based on its service and account.
Nice! Amazing little tip. Thanks for that! I'm converting a bunch of scripts to use this. :smile:
Post Reply