/* Copyright 2018 Wolfgang Thaller. This file is part of Retro68. Retro68 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Retro68 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Retro68. If not, see . */ /* * The following is a simple "Hello, world." MPW tool. * * Everything here should move to a library, * so this can be written using a standard printf. * * The basic idea is that MPW makes the low-memory * global at 0x316 point to a special struct that * contains pointers to callbacks for doing standard * input and output (and a few other things). * The struct also contains argc and argv, * as well as a place to store the tool's exit code. * The tool must exit by returning from main() rather * than by calling ExitToShell. */ #include #include #include #include #if !TARGET_CPU_PPC #include #endif #pragma pack (push, 2) struct MPWFile; struct fsysTable { void (*quit)(void); void (*access)(void); void (*close)(struct MPWFile *); void (*read)(struct MPWFile *); void (*write)(struct MPWFile *); void (*ioctl)(void); }; struct devtable { OSType fsysSig; struct fsysTable fsys; }; struct MPWFile { short flags; short err; struct fsysTable *functions; long cookie; long count; void *buffer; }; struct pgminfo2 { short magic2; int argc; char **argv; char **envp; // 0x0e int exitCode; // 0x12 int x; // 0x16 int y; // 0x1a short tableSize; struct MPWFile *ioptr; struct devtable *devptr; }; struct pgminfo { OSType magic; struct pgminfo2 *rest; }; #pragma pack (pop) // Get MPW's magic struct struct pgminfo2 *getPgmInfo(void) { struct pgminfo *pgm0 = *(struct pgminfo**) 0x316; if(!pgm0) return NULL; if(pgm0 == (struct pgminfo*)-1) return NULL; if(pgm0->magic != 'MPGM') return NULL; if(!pgm0->rest) return NULL; if(pgm0->rest->magic2 != 0x5348) return NULL; return pgm0->rest; } jmp_buf exit_buf; // called by standard library's exit() // Store void _exit(int status) { struct pgminfo2 *pgm = getPgmInfo(); if(pgm) pgm->exitCode = status; longjmp(exit_buf, 1); } const int procInfo = kCStackBased | STACK_ROUTINE_PARAMETER(1, kFourByteCode); int main(int argc, char *argv[], char *envp[]) { struct pgminfo2 *pgm = getPgmInfo(); if(pgm) { struct MPWFile *f = &pgm->ioptr[1]; f->count = 14; f->buffer = "Hello, world.\r"; #if TARGET_CPU_PPC CallUniversalProc((UniversalProcPtr) f->functions->write, procInfo, f); #else f->functions->write(f); #endif } return 0; } #if TARGET_CPU_PPC void __do_global_dtors(void); void __start(void) { if(setjmp(exit_buf)) ; else { atexit(&__do_global_dtors); int result; { char *argv[2] = { "./a.out", NULL }; char *envp[1] = { NULL }; result = main(1, argv, envp); } exit(result); } } void *__dso_handle = &__dso_handle; #else void _start(void) { RETRO68_RELOCATE(); if(setjmp(exit_buf)) ; else { atexit(&Retro68CallDestructors); Retro68CallConstructors(); int result; { char *argv[2] = { "./a.out", NULL }; char *envp[1] = { NULL }; result = main(1, argv, envp); } exit(result); } } #endif