/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
* 2018, 2019, 2020
* 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 "OFApplication.h"
#import "OFArray.h"
#import "OFFile.h"
#import "OFXMLAttribute.h"
#import "OFXMLElement.h"
#import "OFInvalidFormatException.h"
#import "OFUnsupportedVersionException.h"
#import "copyright.h"
@interface LibraryGenerator: OFObject <OFApplicationDelegate>
@end
OF_APPLICATION_DELEGATE(LibraryGenerator)
@implementation LibraryGenerator
- (void)applicationDidFinishLaunching
{
[self generateLinkLibInDirectory: @"../../src/runtime"];
[OFApplication terminate];
}
- (void)generateLinkLibInDirectory: (OFString *)directory
{
OFXMLElement *library = [OFXMLElement elementWithFile:
[directory stringByAppendingPathComponent: @"library.xml"]];
OFString *linklibPath = [[directory
stringByAppendingPathComponent: @"linklib"]
stringByAppendingPathComponent: @"linklib.m"];
OFFile *linklib = [OFFile fileWithPath: linklibPath
mode: @"w"];
OFArray OF_GENERIC(OFXMLElement *) *functions;
size_t funcIndex = 0;
OFString *libBase;
if (![library.name isEqual: @"amiga-library"] ||
library.namespace != nil)
@throw [OFInvalidFormatException exception];
OFXMLAttribute *version = [library attributeForName: @"version"];
if (version == nil)
@throw [OFInvalidFormatException exception];
if (![version.stringValue isEqual: @"1.0"])
@throw [OFUnsupportedVersionException
exceptionWithVersion: version.stringValue];
libBase = [library attributeForName: @"base"].stringValue;
[linklib writeString: COPYRIGHT];
[linklib writeString:
@"/* This file is automatically generated from library.xml */\n"
@"\n"
@"#include \"config.h\"\n"
@"\n"];
for (OFXMLElement *include in [library elementsForName: @"include"])
[linklib writeFormat: @"#import \"%@\"\n", include.stringValue];
[linklib 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";
[linklib 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)
[linklib writeString: @", "];
[linklib writeString: argType];
if (![argType hasSuffix: @"*"])
[linklib writeString: @" "];
[linklib writeString: argName];
}
[linklib 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"])
[linklib writeString: @"return "];
[linklib writeString: @"(("];
[linklib writeString: returnType];
if (![returnType hasSuffix: @"*"])
[linklib writeString: @" "];
[linklib writeString: @"(*)("];
argumentIndex = 0;
for (OFXMLElement *argument in arguments) {
OFString *argType =
[argument attributeForName: @"type"].stringValue;
OFString *m68kReg = [argument
attributeForName: @"m68k-reg"].stringValue;
if (argumentIndex++ > 0)
[linklib writeString: @", "];
[linklib writeString: argType];
if (![argType hasSuffix: @"*"])
[linklib writeString: @" "];
[linklib writeFormat: @"__asm__(\"%@\")", m68kReg];
}
[linklib 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)
[linklib writeString: @", "];
[linklib writeString: argName];
}
[linklib 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"])
[linklib writeString: @"return "];
[linklib writeString: @"(("];
[linklib writeString: returnType];
if (![returnType hasSuffix: @"*"])
[linklib writeString: @" "];
[linklib writeString: @"(*)("];
argumentIndex = 0;
for (OFXMLElement *argument in arguments) {
OFString *argType =
[argument attributeForName: @"type"].stringValue;
if (argumentIndex++ > 0)
[linklib writeString: @", "];
[linklib writeString: argType];
}
[linklib 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)
[linklib writeString: @", "];
[linklib writeString: argName];
}
[linklib writeString: @");\n"
@"#endif\n"];
if ([function attributeForName: @"noreturn"] != nil)
[linklib writeString: @"\n\tOF_UNREACHABLE\n"];
[linklib writeString: @"}\n"];
if (++funcIndex < functions.count)
[linklib writeString: @"\n"];
}
}
@end