/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, * 2018, 2019, 2020 * Jonathan Schleifer * * 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 "LinkLibGenerator.h" #import "OFInvalidFormatException.h" #import "OFUnsupportedVersionException.h" #import "copyright.h" @implementation LinkLibGenerator - (instancetype)initWithLibrary: (OFXMLElement *)library outputStream: (OFStream *)outputStream { 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]; _outputStream = [outputStream retain]; } @catch (id e) { [self release]; @throw e; } return self; } - (void)dealloc { [_library release]; [_outputStream release]; [super dealloc]; } - (void)generate { OFString *libBase = [_library attributeForName: @"base"].stringValue; OFArray OF_GENERIC(OFXMLElement *) *functions; size_t funcIndex = 0; [_outputStream writeString: COPYRIGHT]; [_outputStream writeString: @"/* This file is automatically generated from library.xml */\n" @"\n" @"#include \"config.h\"\n" @"\n"]; for (OFXMLElement *include in [_library elementsForName: @"include"]) [_outputStream writeFormat: @"#import \"%@\"\n", include.stringValue]; [_outputStream writeFormat: @"\n" @"extern struct Library *%@;\n" @"\n", libBase]; functions = [_library elementsForName: @"function"]; for (OFXMLElement *function in functions) { 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"; [_outputStream writeFormat: @"%@\n%@(", returnType, name]; argumentIndex = 0; for (OFXMLElement *argument in [function elementsForName: @"argument"]) { OFString *argName = [argument attributeForName: @"name"].stringValue; OFString *argType = [argument attributeForName: @"type"].stringValue; if (argumentIndex++ > 0) [_outputStream writeString: @", "]; [_outputStream writeString: argType]; if (![argType hasSuffix: @"*"]) [_outputStream writeString: @" "]; [_outputStream writeString: argName]; } [_outputStream writeFormat: @")\n" @"{\n" @"#if defined(OF_AMIGAOS_M68K)\n" @"\tregister struct Library *a6 __asm__(\"a6\") = %@;\n" @"\t(void)a6;\n" @"\t", libBase]; if (![returnType isEqual: @"void"]) [_outputStream writeString: @"return "]; [_outputStream writeString: @"(("]; [_outputStream writeString: returnType]; if (![returnType hasSuffix: @"*"]) [_outputStream writeString: @" "]; [_outputStream writeString: @"(*)("]; argumentIndex = 0; for (OFXMLElement *argument in arguments) { OFString *argType = [argument attributeForName: @"type"].stringValue; OFString *m68kReg = [argument attributeForName: @"m68k-reg"].stringValue; if (argumentIndex++ > 0) [_outputStream writeString: @", "]; [_outputStream writeString: argType]; if (![argType hasSuffix: @"*"]) [_outputStream writeString: @" "]; [_outputStream writeFormat: @"__asm__(\"%@\")", m68kReg]; } [_outputStream writeFormat: @"))(((uintptr_t)%@) - %zu))(", libBase, 30 + funcIndex * 6]; argumentIndex = 0; for (OFXMLElement *argument in [function elementsForName: @"argument"]) { OFString *argName = [argument attributeForName: @"name"].stringValue; if (argumentIndex++ > 0) [_outputStream writeString: @", "]; [_outputStream writeString: argName]; } [_outputStream writeFormat: @");\n" @"#elif defined(OF_MORPHOS)\n" @"\t__asm__ __volatile__ (\n" @"\t \"mr\t\t%%%%r12, %%0\"\n" @"\t :: \"r\"(%@) : \"r12\"\n" @"\t);\n" @"\n" @"\t", libBase, libBase]; if (![returnType isEqual: @"void"]) [_outputStream writeString: @"return "]; [_outputStream writeString: @"__extension__ (("]; [_outputStream writeString: returnType]; if (![returnType hasSuffix: @"*"]) [_outputStream writeString: @" "]; [_outputStream writeString: @"(*)("]; argumentIndex = 0; for (OFXMLElement *argument in arguments) { OFString *argType = [argument attributeForName: @"type"].stringValue; if (argumentIndex++ > 0) [_outputStream writeString: @", "]; [_outputStream writeString: argType]; } [_outputStream writeFormat: @"))*(void **)(((uintptr_t)%@) - %zu))(", libBase, 28 + funcIndex * 6]; argumentIndex = 0; for (OFXMLElement *argument in [function elementsForName: @"argument"]) { OFString *argName = [argument attributeForName: @"name"].stringValue; if (argumentIndex++ > 0) [_outputStream writeString: @", "]; [_outputStream writeString: argName]; } [_outputStream writeString: @");\n" @"#endif\n"]; if ([function attributeForName: @"noreturn"] != nil) [_outputStream writeString: @"\n\tOF_UNREACHABLE\n"]; [_outputStream writeString: @"}\n"]; if (++funcIndex < functions.count) [_outputStream writeString: @"\n"]; } } @end