/* * Copyright (c) 2008-2023 Jonathan Schleifer <js@nil.im> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" #import "OFArray.h" #import "OFXMLAttribute.h" #import "GlueGenerator.h" #import "OFInvalidFormatException.h" #import "OFUnsupportedVersionException.h" #import "copyright.h" @implementation GlueGenerator - (instancetype)initWithLibrary: (OFXMLElement *)library header: (OFStream *)header implementation: (OFStream *)impl { self = [super init]; @try { OFXMLAttribute *version; if (![library.name isEqual: @"amiga-library"] || library.namespace != nil) @throw [OFInvalidFormatException exception]; if ((version = [library attributeForName: @"version"]) == nil) @throw [OFInvalidFormatException exception]; if (![version.stringValue isEqual: @"1.0"]) @throw [OFUnsupportedVersionException exceptionWithVersion: version.stringValue]; _library = [library retain]; _header = [header retain]; _impl = [impl retain]; } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { [_library release]; [_header release]; [_impl release]; [super dealloc]; } - (void)generate { [_header writeString: COPYRIGHT]; [_impl writeString: COPYRIGHT]; [_header writeString: @"/* This file is automatically generated from amiga-library.xml */" @"\n\n"]; [_impl writeString: @"/* This file is automatically generated from amiga-library.xml */" @"\n\n" @"#include \"config.h\"\n" @"\n" @"#import \"amiga-glue.h\"\n" @"\n"]; for (OFXMLElement *include in [_library elementsForName: @"include"]) [_header writeFormat: @"#import \"%@\"\n", include.stringValue]; [_header writeString: @"\n" @"#ifdef OF_AMIGAOS_M68K\n" @"# define PPC_PARAMS(...) (void)\n" @"# define M68K_ARG(type, name, reg)\t\t\\\n" @"\tregister type reg##name __asm__(#reg);\t\\\n" @"\ttype name = reg##name;\n" @"#else\n" @"# define PPC_PARAMS(...) (__VA_ARGS__)\n" @"# define M68K_ARG(...)\n" @"#endif\n" @"\n"]; [_impl writeString: @"#ifdef OF_MORPHOS\n" @"/* All __saveds functions in this file need to use the SysV " @"ABI */\n" @"__asm__ (\n" @" \".section .text\\n\"\n" @" \".align 2\\n\"\n" @" \"__restore_r13:\\n\"\n" @" \"\tlwz\t%r13, 44(%r12)\\n\"\n" @" \"\tblr\\n\"\n" @");\n" @"#endif\n"]; for (OFXMLElement *function in [_library elementsForName: @"function"]) { OFString *name = [function attributeForName: @"name"].stringValue; OFString *returnType = [function attributeForName: @"return-type"].stringValue; OFArray OF_GENERIC(OFXMLElement *) *arguments = [function elementsForName: @"argument"]; size_t argumentIndex; if (returnType == nil) returnType = @"void"; [_header writeFormat: @"extern %@%@glue_%@", returnType, (![returnType hasSuffix: @"*"] ? @" " : @""), name]; [_impl writeFormat: @"\n" @"%@ __saveds\n" @"glue_%@", returnType, name]; if (arguments.count > 0) { [_header writeString: @" PPC_PARAMS("]; [_impl writeString: @" PPC_PARAMS("]; } else { [_header writeString: @"(void"]; [_impl writeString: @"(void"]; } argumentIndex = 0; for (OFXMLElement *argument in arguments) { OFString *argName = [argument attributeForName: @"name"].stringValue; OFString *argType = [argument attributeForName: @"type"].stringValue; if (argumentIndex++ > 0) { [_header writeString: @", "]; [_impl writeString: @", "]; } [_header writeString: argType]; [_impl writeString: argType]; if (![argType hasSuffix: @"*"]) { [_header writeString: @" "]; [_impl writeString: @" "]; } [_header writeString: argName]; [_impl writeString: argName]; } [_header writeString: @");\n"]; [_impl writeString: @")\n{\n"]; for (OFXMLElement *argument in arguments) { OFString *argName = [argument attributeForName: @"name"].stringValue; OFString *argType = [argument attributeForName: @"type"].stringValue; OFString *m68kReg = [argument attributeForName: @"m68k-reg"].stringValue; [_impl writeFormat: @"\tM68K_ARG(%@, %@, %@)\n", argType, argName, m68kReg]; } if (arguments.count > 0) [_impl writeString: @"\n"]; if (![returnType isEqual: @"void"]) [_impl writeString: @"\treturn "]; else [_impl writeString: @"\t"]; [_impl writeFormat: @"%@(", name]; argumentIndex = 0; for (OFXMLElement *argument in arguments) { OFString *argName = [argument attributeForName: @"name"].stringValue; if (argumentIndex++ > 0) [_impl writeString: @", "]; [_impl writeString: argName]; } [_impl writeString: @");\n}\n"]; } } @end